|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using Azure.Core;
using Azure.Identity;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
namespace Aspire.Hosting.Azure.Provisioning.Internal;
internal class DefaultTokenCredentialProvider : ITokenCredentialProvider
{
private readonly ILogger<DefaultTokenCredentialProvider> _logger;
private readonly IOptions<AzureProvisionerOptions> _options;
private readonly DistributedApplicationExecutionContext _distributedApplicationExecutionContext;
private TokenCredential? _credential;
private string? _lastTenantId;
private readonly object _lock = new();
public DefaultTokenCredentialProvider(
ILogger<DefaultTokenCredentialProvider> logger,
IOptions<AzureProvisionerOptions> options,
DistributedApplicationExecutionContext distributedApplicationExecutionContext)
{
_logger = logger;
_options = options;
_distributedApplicationExecutionContext = distributedApplicationExecutionContext;
}
public TokenCredential TokenCredential
{
get
{
lock (_lock)
{
var currentTenantId = _options.Value.TenantId;
// Recreate credential if tenant ID has changed or credential doesn't exist
if (_credential == null || _lastTenantId != currentTenantId)
{
_credential = CreateCredential(currentTenantId);
_lastTenantId = currentTenantId;
}
return _credential;
}
}
}
private TokenCredential CreateCredential(string? tenantId)
{
var credentialSetting = _options.Value.CredentialSource;
TokenCredential credential = credentialSetting switch
{
"AzureCli" => new AzureCliCredential(new()
{
TenantId = tenantId,
AdditionallyAllowedTenants = { "*" }
}),
"AzurePowerShell" => new AzurePowerShellCredential(new()
{
TenantId = tenantId,
AdditionallyAllowedTenants = { "*" }
}),
"VisualStudio" => new VisualStudioCredential(new()
{
TenantId = tenantId,
AdditionallyAllowedTenants = { "*" }
}),
"AzureDeveloperCli" => new AzureDeveloperCliCredential(new()
{
TenantId = tenantId,
AdditionallyAllowedTenants = { "*" }
}),
"InteractiveBrowser" => new InteractiveBrowserCredential(new InteractiveBrowserCredentialOptions()
{
TenantId = tenantId
}),
// Use AzureCli as default for publish mode when no explicit credential source is set
null or "Default" when _distributedApplicationExecutionContext.IsPublishMode => new AzureCliCredential(new()
{
TenantId = tenantId,
AdditionallyAllowedTenants = { "*" }
}),
_ => new DefaultAzureCredential(new DefaultAzureCredentialOptions()
{
TenantId = tenantId,
ExcludeManagedIdentityCredential = true,
ExcludeWorkloadIdentityCredential = true,
ExcludeAzurePowerShellCredential = true,
CredentialProcessTimeout = TimeSpan.FromSeconds(15),
AdditionallyAllowedTenants = { "*" }
})
};
return credential;
}
internal void LogCredentialType()
{
var credential = TokenCredential;
_logger.LogInformation("Using {credentialType} for provisioning.", credential.GetType().Name);
}
}
|