diff options
author | Ben Straub <bs@github.com> | 2013-01-09 03:11:59 +0400 |
---|---|---|
committer | Ben Straub <bs@github.com> | 2013-01-16 19:30:59 +0400 |
commit | 20a6b51fca0083a66b6f892d038f1d8b2d593ce9 (patch) | |
tree | 1f35e2433ad048094546bb568fde1acc8eca4e9a | |
parent | 95a50c31370c43aba6ee66b8705df45810dac0e8 (diff) |
Provide access to basic username/password auth for clone
-rw-r--r-- | LibGit2Sharp.Tests/CloneFixture.cs | 25 | ||||
-rw-r--r-- | LibGit2Sharp.Tests/RemoteFixture.cs | 22 | ||||
-rw-r--r-- | LibGit2Sharp.Tests/TestHelpers/Constants.cs | 5 | ||||
-rw-r--r-- | LibGit2Sharp/Core/GitCloneOptions.cs | 2 | ||||
-rw-r--r-- | LibGit2Sharp/Core/NativeMethods.cs | 23 | ||||
-rw-r--r-- | LibGit2Sharp/Core/Proxy.cs | 5 | ||||
-rw-r--r-- | LibGit2Sharp/Credentials.cs | 18 | ||||
-rw-r--r-- | LibGit2Sharp/LibGit2Sharp.csproj | 1 | ||||
-rw-r--r-- | LibGit2Sharp/Remote.cs | 16 | ||||
-rw-r--r-- | LibGit2Sharp/Repository.cs | 33 |
10 files changed, 138 insertions, 12 deletions
diff --git a/LibGit2Sharp.Tests/CloneFixture.cs b/LibGit2Sharp.Tests/CloneFixture.cs index 05d27521..864ea97e 100644 --- a/LibGit2Sharp.Tests/CloneFixture.cs +++ b/LibGit2Sharp.Tests/CloneFixture.cs @@ -110,5 +110,30 @@ namespace LibGit2Sharp.Tests Assert.True(checkoutWasCalled); } } + + [SkippableFact] + public void CanCloneWithCredentials() + { + InconclusiveIf(() => string.IsNullOrEmpty(Constants.PrivateRepoUrl), + "Populate Constants.PrivateRepo* to run this test"); + + var scd = BuildSelfCleaningDirectory(); + using (Repository repo = Repository.Clone( + Constants.PrivateRepoUrl, scd.RootedDirectoryPath, + credentials: new Credentials + { + Username = Constants.PrivateRepoUsername, + Password = Constants.PrivateRepoPassword + })) + { + string dir = repo.Info.Path; + Assert.True(Path.IsPathRooted(dir)); + Assert.True(Directory.Exists(dir)); + + Assert.NotNull(repo.Info.WorkingDirectory); + Assert.Equal(Path.Combine(scd.RootedDirectoryPath, ".git" + Path.DirectorySeparatorChar), repo.Info.Path); + Assert.False(repo.Info.IsBare); + } + } } } diff --git a/LibGit2Sharp.Tests/RemoteFixture.cs b/LibGit2Sharp.Tests/RemoteFixture.cs index 2fc2bfad..c2831bcf 100644 --- a/LibGit2Sharp.Tests/RemoteFixture.cs +++ b/LibGit2Sharp.Tests/RemoteFixture.cs @@ -110,6 +110,28 @@ namespace LibGit2Sharp.Tests } } + [SkippableFact] + public void CanFetchIntoAnEmptyRepositoryWithCredentials() + { + InconclusiveIf(() => string.IsNullOrEmpty(Constants.PrivateRepoUrl), + "Populate Constants.PrivateRepo* to run this test"); + + string remoteName = "testRemote"; + + var scd = BuildSelfCleaningDirectory(); + using (var repo = Repository.Init(scd.RootedDirectoryPath)) + { + Remote remote = repo.Remotes.Add(remoteName, Constants.PrivateRepoUrl); + + // Perform the actual fetch + remote.Fetch(credentials: new Credentials + { + Username = Constants.PrivateRepoUsername, + Password = Constants.PrivateRepoPassword + }); + } + } + [Theory] [InlineData("http://github.com/libgit2/TestGitRepository")] [InlineData("https://github.com/libgit2/TestGitRepository")] diff --git a/LibGit2Sharp.Tests/TestHelpers/Constants.cs b/LibGit2Sharp.Tests/TestHelpers/Constants.cs index 79ed9580..212c29e1 100644 --- a/LibGit2Sharp.Tests/TestHelpers/Constants.cs +++ b/LibGit2Sharp.Tests/TestHelpers/Constants.cs @@ -7,5 +7,10 @@ namespace LibGit2Sharp.Tests.TestHelpers public const string TemporaryReposPath = "TestRepos"; public const string UnknownSha = "deadbeefdeadbeefdeadbeefdeadbeefdeadbeef"; public static readonly Signature Signature = new Signature("A. U. Thor", "thor@valhalla.asgard.com", new DateTimeOffset(2011, 06, 16, 10, 58, 27, TimeSpan.FromHours(2))); + + // Populate these to turn on live credential tests + public const string PrivateRepoUrl = ""; + public const string PrivateRepoUsername = ""; + public const string PrivateRepoPassword = ""; } } diff --git a/LibGit2Sharp/Core/GitCloneOptions.cs b/LibGit2Sharp/Core/GitCloneOptions.cs index c6efd1a9..4b6c6832 100644 --- a/LibGit2Sharp/Core/GitCloneOptions.cs +++ b/LibGit2Sharp/Core/GitCloneOptions.cs @@ -18,7 +18,7 @@ namespace LibGit2Sharp.Core public IntPtr FetchSpec; public IntPtr PushSpec; - public IntPtr CredAcquireCallback; + public NativeMethods.git_cred_acquire_cb CredAcquireCallback; public IntPtr CredAcquirePayload; public IntPtr Transport; diff --git a/LibGit2Sharp/Core/NativeMethods.cs b/LibGit2Sharp/Core/NativeMethods.cs index 07a4bce3..491cc47f 100644 --- a/LibGit2Sharp/Core/NativeMethods.cs +++ b/LibGit2Sharp/Core/NativeMethods.cs @@ -300,6 +300,23 @@ namespace LibGit2Sharp.Core config_foreach_callback callback, IntPtr payload); + // Ordinarily we would decorate the `url` parameter with the Utf8Marshaler like we do everywhere + // else, but apparently doing a native->managed callback with the 64-bit version of CLR 2.0 can + // sometimes vomit when using a custom IMarshaler. So yeah, don't do that. If you need the url, + // call Utf8Marshaler.FromNative manually. See the discussion here: + // http://social.msdn.microsoft.com/Forums/en-US/netfx64bit/thread/1eb746c6-d695-4632-8a9e-16c4fa98d481 + internal delegate int git_cred_acquire_cb( + out IntPtr cred, + IntPtr url, + uint allowed_types, + IntPtr payload); + + [DllImport(libgit2)] + internal static extern int git_cred_userpass_plaintext_new( + out IntPtr cred, + [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof (Utf8Marshaler))] string username, + [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof (Utf8Marshaler))] string password); + [DllImport(libgit2)] internal static extern void git_diff_list_free(IntPtr diff); @@ -630,6 +647,12 @@ namespace LibGit2Sharp.Core internal static extern int git_remote_save(RemoteSafeHandle remote); [DllImport(libgit2)] + internal static extern void git_remote_set_cred_acquire_cb( + RemoteSafeHandle remote, + git_cred_acquire_cb cred_acquire_cb, + IntPtr payload); + + [DllImport(libgit2)] internal static extern int git_repository_odb(out ObjectDatabaseSafeHandle odb, RepositorySafeHandle repo); [DllImport(libgit2)] diff --git a/LibGit2Sharp/Core/Proxy.cs b/LibGit2Sharp/Core/Proxy.cs index 97973dda..7115fdde 100644 --- a/LibGit2Sharp/Core/Proxy.cs +++ b/LibGit2Sharp/Core/Proxy.cs @@ -1253,6 +1253,11 @@ namespace LibGit2Sharp.Core } } + public static void git_remote_set_cred_acquire_cb(RemoteSafeHandle remote, NativeMethods.git_cred_acquire_cb cred_acquire_cb, IntPtr payload) + { + NativeMethods.git_remote_set_cred_acquire_cb(remote, cred_acquire_cb, payload); + } + public static void git_remote_update_tips(RemoteSafeHandle remote) { using (ThreadAffinity()) diff --git a/LibGit2Sharp/Credentials.cs b/LibGit2Sharp/Credentials.cs new file mode 100644 index 00000000..f03a5cfa --- /dev/null +++ b/LibGit2Sharp/Credentials.cs @@ -0,0 +1,18 @@ +namespace LibGit2Sharp +{ + /// <summary> + /// Class that holds credentials for remote repository access. + /// </summary> + public class Credentials + { + /// <summary> + /// Username for username/password authentication (as in HTTP basic auth). + /// </summary> + public string Username { get; set; } + + /// <summary> + /// Password for username/password authentication (as in HTTP basic auth). + /// </summary> + public string Password { get; set; } + } +} diff --git a/LibGit2Sharp/LibGit2Sharp.csproj b/LibGit2Sharp/LibGit2Sharp.csproj index 7664ce89..0fef0a45 100644 --- a/LibGit2Sharp/LibGit2Sharp.csproj +++ b/LibGit2Sharp/LibGit2Sharp.csproj @@ -84,6 +84,7 @@ <Compile Include="Core\LazyGroup.cs" /> <Compile Include="Core\Handles\GitConfigEntryHandle.cs" /> <Compile Include="Core\Proxy.cs" /> + <Compile Include="Credentials.cs" /> <Compile Include="DiffOptions.cs" /> <Compile Include="DiffTargets.cs" /> <Compile Include="Handlers.cs" /> diff --git a/LibGit2Sharp/Remote.cs b/LibGit2Sharp/Remote.cs index 13316590..25ef6fd7 100644 --- a/LibGit2Sharp/Remote.cs +++ b/LibGit2Sharp/Remote.cs @@ -60,12 +60,14 @@ namespace LibGit2Sharp /// <param name="onUpdateTips">UpdateTips callback. Corresponds to libgit2 update_tips callback.</param> /// <param name="onTransferProgress">Callback method that transfer progress will be reported through. /// Reports the client's state regarding the received and processed (bytes, objects) from the server.</param> + /// <param name="credentials">Credentials to use for username/password authentication.</param> public virtual void Fetch( TagFetchMode tagFetchMode = TagFetchMode.Auto, ProgressHandler onProgress = null, CompletionHandler onCompletion = null, UpdateTipsHandler onUpdateTips = null, - TransferProgressHandler onTransferProgress = null) + TransferProgressHandler onTransferProgress = null, + Credentials credentials = null) { using (RemoteSafeHandle remoteHandle = Proxy.git_remote_load(repository.Handle, this.Name, true)) { @@ -74,6 +76,18 @@ namespace LibGit2Sharp Proxy.git_remote_set_autotag(remoteHandle, tagFetchMode); + // Username/password auth + if (credentials != null) + { + Proxy.git_remote_set_cred_acquire_cb( + remoteHandle, + (out IntPtr cred, IntPtr url, uint types, IntPtr payload) => + NativeMethods.git_cred_userpass_plaintext_new(out cred, + credentials.Username, + credentials.Password), + IntPtr.Zero); + } + // It is OK to pass the reference to the GitCallbacks directly here because libgit2 makes a copy of // the data in the git_remote_callbacks structure. If, in the future, libgit2 changes its implementation // to store a reference to the git_remote_callbacks structure this would introduce a subtle bug diff --git a/LibGit2Sharp/Repository.cs b/LibGit2Sharp/Repository.cs index 40acadb5..3b9fa492 100644 --- a/LibGit2Sharp/Repository.cs +++ b/LibGit2Sharp/Repository.cs @@ -440,24 +440,37 @@ namespace LibGit2Sharp /// <param name="onTransferProgress">Handler for network transfer and indexing progress information</param> /// <param name="onCheckoutProgress">Handler for checkout progress information</param> /// <param name="options">Overrides to the way a repository is opened.</param> + /// <param name="credentials">Credentials to use for user/pass authentication</param> /// <returns></returns> public static Repository Clone(string sourceUrl, string workdirPath, bool bare = false, bool checkout = true, TransferProgressHandler onTransferProgress = null, CheckoutProgressHandler onCheckoutProgress = null, - RepositoryOptions options = null) + RepositoryOptions options = null, + Credentials credentials = null) { var cloneOpts = new GitCloneOptions - { - Bare = bare ? 1 : 0, - TransferProgressCallback = TransferCallbacks.GenerateCallback(onTransferProgress), - }; - cloneOpts.CheckoutOpts.version = 1; - cloneOpts.CheckoutOpts.progress_cb = CheckoutCallbacks.GenerateCheckoutCallbacks(onCheckoutProgress); - cloneOpts.CheckoutOpts.checkout_strategy = checkout - ? CheckoutStrategy.GIT_CHECKOUT_SAFE_CREATE - : CheckoutStrategy.GIT_CHECKOUT_NONE; + { + Bare = bare ? 1 : 0, + TransferProgressCallback = TransferCallbacks.GenerateCallback(onTransferProgress), + CheckoutOpts = + { + version = 1, + progress_cb = + CheckoutCallbacks.GenerateCheckoutCallbacks(onCheckoutProgress), + checkout_strategy = checkout + ? CheckoutStrategy.GIT_CHECKOUT_SAFE_CREATE + : CheckoutStrategy.GIT_CHECKOUT_NONE + }, + }; + + if (credentials != null) + { + cloneOpts.CredAcquireCallback = + (out IntPtr cred, IntPtr url, uint types, IntPtr payload) => + NativeMethods.git_cred_userpass_plaintext_new(out cred, credentials.Username, credentials.Password); + } using(Proxy.git_clone(sourceUrl, workdirPath, cloneOpts)) {} return new Repository(workdirPath, options); |