Skip to content
This repository was archived by the owner on Jan 5, 2026. It is now read-only.
Merged
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 @@ -217,6 +217,7 @@ public async Task<string> GetTokenAsync(bool forceRefresh = false)
/// Builds the lazy <see cref="AdalAuthenticator" /> to be used for token acquisition.
/// </summary>
/// <returns>A lazy <see cref="AdalAuthenticator"/>.</returns>
[Obsolete("This method is deprecated. Use BuildIAuthenticator instead.", false)]
protected abstract Lazy<AdalAuthenticator> BuildAuthenticator();

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ namespace Microsoft.Bot.Connector.Authentication
/// </summary>
public class CertificateAppCredentials : AppCredentials
{
private readonly ClientAssertionCertificate clientCertificate;
private readonly ClientAssertionCertificate adalClientCertificate;
private readonly X509Certificate2 clientCertificate;
private readonly bool sendX5c;

/// <summary>
Expand All @@ -35,9 +36,9 @@ public CertificateAppCredentials(CertificateAppCredentialsOptions options)
throw new ArgumentNullException(nameof(options), "AppId is required.");
}

this.sendX5c = options.SendX5c;
this.clientCertificate = new ClientAssertionCertificate(options.AppId, options.ClientCertificate);
MicrosoftAppId = this.clientCertificate.ClientId;
sendX5c = options.SendX5c;
clientCertificate = options.ClientCertificate;
MicrosoftAppId = options.AppId;
}

/// <summary>
Expand Down Expand Up @@ -76,8 +77,8 @@ public CertificateAppCredentials(X509Certificate2 clientCertificate, bool sendX5
}

this.sendX5c = sendX5c;
this.clientCertificate = new ClientAssertionCertificate(appId, clientCertificate);
MicrosoftAppId = this.clientCertificate.ClientId;
this.clientCertificate = clientCertificate;
MicrosoftAppId = appId;
}

/// <summary>
Expand All @@ -103,26 +104,64 @@ public CertificateAppCredentials(ClientAssertionCertificate clientCertificate, s
public CertificateAppCredentials(ClientAssertionCertificate clientCertificate, bool sendX5c, string channelAuthTenant = null, HttpClient customHttpClient = null, ILogger logger = null)
: base(channelAuthTenant, customHttpClient, logger)
{
if (clientCertificate == null)
{
throw new ArgumentNullException(nameof(clientCertificate));
}

this.sendX5c = sendX5c;
this.clientCertificate = clientCertificate ?? throw new ArgumentNullException(nameof(clientCertificate));
this.clientCertificate = clientCertificate.Certificate;
MicrosoftAppId = clientCertificate.ClientId;
adalClientCertificate = clientCertificate;
}

/// <summary>
/// Builds the lazy <see cref="AdalAuthenticator" /> to be used for token acquisition.
/// </summary>
/// <returns>A lazy <see cref="AdalAuthenticator"/>.</returns>
[Obsolete("This method is deprecated. Use BuildIAuthenticator instead.", false)]
protected override Lazy<AdalAuthenticator> BuildAuthenticator()
{
return new Lazy<AdalAuthenticator>(
() =>
new AdalAuthenticator(
this.clientCertificate,
this.sendX5c,
adalClientCertificate,
sendX5c,
new OAuthConfiguration() { Authority = OAuthEndpoint, ValidateAuthority = ValidateAuthority, Scope = OAuthScope },
this.CustomHttpClient,
this.Logger),
CustomHttpClient,
Logger),
LazyThreadSafetyMode.ExecutionAndPublication);
}

/// <inheritdoc/>
protected override Lazy<IAuthenticator> BuildIAuthenticator()
{
return new Lazy<IAuthenticator>(
() =>
{
var clientApplication = CreateClientApplication(clientCertificate, MicrosoftAppId, CustomHttpClient);
return new MsalAppCredentials(
clientApplication,
MicrosoftAppId,
OAuthEndpoint,
OAuthScope,
ValidateAuthority,
Logger);
},
LazyThreadSafetyMode.ExecutionAndPublication);
}

private Identity.Client.IConfidentialClientApplication CreateClientApplication(X509Certificate2 clientCertificate, string appId, HttpClient customHttpClient = null)
{
var clientBuilder = Identity.Client.ConfidentialClientApplicationBuilder.Create(appId)
.WithCertificate(clientCertificate);

if (customHttpClient != null)
{
clientBuilder.WithHttpClientFactory(new ConstantHttpClientFactory(customHttpClient));
}

return clientBuilder.Build();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@

using System;
using System.Net.Http;
using Microsoft.IdentityModel.Clients.ActiveDirectory;
using Microsoft.Identity.Client;

namespace Microsoft.Bot.Connector.Authentication
{
/// <summary>
/// HttpClientFactory that always returns the same HttpClient instance for ADAL AcquireTokenAsync calls.
/// </summary>
internal class ConstantHttpClientFactory : Microsoft.IdentityModel.Clients.ActiveDirectory.IHttpClientFactory
internal class ConstantHttpClientFactory : IdentityModel.Clients.ActiveDirectory.IHttpClientFactory, IMsalHttpClientFactory
{
private readonly HttpClient httpClient;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System;
using System.Net.Http;
using Microsoft.Azure.Services.AppAuthentication;

Expand All @@ -9,6 +10,7 @@ namespace Microsoft.Bot.Connector.Authentication
/// <summary>
/// A factory that can create OAuth token providers for generating JWT auth tokens.
/// </summary>
[Obsolete("This class is deprecated.", false)]
public interface IJwtTokenProviderFactory
{
/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
namespace Microsoft.Bot.Connector.Authentication
{
/// <inheritdoc />
[Obsolete("This class is deprecated.", false)]
public class JwtTokenProviderFactory : IJwtTokenProviderFactory
{
/// <inheritdoc />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@ namespace Microsoft.Bot.Connector.Authentication
/// </summary>
public class ManagedIdentityAppCredentials : AppCredentials
{
private readonly IJwtTokenProviderFactory _tokenProviderFactory;

/// <summary>
/// Initializes a new instance of the <see cref="ManagedIdentityAppCredentials"/> class.
/// Managed Identity for AAD credentials auth and caching.
Expand All @@ -24,20 +22,33 @@ public class ManagedIdentityAppCredentials : AppCredentials
/// <param name="tokenProviderFactory">The JWT token provider factory to use.</param>
/// <param name="customHttpClient">Optional <see cref="HttpClient"/> to be used when acquiring tokens.</param>
/// <param name="logger">Optional <see cref="ILogger"/> to gather telemetry data while acquiring and managing credentials.</param>
[Obsolete("This method is deprecated, the IJwtTokenProviderFactory argument is now redundant. Use the overload without this argument.", false)]
public ManagedIdentityAppCredentials(string appId, string oAuthScope, IJwtTokenProviderFactory tokenProviderFactory, HttpClient customHttpClient = null, ILogger logger = null)
: this(appId, oAuthScope, customHttpClient, logger)
{
}

/// <summary>
/// Initializes a new instance of the <see cref="ManagedIdentityAppCredentials"/> class.
/// Managed Identity for AAD credentials auth and caching.
/// </summary>
/// <param name="appId">Client ID for the managed identity assigned to the bot.</param>
/// <param name="oAuthScope">The scope for the token.</param>
/// <param name="customHttpClient">Optional <see cref="HttpClient"/> to be used when acquiring tokens.</param>
/// <param name="logger">Optional <see cref="ILogger"/> to gather telemetry data while acquiring and managing credentials.</param>
public ManagedIdentityAppCredentials(string appId, string oAuthScope, HttpClient customHttpClient = null, ILogger logger = null)
: base(channelAuthTenant: null, customHttpClient, logger, oAuthScope)
{
if (string.IsNullOrWhiteSpace(appId))
{
throw new ArgumentNullException(nameof(appId));
}

_tokenProviderFactory = tokenProviderFactory ?? throw new ArgumentNullException(nameof(tokenProviderFactory));

MicrosoftAppId = appId;
}

/// <inheritdoc/>
[Obsolete("This method is deprecated. Use BuildIAuthenticator instead.", false)]
protected override Lazy<AdalAuthenticator> BuildAuthenticator()
{
// Should not be called, legacy
Expand All @@ -48,7 +59,7 @@ protected override Lazy<AdalAuthenticator> BuildAuthenticator()
protected override Lazy<IAuthenticator> BuildIAuthenticator()
{
return new Lazy<IAuthenticator>(
() => new ManagedIdentityAuthenticator(MicrosoftAppId, OAuthScope, _tokenProviderFactory, CustomHttpClient, Logger),
() => new ManagedIdentityAuthenticator(MicrosoftAppId, OAuthScope, CustomHttpClient, Logger),
LazyThreadSafetyMode.ExecutionAndPublication);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
using System.Diagnostics;
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.Azure.Services.AppAuthentication;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Identity.Client;

namespace Microsoft.Bot.Connector.Authentication
{
Expand All @@ -16,9 +16,10 @@ namespace Microsoft.Bot.Connector.Authentication
/// </summary>
public class ManagedIdentityAuthenticator : IAuthenticator
{
private readonly AzureServiceTokenProvider _tokenProvider;
private readonly string _appId;
private readonly string _resource;
private readonly ILogger _logger;
private readonly IConfidentialClientApplication _clientApplication;

/// <summary>
/// Initializes a new instance of the <see cref="ManagedIdentityAuthenticator"/> class.
Expand All @@ -28,7 +29,20 @@ public class ManagedIdentityAuthenticator : IAuthenticator
/// <param name="tokenProviderFactory">The JWT token provider factory to use.</param>
/// <param name="customHttpClient">A customized instance of the HttpClient class.</param>
/// <param name="logger">The type used to perform logging.</param>
[Obsolete("This method is deprecated, the IJwtTokenProviderFactory argument is now redundant. Use the overload without this argument.", false)]
public ManagedIdentityAuthenticator(string appId, string resource, IJwtTokenProviderFactory tokenProviderFactory, HttpClient customHttpClient = null, ILogger logger = null)
: this(appId, resource, customHttpClient, logger)
{
}

/// <summary>
/// Initializes a new instance of the <see cref="ManagedIdentityAuthenticator"/> class.
/// </summary>
/// <param name="appId">Client id for the managed identity to be used for acquiring tokens.</param>
/// <param name="resource">Resource for which to acquire the token.</param>
/// <param name="customHttpClient">A customized instance of the HttpClient class.</param>
/// <param name="logger">The type used to perform logging.</param>
public ManagedIdentityAuthenticator(string appId, string resource, HttpClient customHttpClient = null, ILogger logger = null)
{
if (string.IsNullOrWhiteSpace(appId))
{
Expand All @@ -39,15 +53,11 @@ public ManagedIdentityAuthenticator(string appId, string resource, IJwtTokenProv
{
throw new ArgumentNullException(nameof(resource));
}

if (tokenProviderFactory == null)
{
throw new ArgumentNullException(nameof(tokenProviderFactory));
}


_appId = appId;
_resource = resource;
_tokenProvider = tokenProviderFactory.CreateAzureServiceTokenProvider(appId, customHttpClient);
_logger = logger ?? NullLogger.Instance;
_clientApplication = CreateClientApplication(appId, customHttpClient);
}

/// <inheritdoc/>
Expand All @@ -67,7 +77,13 @@ public async Task<AuthenticatorResult> GetTokenAsync(bool forceRefresh = false)

private async Task<AuthenticatorResult> AcquireTokenAsync(bool forceRefresh)
{
var authResult = await _tokenProvider.GetAuthenticationResultAsync(_resource, forceRefresh).ConfigureAwait(false);
var scopes = new string[] { $"{_resource}/.default" };
var authResult = await _clientApplication
.AcquireTokenForClient(scopes)
.WithManagedIdentity(_appId)
.WithForceRefresh(forceRefresh)
.ExecuteAsync()
.ConfigureAwait(false);
return new AuthenticatorResult
{
AccessToken = authResult.AccessToken,
Expand All @@ -79,9 +95,22 @@ private RetryParams HandleTokenProviderException(Exception e, int retryCount)
{
_logger.LogError(e, "Exception when trying to acquire token using MSI!");

return e is AzureServiceTokenProviderException // BadRequest
return e is MsalServiceException // BadRequest
? RetryParams.StopRetrying
: RetryParams.DefaultBackOff(retryCount);
}

private IConfidentialClientApplication CreateClientApplication(string appId, HttpClient customHttpClient = null)
{
var clientBuilder = ConfidentialClientApplicationBuilder.Create(appId)
.WithExperimentalFeatures();

if (customHttpClient != null)
{
clientBuilder.WithHttpClientFactory(new ConstantHttpClientFactory(customHttpClient));
}

return clientBuilder.Build();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ namespace Microsoft.Bot.Connector.Authentication
public class ManagedIdentityServiceClientCredentialsFactory : ServiceClientCredentialsFactory
{
private readonly string _appId;
private readonly IJwtTokenProviderFactory _tokenProviderFactory;
private readonly HttpClient _httpClient;
private readonly ILogger _logger;

Expand All @@ -27,15 +26,26 @@ public class ManagedIdentityServiceClientCredentialsFactory : ServiceClientCrede
/// <param name="tokenProviderFactory">The JWT token provider factory to use.</param>
/// <param name="httpClient">A custom httpClient to use.</param>
/// <param name="logger">A logger instance to use.</param>
[Obsolete("This method is deprecated, the IJwtTokenProviderFactory argument is now redundant. Use the overload without this argument.", false)]
public ManagedIdentityServiceClientCredentialsFactory(string appId, IJwtTokenProviderFactory tokenProviderFactory, HttpClient httpClient = null, ILogger logger = null)
: this(appId, httpClient, logger)
{
}

/// <summary>
/// Initializes a new instance of the <see cref="ManagedIdentityServiceClientCredentialsFactory"/> class.
/// </summary>
/// <param name="appId">Client ID for the managed identity assigned to the bot.</param>
/// <param name="httpClient">A custom httpClient to use.</param>
/// <param name="logger">A logger instance to use.</param>
public ManagedIdentityServiceClientCredentialsFactory(string appId, HttpClient httpClient = null, ILogger logger = null)
{
if (string.IsNullOrWhiteSpace(appId))
{
throw new ArgumentNullException(nameof(appId));
}

_appId = appId;
_tokenProviderFactory = tokenProviderFactory ?? throw new ArgumentNullException(nameof(tokenProviderFactory));
_httpClient = httpClient;
_logger = logger;
}
Expand Down Expand Up @@ -63,7 +73,7 @@ public override Task<ServiceClientCredentials> CreateCredentialsAsync(
}

return Task.FromResult<ServiceClientCredentials>(
new ManagedIdentityAppCredentials(_appId, audience, _tokenProviderFactory, _httpClient, _logger));
new ManagedIdentityAppCredentials(_appId, audience, _httpClient, _logger));
}
}
}
Loading