From 0d92faa30826a73beaae60d094fa102839a86338 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Chalet?= Date: Wed, 9 Nov 2022 18:56:11 +0100 Subject: [PATCH] Add a new OpenIddictAuthorizationManager.CreateAsync() overload and improve OpenIddictScopeManager.ListResourcesAsync() --- .../Controllers/AuthorizationController.cs | 46 ++++++-------- .../Controllers/AuthorizationController.cs | 62 +++++++++---------- .../IOpenIddictAuthorizationManager.cs | 16 +++++ .../OpenIddictAuthorizationManager.cs | 22 +++++++ .../Managers/OpenIddictScopeManager.cs | 13 ++-- 5 files changed, 93 insertions(+), 66 deletions(-) diff --git a/sandbox/OpenIddict.Sandbox.AspNet.Server/Controllers/AuthorizationController.cs b/sandbox/OpenIddict.Sandbox.AspNet.Server/Controllers/AuthorizationController.cs index 853cb078..7d516538 100644 --- a/sandbox/OpenIddict.Sandbox.AspNet.Server/Controllers/AuthorizationController.cs +++ b/sandbox/OpenIddict.Sandbox.AspNet.Server/Controllers/AuthorizationController.cs @@ -142,10 +142,10 @@ namespace OpenIddict.Sandbox.AspNet.Server.Controllers roleType: Claims.Role); // Add the claims that will be persisted in the tokens. - identity.AddClaim(Claims.Subject, user.Id) - .AddClaim(Claims.Email, user.Email) - .AddClaim(Claims.Name, user.UserName) - .AddClaims(Claims.Role, (await context.Get().GetRolesAsync(user.Id)).ToImmutableArray()); + identity.SetClaim(Claims.Subject, user.Id) + .SetClaim(Claims.Email, user.Email) + .SetClaim(Claims.Name, user.UserName) + .SetClaims(Claims.Role, (await context.Get().GetRolesAsync(user.Id)).ToImmutableArray()); // Note: in this sample, the granted scopes match the requested scope // but you may want to allow the user to uncheck specific scopes. @@ -156,15 +156,12 @@ namespace OpenIddict.Sandbox.AspNet.Server.Controllers // Automatically create a permanent authorization to avoid requiring explicit consent // for future authorization or token requests containing the same scopes. var authorization = authorizations.LastOrDefault(); - if (authorization == null) - { - authorization = await _authorizationManager.CreateAsync( - principal: new ClaimsPrincipal(identity), - subject : user.Id, - client : await _applicationManager.GetIdAsync(application), - type : AuthorizationTypes.Permanent, - scopes : identity.GetScopes()); - } + authorization ??= await _authorizationManager.CreateAsync( + identity: identity, + subject : user.Id, + client : await _applicationManager.GetIdAsync(application), + type : AuthorizationTypes.Permanent, + scopes : identity.GetScopes()); identity.SetAuthorizationId(await _authorizationManager.GetIdAsync(authorization)); identity.SetDestinations(GetDestinations); @@ -263,10 +260,10 @@ namespace OpenIddict.Sandbox.AspNet.Server.Controllers roleType: Claims.Role); // Add the claims that will be persisted in the tokens. - identity.AddClaim(Claims.Subject, user.Id) - .AddClaim(Claims.Email, user.Email) - .AddClaim(Claims.Name, user.UserName) - .AddClaims(Claims.Role, (await context.Get().GetRolesAsync(user.Id)).ToImmutableArray()); + identity.SetClaim(Claims.Subject, user.Id) + .SetClaim(Claims.Email, user.Email) + .SetClaim(Claims.Name, user.UserName) + .SetClaims(Claims.Role, (await context.Get().GetRolesAsync(user.Id)).ToImmutableArray()); // Note: in this sample, the granted scopes match the requested scope // but you may want to allow the user to uncheck specific scopes. @@ -277,15 +274,12 @@ namespace OpenIddict.Sandbox.AspNet.Server.Controllers // Automatically create a permanent authorization to avoid requiring explicit consent // for future authorization or token requests containing the same scopes. var authorization = authorizations.LastOrDefault(); - if (authorization == null) - { - authorization = await _authorizationManager.CreateAsync( - principal: new ClaimsPrincipal(identity), - subject : user.Id, - client : await _applicationManager.GetIdAsync(application), - type : AuthorizationTypes.Permanent, - scopes : identity.GetScopes()); - } + authorization ??= await _authorizationManager.CreateAsync( + identity: identity, + subject : user.Id, + client : await _applicationManager.GetIdAsync(application), + type : AuthorizationTypes.Permanent, + scopes : identity.GetScopes()); identity.SetAuthorizationId(await _authorizationManager.GetIdAsync(authorization)); identity.SetDestinations(GetDestinations); diff --git a/sandbox/OpenIddict.Sandbox.AspNetCore.Server/Controllers/AuthorizationController.cs b/sandbox/OpenIddict.Sandbox.AspNetCore.Server/Controllers/AuthorizationController.cs index f82559d1..4bcf1a71 100644 --- a/sandbox/OpenIddict.Sandbox.AspNetCore.Server/Controllers/AuthorizationController.cs +++ b/sandbox/OpenIddict.Sandbox.AspNetCore.Server/Controllers/AuthorizationController.cs @@ -173,10 +173,10 @@ public class AuthorizationController : Controller roleType: Claims.Role); // Add the claims that will be persisted in the tokens. - identity.AddClaim(Claims.Subject, await _userManager.GetUserIdAsync(user)) - .AddClaim(Claims.Email, await _userManager.GetEmailAsync(user)) - .AddClaim(Claims.Name, await _userManager.GetUserNameAsync(user)) - .AddClaims(Claims.Role, (await _userManager.GetRolesAsync(user)).ToImmutableArray()); + identity.SetClaim(Claims.Subject, await _userManager.GetUserIdAsync(user)) + .SetClaim(Claims.Email, await _userManager.GetEmailAsync(user)) + .SetClaim(Claims.Name, await _userManager.GetUserNameAsync(user)) + .SetClaims(Claims.Role, (await _userManager.GetRolesAsync(user)).ToImmutableArray()); // Note: in this sample, the granted scopes match the requested scope // but you may want to allow the user to uncheck specific scopes. @@ -187,15 +187,12 @@ public class AuthorizationController : Controller // Automatically create a permanent authorization to avoid requiring explicit consent // for future authorization or token requests containing the same scopes. var authorization = authorizations.LastOrDefault(); - if (authorization is null) - { - authorization = await _authorizationManager.CreateAsync( - principal: new ClaimsPrincipal(identity), - subject : await _userManager.GetUserIdAsync(user), - client : await _applicationManager.GetIdAsync(application), - type : AuthorizationTypes.Permanent, - scopes : identity.GetScopes()); - } + authorization ??= await _authorizationManager.CreateAsync( + identity: identity, + subject : await _userManager.GetUserIdAsync(user), + client : await _applicationManager.GetIdAsync(application), + type : AuthorizationTypes.Permanent, + scopes : identity.GetScopes()); identity.SetAuthorizationId(await _authorizationManager.GetIdAsync(authorization)); identity.SetDestinations(GetDestinations); @@ -269,10 +266,10 @@ public class AuthorizationController : Controller roleType: Claims.Role); // Add the claims that will be persisted in the tokens. - identity.AddClaim(Claims.Subject, await _userManager.GetUserIdAsync(user)) - .AddClaim(Claims.Email, await _userManager.GetEmailAsync(user)) - .AddClaim(Claims.Name, await _userManager.GetUserNameAsync(user)) - .AddClaims(Claims.Role, (await _userManager.GetRolesAsync(user)).ToImmutableArray()); + identity.SetClaim(Claims.Subject, await _userManager.GetUserIdAsync(user)) + .SetClaim(Claims.Email, await _userManager.GetEmailAsync(user)) + .SetClaim(Claims.Name, await _userManager.GetUserNameAsync(user)) + .SetClaims(Claims.Role, (await _userManager.GetRolesAsync(user)).ToImmutableArray()); // Note: in this sample, the granted scopes match the requested scope // but you may want to allow the user to uncheck specific scopes. @@ -283,15 +280,12 @@ public class AuthorizationController : Controller // Automatically create a permanent authorization to avoid requiring explicit consent // for future authorization or token requests containing the same scopes. var authorization = authorizations.LastOrDefault(); - if (authorization is null) - { - authorization = await _authorizationManager.CreateAsync( - principal: new ClaimsPrincipal(identity), - subject : await _userManager.GetUserIdAsync(user), - client : await _applicationManager.GetIdAsync(application), - type : AuthorizationTypes.Permanent, - scopes : identity.GetScopes()); - } + authorization ??= await _authorizationManager.CreateAsync( + identity: identity, + subject : await _userManager.GetUserIdAsync(user), + client : await _applicationManager.GetIdAsync(application), + type : AuthorizationTypes.Permanent, + scopes : identity.GetScopes()); identity.SetAuthorizationId(await _authorizationManager.GetIdAsync(authorization)); identity.SetDestinations(GetDestinations); @@ -366,10 +360,10 @@ public class AuthorizationController : Controller roleType: Claims.Role); // Add the claims that will be persisted in the tokens. - identity.AddClaim(Claims.Subject, await _userManager.GetUserIdAsync(user)) - .AddClaim(Claims.Email, await _userManager.GetEmailAsync(user)) - .AddClaim(Claims.Name, await _userManager.GetUserNameAsync(user)) - .AddClaims(Claims.Role, (await _userManager.GetRolesAsync(user)).ToImmutableArray()); + identity.SetClaim(Claims.Subject, await _userManager.GetUserIdAsync(user)) + .SetClaim(Claims.Email, await _userManager.GetEmailAsync(user)) + .SetClaim(Claims.Name, await _userManager.GetUserNameAsync(user)) + .SetClaims(Claims.Role, (await _userManager.GetRolesAsync(user)).ToImmutableArray()); // Note: in this sample, the granted scopes match the requested scope // but you may want to allow the user to uncheck specific scopes. @@ -480,10 +474,10 @@ public class AuthorizationController : Controller roleType: Claims.Role); // Add the claims that will be persisted in the tokens. - identity.AddClaim(Claims.Subject, await _userManager.GetUserIdAsync(user)) - .AddClaim(Claims.Email, await _userManager.GetEmailAsync(user)) - .AddClaim(Claims.Name, await _userManager.GetUserNameAsync(user)) - .AddClaims(Claims.Role, (await _userManager.GetRolesAsync(user)).ToImmutableArray()); + identity.SetClaim(Claims.Subject, await _userManager.GetUserIdAsync(user)) + .SetClaim(Claims.Email, await _userManager.GetEmailAsync(user)) + .SetClaim(Claims.Name, await _userManager.GetUserNameAsync(user)) + .SetClaims(Claims.Role, (await _userManager.GetRolesAsync(user)).ToImmutableArray()); // Note: in this sample, the granted scopes match the requested scope // but you may want to allow the user to uncheck specific scopes. diff --git a/src/OpenIddict.Abstractions/Managers/IOpenIddictAuthorizationManager.cs b/src/OpenIddict.Abstractions/Managers/IOpenIddictAuthorizationManager.cs index 2c64f2bb..a51e983f 100644 --- a/src/OpenIddict.Abstractions/Managers/IOpenIddictAuthorizationManager.cs +++ b/src/OpenIddict.Abstractions/Managers/IOpenIddictAuthorizationManager.cs @@ -44,6 +44,22 @@ public interface IOpenIddictAuthorizationManager ValueTask CountAsync( Func, IQueryable> query, CancellationToken cancellationToken = default); + /// + /// Creates a new permanent authorization based on the specified parameters. + /// + /// The identity associated with the authorization. + /// The subject associated with the authorization. + /// The client associated with the authorization. + /// The authorization type. + /// The minimal scopes associated with the authorization. + /// The that can be used to abort the operation. + /// + /// A that can be used to monitor the asynchronous operation, whose result returns the authorization. + /// + ValueTask CreateAsync( + ClaimsIdentity identity, string subject, string client, + string type, ImmutableArray scopes, CancellationToken cancellationToken = default); + /// /// Creates a new permanent authorization based on the specified parameters. /// diff --git a/src/OpenIddict.Core/Managers/OpenIddictAuthorizationManager.cs b/src/OpenIddict.Core/Managers/OpenIddictAuthorizationManager.cs index 3b39109f..a07ef617 100644 --- a/src/OpenIddict.Core/Managers/OpenIddictAuthorizationManager.cs +++ b/src/OpenIddict.Core/Managers/OpenIddictAuthorizationManager.cs @@ -174,6 +174,24 @@ public class OpenIddictAuthorizationManager : IOpenIddictAuthori return authorization; } + /// + /// Creates a new permanent authorization based on the specified parameters. + /// + /// The identity associated with the authorization. + /// The subject associated with the authorization. + /// The client associated with the authorization. + /// The authorization type. + /// The minimal scopes associated with the authorization. + /// The that can be used to abort the operation. + /// + /// A that can be used to monitor the asynchronous operation, whose result returns the authorization. + /// + public virtual ValueTask CreateAsync( + ClaimsIdentity identity, string subject, string client, + string type, ImmutableArray scopes, CancellationToken cancellationToken = default) + => CreateAsync(new ClaimsPrincipal(identity ?? throw new ArgumentNullException(nameof(identity))), + subject, client, type, scopes, cancellationToken); + /// /// Creates a new permanent authorization based on the specified parameters. /// @@ -1187,6 +1205,10 @@ public class OpenIddictAuthorizationManager : IOpenIddictAuthori ValueTask IOpenIddictAuthorizationManager.CountAsync(Func, IQueryable> query, CancellationToken cancellationToken) => CountAsync(query, cancellationToken); + /// + async ValueTask IOpenIddictAuthorizationManager.CreateAsync(ClaimsIdentity identity, string subject, string client, string type, ImmutableArray scopes, CancellationToken cancellationToken) + => await CreateAsync(identity, subject, client, type, scopes, cancellationToken); + /// async ValueTask IOpenIddictAuthorizationManager.CreateAsync(ClaimsPrincipal principal, string subject, string client, string type, ImmutableArray scopes, CancellationToken cancellationToken) => await CreateAsync(principal, subject, client, type, scopes, cancellationToken); diff --git a/src/OpenIddict.Core/Managers/OpenIddictScopeManager.cs b/src/OpenIddict.Core/Managers/OpenIddictScopeManager.cs index 62b521d4..0c1573fb 100644 --- a/src/OpenIddict.Core/Managers/OpenIddictScopeManager.cs +++ b/src/OpenIddict.Core/Managers/OpenIddictScopeManager.cs @@ -744,12 +744,13 @@ public class OpenIddictScopeManager : IOpenIddictScopeManager where TSco await foreach (var scope in FindByNamesAsync(scopes, cancellationToken)) { - resources.UnionWith(await GetResourcesAsync(scope, cancellationToken)); - } - - foreach (var resource in resources) - { - yield return resource; + foreach (var resource in await GetResourcesAsync(scope, cancellationToken)) + { + if (resources.Add(resource)) + { + yield return resource; + } + } } }