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

Commit e8a1771

Browse files
author
Geoff Kizer
committed
split auth and redirect handling back into two separate handlers
1 parent d4534e7 commit e8a1771

File tree

5 files changed

+266
-235
lines changed

5 files changed

+266
-235
lines changed

src/System.Net.Http/src/System.Net.Http.csproj

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@
124124
</ItemGroup>
125125
<!-- SocketsHttpHandler implementation -->
126126
<ItemGroup Condition="'$(TargetGroup)' == 'netcoreapp'">
127-
<Compile Include="System\Net\Http\SocketsHttpHandler\AuthenticateAndRedirectHandler.cs" />
127+
<Compile Include="System\Net\Http\SocketsHttpHandler\AuthenticationHandler.cs" />
128128
<Compile Include="System\Net\Http\SocketsHttpHandler\AuthenticationHelper.Basic.cs" />
129129
<Compile Include="System\Net\Http\SocketsHttpHandler\AuthenticationHelper.Digest.cs" />
130130
<Compile Include="System\Net\Http\SocketsHttpHandler\ChunkedEncodingReadStream.cs" />
@@ -149,6 +149,7 @@
149149
<Compile Include="System\Net\Http\SocketsHttpHandler\HttpProxyConnectionHandler.cs" />
150150
<Compile Include="System\Net\Http\SocketsHttpHandler\SocketsHttpHandler.cs" />
151151
<Compile Include="System\Net\Http\SocketsHttpHandler\RawConnectionStream.cs" />
152+
<Compile Include="System\Net\Http\SocketsHttpHandler\RedirectHandler.cs" />
152153
</ItemGroup>
153154
<!-- SocketsHttpHandler platform parts -->
154155
<ItemGroup Condition=" '$(TargetsUnix)' == 'true' And '$(TargetGroup)' == 'netcoreapp'">

src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/AuthenticateAndRedirectHandler.cs

Lines changed: 0 additions & 232 deletions
This file was deleted.
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
using System.Diagnostics;
6+
using System.Net.Http.Headers;
7+
using System.Threading;
8+
using System.Threading.Tasks;
9+
10+
namespace System.Net.Http
11+
{
12+
internal sealed partial class AuthenticationHandler : HttpMessageHandler
13+
{
14+
private readonly HttpMessageHandler _innerHandler;
15+
private readonly bool _preAuthenticate;
16+
private readonly ICredentials _credentials;
17+
18+
public AuthenticationHandler(bool preAuthenticate, ICredentials credentials, HttpMessageHandler innerHandler)
19+
{
20+
Debug.Assert(innerHandler != null);
21+
Debug.Assert(credentials != null);
22+
23+
_preAuthenticate = preAuthenticate;
24+
_credentials = credentials;
25+
_innerHandler = innerHandler;
26+
}
27+
28+
protected internal override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
29+
{
30+
if (_preAuthenticate)
31+
{
32+
AuthenticationHelper.TrySetBasicAuthToken(request, _credentials);
33+
}
34+
35+
HttpResponseMessage response = await _innerHandler.SendAsync(request, cancellationToken).ConfigureAwait(false);
36+
37+
if (response.StatusCode == HttpStatusCode.Unauthorized)
38+
{
39+
AuthenticationHeaderValue selectedAuth = GetSupportedAuthScheme(response.Headers.WwwAuthenticate);
40+
if (selectedAuth != null)
41+
{
42+
switch (selectedAuth.Scheme)
43+
{
44+
case AuthenticationHelper.Digest:
45+
// Update digest response with new parameter from WWWAuthenticate
46+
var digestResponse = new AuthenticationHelper.DigestResponse(selectedAuth.Parameter);
47+
if (await AuthenticationHelper.TrySetDigestAuthToken(request, _credentials, digestResponse, HttpKnownHeaderNames.Authorization).ConfigureAwait(false))
48+
{
49+
response.Dispose();
50+
response = await _innerHandler.SendAsync(request, cancellationToken).ConfigureAwait(false);
51+
52+
// Retry in case of nonce timeout in server.
53+
if (response.StatusCode == HttpStatusCode.Unauthorized)
54+
{
55+
foreach (AuthenticationHeaderValue ahv in response.Headers.WwwAuthenticate)
56+
{
57+
if (ahv.Scheme == AuthenticationHelper.Digest)
58+
{
59+
digestResponse = new AuthenticationHelper.DigestResponse(ahv.Parameter);
60+
if (AuthenticationHelper.IsServerNonceStale(digestResponse) &&
61+
await AuthenticationHelper.TrySetDigestAuthToken(request, _credentials, digestResponse, HttpKnownHeaderNames.Authorization).ConfigureAwait(false))
62+
{
63+
response.Dispose();
64+
response = await _innerHandler.SendAsync(request, cancellationToken).ConfigureAwait(false);
65+
}
66+
67+
break;
68+
}
69+
}
70+
}
71+
}
72+
break;
73+
74+
case AuthenticationHelper.Basic:
75+
if (_preAuthenticate)
76+
{
77+
// We already tried these credentials via preauthentication, so no need to try again
78+
break;
79+
}
80+
81+
if (AuthenticationHelper.TrySetBasicAuthToken(request, _credentials))
82+
{
83+
response.Dispose();
84+
response = await _innerHandler.SendAsync(request, cancellationToken).ConfigureAwait(false);
85+
}
86+
break;
87+
}
88+
}
89+
}
90+
91+
return response;
92+
}
93+
94+
private static AuthenticationHeaderValue GetSupportedAuthScheme(HttpHeaderValueCollection<AuthenticationHeaderValue> authenticateValues)
95+
{
96+
AuthenticationHeaderValue basicAuthenticationHeaderValue = null;
97+
98+
// Only Digest and Basic auth supported, ignore others.
99+
foreach (AuthenticationHeaderValue ahv in authenticateValues)
100+
{
101+
if (ahv.Scheme == AuthenticationHelper.Digest)
102+
{
103+
return ahv;
104+
}
105+
else if (ahv.Scheme == AuthenticationHelper.Basic)
106+
{
107+
basicAuthenticationHeaderValue = ahv;
108+
}
109+
}
110+
111+
return basicAuthenticationHeaderValue;
112+
}
113+
114+
protected override void Dispose(bool disposing)
115+
{
116+
if (disposing)
117+
{
118+
_innerHandler.Dispose();
119+
}
120+
121+
base.Dispose(disposing);
122+
}
123+
}
124+
}
125+

0 commit comments

Comments
 (0)