Skip to content

Commit c3a543a

Browse files
authored
Merge pull request #217 from mjcheetham/ntlm-proxy-auth
Treat empty credential proxy configuration as use system default credentials
2 parents edfb863 + 4f91faa commit c3a543a

File tree

2 files changed

+108
-4
lines changed

2 files changed

+108
-4
lines changed

src/shared/Microsoft.Git.CredentialManager.Tests/HttpClientFactoryTests.cs

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,104 @@ public void HttpClientFactory_TryCreateProxy_ProxyWithCredentials_ReturnsTrueOut
118118
Assert.Equal(proxyPass, configuredCredentials.Password);
119119
}
120120

121+
[Fact]
122+
public void HttpClientFactory_TryCreateProxy_ProxyWithNonEmptyUserAndEmptyPass_ReturnsTrueOutProxyWithUrlConfiguredCredentials()
123+
{
124+
const string proxyScheme = "https";
125+
const string proxyUser = "john.doe";
126+
const string proxyHost = "proxy.example.com/git";
127+
const string repoPath = "/tmp/repos/foo";
128+
const string repoRemote = "https://remote.example.com/foo.git";
129+
130+
string proxyConfigString = $"{proxyScheme}://{proxyUser}:@{proxyHost}";
131+
string expectedProxyUrl = $"{proxyScheme}://{proxyHost}";
132+
var repoRemoteUri = new Uri(repoRemote);
133+
134+
var settings = new TestSettings
135+
{
136+
RemoteUri = repoRemoteUri,
137+
RepositoryPath = repoPath,
138+
ProxyConfiguration = new Uri(proxyConfigString)
139+
};
140+
var httpFactory = new HttpClientFactory(Mock.Of<ITrace>(), settings, Mock.Of<IStandardStreams>());
141+
142+
bool result = httpFactory.TryCreateProxy(out IWebProxy proxy);
143+
144+
Assert.True(result);
145+
Assert.NotNull(proxy);
146+
var configuredProxyUrl = proxy.GetProxy(repoRemoteUri);
147+
Assert.Equal(expectedProxyUrl, configuredProxyUrl.ToString());
148+
149+
Assert.NotNull(proxy.Credentials);
150+
Assert.IsType<NetworkCredential>(proxy.Credentials);
151+
var configuredCredentials = (NetworkCredential) proxy.Credentials;
152+
Assert.Equal(proxyUser, configuredCredentials.UserName);
153+
Assert.True(string.IsNullOrWhiteSpace(configuredCredentials.Password));
154+
}
155+
156+
[Fact]
157+
public void HttpClientFactory_TryCreateProxy_ProxyWithEmptyUserAndNonEmptyPass_ReturnsTrueOutProxyWithUrlConfiguredCredentials()
158+
{
159+
const string proxyScheme = "https";
160+
const string proxyPass = "letmein";
161+
const string proxyHost = "proxy.example.com/git";
162+
const string repoPath = "/tmp/repos/foo";
163+
const string repoRemote = "https://remote.example.com/foo.git";
164+
165+
string proxyConfigString = $"{proxyScheme}://:{proxyPass}@{proxyHost}";
166+
string expectedProxyUrl = $"{proxyScheme}://{proxyHost}";
167+
var repoRemoteUri = new Uri(repoRemote);
168+
169+
var settings = new TestSettings
170+
{
171+
RemoteUri = repoRemoteUri,
172+
RepositoryPath = repoPath,
173+
ProxyConfiguration = new Uri(proxyConfigString)
174+
};
175+
var httpFactory = new HttpClientFactory(Mock.Of<ITrace>(), settings, Mock.Of<IStandardStreams>());
176+
177+
bool result = httpFactory.TryCreateProxy(out IWebProxy proxy);
178+
179+
Assert.True(result);
180+
Assert.NotNull(proxy);
181+
var configuredProxyUrl = proxy.GetProxy(repoRemoteUri);
182+
Assert.Equal(expectedProxyUrl, configuredProxyUrl.ToString());
183+
184+
Assert.NotNull(proxy.Credentials);
185+
Assert.IsType<NetworkCredential>(proxy.Credentials);
186+
var configuredCredentials = (NetworkCredential) proxy.Credentials;
187+
Assert.True(string.IsNullOrWhiteSpace(configuredCredentials.UserName));
188+
Assert.Equal(proxyPass, configuredCredentials.Password);
189+
}
190+
191+
[Fact]
192+
public void HttpClientFactory_TryCreateProxy_ProxyEmptyUserAndEmptyPass_ReturnsTrueOutProxyWithUrlDefaultCredentials()
193+
{
194+
const string repoPath = "/tmp/repos/foo";
195+
const string repoRemote = "https://remote.example.com/foo.git";
196+
var repoRemoteUri = new Uri(repoRemote);
197+
198+
string proxyConfigString = "https://:@proxy.example.com/git";
199+
string expectedProxyUrl = "https://proxy.example.com/git";
200+
201+
var settings = new TestSettings
202+
{
203+
RemoteUri = repoRemoteUri,
204+
RepositoryPath = repoPath,
205+
ProxyConfiguration = new Uri(proxyConfigString)
206+
};
207+
var httpFactory = new HttpClientFactory(Mock.Of<ITrace>(), settings, Mock.Of<IStandardStreams>());
208+
209+
bool result = httpFactory.TryCreateProxy(out IWebProxy proxy);
210+
211+
Assert.True(result);
212+
Assert.NotNull(proxy);
213+
var configuredProxyUrl = proxy.GetProxy(repoRemoteUri);
214+
Assert.Equal(expectedProxyUrl, configuredProxyUrl.ToString());
215+
216+
AssertDefaultCredentials(proxy.Credentials);
217+
}
218+
121219
private static void AssertDefaultCredentials(ICredentials credentials)
122220
{
123221
var netCred = (NetworkCredential) credentials;

src/shared/Microsoft.Git.CredentialManager/HttpClientFactory.cs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -120,24 +120,30 @@ public bool TryCreateProxy(out IWebProxy proxy)
120120
// Dictionary of proxy info for tracing
121121
var dict = new Dictionary<string, string> {["uri"] = proxyUri.ToString()};
122122

123-
// Try to extract and configure proxy credentials from the configured URI
124-
if (proxyConfig.TryGetUserInfo(out string userName, out string password))
123+
// Try to extract and configure proxy credentials from the configured URI.
124+
// For an empty username AND password we should use the system default credentials
125+
// (for example for Windows Integrated Authentication-based proxies).
126+
if (proxyConfig.TryGetUserInfo(out string userName, out string password) &&
127+
!(string.IsNullOrEmpty(userName) && string.IsNullOrEmpty(password)))
125128
{
126129
proxy = new WebProxy(proxyUri)
127130
{
128131
Credentials = new NetworkCredential(userName, password)
129132
};
130133

131134
// Add user/pass info to the trace dictionary
132-
if (!string.IsNullOrWhiteSpace(userName)) dict["username"] = userName;
133-
if (!string.IsNullOrEmpty(password)) dict["password"] = password;
135+
dict["username"] = userName;
136+
dict["password"] = password;
134137
}
135138
else
136139
{
137140
proxy = new WebProxy(proxyUri)
138141
{
139142
UseDefaultCredentials = true
140143
};
144+
145+
// Trace the use of system default credentials
146+
dict["useDefaultCredentials"] = "true";
141147
}
142148

143149
// Tracer out proxy info dictionary

0 commit comments

Comments
 (0)