| File: FederatedTokenCredential.cs | Web Access |
| Project: src\tests\Aspire.Hosting.Azure.Tests\Aspire.Hosting.Azure.Tests.csproj (Aspire.Hosting.Azure.Tests) |
// 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; namespace Aspire.Hosting.Azure.Tests; /// <summary> /// Models an audience-specific access-token cache backed by a non-renewable assertion. /// </summary> internal sealed class FederatedTokenCredential : TokenCredential { private readonly object _lock = new(); private readonly Dictionary<string, AccessToken> _tokens = new(StringComparer.Ordinal); private readonly List<string> _requests = []; private readonly DateTimeOffset _assertionExpiresOn; private DateTimeOffset _now = new(2026, 1, 1, 0, 0, 0, TimeSpan.Zero); public FederatedTokenCredential() { _assertionExpiresOn = _now.AddMinutes(5); } public string[] Requests { get { lock (_lock) { return [.. _requests]; } } } public string? FailingScope { get; init; } public Action<string, CancellationToken>? OnRequest { get; init; } public void Advance(TimeSpan elapsed) { lock (_lock) { _now += elapsed; } } public override AccessToken GetToken(TokenRequestContext requestContext, CancellationToken cancellationToken) { lock (_lock) { var scope = Assert.Single(requestContext.Scopes); _requests.Add(scope); OnRequest?.Invoke(scope, cancellationToken); cancellationToken.ThrowIfCancellationRequested(); if (scope == FailingScope) { throw new AuthenticationFailedException("Audience authentication failed."); } if (_tokens.TryGetValue(scope, out var token) && token.ExpiresOn > _now) { return token; } if (_now >= _assertionExpiresOn) { throw new AuthenticationFailedException("AADSTS700024: Client assertion is not within its valid time range."); } token = new AccessToken(new TestTokenCredential().GetToken(requestContext, cancellationToken).Token, _now.AddHours(1)); _tokens[scope] = token; return token; } } public override ValueTask<AccessToken> GetTokenAsync(TokenRequestContext requestContext, CancellationToken cancellationToken) => ValueTask.FromResult(GetToken(requestContext, cancellationToken)); }