diff options
author | Marius Ungureanu <marius.ungureanu@xamarin.com> | 2015-06-04 14:18:12 +0300 |
---|---|---|
committer | Marius Ungureanu <marius.ungureanu@xamarin.com> | 2015-08-25 21:31:16 +0300 |
commit | 78fba9077b52f3b36951e7823aa0bb37fe30eb60 (patch) | |
tree | d93615c784067465207399229d8e91cc07913014 | |
parent | 974237c4f49dd20624467559b6b6efa5b36169be (diff) |
Introduce SSH functionality
Added SshAgentCredentials for querying ssh-agent, SshUserKeyCredentials
for authenticating with a given ssh key-pair.
Introduced UsernameQueryCredentials which returns the supported credential
types.
Authentication exceptions are now translated from libgit2.
-rw-r--r-- | LibGit2Sharp/AuthenticationException.cs | 55 | ||||
-rw-r--r-- | LibGit2Sharp/Core/Ensure.cs | 3 | ||||
-rw-r--r-- | LibGit2Sharp/Core/NativeMethods.cs | 18 | ||||
-rw-r--r-- | LibGit2Sharp/LibGit2Sharp.csproj | 4 | ||||
-rw-r--r-- | LibGit2Sharp/RemoteCallbacks.cs | 8 | ||||
-rw-r--r-- | LibGit2Sharp/SshAgentCredentials.cs | 36 | ||||
-rw-r--r-- | LibGit2Sharp/SshUserKeyCredentials.cs | 66 | ||||
-rw-r--r-- | LibGit2Sharp/SupportedCredentialTypes.cs | 10 | ||||
-rw-r--r-- | LibGit2Sharp/UsernameQueryCredentials.cs | 31 |
9 files changed, 230 insertions, 1 deletions
diff --git a/LibGit2Sharp/AuthenticationException.cs b/LibGit2Sharp/AuthenticationException.cs new file mode 100644 index 00000000..acbf331f --- /dev/null +++ b/LibGit2Sharp/AuthenticationException.cs @@ -0,0 +1,55 @@ +using System; +using System.Runtime.Serialization; +using LibGit2Sharp.Core; + +namespace LibGit2Sharp +{ + /// <summary> + /// The exception that is thrown when an operation which requires an + /// authentication fails. + /// </summary> + [Serializable] + public class AuthenticationException : LibGit2SharpException + { + /// <summary> + /// Initializes a new instance of the <see cref="LibGit2Sharp.AuthenticationException"/> class. + /// </summary> + public AuthenticationException() + { + } + + /// <summary> + /// Initializes a new instance of the <see cref="LibGit2Sharp.AuthenticationException"/> class with a specified error message. + /// </summary> + /// <param name="message">A message that describes the error.</param> + public AuthenticationException(string message) + : base(message) + { + } + + /// <summary> + /// Initializes a new instance of the <see cref="LibGit2Sharp.AuthenticationException"/> class with a specified error message and a reference to the inner exception that is the cause of this exception. + /// </summary> + /// <param name="message">The error message that explains the reason for the exception.</param> + /// <param name="innerException">The exception that is the cause of the current exception. If the <paramref name="innerException"/> parameter is not a null reference, the current exception is raised in a catch block that handles the inner exception.</param> + public AuthenticationException(string message, Exception innerException) + : base(message, innerException) + { + } + + /// <summary> + /// Initializes a new instance of the <see cref="LibGit2Sharp.AuthenticationException"/> class with a serialized data. + /// </summary> + /// <param name="info">The <see cref="SerializationInfo"/> that holds the serialized object data about the exception being thrown.</param> + /// <param name="context">The <see cref="StreamingContext"/> that contains contextual information about the source or destination.</param> + protected AuthenticationException(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + + internal AuthenticationException(string message, GitErrorCode code, GitErrorCategory category) + : base(message, code, category) + { + } + } +} diff --git a/LibGit2Sharp/Core/Ensure.cs b/LibGit2Sharp/Core/Ensure.cs index e0da6413..62796899 100644 --- a/LibGit2Sharp/Core/Ensure.cs +++ b/LibGit2Sharp/Core/Ensure.cs @@ -127,7 +127,8 @@ namespace LibGit2Sharp.Core { GitErrorCode.Conflict, (m, r, c) => new CheckoutConflictException(m, r, c) }, { GitErrorCode.LockedFile, (m, r, c) => new LockedFileException(m, r, c) }, { GitErrorCode.NotFound, (m, r, c) => new NotFoundException(m, r, c) }, - { GitErrorCode.Peel, (m, r, c) => new PeelException(m, r, c) }, + { GitErrorCode.Peel, (m, r, c) => new PeelException(m, r, c) }, + { GitErrorCode.Auth, (m, r, c) => new AuthenticationException(m, r, c) }, }; private static void HandleError(int result) diff --git a/LibGit2Sharp/Core/NativeMethods.cs b/LibGit2Sharp/Core/NativeMethods.cs index 713c2160..406419a0 100644 --- a/LibGit2Sharp/Core/NativeMethods.cs +++ b/LibGit2Sharp/Core/NativeMethods.cs @@ -460,6 +460,24 @@ namespace LibGit2Sharp.Core [MarshalAs(UnmanagedType.CustomMarshaler, MarshalCookie = UniqueId.UniqueIdentifier, MarshalTypeRef = typeof(StrictUtf8Marshaler))] string password); [DllImport(libgit2)] + internal static extern int git_cred_ssh_key_new( + out IntPtr cred, + [MarshalAs(UnmanagedType.CustomMarshaler, MarshalCookie = UniqueId.UniqueIdentifier, MarshalTypeRef = typeof(StrictUtf8Marshaler))] string username, + [MarshalAs(UnmanagedType.CustomMarshaler, MarshalCookie = UniqueId.UniqueIdentifier, MarshalTypeRef = typeof(StrictUtf8Marshaler))] string publickey, + [MarshalAs(UnmanagedType.CustomMarshaler, MarshalCookie = UniqueId.UniqueIdentifier, MarshalTypeRef = typeof(StrictUtf8Marshaler))] string privatekey, + [MarshalAs(UnmanagedType.CustomMarshaler, MarshalCookie = UniqueId.UniqueIdentifier, MarshalTypeRef = typeof(StrictUtf8Marshaler))] string passphrase); + + [DllImport(libgit2)] + internal static extern int git_cred_ssh_key_from_agent( + out IntPtr cred, + [MarshalAs(UnmanagedType.CustomMarshaler, MarshalCookie = UniqueId.UniqueIdentifier, MarshalTypeRef = typeof(StrictUtf8Marshaler))] string username); + + [DllImport(libgit2)] + internal static extern int git_cred_username_new( + out IntPtr cred, + [MarshalAs(UnmanagedType.CustomMarshaler, MarshalCookie = UniqueId.UniqueIdentifier, MarshalTypeRef = typeof(StrictUtf8Marshaler))] string username); + + [DllImport(libgit2)] internal static extern int git_describe_commit( out DescribeResultSafeHandle describe, GitObjectSafeHandle committish, diff --git a/LibGit2Sharp/LibGit2Sharp.csproj b/LibGit2Sharp/LibGit2Sharp.csproj index 561ad767..51351469 100644 --- a/LibGit2Sharp/LibGit2Sharp.csproj +++ b/LibGit2Sharp/LibGit2Sharp.csproj @@ -47,6 +47,7 @@ <Compile Include="AfterRebaseStepInfo.cs" /> <Compile Include="AmbiguousSpecificationException.cs" /> <Compile Include="ArchiverBase.cs" /> + <Compile Include="AuthenticationException.cs" /> <Compile Include="BareRepositoryException.cs" /> <Compile Include="BeforeRebaseStepInfo.cs" /> <Compile Include="BlameHunkCollection.cs" /> @@ -167,6 +168,8 @@ <Compile Include="RevertResult.cs" /> <Compile Include="RevertOptions.cs" /> <Compile Include="SecureUsernamePasswordCredentials.cs" /> + <Compile Include="SshAgentCredentials.cs" /> + <Compile Include="SshUserKeyCredentials.cs" /> <Compile Include="StageOptions.cs" /> <Compile Include="StatusOptions.cs" /> <Compile Include="SimilarityOptions.cs" /> @@ -363,6 +366,7 @@ <Compile Include="TreeEntryDefinition.cs" /> <Compile Include="UserCanceledException.cs" /> <Compile Include="UsernamePasswordCredentials.cs" /> + <Compile Include="UsernameQueryCredentials.cs" /> <Compile Include="Version.cs" /> <Compile Include="VoidReference.cs" /> <Compile Include="Core\RawContentStream.cs" /> diff --git a/LibGit2Sharp/RemoteCallbacks.cs b/LibGit2Sharp/RemoteCallbacks.cs index 42037a22..e5775689 100644 --- a/LibGit2Sharp/RemoteCallbacks.cs +++ b/LibGit2Sharp/RemoteCallbacks.cs @@ -284,6 +284,14 @@ namespace LibGit2Sharp { types |= SupportedCredentialTypes.Default; } + if (credTypes.HasFlag(GitCredentialType.SshKey)) + { + types |= SupportedCredentialTypes.Ssh; + } + if (credTypes.HasFlag(GitCredentialType.Username)) + { + types |= SupportedCredentialTypes.UsernameQuery; + } var cred = CredentialsProvider(url, username, types); diff --git a/LibGit2Sharp/SshAgentCredentials.cs b/LibGit2Sharp/SshAgentCredentials.cs new file mode 100644 index 00000000..5812df2d --- /dev/null +++ b/LibGit2Sharp/SshAgentCredentials.cs @@ -0,0 +1,36 @@ +using System; +using LibGit2Sharp.Core; + +namespace LibGit2Sharp +{ + /// <summary> + /// Class that holds SSH agent credentials for remote repository access. + /// </summary> + public sealed class SshAgentCredentials : Credentials + { + /// <summary> + /// Callback to acquire a credential object. + /// </summary> + /// <param name="cred">The newly created credential object.</param> + /// <returns>0 for success, < 0 to indicate an error, > 0 to indicate no credential was acquired.</returns> + protected internal override int GitCredentialHandler(out IntPtr cred) + { + if (!GlobalSettings.Version.Features.HasFlag(BuiltInFeatures.Ssh)) + { + throw new InvalidOperationException("LibGit2 was not built with SSH support."); + } + + if (Username == null) + { + throw new InvalidOperationException("SshAgentCredentials contains a null Username."); + } + + return NativeMethods.git_cred_ssh_key_from_agent(out cred, Username); + } + + /// <summary> + /// Username for SSH authentication. + /// </summary> + public string Username { get; set; } + } +} diff --git a/LibGit2Sharp/SshUserKeyCredentials.cs b/LibGit2Sharp/SshUserKeyCredentials.cs new file mode 100644 index 00000000..e5c9e470 --- /dev/null +++ b/LibGit2Sharp/SshUserKeyCredentials.cs @@ -0,0 +1,66 @@ +using System; +using LibGit2Sharp.Core; + +namespace LibGit2Sharp +{ + /// <summary> + /// Class that holds SSH username with key credentials for remote repository access. + /// </summary> + public sealed class SshUserKeyCredentials : Credentials + { + /// <summary> + /// Callback to acquire a credential object. + /// </summary> + /// <param name="cred">The newly created credential object.</param> + /// <returns>0 for success, < 0 to indicate an error, > 0 to indicate no credential was acquired.</returns> + protected internal override int GitCredentialHandler(out IntPtr cred) + { + if (!GlobalSettings.Version.Features.HasFlag(BuiltInFeatures.Ssh)) + { + throw new InvalidOperationException("LibGit2 was not built with SSH support."); + } + + if (Username == null) + { + throw new InvalidOperationException("SshUserKeyCredentials contains a null Username."); + } + + if (Passphrase == null) + { + throw new InvalidOperationException("SshUserKeyCredentials contains a null Passphrase."); + } + + if (PublicKey == null) + { + throw new InvalidOperationException("SshUserKeyCredentials contains a null PublicKey."); + } + + if (PrivateKey == null) + { + throw new InvalidOperationException("SshUserKeyCredentials contains a null PrivateKey."); + } + + return NativeMethods.git_cred_ssh_key_new(out cred, Username, PublicKey, PrivateKey, Passphrase); + } + + /// <summary> + /// Username for SSH authentication. + /// </summary> + public string Username { get; set; } + + /// <summary> + /// Public key file location for SSH authentication. + /// </summary> + public string PublicKey { get; set; } + + /// <summary> + /// Private key file location for SSH authentication. + /// </summary> + public string PrivateKey { get; set; } + + /// <summary> + /// Passphrase for SSH authentication. + /// </summary> + public string Passphrase { get; set; } + } +} diff --git a/LibGit2Sharp/SupportedCredentialTypes.cs b/LibGit2Sharp/SupportedCredentialTypes.cs index bc38a259..07759701 100644 --- a/LibGit2Sharp/SupportedCredentialTypes.cs +++ b/LibGit2Sharp/SupportedCredentialTypes.cs @@ -18,5 +18,15 @@ namespace LibGit2Sharp /// Ask Windows to provide its default credentials for the current user (e.g. NTLM) /// </summary> Default = (1 << 1), + + /// <summary> + /// SSH with username and public/private keys. (SshUserKeyCredentials, SshAgentCredentials). + /// </summary> + Ssh = (1 << 2), + + /// <summary> + /// Queries the server with the given username, then later returns the supported credential types. + /// </summary> + UsernameQuery = (1 << 3), } } diff --git a/LibGit2Sharp/UsernameQueryCredentials.cs b/LibGit2Sharp/UsernameQueryCredentials.cs new file mode 100644 index 00000000..14981d74 --- /dev/null +++ b/LibGit2Sharp/UsernameQueryCredentials.cs @@ -0,0 +1,31 @@ +using System; +using LibGit2Sharp.Core; + +namespace LibGit2Sharp +{ + /// <summary> + /// Class that holds username query credentials for remote repository access. + /// </summary> + public sealed class UsernameQueryCredentials : Credentials + { + /// <summary> + /// Callback to acquire a credential object. + /// </summary> + /// <param name="cred">The newly created credential object.</param> + /// <returns>0 for success, < 0 to indicate an error, > 0 to indicate no credential was acquired.</returns> + protected internal override int GitCredentialHandler(out IntPtr cred) + { + if (Username == null) + { + throw new InvalidOperationException("UsernameQueryCredentials contains a null Username."); + } + + return NativeMethods.git_cred_username_new(out cred, Username); + } + + /// <summary> + /// Username for querying the server for supported authentication. + /// </summary> + public string Username { get; set; } + } +} |