src/dotnet/AspireWorker/Authentication/DcpTokenAuthenticationHandler.cs (55 lines of code) (raw):

using System.Security.Claims; using System.Text.Encodings.Web; using JetBrains.Rider.Aspire.Worker.Configuration; using Microsoft.AspNetCore.Authentication; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; namespace JetBrains.Rider.Aspire.Worker.Authentication; /// <summary> /// Authentication handler for handling token-based authentication based on the DCP token. /// </summary> /// <remarks> /// See <see href="https://github.com/dotnet/aspire/blob/main/docs/specs/IDE-execution.md#enabling-ide-execution"/> for more information on how to configure the DCP token. /// </remarks> internal sealed class DcpTokenAuthenticationHandler( IOptionsMonitor<AuthenticationSchemeOptions> options, ILoggerFactory logger, UrlEncoder encoder, IOptions<DcpSessionOptions> dcpOptions) : AuthenticationHandler<AuthenticationSchemeOptions>(options, logger, encoder) { private const string BearerPrefix = "Bearer "; private const string PrincipalName = "dcp"; private const string UnsupportedScheme = "Unsupported authorization scheme."; private const string MissingToken = "Missing token."; private const string InvalidToken = "Invalid token."; protected override Task<AuthenticateResult> HandleAuthenticateAsync() { var authorization = Request.Headers.Authorization.ToString(); if (string.IsNullOrEmpty(authorization)) { Logger.LogInformation("Authorization header contained no usable value"); return Task.FromResult(AuthenticateResult.NoResult()); } if (!authorization.StartsWith(BearerPrefix, StringComparison.OrdinalIgnoreCase)) { Logger.LogInformation("Unsupported authorization scheme"); return Task.FromResult(AuthenticateResult.Fail(UnsupportedScheme)); } var token = authorization[BearerPrefix.Length..].Trim(); if (token.Length == 0) { Logger.LogWarning("Bearer token validation failed."); return Task.FromResult(AuthenticateResult.Fail(MissingToken)); } if (!string.Equals(token, dcpOptions.Value.Token, StringComparison.Ordinal)) { return Task.FromResult(AuthenticateResult.Fail(InvalidToken)); } var identity = new ClaimsIdentity(Scheme.Name); identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, PrincipalName)); var principal = new ClaimsPrincipal(identity); var ticket = new AuthenticationTicket(principal, Scheme.Name); return Task.FromResult(AuthenticateResult.Success(ticket)); } protected override Task HandleChallengeAsync(AuthenticationProperties properties) { Response.StatusCode = StatusCodes.Status401Unauthorized; Response.Headers.Append("WWW-Authenticate", "Bearer"); return Task.CompletedTask; } }