Skip to content

Commit

Permalink
Refactoring of token context evaluation
Browse files Browse the repository at this point in the history
  • Loading branch information
kirill-abblix committed Jul 2, 2024
1 parent b25ef8c commit f19d2ab
Show file tree
Hide file tree
Showing 4 changed files with 127 additions and 43 deletions.
17 changes: 11 additions & 6 deletions Abblix.Oidc.Server/Endpoints/ServiceCollectionExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -138,14 +139,18 @@ public static IServiceCollection AddPushedAuthorizationEndpoint(this IServiceCol
/// <returns>The configured <see cref="IServiceCollection"/>.</returns>
public static IServiceCollection AddTokenEndpoint(this IServiceCollection services)
{
return services
services
.AddAuthorizationGrants()
.AddTokenContextValidators()
.AddTokenContextValidators();

services.TryAddScoped<ITokenAuthorizationContextEvaluator, TokenAuthorizationContextEvaluator>();

services.TryAddScoped<ITokenHandler, TokenHandler>();
services.TryAddScoped<ITokenRequestValidator, TokenRequestValidator>();
services.TryAddScoped<ITokenRequestProcessor, TokenRequestProcessor>();
services.Decorate<ITokenRequestProcessor, AuthorizationCodeReusePreventingDecorator>();

.AddScoped<ITokenHandler, TokenHandler>()
.AddScoped<ITokenRequestValidator, TokenRequestValidator>()
.AddScoped<ITokenRequestProcessor, TokenRequestProcessor>()
.Decorate<ITokenRequestProcessor, AuthorizationCodeReusePreventingDecorator>();
return services;
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
@@ -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;

/// <summary>
/// Defines an evaluator for determining the <see cref="AuthorizationContext"/> based on token requests.
/// </summary>
public interface ITokenAuthorizationContextEvaluator
{
/// <summary>
/// Evaluates and constructs a new <see cref="AuthorizationContext"/> by refining and reconciling the scopes and resources
/// from the original authorization request based on the current token request.
/// </summary>
/// <param name="request">The valid token request that contains the original authorization grant and any additional
/// token-specific requests.</param>
/// <returns>An updated <see cref="AuthorizationContext"/> that reflects the actual scopes and resources that
/// should be considered during the token issuance process.</returns>
AuthorizationContext EvaluateAuthorizationContext(ValidTokenRequest request);
}
Original file line number Diff line number Diff line change
@@ -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;

/// <summary>
/// Evaluates <see cref="AuthorizationContext"/> instances based on token requests.
/// </summary>
public class TokenAuthorizationContextEvaluator : ITokenAuthorizationContextEvaluator
{
/// <summary>
/// Evaluates and constructs a new <see cref="AuthorizationContext"/> by refining and reconciling the scopes
/// and resources from the original authorization request based on the current token request.
/// </summary>
/// <param name="request">The valid token request that contains the original authorization grant and any additional
/// token-specific requests.</param>
/// <returns>An updated <see cref="AuthorizationContext"/> that reflects the actual scopes and resources that
/// should be considered during the token issuance process.</returns>
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,
};
}
}
44 changes: 7 additions & 37 deletions Abblix.Oidc.Server/Endpoints/Token/TokenRequestProcessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,19 +43,23 @@ public class TokenRequestProcessor : ITokenRequestProcessor
/// <param name="accessTokenService">Service for creating and managing access tokens.</param>
/// <param name="refreshTokenService">Service for creating and managing refresh tokens.</param>
/// <param name="identityTokenService">Service for creating and managing ID tokens in OpenID Connect flows.</param>
/// <param name="tokenContextEvaluator">Service for building the authorization context from a token request.</param>
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;

/// <summary>
/// Asynchronously processes a valid token request, determining the necessary tokens to generate based on
Expand All @@ -77,7 +81,7 @@ public async Task<TokenResponse> 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,
Expand All @@ -96,11 +100,7 @@ public async Task<TokenResponse> 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))
Expand All @@ -116,34 +116,4 @@ public async Task<TokenResponse> ProcessAsync(ValidTokenRequest request)

return response;
}

/// <summary>
/// Constructs a new <see cref="AuthorizationContext"/> by refining and reconciling the scopes and resources
/// from the original authorization request based on the current token request.
/// </summary>
/// <param name="request">The valid token request that contains the original authorization grant and any additional
/// token-specific requests.</param>
/// <returns>An updated <see cref="AuthorizationContext"/> that reflects the actual scopes and resources that
/// should be considered during the token issuance process.</returns>
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<Uri>();

// Return a new authorization context updated with the determined scopes and resources.
return authContext with
{
Scope = scope,
Resources = resources,
};
}
}

0 comments on commit f19d2ab

Please sign in to comment.