Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.
/ corefx Public archive

Commit

Permalink
Fix WinHttpHandler for Basic auth with default credentials
Browse files Browse the repository at this point in the history
We were getting an error "The parameter is incorrect" from WinHTTP when we tried to invoke default credential handling even for cases where the server doesn't use Negotiate or NTLM. Negotiate and NTLM are the only schemes that can use default credentials since they need to be transmitted via a challenge-response mechanism.

The fix here is to only set WinHTTP default credentials handling for Negotiate or NTLM schemes. Otherwise, it should behave as-if there were no credentials set.

Fixes #11266
  • Loading branch information
davidsh authored and stephentoub committed Sep 28, 2016
1 parent b7f2f69 commit 2beedc5
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -103,14 +103,15 @@ public void CheckResponseForAuthentication(
serverAuthScheme = ChooseAuthScheme(supportedSchemes);
if (serverAuthScheme != 0)
{
SetWinHttpCredential(
if (SetWinHttpCredential(
state.RequestHandle,
state.ServerCredentials,
uri,
serverAuthScheme,
authTarget);

state.RetryRequest = true;
authTarget))
{
state.RetryRequest = true;
}
}

break;
Expand Down Expand Up @@ -295,7 +296,7 @@ public void ChangeDefaultCredentialsPolicy(
}
}

private void SetWinHttpCredential(
private bool SetWinHttpCredential(
SafeWinHttpHandle requestHandle,
ICredentials credentials,
Uri uri,
Expand All @@ -314,15 +315,25 @@ private void SetWinHttpCredential(

if (networkCredential == null)
{
return;
return false;
}

if (networkCredential == CredentialCache.DefaultNetworkCredentials)
{
// Allow WinHTTP to transmit the default credentials.
ChangeDefaultCredentialsPolicy(requestHandle, authTarget, allowDefaultCredentials:true);
userName = null;
password = null;
// Only Negotiate and NTLM can use default credentials. Otherwise,
// behave as-if there were no credentials.
if (authScheme == Interop.WinHttp.WINHTTP_AUTH_SCHEME_NEGOTIATE ||
authScheme == Interop.WinHttp.WINHTTP_AUTH_SCHEME_NTLM)
{
// Allow WinHTTP to transmit the default credentials.
ChangeDefaultCredentialsPolicy(requestHandle, authTarget, allowDefaultCredentials:true);
userName = null;
password = null;
}
else
{
return false;
}
}
else
{
Expand Down Expand Up @@ -352,6 +363,8 @@ private void SetWinHttpCredential(
{
WinHttpException.ThrowExceptionUsingLastError();
}

return true;
}

private static uint ChooseAuthScheme(uint supportedSchemes)
Expand Down
16 changes: 16 additions & 0 deletions src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,22 @@ public async Task GetAsync_DefaultAutomaticDecompression_HeadersRemoved(Uri serv
}
}

[Fact]
public async Task GetAsync_ServerNeedsBasicAuthAndSetDefaultCredentials_StatusCodeUnauthorized()
{
var handler = new HttpClientHandler();
handler.Credentials = CredentialCache.DefaultCredentials;
using (var client = new HttpClient(handler))
{
Uri uri = HttpTestServers.BasicAuthUriForCreds(secure:false, userName:Username, password:Password);
using (HttpResponseMessage response = await client.GetAsync(uri))
{
Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode);
}
}
}

[OuterLoop] // TODO: Issue #11345
[Fact]
public async Task GetAsync_ServerNeedsAuthAndSetCredential_StatusCodeOK()
{
Expand Down

0 comments on commit 2beedc5

Please sign in to comment.