Skip to content

Commit bebede8

Browse files
committed
Let a smart subtransport ask for credentials and show the cert
Implement a method for a smart subtransport implementation ask the caller for what credentials to use. The certificate callback is also here, but untested as the web requests go to the central service point instead of asking individually.
1 parent 6fbadd2 commit bebede8

File tree

3 files changed

+110
-3
lines changed

3 files changed

+110
-3
lines changed

LibGit2Sharp.Tests/SmartSubtransportFixture.cs

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using System.Net;
55
using System.Net.Security;
66
using LibGit2Sharp.Tests.TestHelpers;
7+
using LibGit2Sharp.Core;
78
using Xunit;
89
using Xunit.Extensions;
910

@@ -20,6 +21,8 @@ public class SmartSubtransportFixture : BaseFixture
2021
[Theory]
2122
[InlineData("http", "http://github.com/libgit2/TestGitRepository")]
2223
[InlineData("https", "https://github.com/libgit2/TestGitRepository")]
24+
// this one should probably be in on its own test
25+
[InlineData("https", "https://bitbucket.org/libgit2/testgitrepository.git")]
2326
public void CustomSmartSubtransportTest(string scheme, string url)
2427
{
2528
string remoteName = "testRemote";
@@ -62,7 +65,11 @@ public void CustomSmartSubtransportTest(string scheme, string url)
6265
}
6366

6467
// Perform the actual fetch
65-
repo.Network.Fetch(remote, new FetchOptions { OnUpdateTips = expectedFetchState.RemoteUpdateTipsHandler, TagFetchMode = TagFetchMode.Auto });
68+
repo.Network.Fetch(remote, new FetchOptions { OnUpdateTips = expectedFetchState.RemoteUpdateTipsHandler, TagFetchMode = TagFetchMode.Auto,
69+
CredentialsProvider = (_user, _valid, _hostname) => {
70+
return new UsernamePasswordCredentials() { Username = "libgit3", Password = "libgit3" };
71+
}
72+
});
6673

6774
// Verify the expected
6875
expectedFetchState.CheckUpdatedReferences(repo);
@@ -234,14 +241,39 @@ private HttpWebResponse GetResponseWithRedirects()
234241
}
235242
}
236243

237-
response = (HttpWebResponse)request.GetResponse();
244+
try
245+
{
246+
response = (HttpWebResponse)request.GetResponse();
247+
}
248+
catch (WebException ex)
249+
{
250+
response = ex.Response as HttpWebResponse;
251+
if (response.StatusCode == HttpStatusCode.Unauthorized)
252+
{
253+
Credentials cred;
254+
int ret = SmartTransport.AcquireCredentials(out cred, null, typeof(UsernamePasswordCredentials));
255+
if (ret != 0)
256+
{
257+
throw new InvalidOperationException("dunno");
258+
}
259+
260+
request = CreateWebRequest(EndpointUrl, IsPost, ContentType);
261+
UsernamePasswordCredentials userpass = (UsernamePasswordCredentials)cred;
262+
request.Credentials = new NetworkCredential(userpass.Username, userpass.Password);
263+
continue;
264+
}
265+
266+
// rethrow if it's not 401
267+
throw ex;
268+
}
238269

239270
if (response.StatusCode == HttpStatusCode.Moved || response.StatusCode == HttpStatusCode.Redirect)
240271
{
241272
request = CreateWebRequest(response.Headers["Location"], IsPost, ContentType);
242273
continue;
243274
}
244275

276+
245277
break;
246278
}
247279

LibGit2Sharp/SmartSubtransport.cs

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
using System;
22
using System.Runtime.InteropServices;
3+
using System.Text;
34
using LibGit2Sharp.Core;
5+
using LibGit2Sharp.Core.Handles;
46

57
namespace LibGit2Sharp
68
{
@@ -47,6 +49,76 @@ public abstract class RpcSmartSubtransport : SmartSubtransport
4749
/// </summary>
4850
public abstract class SmartSubtransport
4951
{
52+
internal IntPtr Transport { get; set; }
53+
54+
/// <summary>
55+
/// Call the certificate check callback
56+
/// </summary>
57+
/// <param name="cert">The certificate to send</param>
58+
/// <param name="valid">Whether we consider the certificate to be valid</param>
59+
/// <param name="hostname">The hostname we connected to</param>
60+
public int CertificateCheck(Certificate cert, bool valid, string hostname)
61+
{
62+
CertificateSsh sshCert = cert as CertificateSsh;
63+
CertificateX509 x509Cert = cert as CertificateX509;
64+
65+
if (sshCert == null && x509Cert == null)
66+
{
67+
throw new InvalidOperationException("Unsupported certificate type");
68+
}
69+
70+
int ret;
71+
if (sshCert != null)
72+
{
73+
var certPtr = sshCert.ToPointer();
74+
ret = NativeMethods.git_transport_smart_certificate_check(Transport, certPtr, valid ? 1 : 0, hostname);
75+
Marshal.FreeHGlobal(certPtr);
76+
} else {
77+
IntPtr certPtr, dataPtr;
78+
certPtr = x509Cert.ToPointers(out dataPtr);
79+
ret = NativeMethods.git_transport_smart_certificate_check(Transport, certPtr, valid ? 1 : 0, hostname);
80+
Marshal.FreeHGlobal(dataPtr);
81+
Marshal.FreeHGlobal(certPtr);
82+
}
83+
84+
return ret;
85+
}
86+
87+
public int AcquireCredentials(out Credentials cred, string user, params Type[] methods)
88+
{
89+
// Convert the user-provided types to libgit2's flags
90+
int allowed = 0;
91+
foreach (var method in methods)
92+
{
93+
if (method == typeof(UsernamePasswordCredentials))
94+
{
95+
allowed |= (int)GitCredentialType.UserPassPlaintext;
96+
}
97+
else
98+
{
99+
throw new InvalidOperationException("Unknown type passes as allowed credential");
100+
}
101+
}
102+
103+
IntPtr credHandle = IntPtr.Zero;
104+
int res = Proxy.git_transport_smart_credentials(out credHandle, Transport, user, allowed);
105+
if (res != 0)
106+
{
107+
cred = null;
108+
return res;
109+
}
110+
111+
var baseCred = credHandle.MarshalAs<GitCredential>();
112+
switch (baseCred.credtype)
113+
{
114+
case GitCredentialType.UserPassPlaintext:
115+
cred = UsernamePasswordCredentials.FromNative(credHandle.MarshalAs<GitCredentialUserpass>());
116+
return 0;
117+
default:
118+
throw new InvalidOperationException("User returned an unkown credential type");
119+
}
120+
}
121+
50122
/// <summary>
51123
/// Invoked by libgit2 to create a connection using this subtransport.
52124
/// </summary>

LibGit2Sharp/SmartSubtransportRegistration.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System;
22
using System.Runtime.InteropServices;
33
using LibGit2Sharp.Core;
4+
using LibGit2Sharp.Core.Handles;
45

56
namespace LibGit2Sharp
67
{
@@ -75,7 +76,9 @@ private static int Subtransport(
7576

7677
try
7778
{
78-
subtransport = new T().GitSmartSubtransportPointer;
79+
var obj = new T();
80+
obj.Transport = transport;
81+
subtransport = obj.GitSmartSubtransportPointer;
7982

8083
return 0;
8184
}

0 commit comments

Comments
 (0)