-
Notifications
You must be signed in to change notification settings - Fork 4.9k
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
Implemement OnBehalfOfCredential #22146
Merged
Merged
Changes from 28 commits
Commits
Show all changes
31 commits
Select commit
Hold shift + click to select a range
264bff6
SupportsCaching property, OBO credential
christothes 1eaca9f
export
christothes 3abc6a3
BAP test
christothes 568908a
missing xml docs
christothes 5287642
CredentialTestBase
christothes 66adcea
add new virtual to UnsafeTokenCacheOptions
christothes ac08680
refactor UserAssertionScope
christothes 0bb3d6a
merge
christothes 1a7b5c1
export
christothes ae2b022
UnsafeTokenCacheOptions and TokenCacheNotificationDetails
christothes 05fee10
tweaks
christothes cc4ac48
Merge remote-tracking branch 'upstream/main' into chriss/OnBehalfOf
christothes 5029352
Merge remote-tracking branch 'upstream/main' into chriss/OnBehalfOf
christothes 64d2788
fb
christothes 4a68ef1
refactor using AccessToken.RefreshOn
christothes 6be7493
export
christothes 7f52c10
fb
christothes 8a6be33
tweaks
christothes 0440c00
remove comment
christothes 52fe1b1
Merge remote-tracking branch 'upstream/main' into chriss/OnBehalfOf
christothes 916eed1
Merge branch 'chriss/OnBehalfOf' of https://github.com/christothes/az…
christothes d7b582d
use DateTimeOffset.MinValue as no-cache indicator
christothes 3b10559
protect against datetimeoffset underflow
christothes cecffe1
update RefreshOn doc comment
christothes cc7fd2f
Simple OBO
christothes bab4afc
revert core changes
christothes 837d1d6
proj tweak
christothes ea9066f
merge
christothes baed5fe
more ctor overloads
christothes cf193ab
fb
christothes aea16af
merge
christothes File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
// Copyright (c) Microsoft Corporation. All rights reserved. | ||
// Licensed under the MIT License. | ||
|
||
using System; | ||
using System.Threading; | ||
using System.Threading.Tasks; | ||
using Azure.Core; | ||
using Azure.Core.Pipeline; | ||
using Microsoft.Identity.Client; | ||
|
||
namespace Azure.Identity | ||
{ | ||
/// <summary> | ||
/// Enables authentication to Azure Active Directory using an On-Behalf-Of flow.`` | ||
/// </summary> | ||
public class OnBehalfOfCredential : TokenCredential | ||
christothes marked this conversation as resolved.
Show resolved
Hide resolved
|
||
{ | ||
private readonly MsalConfidentialClient _client; | ||
private readonly string _tenantId; | ||
private readonly CredentialPipeline _pipeline; | ||
private readonly bool _allowMultiTenantAuthentication; | ||
private readonly string _clientId; | ||
private readonly string _clientSecret; | ||
private readonly UserAssertion _userAssertion; | ||
|
||
/// <summary> | ||
/// Protected constructor for mocking. | ||
/// </summary> | ||
protected OnBehalfOfCredential() | ||
{ } | ||
|
||
/// <summary> | ||
/// Creates an instance of the <see cref="OnBehalfOfCredential"/> with the details needed to authenticate with Azure Active Directory. | ||
/// </summary> | ||
/// <param name="tenantId">The Azure Active Directory tenant (directory) Id of the service principal.</param> | ||
/// <param name="clientId">The client (application) ID of the service principal</param> | ||
/// <param name="clientSecret">A client secret that was generated for the App Registration used to authenticate the client.</param> | ||
/// <param name="userAssertion">The access token that will be used by <see cref="OnBehalfOfCredential"/> as the user assertion when requesting On-Behalf-Of tokens.</param> | ||
/// <param name="options">Options that allow to configure the management of the requests sent to the Azure Active Directory service.</param> | ||
public OnBehalfOfCredential( | ||
string tenantId, | ||
string clientId, | ||
string clientSecret, | ||
string userAssertion, | ||
OnBehalfOfCredentialOptions options = null) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: why does this ctor use a default parameter where the ctor which takes an X509Cert has an explicit overload? |
||
: this(tenantId, clientId, clientSecret, userAssertion, options, null, null) | ||
{ } | ||
|
||
internal OnBehalfOfCredential( | ||
string tenantId, | ||
string clientId, | ||
string clientSecret, | ||
christothes marked this conversation as resolved.
Show resolved
Hide resolved
|
||
string userAssertion, | ||
OnBehalfOfCredentialOptions options, | ||
CredentialPipeline pipeline, | ||
MsalConfidentialClient client) | ||
{ | ||
Argument.AssertNotNull(clientId, nameof(clientId)); | ||
Argument.AssertNotNull(clientSecret, nameof(clientSecret)); | ||
|
||
options ??= new OnBehalfOfCredentialOptions(); | ||
_pipeline = pipeline ?? CredentialPipeline.GetInstance(options); | ||
_allowMultiTenantAuthentication = options.AllowMultiTenantAuthentication; | ||
_tenantId = Validations.ValidateTenantId(tenantId, nameof(tenantId)); | ||
_clientId = clientId; | ||
_clientSecret = clientSecret; | ||
_userAssertion = new UserAssertion(userAssertion); | ||
_client = client ?? new MsalConfidentialClient(_pipeline, _tenantId, _clientId, _clientSecret, options, default, options.IsLoggingPIIEnabled); | ||
} | ||
|
||
/// <inheritdoc /> | ||
public override AccessToken GetToken(TokenRequestContext requestContext, CancellationToken cancellationToken) => | ||
GetTokenInternalAsync(requestContext, false, cancellationToken).EnsureCompleted(); | ||
|
||
/// <inheritdoc /> | ||
public override ValueTask<AccessToken> GetTokenAsync(TokenRequestContext requestContext, CancellationToken cancellationToken) => | ||
GetTokenInternalAsync(requestContext, true, cancellationToken); | ||
|
||
internal async ValueTask<AccessToken> GetTokenInternalAsync(TokenRequestContext requestContext, bool async, CancellationToken cancellationToken) | ||
{ | ||
using CredentialDiagnosticScope scope = _pipeline.StartGetTokenScope("OnBehalfOfCredential.GetToken", requestContext); | ||
|
||
try | ||
{ | ||
var tenantId = TenantIdResolver.Resolve(_tenantId, requestContext, _allowMultiTenantAuthentication); | ||
|
||
AuthenticationResult result = await _client | ||
.AcquireTokenOnBehalfOf(requestContext.Scopes, tenantId, _userAssertion, async, cancellationToken) | ||
christothes marked this conversation as resolved.
Show resolved
Hide resolved
|
||
.ConfigureAwait(false); | ||
|
||
return new AccessToken(result.AccessToken, result.ExpiresOn); | ||
} | ||
catch (Exception e) | ||
{ | ||
throw scope.FailWrapAndThrow(e); | ||
} | ||
} | ||
} | ||
} |
16 changes: 16 additions & 0 deletions
16
sdk/identity/Azure.Identity/src/OnBehalfOfCredentialOptions.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,16 @@ | ||
// Copyright (c) Microsoft Corporation. All rights reserved. | ||
// Licensed under the MIT License. | ||
|
||
namespace Azure.Identity | ||
{ | ||
/// <summary> | ||
/// | ||
/// </summary> | ||
public class OnBehalfOfCredentialOptions : TokenCredentialOptions, ITokenCacheOptions | ||
{ | ||
/// <summary> | ||
/// The <see cref="TokenCachePersistenceOptions"/>. | ||
/// </summary> | ||
public TokenCachePersistenceOptions TokenCachePersistenceOptions { get; set; } | ||
} | ||
} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
// Copyright (c) Microsoft Corporation. All rights reserved. | ||
// Licensed under the MIT License. | ||
|
||
using System; | ||
|
||
namespace Azure.Identity | ||
{ | ||
/// <summary> | ||
/// Details related to a <see cref="UnsafeTokenCacheOptions"/> cache delegate. | ||
/// </summary> | ||
public struct TokenCacheDetails | ||
{ | ||
/// <summary> | ||
/// The bytes representing the state of the token cache. | ||
/// </summary> | ||
public ReadOnlyMemory<byte> CacheBytes { get; set; } | ||
} | ||
} |
34 changes: 34 additions & 0 deletions
34
sdk/identity/Azure.Identity/src/TokenCacheNotificationDetails.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,34 @@ | ||
// Copyright (c) Microsoft Corporation. All rights reserved. | ||
// Licensed under the MIT License. | ||
|
||
using Microsoft.Identity.Client; | ||
|
||
namespace Azure.Identity | ||
{ | ||
/// <summary> | ||
/// Args setnt to TokenCache OnBefore and OnAfter events. | ||
/// </summary> | ||
public class TokenCacheNotificationDetails | ||
{ | ||
/// <summary> | ||
/// A suggested token cache key, which can be used with general purpose storage mechanisms that allow | ||
/// storing key-value pairs and key based retrieval. Useful in applications that store 1 token cache per user, | ||
/// the recommended pattern for web apps. | ||
/// | ||
/// The value is: | ||
/// | ||
/// <list type="bullet"> | ||
/// <item>the homeAccountId for AcquireTokenSilent, GetAccount(homeAccountId), RemoveAccount and when writing tokens on confidential client calls</item> | ||
/// <item>clientID + "_AppTokenCache" for AcquireTokenForClient</item> | ||
/// <item>clientID_tenantID + "_AppTokenCache" for AcquireTokenForClient when tenant specific authority</item> | ||
/// <item>the hash of the original token for AcquireTokenOnBehalfOf</item> | ||
/// </list> | ||
/// </summary> | ||
public string SuggestedCacheKey { get; } | ||
|
||
internal TokenCacheNotificationDetails(TokenCacheNotificationArgs args) | ||
{ | ||
SuggestedCacheKey = args.SuggestedCacheKey; | ||
} | ||
} | ||
} |
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
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this feature deserves a sample.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed - I plan to add one in a follow up PR