Skip to content

GetResponseWithRedirects only adds credentials to cache for matching schemes #1

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
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: 43 additions & 12 deletions LibGit2Sharp/Core/ManagedHttpSmartSubtransport.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
Expand Down Expand Up @@ -47,6 +48,13 @@ private class ManagedHttpSmartSubtransportStream : SmartSubtransportStream
{
private static int MAX_REDIRECTS = 7;

private static readonly IReadOnlyDictionary<Type, string[]> SUPPORTED_SCHEMES_FOR_CREDENTIALS =
new Dictionary<Type, string[]>
{
{ typeof(DefaultCredentials), new[] { "Negotiate" } },
{ typeof(UsernamePasswordCredentials), new[] { "NTLM", "Basic" } }
};

#if NETCOREAPP
private static readonly SocketsHttpHandler httpHandler;
#else
Expand Down Expand Up @@ -189,20 +197,14 @@ private HttpResponseMessage GetResponseWithRedirects()
throw new InvalidOperationException("authentication cancelled");
}

var scheme = response.Headers.WwwAuthenticate.First().Scheme;

if (cred is DefaultCredentials)
{
lock (credentialCache)
{
credentialCache.Add(url, scheme, CredentialCache.DefaultNetworkCredentials);
}
}
else if (cred is UsernamePasswordCredentials userpass)
foreach (var authenticationHeader in response.Headers.WwwAuthenticate)
{
lock (credentialCache)
if (CredentialsAreValidForScheme(cred, authenticationHeader.Scheme, out var networkCredential))
{
credentialCache.Add(url, scheme, new NetworkCredential(userpass.Username, userpass.Password));
lock (credentialCache)
{
credentialCache.Add(url, authenticationHeader.Scheme, networkCredential);
}
}
}

Expand All @@ -221,6 +223,35 @@ private HttpResponseMessage GetResponseWithRedirects()
throw new Exception("too many redirects or authentication replays");
}

bool IsSupportedAuth<T>(Credentials credentials, string scheme, out T typedCredentials) where T : Credentials
{
if (credentials is T innerTypedCredentials && SUPPORTED_SCHEMES_FOR_CREDENTIALS.TryGetValue(typeof(T), out var schemes) &&
schemes.Contains(scheme, StringComparer.InvariantCultureIgnoreCase))
{
typedCredentials = innerTypedCredentials;
return true;
}

typedCredentials = null;
return false;
}

bool CredentialsAreValidForScheme(Credentials credentials, string scheme, out NetworkCredential networkCredential)
{
networkCredential = null;

if (IsSupportedAuth<DefaultCredentials>(credentials, scheme, out _))
{
networkCredential = CredentialCache.DefaultNetworkCredentials;
}
else if (IsSupportedAuth<UsernamePasswordCredentials>(credentials, scheme, out var usernamePasswordCredentials))
{
networkCredential = new NetworkCredential(usernamePasswordCredentials.Username, usernamePasswordCredentials.Password);
}

return networkCredential != null;
}

public override int Read(Stream dataStream, long length, out long readTotal)
{
byte[] buffer = new byte[4096];
Expand Down