From f19d2ab646bf56eef92ac47905b85c373ff28778 Mon Sep 17 00:00:00 2001 From: Kirill Kovalev Date: Tue, 2 Jul 2024 19:31:12 +0300 Subject: [PATCH] Refactoring of token context evaluation --- .../Endpoints/ServiceCollectionExtensions.cs | 17 +++-- .../ITokenAuthorizationContextEvaluator.cs | 41 +++++++++++ .../TokenAuthorizationContextEvaluator.cs | 68 +++++++++++++++++++ .../Endpoints/Token/TokenRequestProcessor.cs | 44 ++---------- 4 files changed, 127 insertions(+), 43 deletions(-) create mode 100644 Abblix.Oidc.Server/Endpoints/Token/Interfaces/ITokenAuthorizationContextEvaluator.cs create mode 100644 Abblix.Oidc.Server/Endpoints/Token/TokenAuthorizationContextEvaluator.cs diff --git a/Abblix.Oidc.Server/Endpoints/ServiceCollectionExtensions.cs b/Abblix.Oidc.Server/Endpoints/ServiceCollectionExtensions.cs index ac214e2..44c0ff3 100644 --- a/Abblix.Oidc.Server/Endpoints/ServiceCollectionExtensions.cs +++ b/Abblix.Oidc.Server/Endpoints/ServiceCollectionExtensions.cs @@ -51,6 +51,7 @@ using Abblix.Oidc.Server.Endpoints.UserInfo; using Abblix.Oidc.Server.Endpoints.UserInfo.Interfaces; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; namespace Abblix.Oidc.Server.Endpoints; @@ -138,14 +139,18 @@ public static IServiceCollection AddPushedAuthorizationEndpoint(this IServiceCol /// The configured . public static IServiceCollection AddTokenEndpoint(this IServiceCollection services) { - return services + services .AddAuthorizationGrants() - .AddTokenContextValidators() + .AddTokenContextValidators(); + + services.TryAddScoped(); + + services.TryAddScoped(); + services.TryAddScoped(); + services.TryAddScoped(); + services.Decorate(); - .AddScoped() - .AddScoped() - .AddScoped() - .Decorate(); + return services; } /// diff --git a/Abblix.Oidc.Server/Endpoints/Token/Interfaces/ITokenAuthorizationContextEvaluator.cs b/Abblix.Oidc.Server/Endpoints/Token/Interfaces/ITokenAuthorizationContextEvaluator.cs new file mode 100644 index 0000000..8fb1f36 --- /dev/null +++ b/Abblix.Oidc.Server/Endpoints/Token/Interfaces/ITokenAuthorizationContextEvaluator.cs @@ -0,0 +1,41 @@ +// Abblix OIDC Server Library +// Copyright (c) Abblix LLP. All rights reserved. +// +// DISCLAIMER: This software is provided 'as-is', without any express or implied +// warranty. Use at your own risk. Abblix LLP is not liable for any damages +// arising from the use of this software. +// +// LICENSE RESTRICTIONS: This code may not be modified, copied, or redistributed +// in any form outside of the official GitHub repository at: +// https://github.com/Abblix/OIDC.Server. All development and modifications +// must occur within the official repository and are managed solely by Abblix LLP. +// +// Unauthorized use, modification, or distribution of this software is strictly +// prohibited and may be subject to legal action. +// +// For full licensing terms, please visit: +// +// https://oidc.abblix.com/license +// +// CONTACT: For license inquiries or permissions, contact Abblix LLP at +// info@abblix.com + +using Abblix.Oidc.Server.Common; + +namespace Abblix.Oidc.Server.Endpoints.Token.Interfaces; + +/// +/// Defines an evaluator for determining the based on token requests. +/// +public interface ITokenAuthorizationContextEvaluator +{ + /// + /// Evaluates and constructs a new by refining and reconciling the scopes and resources + /// from the original authorization request based on the current token request. + /// + /// The valid token request that contains the original authorization grant and any additional + /// token-specific requests. + /// An updated that reflects the actual scopes and resources that + /// should be considered during the token issuance process. + AuthorizationContext EvaluateAuthorizationContext(ValidTokenRequest request); +} diff --git a/Abblix.Oidc.Server/Endpoints/Token/TokenAuthorizationContextEvaluator.cs b/Abblix.Oidc.Server/Endpoints/Token/TokenAuthorizationContextEvaluator.cs new file mode 100644 index 0000000..384609f --- /dev/null +++ b/Abblix.Oidc.Server/Endpoints/Token/TokenAuthorizationContextEvaluator.cs @@ -0,0 +1,68 @@ +// Abblix OIDC Server Library +// Copyright (c) Abblix LLP. All rights reserved. +// +// DISCLAIMER: This software is provided 'as-is', without any express or implied +// warranty. Use at your own risk. Abblix LLP is not liable for any damages +// arising from the use of this software. +// +// LICENSE RESTRICTIONS: This code may not be modified, copied, or redistributed +// in any form outside of the official GitHub repository at: +// https://github.com/Abblix/OIDC.Server. All development and modifications +// must occur within the official repository and are managed solely by Abblix LLP. +// +// Unauthorized use, modification, or distribution of this software is strictly +// prohibited and may be subject to legal action. +// +// For full licensing terms, please visit: +// +// https://oidc.abblix.com/license +// +// CONTACT: For license inquiries or permissions, contact Abblix LLP at +// info@abblix.com + +using Abblix.Oidc.Server.Common; +using Abblix.Oidc.Server.Endpoints.Token.Interfaces; + +namespace Abblix.Oidc.Server.Endpoints.Token; + +/// +/// Evaluates instances based on token requests. +/// +public class TokenAuthorizationContextEvaluator : ITokenAuthorizationContextEvaluator +{ + /// + /// Evaluates and constructs a new by refining and reconciling the scopes + /// and resources from the original authorization request based on the current token request. + /// + /// The valid token request that contains the original authorization grant and any additional + /// token-specific requests. + /// An updated that reflects the actual scopes and resources that + /// should be considered during the token issuance process. + public AuthorizationContext EvaluateAuthorizationContext(ValidTokenRequest request) + { + var authContext = request.AuthorizedGrant.Context; + + // Determine the effective scopes for the token request. + var scope = authContext.Scope; + if (scope is { Length: > 0 } && request.Scope is { Length: > 0 }) + { + scope = scope + .Intersect(from sd in request.Scope select sd.Scope, StringComparer.Ordinal) + .ToArray(); + } + + // Determine the effective resources for the token request. + var resources = authContext.Resources; + if (resources is { Length: > 0 } && request.Resources is { Length: > 0 }) + { + resources = resources.Intersect(from rd in request.Resources select rd.Resource).ToArray(); + } + + // Return a new authorization context updated with the determined scopes and resources. + return authContext with + { + Scope = scope, + Resources = resources, + }; + } +} diff --git a/Abblix.Oidc.Server/Endpoints/Token/TokenRequestProcessor.cs b/Abblix.Oidc.Server/Endpoints/Token/TokenRequestProcessor.cs index b029891..0ce7d8b 100644 --- a/Abblix.Oidc.Server/Endpoints/Token/TokenRequestProcessor.cs +++ b/Abblix.Oidc.Server/Endpoints/Token/TokenRequestProcessor.cs @@ -43,19 +43,23 @@ public class TokenRequestProcessor : ITokenRequestProcessor /// Service for creating and managing access tokens. /// Service for creating and managing refresh tokens. /// Service for creating and managing ID tokens in OpenID Connect flows. + /// Service for building the authorization context from a token request. public TokenRequestProcessor( IAccessTokenService accessTokenService, IRefreshTokenService refreshTokenService, - IIdentityTokenService identityTokenService) + IIdentityTokenService identityTokenService, + ITokenAuthorizationContextEvaluator tokenContextEvaluator) { _accessTokenService = accessTokenService; _refreshTokenService = refreshTokenService; _identityTokenService = identityTokenService; + _tokenContextEvaluator = tokenContextEvaluator; } private readonly IAccessTokenService _accessTokenService; private readonly IRefreshTokenService _refreshTokenService; private readonly IIdentityTokenService _identityTokenService; + private readonly ITokenAuthorizationContextEvaluator _tokenContextEvaluator; /// /// Asynchronously processes a valid token request, determining the necessary tokens to generate based on @@ -77,7 +81,7 @@ public async Task ProcessAsync(ValidTokenRequest request) var clientInfo = request.ClientInfo; clientInfo.CheckClient(); - var authContext = BuildAuthorizationContextFor(request); + var authContext = _tokenContextEvaluator.EvaluateAuthorizationContext(request); var accessToken = await _accessTokenService.CreateAccessTokenAsync( request.AuthorizedGrant.AuthSession, @@ -96,11 +100,7 @@ public async Task ProcessAsync(ValidTokenRequest request) request.AuthorizedGrant.AuthSession, request.AuthorizedGrant.Context, clientInfo, - request.AuthorizedGrant switch - { - RefreshTokenAuthorizedGrant grant => grant.RefreshToken, - _ => null, - }); + request.AuthorizedGrant is RefreshTokenAuthorizedGrant { RefreshToken: var refreshToken } ? refreshToken : null); } if (authContext.Scope.HasFlag(Scopes.OpenId)) @@ -116,34 +116,4 @@ public async Task ProcessAsync(ValidTokenRequest request) return response; } - - /// - /// Constructs a new by refining and reconciling the scopes and resources - /// from the original authorization request based on the current token request. - /// - /// The valid token request that contains the original authorization grant and any additional - /// token-specific requests. - /// An updated that reflects the actual scopes and resources that - /// should be considered during the token issuance process. - private static AuthorizationContext BuildAuthorizationContextFor(ValidTokenRequest request) - { - var authContext = request.AuthorizedGrant.Context; - - // Determine the effective scopes for the token request, defaulting to OpenId if no specific scopes are requested. - var scope = authContext.Scope is { Length: > 0 } - ? request.Scope.Select(sd => sd.Scope).Intersect(authContext.Scope, StringComparer.Ordinal).ToArray() - : new[] { Scopes.OpenId }; - - // Determine the effective resources for the token request, defaulting to none if no specific resources are requested. - var resources = authContext.Resources is { Length: > 0 } - ? request.Resources.Select(rd => rd.Resource).Intersect(authContext.Resources).ToArray() - : Array.Empty(); - - // Return a new authorization context updated with the determined scopes and resources. - return authContext with - { - Scope = scope, - Resources = resources, - }; - } }