Skip to content
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

Turn BearerTokenAuthenticationPolicy into BearerTokenChallengeAuthenticationPolicy #20670

Merged
merged 15 commits into from
May 4, 2021
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
<Compile Include="$(AzureCoreSharedSources)ArrayBufferWriter.cs" LinkBase="Shared" />
<Compile Include="$(AzureCoreSharedSources)AuthorizationChallengeParser.cs" LinkBase="Shared" />
<Compile Include="$(AzureCoreSharedSources)AzureResourceProviderNamespaceAttribute.cs" LinkBase="Shared" />
<Compile Include="$(AzureCoreSharedSources)BearerTokenChallengeAuthenticationPolicy.cs" LinkBase="Shared" />
<Compile Include="$(AzureCoreSharedSources)ClientDiagnostics.cs" LinkBase="Shared" />
<Compile Include="$(AzureCoreSharedSources)ContentTypeUtilities.cs" LinkBase="Shared" />
<Compile Include="$(AzureCoreSharedSources)DiagnosticScope.cs" LinkBase="Shared" />
Expand All @@ -28,6 +27,12 @@
<Compile Include="$(AzureCoreSharedSources)PageResponseEnumerator.cs" LinkBase="Shared" />
</ItemGroup>

<!-- TODO: revert when Azure.Core ships -->
<ItemGroup>
<ProjectReference Include="..\..\..\core\Azure.Core\src\Azure.Core.csproj" />
</ItemGroup>
<!-- end TODO-->

<Import Project="$(MSBuildThisFileDirectory)..\..\..\core\Azure.Core\src\Azure.Core.props" />

</Project>
3 changes: 3 additions & 0 deletions sdk/core/Azure.Core/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

## 1.14.0-beta.1 (Unreleased)

### Added

- Added `BearerTokenChallengeAuthenticationPolicy`, which enables creation of authentication policies that can handle challenges.

## 1.13.0 (2021-04-07)

Expand Down
11 changes: 11 additions & 0 deletions sdk/core/Azure.Core/api/Azure.Core.net461.cs
Original file line number Diff line number Diff line change
Expand Up @@ -516,6 +516,17 @@ public BearerTokenAuthenticationPolicy(Azure.Core.TokenCredential credential, st
public override void Process(Azure.Core.HttpMessage message, System.ReadOnlyMemory<Azure.Core.Pipeline.HttpPipelinePolicy> pipeline) { }
public override System.Threading.Tasks.ValueTask ProcessAsync(Azure.Core.HttpMessage message, System.ReadOnlyMemory<Azure.Core.Pipeline.HttpPipelinePolicy> pipeline) { throw null; }
}
public partial class BearerTokenChallengeAuthenticationPolicy : Azure.Core.Pipeline.HttpPipelinePolicy
{
public BearerTokenChallengeAuthenticationPolicy(Azure.Core.TokenCredential credential, System.Collections.Generic.IEnumerable<string> scopes) { }
public BearerTokenChallengeAuthenticationPolicy(Azure.Core.TokenCredential credential, string scope) { }
protected System.Collections.ObjectModel.ReadOnlyCollection<string> Scopes { get { throw null; } }
protected virtual System.Threading.Tasks.ValueTask AuthorizeRequestAsync(Azure.Core.HttpMessage message, bool async) { throw null; }
protected virtual System.Threading.Tasks.ValueTask<bool> AuthorizeRequestOnChallengeAsync(Azure.Core.HttpMessage message, bool async) { throw null; }
public override void Process(Azure.Core.HttpMessage message, System.ReadOnlyMemory<Azure.Core.Pipeline.HttpPipelinePolicy> pipeline) { }
public override System.Threading.Tasks.ValueTask ProcessAsync(Azure.Core.HttpMessage message, System.ReadOnlyMemory<Azure.Core.Pipeline.HttpPipelinePolicy> pipeline) { throw null; }
protected System.Threading.Tasks.ValueTask SetAuthorizationHeader(Azure.Core.HttpMessage message, Azure.Core.TokenRequestContext context, bool async) { throw null; }
}
public partial class HttpClientTransport : Azure.Core.Pipeline.HttpPipelineTransport
{
public static readonly Azure.Core.Pipeline.HttpClientTransport Shared;
Expand Down
11 changes: 11 additions & 0 deletions sdk/core/Azure.Core/api/Azure.Core.net5.0.cs
Original file line number Diff line number Diff line change
Expand Up @@ -516,6 +516,17 @@ public BearerTokenAuthenticationPolicy(Azure.Core.TokenCredential credential, st
public override void Process(Azure.Core.HttpMessage message, System.ReadOnlyMemory<Azure.Core.Pipeline.HttpPipelinePolicy> pipeline) { }
public override System.Threading.Tasks.ValueTask ProcessAsync(Azure.Core.HttpMessage message, System.ReadOnlyMemory<Azure.Core.Pipeline.HttpPipelinePolicy> pipeline) { throw null; }
}
public partial class BearerTokenChallengeAuthenticationPolicy : Azure.Core.Pipeline.HttpPipelinePolicy
{
public BearerTokenChallengeAuthenticationPolicy(Azure.Core.TokenCredential credential, System.Collections.Generic.IEnumerable<string> scopes) { }
public BearerTokenChallengeAuthenticationPolicy(Azure.Core.TokenCredential credential, string scope) { }
protected System.Collections.ObjectModel.ReadOnlyCollection<string> Scopes { get { throw null; } }
protected virtual System.Threading.Tasks.ValueTask AuthorizeRequestAsync(Azure.Core.HttpMessage message, bool async) { throw null; }
protected virtual System.Threading.Tasks.ValueTask<bool> AuthorizeRequestOnChallengeAsync(Azure.Core.HttpMessage message, bool async) { throw null; }
public override void Process(Azure.Core.HttpMessage message, System.ReadOnlyMemory<Azure.Core.Pipeline.HttpPipelinePolicy> pipeline) { }
public override System.Threading.Tasks.ValueTask ProcessAsync(Azure.Core.HttpMessage message, System.ReadOnlyMemory<Azure.Core.Pipeline.HttpPipelinePolicy> pipeline) { throw null; }
protected System.Threading.Tasks.ValueTask SetAuthorizationHeader(Azure.Core.HttpMessage message, Azure.Core.TokenRequestContext context, bool async) { throw null; }
}
public partial class HttpClientTransport : Azure.Core.Pipeline.HttpPipelineTransport
{
public static readonly Azure.Core.Pipeline.HttpClientTransport Shared;
Expand Down
11 changes: 11 additions & 0 deletions sdk/core/Azure.Core/api/Azure.Core.netcoreapp2.1.cs
Original file line number Diff line number Diff line change
Expand Up @@ -516,6 +516,17 @@ public BearerTokenAuthenticationPolicy(Azure.Core.TokenCredential credential, st
public override void Process(Azure.Core.HttpMessage message, System.ReadOnlyMemory<Azure.Core.Pipeline.HttpPipelinePolicy> pipeline) { }
public override System.Threading.Tasks.ValueTask ProcessAsync(Azure.Core.HttpMessage message, System.ReadOnlyMemory<Azure.Core.Pipeline.HttpPipelinePolicy> pipeline) { throw null; }
}
public partial class BearerTokenChallengeAuthenticationPolicy : Azure.Core.Pipeline.HttpPipelinePolicy
{
public BearerTokenChallengeAuthenticationPolicy(Azure.Core.TokenCredential credential, System.Collections.Generic.IEnumerable<string> scopes) { }
public BearerTokenChallengeAuthenticationPolicy(Azure.Core.TokenCredential credential, string scope) { }
protected System.Collections.ObjectModel.ReadOnlyCollection<string> Scopes { get { throw null; } }
protected virtual System.Threading.Tasks.ValueTask AuthorizeRequestAsync(Azure.Core.HttpMessage message, bool async) { throw null; }
protected virtual System.Threading.Tasks.ValueTask<bool> AuthorizeRequestOnChallengeAsync(Azure.Core.HttpMessage message, bool async) { throw null; }
public override void Process(Azure.Core.HttpMessage message, System.ReadOnlyMemory<Azure.Core.Pipeline.HttpPipelinePolicy> pipeline) { }
public override System.Threading.Tasks.ValueTask ProcessAsync(Azure.Core.HttpMessage message, System.ReadOnlyMemory<Azure.Core.Pipeline.HttpPipelinePolicy> pipeline) { throw null; }
protected System.Threading.Tasks.ValueTask SetAuthorizationHeader(Azure.Core.HttpMessage message, Azure.Core.TokenRequestContext context, bool async) { throw null; }
}
public partial class HttpClientTransport : Azure.Core.Pipeline.HttpPipelineTransport
{
public static readonly Azure.Core.Pipeline.HttpClientTransport Shared;
Expand Down
11 changes: 11 additions & 0 deletions sdk/core/Azure.Core/api/Azure.Core.netstandard2.0.cs
Original file line number Diff line number Diff line change
Expand Up @@ -516,6 +516,17 @@ public BearerTokenAuthenticationPolicy(Azure.Core.TokenCredential credential, st
public override void Process(Azure.Core.HttpMessage message, System.ReadOnlyMemory<Azure.Core.Pipeline.HttpPipelinePolicy> pipeline) { }
public override System.Threading.Tasks.ValueTask ProcessAsync(Azure.Core.HttpMessage message, System.ReadOnlyMemory<Azure.Core.Pipeline.HttpPipelinePolicy> pipeline) { throw null; }
}
public partial class BearerTokenChallengeAuthenticationPolicy : Azure.Core.Pipeline.HttpPipelinePolicy
{
public BearerTokenChallengeAuthenticationPolicy(Azure.Core.TokenCredential credential, System.Collections.Generic.IEnumerable<string> scopes) { }
public BearerTokenChallengeAuthenticationPolicy(Azure.Core.TokenCredential credential, string scope) { }
protected System.Collections.ObjectModel.ReadOnlyCollection<string> Scopes { get { throw null; } }
protected virtual System.Threading.Tasks.ValueTask AuthorizeRequestAsync(Azure.Core.HttpMessage message, bool async) { throw null; }
protected virtual System.Threading.Tasks.ValueTask<bool> AuthorizeRequestOnChallengeAsync(Azure.Core.HttpMessage message, bool async) { throw null; }
christothes marked this conversation as resolved.
Show resolved Hide resolved
public override void Process(Azure.Core.HttpMessage message, System.ReadOnlyMemory<Azure.Core.Pipeline.HttpPipelinePolicy> pipeline) { }
public override System.Threading.Tasks.ValueTask ProcessAsync(Azure.Core.HttpMessage message, System.ReadOnlyMemory<Azure.Core.Pipeline.HttpPipelinePolicy> pipeline) { throw null; }
protected System.Threading.Tasks.ValueTask SetAuthorizationHeader(Azure.Core.HttpMessage message, Azure.Core.TokenRequestContext context, bool async) { throw null; }
christothes marked this conversation as resolved.
Show resolved Hide resolved
}
public partial class HttpClientTransport : Azure.Core.Pipeline.HttpPipelineTransport
{
public static readonly Azure.Core.Pipeline.HttpClientTransport Shared;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
using Azure.Core.Diagnostics;

#nullable enable

Expand All @@ -16,11 +18,18 @@ namespace Azure.Core.Pipeline
/// A policy that sends an <see cref="AccessToken"/> provided by a <see cref="TokenCredential"/> as an Authentication header.
/// Note: This class is currently in preview and is therefore subject to possible future breaking changes.
/// </summary>
internal class BearerTokenChallengeAuthenticationPolicy : HttpPipelinePolicy
public class BearerTokenChallengeAuthenticationPolicy : HttpPipelinePolicy
{
/// <summary>
/// The scopes currently configured for token requests to the credential
/// </summary>
protected ReadOnlyCollection<string> Scopes => _readOnlyScopes ??= Array.AsReadOnly(_scopes);

private string[] _scopes;
private ReadOnlyCollection<string>? _readOnlyScopes;

private readonly AccessTokenCache _accessTokenCache;
protected string[] Scopes { get; private set; }
private readonly ValueTask<bool> _falseValueTask = new ValueTask<bool>(Task.FromResult(false));
private readonly ValueTask<bool> _falseValueTask = new(Task.FromResult(false));
christothes marked this conversation as resolved.
Show resolved Hide resolved

/// <summary>
/// Creates a new instance of <see cref="BearerTokenChallengeAuthenticationPolicy"/> using provided token credential and scope to authenticate for.
Expand All @@ -33,16 +42,17 @@ public BearerTokenChallengeAuthenticationPolicy(TokenCredential credential, stri
/// Creates a new instance of <see cref="BearerTokenChallengeAuthenticationPolicy"/> using provided token credential and scopes to authenticate for.
/// </summary>
/// <param name="credential">The token credential to use for authentication.</param>
/// <param name="scopes">Scopes to authenticate for.</param>
/// <param name="scopes">_scopes to authenticate for.</param>
christothes marked this conversation as resolved.
Show resolved Hide resolved
public BearerTokenChallengeAuthenticationPolicy(TokenCredential credential, IEnumerable<string> scopes)
: this(credential, scopes, TimeSpan.FromMinutes(5), TimeSpan.FromSeconds(30)) { }
: this(credential, scopes, TimeSpan.FromMinutes(5), TimeSpan.FromSeconds(30))
{ }

internal BearerTokenChallengeAuthenticationPolicy(TokenCredential credential, IEnumerable<string> scopes, TimeSpan tokenRefreshOffset, TimeSpan tokenRefreshRetryDelay)
{
Argument.AssertNotNull(credential, nameof(credential));
Argument.AssertNotNull(scopes, nameof(scopes));

Scopes = scopes.ToArray();
_scopes = scopes.ToArray();
_accessTokenCache = new AccessTokenCache(credential, tokenRefreshOffset, tokenRefreshRetryDelay, scopes.ToArray());
}

Expand All @@ -65,9 +75,9 @@ public override void Process(HttpMessage message, ReadOnlyMemory<HttpPipelinePol
/// <param name="message">The <see cref="HttpMessage"/> this policy would be applied to.</param>
/// <param name="async">Indicates whether the method was called from an asynchronous context.</param>
/// <returns>The <see cref="ValueTask"/> representing the asynchronous operation.</returns>
protected virtual Task AuthorizeRequestAsync(HttpMessage message, bool async)
protected virtual ValueTask AuthorizeRequestAsync(HttpMessage message, bool async)
{
var context = new TokenRequestContext(Scopes, message.Request.ClientRequestId);
var context = new TokenRequestContext(_scopes, message.Request.ClientRequestId);
return SetAuthorizationHeader(message, context, async);
}

Expand Down Expand Up @@ -127,7 +137,7 @@ private async ValueTask ProcessAsync(HttpMessage message, ReadOnlyMemory<HttpPip
/// <param name="message">The <see cref="HttpMessage"/> with the <see cref="Request"/> to be authorized.</param>
/// <param name="context">The <see cref="TokenRequestContext"/> used to authorize the <see cref="Request"/>.</param>
/// <param name="async">Indicates whether the method was called from an asynchronous context.</param>
protected async Task SetAuthorizationHeader(HttpMessage message, TokenRequestContext context, bool async)
protected async ValueTask SetAuthorizationHeader(HttpMessage message, TokenRequestContext context, bool async)
{
string headerValue;
if (async)
Expand All @@ -152,6 +162,7 @@ private class AccessTokenCache
private TokenRequestContext? _currentContext;
private TaskCompletionSource<HeaderValueInfo>? _infoTcs;
private TaskCompletionSource<HeaderValueInfo>? _backgroundUpdateTcs;

public AccessTokenCache(TokenCredential credential, TimeSpan tokenRefreshOffset, TimeSpan tokenRefreshRetryDelay, string[] initialScopes)
{
_credential = credential;
Expand Down Expand Up @@ -315,19 +326,15 @@ private async ValueTask GetHeaderValueFromCredentialInBackgroundAsync(TaskComple
HeaderValueInfo newInfo = await GetHeaderValueFromCredentialAsync(context, async, cts.Token).ConfigureAwait(false);
backgroundUpdateTcs.SetResult(newInfo);
}
catch (OperationCanceledException) when (cts.IsCancellationRequested)
catch (OperationCanceledException oce) when (cts.IsCancellationRequested)
{
backgroundUpdateTcs.SetResult(new HeaderValueInfo(info.HeaderValue, info.ExpiresOn, DateTimeOffset.UtcNow));

// https://github.com/Azure/azure-sdk-for-net/issues/18539
//AzureCoreEventSource.Singleton.BackgroundRefreshFailed(context.ParentRequestId ?? string.Empty, oce.ToString());
AzureCoreEventSource.Singleton.BackgroundRefreshFailed(context.ParentRequestId ?? string.Empty, oce.ToString());
}
catch (Exception)
catch (Exception e)
{
backgroundUpdateTcs.SetResult(new HeaderValueInfo(info.HeaderValue, info.ExpiresOn, DateTimeOffset.UtcNow + _tokenRefreshRetryDelay));

// https://github.com/Azure/azure-sdk-for-net/issues/18539
//AzureCoreEventSource.Singleton.BackgroundRefreshFailed(context.ParentRequestId ?? string.Empty, e.ToString());
AzureCoreEventSource.Singleton.BackgroundRefreshFailed(context.ParentRequestId ?? string.Empty, e.ToString());
christothes marked this conversation as resolved.
Show resolved Hide resolved
}
finally
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System;
using System.Threading.Tasks;
using System.Collections.Generic;
using System.Linq;

#nullable enable

Expand Down Expand Up @@ -39,8 +40,8 @@ protected override async ValueTask<bool> AuthorizeRequestOnChallengeAsync(HttpMe
return false;
}

string claimsChallenge = Base64Url.DecodeString(challenge.ToString());
var context = new TokenRequestContext(Scopes, message.Request.ClientRequestId, claimsChallenge);
string claimsChallenge = Base64Url.DecodeString(challenge);
var context = new TokenRequestContext(Scopes.ToArray(), message.Request.ClientRequestId, claimsChallenge);
await SetAuthorizationHeader(message, context, async);
return true;
}
Expand Down
1 change: 0 additions & 1 deletion sdk/core/Azure.Core/tests/Azure.Core.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
<Compile Include="..\src\Shared\ArrayBufferWriter.cs" LinkBase="Shared" />
<Compile Include="..\src\Shared\ARMChallengeAuthenticationPolicy.cs" LinkBase="Shared" />
<Compile Include="..\src\Shared\AzureResourceProviderNamespaceAttribute.cs" LinkBase="Shared" />
<Compile Include="..\src\Shared\BearerTokenChallengeAuthenticationPolicy.cs" LinkBase="Shared" />
<Compile Include="..\src\Shared\ConnectionString.cs" LinkBase="Shared" />
<Compile Include="..\src\Shared\ForwardsClientCallsAttribute.cs" LinkBase="Shared" />
<Compile Include="..\src\Shared\HttpPipelineMessageHandler.cs" LinkBase="Shared" />
Expand Down
Loading