Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Identity.Client.Advanced;
using Microsoft.Identity.Client.Extensibility;
using Microsoft.Identity.Client.ApiConfig.Executors;
using Microsoft.Identity.Client.ApiConfig.Parameters;
using Microsoft.Identity.Client.Internal;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,184 +1,184 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

space errors. Use
image

// Licensed under the MIT License.

using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Identity.Client.Advanced;
using Microsoft.Identity.Client.ApiConfig.Executors;
using Microsoft.Identity.Client.ApiConfig.Parameters;
using Microsoft.Identity.Client.Internal;
using Microsoft.Identity.Client.TelemetryCore.Internal.Events;
using Microsoft.Identity.Client.Utils;

namespace Microsoft.Identity.Client
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Identity.Client.Extensibility;
using Microsoft.Identity.Client.ApiConfig.Executors;
using Microsoft.Identity.Client.ApiConfig.Parameters;
using Microsoft.Identity.Client.Internal;
using Microsoft.Identity.Client.TelemetryCore.Internal.Events;
using Microsoft.Identity.Client.Utils;
namespace Microsoft.Identity.Client
{
/// <summary>
/// Builder for AcquireTokenOnBehalfOf (OBO flow)
/// See https://aka.ms/msal-net-on-behalf-of
/// </summary>
#if !SUPPORTS_CONFIDENTIAL_CLIENT
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] // hide confidential client on mobile
#endif
public sealed class AcquireTokenOnBehalfOfParameterBuilder :
AbstractConfidentialClientAcquireTokenParameterBuilder<AcquireTokenOnBehalfOfParameterBuilder>
{
internal AcquireTokenOnBehalfOfParameters Parameters { get; } = new AcquireTokenOnBehalfOfParameters();

/// <inheritdoc/>
internal AcquireTokenOnBehalfOfParameterBuilder(IConfidentialClientApplicationExecutor confidentialClientApplicationExecutor)
: base(confidentialClientApplicationExecutor)
{
}

internal static AcquireTokenOnBehalfOfParameterBuilder Create(
IConfidentialClientApplicationExecutor confidentialClientApplicationExecutor,
IEnumerable<string> scopes,
UserAssertion userAssertion)
{
return new AcquireTokenOnBehalfOfParameterBuilder(confidentialClientApplicationExecutor)
.WithScopes(scopes)
.WithUserAssertion(userAssertion);
}

internal static AcquireTokenOnBehalfOfParameterBuilder Create(
IConfidentialClientApplicationExecutor confidentialClientApplicationExecutor,
IEnumerable<string> scopes,
UserAssertion userAssertion,
string cacheKey)
{
return new AcquireTokenOnBehalfOfParameterBuilder(confidentialClientApplicationExecutor)
.WithScopes(scopes)
.WithUserAssertion(userAssertion)
.WithCacheKey(cacheKey);
}

internal static AcquireTokenOnBehalfOfParameterBuilder Create(
IConfidentialClientApplicationExecutor confidentialClientApplicationExecutor,
IEnumerable<string> scopes,
string cacheKey)
{
return new AcquireTokenOnBehalfOfParameterBuilder(confidentialClientApplicationExecutor)
.WithScopes(scopes)
.WithCacheKey(cacheKey);
}

private AcquireTokenOnBehalfOfParameterBuilder WithUserAssertion(UserAssertion userAssertion)
{
Parameters.UserAssertion = userAssertion;
return this;
}

/// <summary>
/// Specifies a key by which to look up the token in the cache instead of searching by an assertion.
/// </summary>
/// <param name="cacheKey">Key by which to look up the token in the cache</param>
/// <returns>A builder enabling you to add optional parameters before executing the token request</returns>
private AcquireTokenOnBehalfOfParameterBuilder WithCacheKey(string cacheKey)
{
Parameters.LongRunningOboCacheKey = cacheKey ?? throw new ArgumentNullException(nameof(cacheKey));
return this;
}

/// <summary>
/// <summary>
/// Builder for AcquireTokenOnBehalfOf (OBO flow)
/// See https://aka.ms/msal-net-on-behalf-of
/// </summary>
#if !SUPPORTS_CONFIDENTIAL_CLIENT
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] // hide confidential client on mobile
#endif
public sealed class AcquireTokenOnBehalfOfParameterBuilder :
AbstractConfidentialClientAcquireTokenParameterBuilder<AcquireTokenOnBehalfOfParameterBuilder>
{
internal AcquireTokenOnBehalfOfParameters Parameters { get; } = new AcquireTokenOnBehalfOfParameters();
/// <inheritdoc/>
internal AcquireTokenOnBehalfOfParameterBuilder(IConfidentialClientApplicationExecutor confidentialClientApplicationExecutor)
: base(confidentialClientApplicationExecutor)
{
}
internal static AcquireTokenOnBehalfOfParameterBuilder Create(
IConfidentialClientApplicationExecutor confidentialClientApplicationExecutor,
IEnumerable<string> scopes,
UserAssertion userAssertion)
{
return new AcquireTokenOnBehalfOfParameterBuilder(confidentialClientApplicationExecutor)
.WithScopes(scopes)
.WithUserAssertion(userAssertion);
}
internal static AcquireTokenOnBehalfOfParameterBuilder Create(
IConfidentialClientApplicationExecutor confidentialClientApplicationExecutor,
IEnumerable<string> scopes,
UserAssertion userAssertion,
string cacheKey)
{
return new AcquireTokenOnBehalfOfParameterBuilder(confidentialClientApplicationExecutor)
.WithScopes(scopes)
.WithUserAssertion(userAssertion)
.WithCacheKey(cacheKey);
}
internal static AcquireTokenOnBehalfOfParameterBuilder Create(
IConfidentialClientApplicationExecutor confidentialClientApplicationExecutor,
IEnumerable<string> scopes,
string cacheKey)
{
return new AcquireTokenOnBehalfOfParameterBuilder(confidentialClientApplicationExecutor)
.WithScopes(scopes)
.WithCacheKey(cacheKey);
}
private AcquireTokenOnBehalfOfParameterBuilder WithUserAssertion(UserAssertion userAssertion)
{
Parameters.UserAssertion = userAssertion;
return this;
}
/// <summary>
/// Specifies a key by which to look up the token in the cache instead of searching by an assertion.
/// </summary>
/// <param name="cacheKey">Key by which to look up the token in the cache</param>
/// <returns>A builder enabling you to add optional parameters before executing the token request</returns>
private AcquireTokenOnBehalfOfParameterBuilder WithCacheKey(string cacheKey)
{
Parameters.LongRunningOboCacheKey = cacheKey ?? throw new ArgumentNullException(nameof(cacheKey));
return this;
}
/// <summary>
/// Applicable to first-party applications only, this method also allows to specify
/// if the <see href="https://datatracker.ietf.org/doc/html/rfc7517#section-4.7">x5c claim</see> should be sent to Azure AD.
/// Sending the x5c enables application developers to achieve easy certificate roll-over in Azure AD:
/// this method will send the certificate chain to Azure AD along with the token request,
/// so that Azure AD can use it to validate the subject name based on a trusted issuer policy.
/// This saves the application admin from the need to explicitly manage the certificate rollover
/// (either via portal or PowerShell/CLI operation). For details see https://aka.ms/msal-net-sni
/// </summary>
/// <param name="withSendX5C"><c>true</c> if the x5c should be sent. Otherwise <c>false</c>.
/// The default is <c>false</c></param>
/// <returns>The builder to chain the .With methods</returns>
public AcquireTokenOnBehalfOfParameterBuilder WithSendX5C(bool withSendX5C)
{
/// </summary>
/// <param name="withSendX5C"><c>true</c> if the x5c should be sent. Otherwise <c>false</c>.
/// The default is <c>false</c></param>
/// <returns>The builder to chain the .With methods</returns>
public AcquireTokenOnBehalfOfParameterBuilder WithSendX5C(bool withSendX5C)
{
Parameters.SendX5C = withSendX5C;
return this;
}

/// <summary>
return this;
}
/// <summary>
/// Specifies if the client application should ignore access tokens when reading the token cache.
/// New tokens will still be written to the token cache.
/// By default the token is taken from the the user token cache (forceRefresh=false)
/// </summary>
/// <param name="forceRefresh">If <c>true</c>, ignore any access token in the user token cache
/// and attempt to acquire new access token using the refresh token for the account
/// </summary>
/// <param name="forceRefresh">If <c>true</c>, ignore any access token in the user token cache
/// and attempt to acquire new access token using the refresh token for the account
/// if one is available. The default is <c>false</c></param>
/// <returns>The builder to chain the .With methods</returns>
/// <returns>The builder to chain the .With methods</returns>
/// <remarks>
/// Do not use this flag except in well understood cases. Identity Providers will throttle clients that issue too many similar token requests.
/// </remarks>
public AcquireTokenOnBehalfOfParameterBuilder WithForceRefresh(bool forceRefresh)
{
Parameters.ForceRefresh = forceRefresh;
return this;
}

/// <summary>
/// To help with resiliency, the AAD backup authentication system operates as an AAD backup.
/// This will provide the AAD backup authentication system with a routing hint to help improve performance during authentication.
/// </summary>
/// <param name="userObjectIdentifier">GUID which is unique to the user, parsed from the client_info.</param>
/// <param name="tenantIdentifier">GUID format of the tenant ID, parsed from the client_info.</param>
/// <returns>The builder to chain the .With methods</returns>
public AcquireTokenOnBehalfOfParameterBuilder WithCcsRoutingHint(string userObjectIdentifier, string tenantIdentifier)
{
if (string.IsNullOrEmpty(userObjectIdentifier) || string.IsNullOrEmpty(tenantIdentifier))
{
return this;
}

var ccsRoutingHeader = new Dictionary<string, string>()
{
{ Constants.CcsRoutingHintHeader, CoreHelpers.GetCcsClientInfoHint(userObjectIdentifier, tenantIdentifier) }
};

this.WithExtraHttpHeaders(ccsRoutingHeader);
return this;
}

/// <summary>
/// To help with resiliency, the AAD backup authentication system operates as an AAD backup.
/// This will provide the AAD backup authentication system with a routing hint to help improve performance during authentication.
/// </summary>
/// <param name="userName">Identifier of the user. Generally in UserPrincipalName (UPN) format, e.g. <c>john.doe@contoso.com</c></param>
/// <returns>The builder to chain the .With methods</returns>
public AcquireTokenOnBehalfOfParameterBuilder WithCcsRoutingHint(string userName)
{
if (string.IsNullOrEmpty(userName))
{
return this;
}

var ccsRoutingHeader = new Dictionary<string, string>()
{
{ Constants.CcsRoutingHintHeader, CoreHelpers.GetCcsUpnHint(userName) }
};

this.WithExtraHttpHeaders(ccsRoutingHeader);
return this;
public AcquireTokenOnBehalfOfParameterBuilder WithForceRefresh(bool forceRefresh)
{
Parameters.ForceRefresh = forceRefresh;
return this;
}
/// <summary>
/// To help with resiliency, the AAD backup authentication system operates as an AAD backup.
/// This will provide the AAD backup authentication system with a routing hint to help improve performance during authentication.
/// </summary>
/// <param name="userObjectIdentifier">GUID which is unique to the user, parsed from the client_info.</param>
/// <param name="tenantIdentifier">GUID format of the tenant ID, parsed from the client_info.</param>
/// <returns>The builder to chain the .With methods</returns>
public AcquireTokenOnBehalfOfParameterBuilder WithCcsRoutingHint(string userObjectIdentifier, string tenantIdentifier)
{
if (string.IsNullOrEmpty(userObjectIdentifier) || string.IsNullOrEmpty(tenantIdentifier))
{
return this;
}
var ccsRoutingHeader = new Dictionary<string, string>()
{
{ Constants.CcsRoutingHintHeader, CoreHelpers.GetCcsClientInfoHint(userObjectIdentifier, tenantIdentifier) }
};
this.WithExtraHttpHeaders(ccsRoutingHeader);
return this;
}
/// <summary>
/// To help with resiliency, the AAD backup authentication system operates as an AAD backup.
/// This will provide the AAD backup authentication system with a routing hint to help improve performance during authentication.
/// </summary>
/// <param name="userName">Identifier of the user. Generally in UserPrincipalName (UPN) format, e.g. <c>john.doe@contoso.com</c></param>
/// <returns>The builder to chain the .With methods</returns>
public AcquireTokenOnBehalfOfParameterBuilder WithCcsRoutingHint(string userName)
{
if (string.IsNullOrEmpty(userName))
{
return this;
}
var ccsRoutingHeader = new Dictionary<string, string>()
{
{ Constants.CcsRoutingHintHeader, CoreHelpers.GetCcsUpnHint(userName) }
};
this.WithExtraHttpHeaders(ccsRoutingHeader);
return this;
}

/// <inheritdoc/>
internal override Task<AuthenticationResult> ExecuteInternalAsync(CancellationToken cancellationToken)
{
return ConfidentialClientApplicationExecutor.ExecuteAsync(CommonParameters, Parameters, cancellationToken);
}

/// <inheritdoc/>
internal override Task<AuthenticationResult> ExecuteInternalAsync(CancellationToken cancellationToken)
{
return ConfidentialClientApplicationExecutor.ExecuteAsync(CommonParameters, Parameters, cancellationToken);
}
/// <inheritdoc/>
protected override void Validate()
{
base.Validate();
if (Parameters.SendX5C == null)
{
Parameters.SendX5C = this.ServiceBundle.Config?.SendX5C ?? false;
if (Parameters.SendX5C == null)
{
Parameters.SendX5C = this.ServiceBundle.Config?.SendX5C ?? false;
}
}
/// <inheritdoc/>
internal override ApiEvent.ApiIds CalculateApiEventId()
}
/// <inheritdoc/>
internal override ApiEvent.ApiIds CalculateApiEventId()
{
if (string.IsNullOrEmpty(Parameters.LongRunningOboCacheKey))
{
Expand All @@ -194,7 +194,7 @@ internal override ApiEvent.ApiIds CalculateApiEventId()
{
return ApiEvent.ApiIds.AcquireTokenInLongRunningObo;
}
}
}
}
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@ public T WithLogging(
/// <exception cref="InvalidOperationException"/> is thrown if the loggingCallback
/// was already set on the application builder by calling <see cref="WithLogging(LogCallback, LogLevel?, bool?, bool?)"/>
/// <seealso cref="WithLogging(LogCallback, LogLevel?, bool?, bool?)"/>
[EditorBrowsable(EditorBrowsableState.Never)]
public T WithDebugLoggingCallback(
LogLevel logLevel = LogLevel.Info,
bool enablePiiLogging = false,
Expand Down Expand Up @@ -218,6 +219,7 @@ public T WithExperimentalFeatures(bool enableExperimentalFeatures = true)
/// </summary>
/// <param name="clientName">The name of the SDK API for telemetry purposes.</param>
/// <returns></returns>
[EditorBrowsable(EditorBrowsableState.Never)]
public T WithClientName(string clientName)
{
Config.ClientName = GetValueIfNotEmpty(Config.ClientName, clientName);
Expand All @@ -229,6 +231,7 @@ public T WithClientName(string clientName)
/// </summary>
/// <param name="clientVersion">The version of the calling SDK for telemetry purposes.</param>
/// <returns></returns>
[EditorBrowsable(EditorBrowsableState.Never)]
public T WithClientVersion(string clientVersion)
{
Config.ClientVersion = GetValueIfNotEmpty(Config.ClientVersion, clientVersion);
Expand Down
Loading