-
Notifications
You must be signed in to change notification settings - Fork 222
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Adding a base class for AuthorizationHeaderProvider for extensibility (#2857) * Adding a base class for AuthorizationHeaderProvider usable by extensions that want to leverage IdWeb for Bearer and Pop and process their own protocols * Update src/Microsoft.Identity.Web.TokenAcquisition/BaseAuthorizationHeaderProvider.cs Co-authored-by: jennyf19 <[email protected]> --------- Co-authored-by: jennyf19 <[email protected]> * Fixes #2855 (#2859) Tested with End to end test --------- Co-authored-by: jennyf19 <[email protected]>
- Loading branch information
Showing
9 changed files
with
230 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
49 changes: 49 additions & 0 deletions
49
src/Microsoft.Identity.Web.TokenAcquisition/BaseAuthorizationHeaderProvider.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
// Copyright (c) Microsoft Corporation. All rights reserved. | ||
// Licensed under the MIT License. | ||
|
||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Security.Claims; | ||
using System.Text; | ||
using System.Threading; | ||
using System.Threading.Tasks; | ||
using Microsoft.Extensions.DependencyInjection; | ||
using Microsoft.Identity.Abstractions; | ||
|
||
namespace Microsoft.Identity.Web.Extensibility | ||
{ | ||
/// <summary> | ||
/// Base class for custom implementations of <see cref="IAuthorizationHeaderProvider"/> that | ||
/// would still want to leverage the default implementation for the bearer and Pop protocols. | ||
/// </summary> | ||
public class BaseAuthorizationHeaderProvider : IAuthorizationHeaderProvider | ||
{ | ||
/// <summary> | ||
/// Constructor from a service provider | ||
/// </summary> | ||
/// <param name="serviceProvider"></param> | ||
public BaseAuthorizationHeaderProvider(IServiceProvider serviceProvider) | ||
{ | ||
// We, intentionally, use a locator pattern here, because we don't want to expose ITokenAcquisition | ||
// in the public API as it's going to be deprecated in future versions of IdWeb. Here this | ||
// is an implementation detail. | ||
var _tokenAcquisition = serviceProvider.GetRequiredService<ITokenAcquisition>(); | ||
implementation = new DefaultAuthorizationHeaderProvider(_tokenAcquisition); | ||
} | ||
|
||
private IAuthorizationHeaderProvider implementation; | ||
|
||
/// <inheritdoc/> | ||
public virtual Task<string> CreateAuthorizationHeaderForUserAsync(IEnumerable<string> scopes, AuthorizationHeaderProviderOptions? authorizationHeaderProviderOptions = null, ClaimsPrincipal? claimsPrincipal = null, CancellationToken cancellationToken = default) | ||
{ | ||
return implementation.CreateAuthorizationHeaderForUserAsync(scopes, authorizationHeaderProviderOptions, claimsPrincipal, cancellationToken); | ||
} | ||
|
||
/// <inheritdoc/> | ||
public virtual Task<string> CreateAuthorizationHeaderForAppAsync(string scopes, AuthorizationHeaderProviderOptions? downstreamApiOptions = null, CancellationToken cancellationToken = default) | ||
{ | ||
return implementation.CreateAuthorizationHeaderForAppAsync(scopes, downstreamApiOptions, cancellationToken); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
120 changes: 120 additions & 0 deletions
120
tests/E2E Tests/TokenAcquirerTests/BaseAuthorizationHeaderProviderTest.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
// Copyright (c) Microsoft Corporation. All rights reserved. | ||
// Licensed under the MIT License. | ||
|
||
using System; | ||
using System.Collections.Generic; | ||
using System.Security.Claims; | ||
using System.Threading; | ||
using System.Threading.Tasks; | ||
using Microsoft.AspNetCore.Http; | ||
using Microsoft.Extensions.DependencyInjection; | ||
using Microsoft.Identity.Abstractions; | ||
using Microsoft.Identity.Client; | ||
using Microsoft.Identity.Web; | ||
using Microsoft.Identity.Web.Extensibility; | ||
using Xunit; | ||
|
||
namespace TokenAcquirerTests | ||
{ | ||
public class BaseAuthorizationHeaderProviderTest | ||
{ | ||
public BaseAuthorizationHeaderProviderTest() | ||
{ | ||
TokenAcquirerFactory.ResetDefaultInstance(); // Test only | ||
} | ||
|
||
// Example of extension | ||
class CustomAuthorizationHeaderProvider : BaseAuthorizationHeaderProvider | ||
{ | ||
public CustomAuthorizationHeaderProvider(IServiceProvider serviceProvider) : base(serviceProvider) | ||
{ | ||
} | ||
public override Task<string> CreateAuthorizationHeaderForAppAsync(string scopes, AuthorizationHeaderProviderOptions? downstreamApiOptions = null, CancellationToken cancellationToken = default) | ||
{ | ||
if (downstreamApiOptions?.ProtocolScheme == "Custom") | ||
return Task.FromResult("Custom"); | ||
else | ||
return base.CreateAuthorizationHeaderForAppAsync(scopes, downstreamApiOptions, cancellationToken); | ||
} | ||
|
||
public override Task<string> CreateAuthorizationHeaderForUserAsync(IEnumerable<string> scopes, AuthorizationHeaderProviderOptions? authorizationHeaderProviderOptions = null, ClaimsPrincipal? claimsPrincipal = null, CancellationToken cancellationToken = default) | ||
{ | ||
if (authorizationHeaderProviderOptions?.ProtocolScheme == "Custom") | ||
return Task.FromResult("Custom"); | ||
else | ||
return base.CreateAuthorizationHeaderForUserAsync(scopes, authorizationHeaderProviderOptions, claimsPrincipal, cancellationToken); | ||
} | ||
} | ||
|
||
// Mock for ITokenAcquisition | ||
class CustomTokenAcquisition : ITokenAcquisition | ||
{ | ||
public Task<string> GetAccessTokenForAppAsync(string scope, string? authenticationScheme, string? tenant = null, TokenAcquisitionOptions? tokenAcquisitionOptions = null) | ||
{ | ||
throw new NotImplementedException(); | ||
} | ||
|
||
public Task<string> GetAccessTokenForUserAsync(IEnumerable<string> scopes, string? authenticationScheme, string? tenantId = null, string? userFlow = null, ClaimsPrincipal? user = null, TokenAcquisitionOptions? tokenAcquisitionOptions = null) | ||
{ | ||
throw new NotImplementedException(); | ||
} | ||
|
||
public Task<AuthenticationResult> GetAuthenticationResultForAppAsync(string scopes, string? authenticationOptionsName = null, string? tenant = null, TokenAcquisitionOptions? tokenAcquisitionOptions = null, CancellationToken cancellationToken = default) | ||
{ | ||
throw new NotImplementedException(); | ||
} | ||
|
||
public Task<AuthenticationResult> GetAuthenticationResultForAppAsync(string scope, string? authenticationScheme, string? tenant = null, TokenAcquisitionOptions? tokenAcquisitionOptions = null) | ||
{ | ||
throw new NotImplementedException(); | ||
} | ||
|
||
public Task<AuthenticationResult> GetAuthenticationResultForUserAsync(IEnumerable<string> scopes, string? authenticationOptionsName = null, string? tenant = null, string? userFlow = null, ClaimsPrincipal? claimsPrincipal = null, TokenAcquisitionOptions? tokenAcquisitionOptions = null, CancellationToken cancellationToken = default) | ||
{ | ||
throw new NotImplementedException(); | ||
} | ||
|
||
public Task<AuthenticationResult> GetAuthenticationResultForUserAsync(IEnumerable<string> scopes, string? authenticationScheme, string? tenantId = null, string? userFlow = null, ClaimsPrincipal? user = null, TokenAcquisitionOptions? tokenAcquisitionOptions = null) | ||
{ | ||
return Task.FromResult(new AuthenticationResult("eXY", false, null, DateTimeOffset.Now, DateTimeOffset.Now, null, null, null, null, Guid.Empty)); | ||
} | ||
|
||
public string GetEffectiveAuthenticationScheme(string? authenticationScheme) | ||
{ | ||
throw new NotImplementedException(); | ||
} | ||
|
||
public void ReplyForbiddenWithWwwAuthenticateHeader(IEnumerable<string> scopes, MsalUiRequiredException msalServiceException, string? authenticationScheme, HttpResponse? httpResponse = null) | ||
{ | ||
throw new NotImplementedException(); | ||
} | ||
|
||
public Task ReplyForbiddenWithWwwAuthenticateHeaderAsync(IEnumerable<string> scopes, MsalUiRequiredException msalServiceException, HttpResponse? httpResponse = null) | ||
{ | ||
throw new NotImplementedException(); | ||
} | ||
} | ||
|
||
[Fact] | ||
public async Task TestBaseAuthorizationHeaderProvider() | ||
{ | ||
TokenAcquirerFactory tokenAcquirerFactory = TokenAcquirerFactory.GetDefaultInstance(); | ||
// Test the extensibility | ||
tokenAcquirerFactory.Services.AddSingleton<IAuthorizationHeaderProvider, CustomAuthorizationHeaderProvider>(); | ||
|
||
// Mock the token acquisition | ||
tokenAcquirerFactory.Services.AddSingleton<ITokenAcquisition, CustomTokenAcquisition>(); | ||
var serviceProvider = tokenAcquirerFactory.Build(); | ||
|
||
IAuthorizationHeaderProvider authorizationHeaderProvider = serviceProvider.GetRequiredService<IAuthorizationHeaderProvider>(); | ||
string result = await authorizationHeaderProvider.CreateAuthorizationHeaderForUserAsync(["scope"], | ||
new AuthorizationHeaderProviderOptions { ProtocolScheme = "Custom" }, null, CancellationToken.None); | ||
Assert.Equal("Custom", result); | ||
|
||
result = await authorizationHeaderProvider.CreateAuthorizationHeaderForUserAsync(["scope"], | ||
new AuthorizationHeaderProviderOptions { }, null, CancellationToken.None); | ||
Assert.Equal("Bearer eXY", result); | ||
|
||
} | ||
} | ||
} |