diff --git a/Lib/NativeBinaries/amd64/git2-9bbc8f3.dll b/Lib/NativeBinaries/amd64/git2-9bbc8f3.dll
index f162e6c60..4700837ad 100644
Binary files a/Lib/NativeBinaries/amd64/git2-9bbc8f3.dll and b/Lib/NativeBinaries/amd64/git2-9bbc8f3.dll differ
diff --git a/Lib/NativeBinaries/amd64/git2-9bbc8f3.pdb b/Lib/NativeBinaries/amd64/git2-9bbc8f3.pdb
index 43f4171fc..b4b9c04c5 100644
Binary files a/Lib/NativeBinaries/amd64/git2-9bbc8f3.pdb and b/Lib/NativeBinaries/amd64/git2-9bbc8f3.pdb differ
diff --git a/Lib/NativeBinaries/x86/git2-9bbc8f3.dll b/Lib/NativeBinaries/x86/git2-9bbc8f3.dll
index db04bb5b2..b061e8d51 100644
Binary files a/Lib/NativeBinaries/x86/git2-9bbc8f3.dll and b/Lib/NativeBinaries/x86/git2-9bbc8f3.dll differ
diff --git a/Lib/NativeBinaries/x86/git2-9bbc8f3.pdb b/Lib/NativeBinaries/x86/git2-9bbc8f3.pdb
index 89c4624fc..cf55c0bc4 100644
Binary files a/Lib/NativeBinaries/x86/git2-9bbc8f3.pdb and b/Lib/NativeBinaries/x86/git2-9bbc8f3.pdb differ
diff --git a/LibGit2Sharp.Tests/GlobalSettingsFixture.cs b/LibGit2Sharp.Tests/GlobalSettingsFixture.cs
index 698595042..fc791d6ca 100644
--- a/LibGit2Sharp.Tests/GlobalSettingsFixture.cs
+++ b/LibGit2Sharp.Tests/GlobalSettingsFixture.cs
@@ -1,6 +1,8 @@
using System.Text.RegularExpressions;
using LibGit2Sharp.Tests.TestHelpers;
using Xunit;
+using System.Globalization;
+using System.IO;
namespace LibGit2Sharp.Tests
{
@@ -13,6 +15,14 @@ public void CanGetMinimumCompiledInFeatures()
Assert.True(features.HasFlag(BuiltInFeatures.Threads));
Assert.True(features.HasFlag(BuiltInFeatures.Https));
+
+ bool hasSsh;
+ using (var sr = new StreamReader(typeof(GlobalSettingsFixture).Assembly.GetManifestResourceStream("LibGit2Sharp.Tests.ssh_used.txt")))
+ {
+ if (!bool.TryParse(sr.ReadLine(), out hasSsh))
+ hasSsh = false;
+ }
+ Assert.Equal(hasSsh, features.HasFlag(BuiltInFeatures.Ssh));
}
[Fact]
diff --git a/LibGit2Sharp.Tests/LibGit2Sharp.Tests.csproj b/LibGit2Sharp.Tests/LibGit2Sharp.Tests.csproj
index f93a24f30..a2d168b62 100644
--- a/LibGit2Sharp.Tests/LibGit2Sharp.Tests.csproj
+++ b/LibGit2Sharp.Tests/LibGit2Sharp.Tests.csproj
@@ -157,4 +157,7 @@
-->
+
+
+
diff --git a/LibGit2Sharp.Tests/ssh_used.txt b/LibGit2Sharp.Tests/ssh_used.txt
new file mode 100644
index 000000000..bc59c12aa
--- /dev/null
+++ b/LibGit2Sharp.Tests/ssh_used.txt
@@ -0,0 +1 @@
+False
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 343fc1887..357b4302e 100644
--- a/LibGit2Sharp/Core/Ensure.cs
+++ b/LibGit2Sharp/Core/Ensure.cs
@@ -101,6 +101,7 @@ private static readonly Dictionary 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.Auth, (m, r, c) => new AuthenticationException(m, r, c) },
};
private static void HandleError(int result)
diff --git a/LibGit2Sharp/Core/GitCredentialType.cs b/LibGit2Sharp/Core/GitCredentialType.cs
index 00a7460d9..37328a2c1 100644
--- a/LibGit2Sharp/Core/GitCredentialType.cs
+++ b/LibGit2Sharp/Core/GitCredentialType.cs
@@ -32,5 +32,10 @@ internal enum GitCredentialType
/// TODO
///
SshInteractive = (1 << 4),
+
+ ///
+ /// Username only information.
+ ///
+ UsernameQuery = (1 << 5),
}
}
diff --git a/LibGit2Sharp/Core/NativeMethods.cs b/LibGit2Sharp/Core/NativeMethods.cs
index a8fb1eacf..ad2d51413 100644
--- a/LibGit2Sharp/Core/NativeMethods.cs
+++ b/LibGit2Sharp/Core/NativeMethods.cs
@@ -398,6 +398,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_username_new(
+ out IntPtr cred,
+ [MarshalAs(UnmanagedType.CustomMarshaler, MarshalCookie = UniqueId.UniqueIdentifier, MarshalTypeRef = typeof(StrictUtf8Marshaler))] string username);
+
+ [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_describe_commit(
out DescribeResultSafeHandle describe,
diff --git a/LibGit2Sharp/LibGit2Sharp.csproj b/LibGit2Sharp/LibGit2Sharp.csproj
index 3ca4a3892..6c65c1540 100644
--- a/LibGit2Sharp/LibGit2Sharp.csproj
+++ b/LibGit2Sharp/LibGit2Sharp.csproj
@@ -340,6 +340,10 @@
+
+
+
+
diff --git a/LibGit2Sharp/RemoteCallbacks.cs b/LibGit2Sharp/RemoteCallbacks.cs
index 55be945d2..dd7561042 100644
--- a/LibGit2Sharp/RemoteCallbacks.cs
+++ b/LibGit2Sharp/RemoteCallbacks.cs
@@ -256,6 +256,14 @@ private int GitCredentialHandler(out IntPtr ptr, IntPtr cUrl, IntPtr usernameFro
{
types |= SupportedCredentialTypes.Default;
}
+ if (credTypes.HasFlag(GitCredentialType.SshKey))
+ {
+ types |= SupportedCredentialTypes.Ssh;
+ }
+ if (credTypes.HasFlag(GitCredentialType.UsernameQuery))
+ {
+ 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..f53d5d1cb
--- /dev/null
+++ b/LibGit2Sharp/SshAgentCredentials.cs
@@ -0,0 +1,32 @@
+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 (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..044ce69c0
--- /dev/null
+++ b/LibGit2Sharp/SshUserKeyCredentials.cs
@@ -0,0 +1,61 @@
+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 (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..37114c19a 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 key. (SshUserKeyCredentials, SshAgentCredentials)
+ ///
+ Ssh = (1 << 2),
+
+ ///
+ /// Queries the server with the specified 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/UpdateLibgit2ToSha.ps1 b/UpdateLibgit2ToSha.ps1
index 4a90841e4..b4692750f 100644
--- a/UpdateLibgit2ToSha.ps1
+++ b/UpdateLibgit2ToSha.ps1
@@ -11,6 +11,8 @@
If set, run the libgit2 tests on the desired version.
.PARAMETER debug
If set, build the "Debug" configuration of libgit2, rather than "RelWithDebInfo" (default).
+.PARAMETER ssh
+ If set embeds SSH at the path pointed to by the value.
#>
Param(
@@ -18,7 +20,8 @@ Param(
[string]$vs = '10',
[string]$libgit2Name = '',
[switch]$test,
- [switch]$debug
+ [switch]$debug,
+ [string]$ssh = ''
)
Set-StrictMode -Version Latest
@@ -28,12 +31,19 @@ $libgit2sharpDirectory = Split-Path $MyInvocation.MyCommand.Path
$libgit2Directory = Join-Path $libgit2sharpDirectory "libgit2"
$x86Directory = Join-Path $libgit2sharpDirectory "Lib\NativeBinaries\x86"
$x64Directory = Join-Path $libgit2sharpDirectory "Lib\NativeBinaries\amd64"
+$sshFile = Join-Path $libgit2sharpDirectory "LibGit2Sharp.Tests\ssh_used.txt"
$build_clar = 'OFF'
if ($test.IsPresent) { $build_clar = 'ON' }
$configuration = "RelWithDebInfo"
if ($debug.IsPresent) { $configuration = "Debug" }
+if (![string]::IsNullOrEmpty($ssh)) {
+ $embed_ssh = "-D EMBED_SSH_PATH=""$ssh"""
+} else {
+ $embed_ssh = ''
+}
+
function Run-Command([scriptblock]$Command, [switch]$Fatal, [switch]$Quiet) {
$output = ""
if ($Quiet) {
@@ -144,7 +154,7 @@ function Assert-Consistent-Naming($expected, $path) {
Run-Command -Quiet { & remove-item build -recurse -force }
Run-Command -Quiet { & mkdir build }
cd build
- Run-Command -Quiet -Fatal { & $cmake -G "Visual Studio $vs" -D ENABLE_TRACE=ON -D "BUILD_CLAR=$build_clar" -D "LIBGIT2_FILENAME=$binaryFilename" -DSTDCALL=ON .. }
+ Run-Command -Quiet -Fatal { & $cmake -G "Visual Studio $vs" -D THREADSAFE=ON -D ENABLE_TRACE=ON -D "BUILD_CLAR=$build_clar" -D "LIBGIT2_FILENAME=$binaryFilename" -DSTDCALL=ON $embed_ssh .. }
Run-Command -Quiet -Fatal { & $cmake --build . --config $configuration }
if ($test.IsPresent) { Run-Command -Quiet -Fatal { & $ctest -V . } }
cd $configuration
@@ -157,7 +167,7 @@ function Assert-Consistent-Naming($expected, $path) {
cd ..
Run-Command -Quiet { & mkdir build64 }
cd build64
- Run-Command -Quiet -Fatal { & $cmake -G "Visual Studio $vs Win64" -D THREADSAFE=ON -D ENABLE_TRACE=ON -D "BUILD_CLAR=$build_clar" -D "LIBGIT2_FILENAME=$binaryFilename" -DSTDCALL=ON ../.. }
+ Run-Command -Quiet -Fatal { & $cmake -G "Visual Studio $vs Win64" -D THREADSAFE=ON -D ENABLE_TRACE=ON -D "BUILD_CLAR=$build_clar" -D "LIBGIT2_FILENAME=$binaryFilename" -DSTDCALL=ON $embed_ssh ../.. }
Run-Command -Quiet -Fatal { & $cmake --build . --config $configuration }
if ($test.IsPresent) { Run-Command -Quiet -Fatal { & $ctest -V . } }
cd $configuration
@@ -180,6 +190,7 @@ namespace LibGit2Sharp.Core
sc -Encoding ASCII (Join-Path $libgit2sharpDirectory "Libgit2sharp\Core\NativeDllName.cs") $dllNameClass
sc -Encoding ASCII (Join-Path $libgit2sharpDirectory "Libgit2sharp\libgit2_hash.txt") $sha
+ sc -Encoding ASCII (Join-Path $libgit2sharpDirectory "Libgit2sharp.Tests\ssh_used.txt") (![string]::IsNullOrEmpty($ssh))
$buildProperties = @"
diff --git a/build.libgit2sharp.sh b/build.libgit2sharp.sh
index d650afd26..96e525c0e 100755
--- a/build.libgit2sharp.sh
+++ b/build.libgit2sharp.sh
@@ -3,6 +3,8 @@
LIBGIT2SHA=`cat ./LibGit2Sharp/libgit2_hash.txt`
SHORTSHA=${LIBGIT2SHA:0:7}
EXTRADEFINE="$1"
+USESSH=${1-OFF}
+SSH_FILE="$(pwd)/LibGit2Sharp.Tests/ssh_used.txt"
rm -rf libgit2/build
mkdir libgit2/build
@@ -11,13 +13,17 @@ export _BINPATH=`pwd`
cmake -DCMAKE_BUILD_TYPE:STRING=RelWithDebInfo \
-DBUILD_CLAR:BOOL=OFF \
- -DUSE_SSH=OFF \
+ -DUSE_SSH=$USESSH \
-DENABLE_TRACE=ON \
-DLIBGIT2_FILENAME=git2-$SHORTSHA \
-DCMAKE_OSX_ARCHITECTURES="i386;x86_64" \
..
cmake --build .
+shopt -s nocasematch
+[[ $USESSH == "ON" ]] && echo "True" > $SSH_FILE || echo "False" > $SSH_FILE
+shopt -u nocasematch
+
export LD_LIBRARY_PATH=$_BINPATH:$LD_LIBRARY_PATH
export DYLD_LIBRARY_PATH=$_BINPATH:$DYLD_LIBRARY_PATH