From 802af9d1bd52fb812346a8bae48048449a46489d Mon Sep 17 00:00:00 2001 From: Marius Ungureanu Date: Thu, 4 Jun 2015 14:18:12 +0300 Subject: [PATCH 01/19] 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. --- LibGit2Sharp/AuthenticationException.cs | 55 ++++++++++++++++++++ LibGit2Sharp/Core/Ensure.cs | 3 +- LibGit2Sharp/Core/NativeMethods.cs | 18 +++++++ LibGit2Sharp/LibGit2Sharp.csproj | 4 ++ LibGit2Sharp/RemoteCallbacks.cs | 8 +++ LibGit2Sharp/SshAgentCredentials.cs | 36 +++++++++++++ LibGit2Sharp/SshUserKeyCredentials.cs | 66 ++++++++++++++++++++++++ LibGit2Sharp/SupportedCredentialTypes.cs | 10 ++++ LibGit2Sharp/UsernameQueryCredentials.cs | 31 +++++++++++ 9 files changed, 230 insertions(+), 1 deletion(-) create mode 100644 LibGit2Sharp/AuthenticationException.cs create mode 100644 LibGit2Sharp/SshAgentCredentials.cs create mode 100644 LibGit2Sharp/SshUserKeyCredentials.cs create mode 100644 LibGit2Sharp/UsernameQueryCredentials.cs diff --git a/LibGit2Sharp/AuthenticationException.cs b/LibGit2Sharp/AuthenticationException.cs new file mode 100644 index 000000000..acbf331ff --- /dev/null +++ b/LibGit2Sharp/AuthenticationException.cs @@ -0,0 +1,55 @@ +using System; +using System.Runtime.Serialization; +using LibGit2Sharp.Core; + +namespace LibGit2Sharp +{ + /// + /// The exception that is thrown when an operation which requires an + /// authentication fails. + /// + [Serializable] + public class AuthenticationException : LibGit2SharpException + { + /// + /// Initializes a new instance of the class. + /// + public AuthenticationException() + { + } + + /// + /// Initializes a new instance of the class with a specified error message. + /// + /// A message that describes the error. + public AuthenticationException(string message) + : base(message) + { + } + + /// + /// Initializes a new instance of the class with a specified error message and a reference to the inner exception that is the cause of this exception. + /// + /// The error message that explains the reason for the exception. + /// The exception that is the cause of the current exception. If the parameter is not a null reference, the current exception is raised in a catch block that handles the inner exception. + public AuthenticationException(string message, Exception innerException) + : base(message, innerException) + { + } + + /// + /// Initializes a new instance of the class with a serialized data. + /// + /// The that holds the serialized object data about the exception being thrown. + /// The that contains contextual information about the source or destination. + 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 e0da6413b..627968993 100644 --- a/LibGit2Sharp/Core/Ensure.cs +++ b/LibGit2Sharp/Core/Ensure.cs @@ -127,7 +127,8 @@ private static readonly Dictionary 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 a1b5b5cf1..3b98c9c4a 100644 --- a/LibGit2Sharp/Core/NativeMethods.cs +++ b/LibGit2Sharp/Core/NativeMethods.cs @@ -459,6 +459,24 @@ internal static extern int git_cred_userpass_plaintext_new( [MarshalAs(UnmanagedType.CustomMarshaler, MarshalCookie = UniqueId.UniqueIdentifier, MarshalTypeRef = typeof(StrictUtf8Marshaler))] string username, [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, diff --git a/LibGit2Sharp/LibGit2Sharp.csproj b/LibGit2Sharp/LibGit2Sharp.csproj index 561ad7676..51351469c 100644 --- a/LibGit2Sharp/LibGit2Sharp.csproj +++ b/LibGit2Sharp/LibGit2Sharp.csproj @@ -47,6 +47,7 @@ + @@ -167,6 +168,8 @@ + + @@ -363,6 +366,7 @@ + diff --git a/LibGit2Sharp/RemoteCallbacks.cs b/LibGit2Sharp/RemoteCallbacks.cs index 42037a22e..e57756892 100644 --- a/LibGit2Sharp/RemoteCallbacks.cs +++ b/LibGit2Sharp/RemoteCallbacks.cs @@ -284,6 +284,14 @@ private int GitCredentialHandler( { 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 000000000..5812df2d3 --- /dev/null +++ b/LibGit2Sharp/SshAgentCredentials.cs @@ -0,0 +1,36 @@ +using System; +using LibGit2Sharp.Core; + +namespace LibGit2Sharp +{ + /// + /// Class that holds SSH agent credentials for remote repository access. + /// + public sealed class SshAgentCredentials : Credentials + { + /// + /// Callback to acquire a credential object. + /// + /// The newly created credential object. + /// 0 for success, < 0 to indicate an error, > 0 to indicate no credential was acquired. + 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); + } + + /// + /// Username for SSH authentication. + /// + public string Username { get; set; } + } +} diff --git a/LibGit2Sharp/SshUserKeyCredentials.cs b/LibGit2Sharp/SshUserKeyCredentials.cs new file mode 100644 index 000000000..e5c9e4701 --- /dev/null +++ b/LibGit2Sharp/SshUserKeyCredentials.cs @@ -0,0 +1,66 @@ +using System; +using LibGit2Sharp.Core; + +namespace LibGit2Sharp +{ + /// + /// Class that holds SSH username with key credentials for remote repository access. + /// + public sealed class SshUserKeyCredentials : Credentials + { + /// + /// Callback to acquire a credential object. + /// + /// The newly created credential object. + /// 0 for success, < 0 to indicate an error, > 0 to indicate no credential was acquired. + 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); + } + + /// + /// Username for SSH authentication. + /// + public string Username { get; set; } + + /// + /// Public key file location for SSH authentication. + /// + public string PublicKey { get; set; } + + /// + /// Private key file location for SSH authentication. + /// + public string PrivateKey { get; set; } + + /// + /// Passphrase for SSH authentication. + /// + public string Passphrase { get; set; } + } +} diff --git a/LibGit2Sharp/SupportedCredentialTypes.cs b/LibGit2Sharp/SupportedCredentialTypes.cs index bc38a259e..077597011 100644 --- a/LibGit2Sharp/SupportedCredentialTypes.cs +++ b/LibGit2Sharp/SupportedCredentialTypes.cs @@ -18,5 +18,15 @@ public enum SupportedCredentialTypes /// Ask Windows to provide its default credentials for the current user (e.g. NTLM) /// Default = (1 << 1), + + /// + /// SSH with username and public/private keys. (SshUserKeyCredentials, SshAgentCredentials). + /// + Ssh = (1 << 2), + + /// + /// Queries the server with the given username, then later returns the supported credential types. + /// + UsernameQuery = (1 << 3), } } diff --git a/LibGit2Sharp/UsernameQueryCredentials.cs b/LibGit2Sharp/UsernameQueryCredentials.cs new file mode 100644 index 000000000..14981d74e --- /dev/null +++ b/LibGit2Sharp/UsernameQueryCredentials.cs @@ -0,0 +1,31 @@ +using System; +using LibGit2Sharp.Core; + +namespace LibGit2Sharp +{ + /// + /// Class that holds username query credentials for remote repository access. + /// + public sealed class UsernameQueryCredentials : Credentials + { + /// + /// Callback to acquire a credential object. + /// + /// The newly created credential object. + /// 0 for success, < 0 to indicate an error, > 0 to indicate no credential was acquired. + 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); + } + + /// + /// Username for querying the server for supported authentication. + /// + public string Username { get; set; } + } +} From c9977fc6ff959ffd937e27ff4b6f2692048574de Mon Sep 17 00:00:00 2001 From: Leonard Buskin Date: Mon, 31 Oct 2016 12:23:56 -0700 Subject: [PATCH 02/19] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e82907553..2d3384673 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# LibGit2Sharp +# LibGit2Sharp (+SSH) **LibGit2Sharp brings all the might and speed of [libgit2][libgit2], a native Git implementation, to the managed world of .NET and Mono.** From f456c815e3f672d9aa0388a400edb95ab4666876 Mon Sep 17 00:00:00 2001 From: Leonard Buskin Date: Mon, 31 Oct 2016 14:32:38 -0700 Subject: [PATCH 03/19] Change Travis-CI notifications --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index d0e35f585..e7ce6e9c9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -34,4 +34,4 @@ branches: # Notify of build changes notifications: email: - - emeric.fermas@gmail.com + - leonardbuskin@gmail.com From 8045fbcb89961720b3a09545772ab8e685166c56 Mon Sep 17 00:00:00 2001 From: Leonard Buskin Date: Mon, 31 Oct 2016 14:33:00 -0700 Subject: [PATCH 04/19] Change Appveyor notifications --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index dd4c82f1e..b518fa45a 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -180,5 +180,5 @@ after_test: notifications: - provider: Email to: - - emeric.fermas@gmail.com + - leonardbuskin@gmail.com on_build_status_changed: true From f2cebbcd227711c7aa9a38d718ece5a49f4ec587 Mon Sep 17 00:00:00 2001 From: Leonard Buskin Date: Mon, 31 Oct 2016 14:33:53 -0700 Subject: [PATCH 05/19] Change projectUrl, tags --- nuget.package/LibGit2Sharp.nuspec | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nuget.package/LibGit2Sharp.nuspec b/nuget.package/LibGit2Sharp.nuspec index c8381e2cf..2b585d8bb 100644 --- a/nuget.package/LibGit2Sharp.nuspec +++ b/nuget.package/LibGit2Sharp.nuspec @@ -6,12 +6,12 @@ $author$ nulltoken https://github.com/libgit2/libgit2sharp/raw/master/LICENSE.md - https://github.com/libgit2/libgit2sharp/ + https://github.com/leobuskin/libgit2sharp-ssh/ false $description$ https://github.com/libgit2/libgit2sharp/blob/master/CHANGES.md#libgit2sharp-changes https://github.com/libgit2/libgit2sharp/raw/master/square-logo.png - libgit2 git wrapper bindings API dvcs vcs + libgit2 git wrapper bindings API dvcs vcs ssh From c9d64f243b26cbe8737171251f9ae3287c90b739 Mon Sep 17 00:00:00 2001 From: Leonard Buskin Date: Tue, 1 Nov 2016 10:53:53 -0700 Subject: [PATCH 06/19] First stable build --- LibGit2Sharp/packages.config | 2 +- appveyor.yml | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/LibGit2Sharp/packages.config b/LibGit2Sharp/packages.config index ee6d18e01..7a24d2196 100644 --- a/LibGit2Sharp/packages.config +++ b/LibGit2Sharp/packages.config @@ -1,4 +1,4 @@  - + diff --git a/appveyor.yml b/appveyor.yml index b518fa45a..e57a218ea 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -11,11 +11,11 @@ clone_folder: C:\projects\libgit2sharp environment: coveralls_token: - secure: ixIsBslo9NheDb5lJknF58EYdgvZ0r3/L0ecRiXjfXmjHBLvoSU6/ZRwaMM+BAlG + secure: yJeN1Bg1gr+uMQwGuyI0eB1DaOrYFlCGdFvsxQ+ghRY1WYcTtxrmYVWET2YHZHkO coverity_token: - secure: nuzUT+HecXGIi3KaPd/1hgFEZJan/j6+oNbPV75JKjk= + secure: Qt0nW2AGSg53C5CtP/qjXShqq8GJQIzeKqV6bPbTLRk= coverity_email: - secure: eGVilNg1Yuq+Xj+SW8r3WCtjnzhoDV0sNJkma4NRq7A= + secure: SdBQ5hDR0q/uA+NNJPiKM5nv606Q2zJOg0BlAP2hwds= version : 0.23.0 matrix: - xunit_runner: xunit.console.x86.exe @@ -172,7 +172,7 @@ after_test: --form "file=@$Env:APPVEYOR_BUILD_FOLDER\$Env:APPVEYOR_PROJECT_NAME.zip" ` --form version="$Env:APPVEYOR_REPO_COMMIT" ` --form description="CI server scheduled build." ` - https://scan.coverity.com/builds?project=libgit2%2Flibgit2sharp + https://scan.coverity.com/builds?project=leobuskin%2Flibgit2sharp-ssh cat .\curl-out.txt } From 905e1374c8202e059158a481024f327fffac236b Mon Sep 17 00:00:00 2001 From: Leonard Buskin Date: Tue, 1 Nov 2016 11:00:20 -0700 Subject: [PATCH 07/19] Fix native binaries version --- LibGit2Sharp/LibGit2Sharp.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LibGit2Sharp/LibGit2Sharp.csproj b/LibGit2Sharp/LibGit2Sharp.csproj index 02792ad2c..6be1ed5a3 100644 --- a/LibGit2Sharp/LibGit2Sharp.csproj +++ b/LibGit2Sharp/LibGit2Sharp.csproj @@ -1,6 +1,6 @@  - + Debug AnyCPU From 3c33f5beeb0e459d67c20fa5acf56aeb3d33b6ce Mon Sep 17 00:00:00 2001 From: Leonard Buskin Date: Tue, 1 Nov 2016 11:05:26 -0700 Subject: [PATCH 08/19] Fixes native binaries version (second) --- LibGit2Sharp/LibGit2Sharp.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LibGit2Sharp/LibGit2Sharp.csproj b/LibGit2Sharp/LibGit2Sharp.csproj index 6be1ed5a3..e8acfbd5a 100644 --- a/LibGit2Sharp/LibGit2Sharp.csproj +++ b/LibGit2Sharp/LibGit2Sharp.csproj @@ -388,7 +388,7 @@ This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - +