Skip to content

Commit 1e14cc2

Browse files
github-actions[bot]tmdsMichaelSimons
authored
[release/9.0.1xx] AuthHandshakeMessageHandler: sync behavior with other clients. (#43942)
Co-authored-by: Tom Deseyn <[email protected]> Co-authored-by: Michael Simons <[email protected]>
1 parent 6584704 commit 1e14cc2

File tree

2 files changed

+296
-27
lines changed

2 files changed

+296
-27
lines changed

src/Containers/Microsoft.NET.Build.Containers/AuthHandshakeMessageHandler.cs

Lines changed: 25 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -71,18 +71,19 @@ private static bool TryParseAuthenticationInfo(HttpResponseMessage msg, [NotNull
7171
if (header.Scheme is not null)
7272
{
7373
scheme = header.Scheme;
74-
var keyValues = ParseBearerArgs(header.Parameter);
75-
if (keyValues is null)
76-
{
77-
return false;
78-
}
7974

8075
if (header.Scheme.Equals(BasicAuthScheme, StringComparison.OrdinalIgnoreCase))
8176
{
82-
return TryParseBasicAuthInfo(keyValues, msg.RequestMessage!.RequestUri!, out bearerAuthInfo);
77+
bearerAuthInfo = null;
78+
return true;
8379
}
8480
else if (header.Scheme.Equals(BearerAuthScheme, StringComparison.OrdinalIgnoreCase))
8581
{
82+
var keyValues = ParseBearerArgs(header.Parameter);
83+
if (keyValues is null)
84+
{
85+
return false;
86+
}
8687
return TryParseBearerAuthInfo(keyValues, out bearerAuthInfo);
8788
}
8889
else
@@ -110,12 +111,6 @@ static bool TryParseBearerAuthInfo(Dictionary<string, string> authValues, [NotNu
110111
}
111112
}
112113

113-
static bool TryParseBasicAuthInfo(Dictionary<string, string> authValues, Uri requestUri, out AuthInfo? authInfo)
114-
{
115-
authInfo = null;
116-
return true;
117-
}
118-
119114
static Dictionary<string, string>? ParseBearerArgs(string? bearerHeaderArgs)
120115
{
121116
if (bearerHeaderArgs is null)
@@ -159,7 +154,6 @@ public DateTimeOffset ResolvedExpiration
159154
/// </summary>
160155
private async Task<(AuthenticationHeaderValue, DateTimeOffset)?> GetAuthenticationAsync(string registry, string scheme, AuthInfo? bearerAuthInfo, CancellationToken cancellationToken)
161156
{
162-
163157
DockerCredentials? privateRepoCreds;
164158
// Allow overrides for auth via environment variables
165159
if (GetDockerCredentialsFromEnvironment(_registryMode) is (string credU, string credP))
@@ -180,14 +174,20 @@ public DateTimeOffset ResolvedExpiration
180174
{
181175
Debug.Assert(bearerAuthInfo is not null);
182176

183-
var authenticationValueAndDuration = await TryOAuthPostAsync(privateRepoCreds, bearerAuthInfo, cancellationToken).ConfigureAwait(false);
184-
if (authenticationValueAndDuration is not null)
177+
// Obtain a Bearer token, when the credentials are:
178+
// - an identity token: use it for OAuth
179+
// - a username/password: use them for Basic auth, and fall back to OAuth
180+
181+
if (string.IsNullOrWhiteSpace(privateRepoCreds.IdentityToken))
185182
{
186-
return authenticationValueAndDuration;
183+
var authenticationValueAndDuration = await TryTokenGetAsync(privateRepoCreds, bearerAuthInfo, cancellationToken).ConfigureAwait(false);
184+
if (authenticationValueAndDuration is not null)
185+
{
186+
return authenticationValueAndDuration;
187+
}
187188
}
188189

189-
authenticationValueAndDuration = await TryTokenGetAsync(privateRepoCreds, bearerAuthInfo, cancellationToken).ConfigureAwait(false);
190-
return authenticationValueAndDuration;
190+
return await TryOAuthPostAsync(privateRepoCreds, bearerAuthInfo, cancellationToken).ConfigureAwait(false);
191191
}
192192
else
193193
{
@@ -293,8 +293,7 @@ internal static (string credU, string credP)? GetDockerCredentialsFromEnvironmen
293293
if (!postResponse.IsSuccessStatusCode)
294294
{
295295
await postResponse.LogHttpResponseAsync(_logger, cancellationToken).ConfigureAwait(false);
296-
//return null to try HTTP GET instead
297-
return null;
296+
return null; // try next method
298297
}
299298
_logger.LogTrace("Received '{statuscode}'.", postResponse.StatusCode);
300299
TokenResponse? tokenResponse = JsonSerializer.Deserialize<TokenResponse>(postResponse.Content.ReadAsStream(cancellationToken));
@@ -306,8 +305,7 @@ internal static (string credU, string credP)? GetDockerCredentialsFromEnvironmen
306305
else
307306
{
308307
_logger.LogTrace(Resource.GetString(nameof(Strings.CouldntDeserializeJsonToken)));
309-
// logging and returning null to try HTTP GET instead
310-
return null;
308+
return null; // try next method
311309
}
312310
}
313311

@@ -318,9 +316,7 @@ internal static (string credU, string credP)? GetDockerCredentialsFromEnvironmen
318316
{
319317
// this doesn't seem to be called out in the spec, but actual username/password auth information should be converted into Basic auth here,
320318
// even though the overall Scheme we're authenticating for is Bearer
321-
var header = privateRepoCreds.Username == "<token>"
322-
? new AuthenticationHeaderValue(BearerAuthScheme, privateRepoCreds.Password)
323-
: new AuthenticationHeaderValue(BasicAuthScheme, Convert.ToBase64String(Encoding.ASCII.GetBytes($"{privateRepoCreds.Username}:{privateRepoCreds.Password}")));
319+
var header = new AuthenticationHeaderValue(BasicAuthScheme, Convert.ToBase64String(Encoding.ASCII.GetBytes($"{privateRepoCreds.Username}:{privateRepoCreds.Password}")));
324320
var builder = new UriBuilder(new Uri(bearerAuthInfo.Realm));
325321

326322
_logger.LogTrace("Attempting to authenticate on {uri} using GET.", bearerAuthInfo.Realm);
@@ -340,7 +336,8 @@ internal static (string credU, string credP)? GetDockerCredentialsFromEnvironmen
340336
using var tokenResponse = await base.SendAsync(message, cancellationToken).ConfigureAwait(false);
341337
if (!tokenResponse.IsSuccessStatusCode)
342338
{
343-
throw new UnableToAccessRepositoryException(_registryName);
339+
await tokenResponse.LogHttpResponseAsync(_logger, cancellationToken).ConfigureAwait(false);
340+
return null; // try next method
344341
}
345342

346343
TokenResponse? token = JsonSerializer.Deserialize<TokenResponse>(tokenResponse.Content.ReadAsStream(cancellationToken));
@@ -412,7 +409,8 @@ protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage
412409
request.Headers.Authorization = authHeader;
413410
return await base.SendAsync(request, cancellationToken).ConfigureAwait(false);
414411
}
415-
return response;
412+
413+
throw new UnableToAccessRepositoryException(_registryName);
416414
}
417415
else
418416
{

0 commit comments

Comments
 (0)