microsoft/teams.net
Publicmirrored fromhttps://github.com/microsoft/teams.netAvailable
core/samples/PABot/PACustomAuthHandler.cs
76lines · modecode
| 1 | // Copyright (c) Microsoft Corporation. |
| 2 | // Licensed under the MIT License. |
| 3 | |
| 4 | using System.Net.Http.Headers; |
| 5 | using Microsoft.Extensions.Options; |
| 6 | using Microsoft.Identity.Abstractions; |
| 7 | using Microsoft.Identity.Web; |
| 8 | using Microsoft.Teams.Bot.Core.Schema; |
| 9 | |
| 10 | namespace PABot |
| 11 | { |
| 12 | internal class PACustomAuthHandler( |
| 13 | IAuthorizationHeaderProvider authorizationHeaderProvider, |
| 14 | IRoutedTokenAcquisitionService routedTokenService, |
| 15 | ILogger<PACustomAuthHandler> logger, |
| 16 | string botScope, |
| 17 | string? agenticScope = null, |
| 18 | IOptions<ManagedIdentityOptions>? managedIdentityOptions = null) : DelegatingHandler |
| 19 | { |
| 20 | private readonly IAuthorizationHeaderProvider _authorizationHeaderProvider = authorizationHeaderProvider ?? throw new ArgumentNullException(nameof(authorizationHeaderProvider)); |
| 21 | private readonly IRoutedTokenAcquisitionService _routedTokenService = routedTokenService ?? throw new ArgumentNullException(nameof(routedTokenService)); |
| 22 | private readonly ILogger<PACustomAuthHandler> _logger = logger ?? throw new ArgumentNullException(nameof(logger)); |
| 23 | private readonly string _botScope = botScope ?? throw new ArgumentNullException(nameof(botScope)); |
| 24 | private readonly string _agenticScope = agenticScope ?? botScope; // Default to bot scope if not specified |
| 25 | private readonly IOptions<ManagedIdentityOptions>? _managedIdentityOptions = managedIdentityOptions; |
| 26 | |
| 27 | /// <summary> |
| 28 | /// Key used to store the agentic identity in HttpRequestMessage options. |
| 29 | /// When set, agentic application credentials will be used instead of bot credentials. |
| 30 | /// </summary> |
| 31 | public static readonly HttpRequestOptionsKey<AgenticIdentity?> AgenticIdentityKey = new("AgenticIdentity"); |
| 32 | |
| 33 | /// <inheritdoc/> |
| 34 | protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) |
| 35 | { |
| 36 | request.Options.TryGetValue(AgenticIdentityKey, out AgenticIdentity? agenticIdentity); |
| 37 | |
| 38 | string token = await GetAuthorizationHeaderAsync(agenticIdentity, cancellationToken).ConfigureAwait(false); |
| 39 | |
| 40 | string tokenValue = token.StartsWith("Bearer ", StringComparison.OrdinalIgnoreCase) |
| 41 | ? token["Bearer ".Length..] |
| 42 | : token; |
| 43 | |
| 44 | request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", tokenValue); |
| 45 | |
| 46 | return await base.SendAsync(request, cancellationToken).ConfigureAwait(false); |
| 47 | } |
| 48 | |
| 49 | /// <summary> |
| 50 | /// Gets an authorization header for API calls. |
| 51 | /// Routes to either bot credentials or agentic application credentials based on the presence of AgenticIdentity. |
| 52 | /// </summary> |
| 53 | /// <param name="agenticIdentity">Optional agentic identity. When provided, agentic application credentials are used.</param> |
| 54 | /// <param name="cancellationToken">Cancellation token.</param> |
| 55 | /// <returns>The authorization header value.</returns> |
| 56 | private async Task<string> GetAuthorizationHeaderAsync(AgenticIdentity? agenticIdentity, CancellationToken cancellationToken) |
| 57 | { |
| 58 | // If agentic identity is provided, use agentic application credentials with agentic scope |
| 59 | if (agenticIdentity is not null && |
| 60 | !string.IsNullOrEmpty(agenticIdentity.AgenticAppId) && |
| 61 | !string.IsNullOrEmpty(agenticIdentity.AgenticUserId)) |
| 62 | { |
| 63 | _logger.LogInformation("Acquiring token using agentic credentials for scope '{Scope}' with AppId '{AppId}' and UserId '{UserId}'.", |
| 64 | _agenticScope, |
| 65 | agenticIdentity.AgenticAppId, |
| 66 | agenticIdentity.AgenticUserId); |
| 67 | |
| 68 | return await _routedTokenService.AcquireTokenForAgenticAsync(agenticIdentity, _agenticScope, cancellationToken).ConfigureAwait(false); |
| 69 | } |
| 70 | |
| 71 | // Otherwise, use bot credentials with bot scope |
| 72 | _logger.LogInformation("Acquiring token using bot credentials for scope: {Scope}", _botScope); |
| 73 | return await _routedTokenService.AcquireTokenForBotAsync(_botScope, cancellationToken).ConfigureAwait(false); |
| 74 | } |
| 75 | } |
| 76 | } |
| 77 | |