Skip to content

Introduce SSH functionality #1072

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 55 additions & 0 deletions LibGit2Sharp/AuthenticationException.cs
Original file line number Diff line number Diff line change
@@ -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)
{
}
}
}
3 changes: 2 additions & 1 deletion LibGit2Sharp/Core/Ensure.cs
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,8 @@ private static readonly Dictionary<GitErrorCode, Func<string, GitErrorCode, GitE
{ 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)
Expand Down
18 changes: 18 additions & 0 deletions LibGit2Sharp/Core/NativeMethods.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
4 changes: 4 additions & 0 deletions LibGit2Sharp/LibGit2Sharp.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -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" />
Expand Down Expand Up @@ -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" />
Expand Down Expand Up @@ -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" />
Expand Down
8 changes: 8 additions & 0 deletions LibGit2Sharp/RemoteCallbacks.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
36 changes: 36 additions & 0 deletions LibGit2Sharp/SshAgentCredentials.cs
Original file line number Diff line number Diff line change
@@ -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, &lt; 0 to indicate an error, &gt; 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; }
}
}
66 changes: 66 additions & 0 deletions LibGit2Sharp/SshUserKeyCredentials.cs
Original file line number Diff line number Diff line change
@@ -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, &lt; 0 to indicate an error, &gt; 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; }
}
}
10 changes: 10 additions & 0 deletions LibGit2Sharp/SupportedCredentialTypes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,15 @@ public enum SupportedCredentialTypes
/// 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),
}
}
31 changes: 31 additions & 0 deletions LibGit2Sharp/UsernameQueryCredentials.cs
Original file line number Diff line number Diff line change
@@ -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, &lt; 0 to indicate an error, &gt; 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; }
}
}