diff --git a/LibGit2Sharp/AuthenticationException.cs b/LibGit2Sharp/AuthenticationException.cs
new file mode 100644
index 000000000..416d01719
--- /dev/null
+++ b/LibGit2Sharp/AuthenticationException.cs
@@ -0,0 +1,58 @@
+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, GitErrorCategory category)
+ : base(message, category)
+ { }
+
+ 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 3cf03d24b..d32efd1e5 100644
--- a/LibGit2Sharp/Core/Ensure.cs
+++ b/LibGit2Sharp/Core/Ensure.cs
@@ -128,6 +128,7 @@ private static readonly Dictionary new LockedFileException(m, c) },
{ GitErrorCode.NotFound, (m, c) => new NotFoundException(m, c) },
{ GitErrorCode.Peel, (m, c) => new PeelException(m, c) },
+ { GitErrorCode.Auth, (m, c) => new AuthenticationException(m, c) },
};
private static unsafe void HandleError(int result)
diff --git a/LibGit2Sharp/Core/NativeMethods.cs b/LibGit2Sharp/Core/NativeMethods.cs
index e20d755ba..f45b211c2 100644
--- a/LibGit2Sharp/Core/NativeMethods.cs
+++ b/LibGit2Sharp/Core/NativeMethods.cs
@@ -599,6 +599,24 @@ internal static extern int git_cred_userpass_plaintext_new(
[DllImport(libgit2, CallingConvention = CallingConvention.Cdecl)]
internal static extern void git_cred_free(IntPtr cred);
+ [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, CallingConvention = CallingConvention.Cdecl)]
internal static extern unsafe int git_describe_commit(
out git_describe_result* describe,
diff --git a/LibGit2Sharp/LibGit2Sharp.csproj b/LibGit2Sharp/LibGit2Sharp.csproj
index f690c9107..4a52626d0 100644
--- a/LibGit2Sharp/LibGit2Sharp.csproj
+++ b/LibGit2Sharp/LibGit2Sharp.csproj
@@ -33,7 +33,7 @@
-
+
diff --git a/LibGit2Sharp/RemoteCallbacks.cs b/LibGit2Sharp/RemoteCallbacks.cs
index ce5dccf81..2cd8569d3 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;
+ }
ptr = IntPtr.Zero;
try
diff --git a/LibGit2Sharp/SshAgentCredentials.cs b/LibGit2Sharp/SshAgentCredentials.cs
new file mode 100644
index 000000000..67267b656
--- /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..f32916fcc
--- /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; }
+ }
+}
diff --git a/README.md b/README.md
index 3aafdceb1..52adc70e6 100644
--- a/README.md
+++ b/README.md
@@ -10,6 +10,41 @@
- [NuGet package](http://nuget.org/List/Packages/LibGit2Sharp)
- [Source code](https://github.com/libgit2/libgit2sharp/)
+## MadCap steps for building locally
+
+1. Clone this repository as well as libgit2sharp.nativebinaries so they are in folders next to each other:
+
+ ```
+ git clone https://github.com/madcapsoftware/libgit2sharp.git
+ git clone https://github.com/madcapsoftware/libgit2sharp.nativebinaries.git
+ ```
+
+ Example folder structure:
+
+ ```
+ C:\source\madcapsoftware\libgit2sharp
+ C:\source\madcapsoftware\libgit2sharp.nativebinaries
+ ```
+
+2. Open a powershell terminal to the root of the libgit2sharp.nativebinaries repository
+3. Build `libgit2sharp.nativebinaries` and create a local nuget package, specifying the version to use. The version at time of writing matches the main `libgit2sharp.nativebinaries` repository with a `-ssh` suffix.
+
+ ```
+ .\UpdateAllLibsToSha.ps1 -libgit2sha main -libssh2sha master -zlibsha master
+ .\build.libgit2.ps1 -x86 -x64 -libssh2
+ .\nuget.exe Pack nuget.package/NativeBinaries.nuspec -Version 2.0.320-ssh -NoPackageAnalysis
+ ```
+
+4. Open the LibGit2Sharp solution
+5. Right click the LibGit2Sharp project and click "Manage NuGet packages..."
+6. Make sure "Package source" is set to "libgit2sharp.nativebinaries" which is a local relative path to the package generated in step 3
+7. Check "Include prerelease" as the package version is a prerelease version due to the `-ssh` suffix
+8. Click Install to update to the latest version
+9. Build the `Release` solution configuration.
+
+NOTE: The version of the resulting dll is based on the most recent git tag, which in this case is `0.27.2-ssh.0`.
+For more details, see: https://github.com/adamralph/minver
+
## Troubleshooting and support
- Usage or programming related question? Post it on [StackOverflow](http://stackoverflow.com/questions/tagged/libgit2sharp) using the tag *libgit2sharp*
diff --git a/nuget.config b/nuget.config
index 35696f810..678a24680 100644
--- a/nuget.config
+++ b/nuget.config
@@ -2,5 +2,6 @@
+