From fa264642d451012ca18fe2e067b5e1aaa7539204 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Chalet?= Date: Wed, 25 Oct 2017 13:40:45 +0200 Subject: [PATCH 1/3] Flow the claims principal/authentication properties from the OpenIddict provider to the authorizations/tokens stores --- .../OpenIddictAuthorizationDescriptor.cs | 14 +++ .../Descriptors/OpenIddictScopeDescriptor.cs | 6 ++ .../Descriptors/OpenIddictTokenDescriptor.cs | 15 ++++ .../Stores/OpenIddictAuthorizationStore.cs | 2 +- .../Stores/OpenIddictApplicationStore.cs | 70 ++++++++++----- .../Stores/OpenIddictAuthorizationStore.cs | 68 +++++++++----- .../Stores/OpenIddictScopeStore.cs | 37 ++++++-- .../Stores/OpenIddictTokenStore.cs | 90 ++++++++++++------- .../Stores/OpenIddictApplicationStore.cs | 70 ++++++++++----- .../Stores/OpenIddictAuthorizationStore.cs | 68 +++++++++----- .../Stores/OpenIddictScopeStore.cs | 37 ++++++-- .../Stores/OpenIddictTokenStore.cs | 90 ++++++++++++------- src/OpenIddict/OpenIddictProvider.Helpers.cs | 14 ++- 13 files changed, 407 insertions(+), 174 deletions(-) diff --git a/src/OpenIddict.Core/Descriptors/OpenIddictAuthorizationDescriptor.cs b/src/OpenIddict.Core/Descriptors/OpenIddictAuthorizationDescriptor.cs index 292de19e..a34603f9 100644 --- a/src/OpenIddict.Core/Descriptors/OpenIddictAuthorizationDescriptor.cs +++ b/src/OpenIddict.Core/Descriptors/OpenIddictAuthorizationDescriptor.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Security.Claims; namespace OpenIddict.Core { @@ -13,6 +14,19 @@ namespace OpenIddict.Core /// public string ApplicationId { get; set; } + /// + /// Gets or sets the optional principal associated with the authorization. + /// Note: this property is not stored by the default authorization stores. + /// + public ClaimsPrincipal Principal { get; set; } + + /// + /// Gets the optional authentication properties associated with the authorization. + /// Note: this property is not stored by the default authorization stores. + /// + public IDictionary Properties { get; } = + new Dictionary(StringComparer.Ordinal); + /// /// Gets the scopes associated with the authorization. /// diff --git a/src/OpenIddict.Core/Descriptors/OpenIddictScopeDescriptor.cs b/src/OpenIddict.Core/Descriptors/OpenIddictScopeDescriptor.cs index edcc69d4..9900a704 100644 --- a/src/OpenIddict.Core/Descriptors/OpenIddictScopeDescriptor.cs +++ b/src/OpenIddict.Core/Descriptors/OpenIddictScopeDescriptor.cs @@ -5,6 +5,12 @@ /// public class OpenIddictScopeDescriptor { + /// + /// Gets or sets the description + /// associated with the scope. + /// + public virtual string Description { get; set; } + /// /// Gets or sets the unique name /// associated with the scope. diff --git a/src/OpenIddict.Core/Descriptors/OpenIddictTokenDescriptor.cs b/src/OpenIddict.Core/Descriptors/OpenIddictTokenDescriptor.cs index 258713a9..370ccd07 100644 --- a/src/OpenIddict.Core/Descriptors/OpenIddictTokenDescriptor.cs +++ b/src/OpenIddict.Core/Descriptors/OpenIddictTokenDescriptor.cs @@ -1,4 +1,6 @@ using System; +using System.Collections.Generic; +using System.Security.Claims; namespace OpenIddict.Core { @@ -37,6 +39,19 @@ namespace OpenIddict.Core /// public string Hash { get; set; } + /// + /// Gets or sets the optional principal associated with the token. + /// Note: this property is not stored by the default token stores. + /// + public ClaimsPrincipal Principal { get; set; } + + /// + /// Gets the optional authentication properties associated with the token. + /// Note: this property is not stored by the default token stores. + /// + public IDictionary Properties { get; } = + new Dictionary(StringComparer.Ordinal); + /// /// Gets or sets the status associated with the token. /// diff --git a/src/OpenIddict.Core/Stores/OpenIddictAuthorizationStore.cs b/src/OpenIddict.Core/Stores/OpenIddictAuthorizationStore.cs index 0d08b0ff..308eaa6f 100644 --- a/src/OpenIddict.Core/Stores/OpenIddictAuthorizationStore.cs +++ b/src/OpenIddict.Core/Stores/OpenIddictAuthorizationStore.cs @@ -380,7 +380,7 @@ namespace OpenIddict.Core authorization.Type = type; - return Task.FromResult(0); + return Task.CompletedTask; } /// diff --git a/src/OpenIddict.EntityFramework/Stores/OpenIddictApplicationStore.cs b/src/OpenIddict.EntityFramework/Stores/OpenIddictApplicationStore.cs index ae9a1652..e473b984 100644 --- a/src/OpenIddict.EntityFramework/Stores/OpenIddictApplicationStore.cs +++ b/src/OpenIddict.EntityFramework/Stores/OpenIddictApplicationStore.cs @@ -141,36 +141,17 @@ namespace OpenIddict.EntityFramework /// /// A that can be used to monitor the asynchronous operation, whose result returns the application. /// - public override Task CreateAsync([NotNull] OpenIddictApplicationDescriptor descriptor, CancellationToken cancellationToken) + public override async Task CreateAsync([NotNull] OpenIddictApplicationDescriptor descriptor, CancellationToken cancellationToken) { if (descriptor == null) { throw new ArgumentNullException(nameof(descriptor)); } - var application = new TApplication - { - ClientId = descriptor.ClientId, - ClientSecret = descriptor.ClientSecret, - DisplayName = descriptor.DisplayName, - Type = descriptor.Type - }; - - if (descriptor.PostLogoutRedirectUris.Count != 0) - { - application.PostLogoutRedirectUris = string.Join( - OpenIddictConstants.Separators.Space, - descriptor.PostLogoutRedirectUris.Select(uri => uri.OriginalString)); - } - - if (descriptor.RedirectUris.Count != 0) - { - application.RedirectUris = string.Join( - OpenIddictConstants.Separators.Space, - descriptor.RedirectUris.Select(uri => uri.OriginalString)); - } + var application = new TApplication(); - return CreateAsync(application, cancellationToken); + await BindAsync(application, descriptor, cancellationToken); + return await CreateAsync(application, cancellationToken); } /// @@ -304,5 +285,48 @@ namespace OpenIddict.EntityFramework return Context.SaveChangesAsync(cancellationToken); } + + /// + /// Sets the application properties based on the specified descriptor. + /// + /// The application to update. + /// The application descriptor. + /// The that can be used to abort the operation. + /// + /// A that can be used to monitor the asynchronous operation. + /// + protected virtual Task BindAsync([NotNull] TApplication application, [NotNull] OpenIddictApplicationDescriptor descriptor, CancellationToken cancellationToken) + { + if (application == null) + { + throw new ArgumentNullException(nameof(application)); + } + + if (descriptor == null) + { + throw new ArgumentNullException(nameof(descriptor)); + } + + application.ClientId = descriptor.ClientId; + application.ClientSecret = descriptor.ClientSecret; + application.DisplayName = descriptor.DisplayName; + application.Type = descriptor.Type; + + if (descriptor.PostLogoutRedirectUris.Count != 0) + { + application.PostLogoutRedirectUris = string.Join( + OpenIddictConstants.Separators.Space, + descriptor.PostLogoutRedirectUris.Select(uri => uri.OriginalString)); + } + + if (descriptor.RedirectUris.Count != 0) + { + application.RedirectUris = string.Join( + OpenIddictConstants.Separators.Space, + descriptor.RedirectUris.Select(uri => uri.OriginalString)); + } + + return Task.CompletedTask; + } } } \ No newline at end of file diff --git a/src/OpenIddict.EntityFramework/Stores/OpenIddictAuthorizationStore.cs b/src/OpenIddict.EntityFramework/Stores/OpenIddictAuthorizationStore.cs index f93d8a60..1778ca94 100644 --- a/src/OpenIddict.EntityFramework/Stores/OpenIddictAuthorizationStore.cs +++ b/src/OpenIddict.EntityFramework/Stores/OpenIddictAuthorizationStore.cs @@ -148,30 +148,9 @@ namespace OpenIddict.EntityFramework throw new ArgumentNullException(nameof(descriptor)); } - var authorization = new TAuthorization - { - Status = descriptor.Status, - Subject = descriptor.Subject, - Type = descriptor.Type - }; - - if (descriptor.Scopes.Count != 0) - { - authorization.Scopes = string.Join(OpenIddictConstants.Separators.Space, descriptor.Scopes); - } - - // Bind the authorization to the specified application, if applicable. - if (!string.IsNullOrEmpty(descriptor.ApplicationId)) - { - var application = await Applications.FindAsync(cancellationToken, ConvertIdentifierFromString(descriptor.ApplicationId)); - if (application == null) - { - throw new InvalidOperationException("The application associated with the authorization cannot be found."); - } - - authorization.Application = application; - } + var authorization = new TAuthorization(); + await BindAsync(authorization, descriptor, cancellationToken); return await CreateAsync(authorization, cancellationToken); } @@ -356,5 +335,48 @@ namespace OpenIddict.EntityFramework return Context.SaveChangesAsync(cancellationToken); } + + /// + /// Sets the authorization properties based on the specified descriptor. + /// + /// The authorization to update. + /// The authorization descriptor. + /// The that can be used to abort the operation. + /// + /// A that can be used to monitor the asynchronous operation. + /// + protected virtual async Task BindAsync([NotNull] TAuthorization authorization, [NotNull] OpenIddictAuthorizationDescriptor descriptor, CancellationToken cancellationToken) + { + if (authorization == null) + { + throw new ArgumentNullException(nameof(authorization)); + } + + if (descriptor == null) + { + throw new ArgumentNullException(nameof(descriptor)); + } + + authorization.Status = descriptor.Status; + authorization.Subject = descriptor.Subject; + authorization.Type = descriptor.Type; + + if (descriptor.Scopes.Count != 0) + { + authorization.Scopes = string.Join(OpenIddictConstants.Separators.Space, descriptor.Scopes); + } + + // Bind the authorization to the specified application, if applicable. + if (!string.IsNullOrEmpty(descriptor.ApplicationId)) + { + var application = await Applications.FindAsync(new object[] { ConvertIdentifierFromString(descriptor.ApplicationId) }, cancellationToken); + if (application == null) + { + throw new InvalidOperationException("The application associated with the authorization cannot be found."); + } + + authorization.Application = application; + } + } } } \ No newline at end of file diff --git a/src/OpenIddict.EntityFramework/Stores/OpenIddictScopeStore.cs b/src/OpenIddict.EntityFramework/Stores/OpenIddictScopeStore.cs index 4732f7b8..992e8d82 100644 --- a/src/OpenIddict.EntityFramework/Stores/OpenIddictScopeStore.cs +++ b/src/OpenIddict.EntityFramework/Stores/OpenIddictScopeStore.cs @@ -122,14 +122,12 @@ namespace OpenIddict.EntityFramework /// /// A that can be used to monitor the asynchronous operation, whose result returns the scope. /// - public override Task CreateAsync([NotNull] OpenIddictScopeDescriptor descriptor, CancellationToken cancellationToken) + public override async Task CreateAsync([NotNull] OpenIddictScopeDescriptor descriptor, CancellationToken cancellationToken) { - var scope = new TScope - { - Name = descriptor.Name - }; + var scope = new TScope(); - return CreateAsync(scope, cancellationToken); + await BindAsync(scope, descriptor, cancellationToken); + return await CreateAsync(scope, cancellationToken); } /// @@ -212,5 +210,32 @@ namespace OpenIddict.EntityFramework return Context.SaveChangesAsync(cancellationToken); } + + /// + /// Sets the scope properties based on the specified descriptor. + /// + /// The scope to update. + /// The scope descriptor. + /// The that can be used to abort the operation. + /// + /// A that can be used to monitor the asynchronous operation. + /// + protected virtual Task BindAsync([NotNull] TScope scope, [NotNull] OpenIddictScopeDescriptor descriptor, CancellationToken cancellationToken) + { + if (scope == null) + { + throw new ArgumentNullException(nameof(scope)); + } + + if (descriptor == null) + { + throw new ArgumentNullException(nameof(descriptor)); + } + + scope.Description = descriptor.Description; + scope.Name = descriptor.Name; + + return Task.CompletedTask; + } } } \ No newline at end of file diff --git a/src/OpenIddict.EntityFramework/Stores/OpenIddictTokenStore.cs b/src/OpenIddict.EntityFramework/Stores/OpenIddictTokenStore.cs index 5d7c4f06..1e6135b8 100644 --- a/src/OpenIddict.EntityFramework/Stores/OpenIddictTokenStore.cs +++ b/src/OpenIddict.EntityFramework/Stores/OpenIddictTokenStore.cs @@ -148,41 +148,9 @@ namespace OpenIddict.EntityFramework throw new ArgumentNullException(nameof(descriptor)); } - var token = new TToken - { - Ciphertext = descriptor.Ciphertext, - CreationDate = descriptor.CreationDate, - ExpirationDate = descriptor.ExpirationDate, - Hash = descriptor.Hash, - Status = descriptor.Status, - Subject = descriptor.Subject, - Type = descriptor.Type - }; - - // Bind the token to the specified client application, if applicable. - if (!string.IsNullOrEmpty(descriptor.ApplicationId)) - { - var application = await Applications.FindAsync(cancellationToken, ConvertIdentifierFromString(descriptor.ApplicationId)); - if (application == null) - { - throw new InvalidOperationException("The application associated with the token cannot be found."); - } - - token.Application = application; - } - - // Bind the token to the specified authorization, if applicable. - if (!string.IsNullOrEmpty(descriptor.AuthorizationId)) - { - var authorization = await Authorizations.FindAsync(cancellationToken, ConvertIdentifierFromString(descriptor.AuthorizationId)); - if (authorization == null) - { - throw new InvalidOperationException("The authorization associated with the token cannot be found."); - } - - token.Authorization = authorization; - } + var token = new TToken(); + await BindAsync(token, descriptor, cancellationToken); return await CreateAsync(token, cancellationToken); } @@ -429,5 +397,59 @@ namespace OpenIddict.EntityFramework return Context.SaveChangesAsync(cancellationToken); } + + /// + /// Sets the token properties based on the specified descriptor. + /// + /// The token to update. + /// The token descriptor. + /// The that can be used to abort the operation. + /// + /// A that can be used to monitor the asynchronous operation. + /// + protected virtual async Task BindAsync([NotNull] TToken token, [NotNull] OpenIddictTokenDescriptor descriptor, CancellationToken cancellationToken) + { + if (token == null) + { + throw new ArgumentNullException(nameof(token)); + } + + if (descriptor == null) + { + throw new ArgumentNullException(nameof(descriptor)); + } + + token.Ciphertext = descriptor.Ciphertext; + token.CreationDate = descriptor.CreationDate; + token.ExpirationDate = descriptor.ExpirationDate; + token.Hash = descriptor.Hash; + token.Status = descriptor.Status; + token.Subject = descriptor.Subject; + token.Type = descriptor.Type; + + // Bind the token to the specified client application, if applicable. + if (!string.IsNullOrEmpty(descriptor.ApplicationId)) + { + var application = await Applications.FindAsync(new object[] { ConvertIdentifierFromString(descriptor.ApplicationId) }, cancellationToken); + if (application == null) + { + throw new InvalidOperationException("The application associated with the token cannot be found."); + } + + token.Application = application; + } + + // Bind the token to the specified authorization, if applicable. + if (!string.IsNullOrEmpty(descriptor.AuthorizationId)) + { + var authorization = await Authorizations.FindAsync(new object[] { ConvertIdentifierFromString(descriptor.AuthorizationId) }, cancellationToken); + if (authorization == null) + { + throw new InvalidOperationException("The authorization associated with the token cannot be found."); + } + + token.Authorization = authorization; + } + } } } \ No newline at end of file diff --git a/src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictApplicationStore.cs b/src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictApplicationStore.cs index 92c8affb..4db5055a 100644 --- a/src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictApplicationStore.cs +++ b/src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictApplicationStore.cs @@ -141,36 +141,17 @@ namespace OpenIddict.EntityFrameworkCore /// /// A that can be used to monitor the asynchronous operation, whose result returns the application. /// - public override Task CreateAsync([NotNull] OpenIddictApplicationDescriptor descriptor, CancellationToken cancellationToken) + public override async Task CreateAsync([NotNull] OpenIddictApplicationDescriptor descriptor, CancellationToken cancellationToken) { if (descriptor == null) { throw new ArgumentNullException(nameof(descriptor)); } - var application = new TApplication - { - ClientId = descriptor.ClientId, - ClientSecret = descriptor.ClientSecret, - DisplayName = descriptor.DisplayName, - Type = descriptor.Type - }; - - if (descriptor.PostLogoutRedirectUris.Count != 0) - { - application.PostLogoutRedirectUris = string.Join( - OpenIddictConstants.Separators.Space, - descriptor.PostLogoutRedirectUris.Select(uri => uri.OriginalString)); - } - - if (descriptor.RedirectUris.Count != 0) - { - application.RedirectUris = string.Join( - OpenIddictConstants.Separators.Space, - descriptor.RedirectUris.Select(uri => uri.OriginalString)); - } + var application = new TApplication(); - return CreateAsync(application, cancellationToken); + await BindAsync(application, descriptor, cancellationToken); + return await CreateAsync(application, cancellationToken); } /// @@ -304,5 +285,48 @@ namespace OpenIddict.EntityFrameworkCore return Context.SaveChangesAsync(cancellationToken); } + + /// + /// Sets the application properties based on the specified descriptor. + /// + /// The application to update. + /// The application descriptor. + /// The that can be used to abort the operation. + /// + /// A that can be used to monitor the asynchronous operation. + /// + protected virtual Task BindAsync([NotNull] TApplication application, [NotNull] OpenIddictApplicationDescriptor descriptor, CancellationToken cancellationToken) + { + if (application == null) + { + throw new ArgumentNullException(nameof(application)); + } + + if (descriptor == null) + { + throw new ArgumentNullException(nameof(descriptor)); + } + + application.ClientId = descriptor.ClientId; + application.ClientSecret = descriptor.ClientSecret; + application.DisplayName = descriptor.DisplayName; + application.Type = descriptor.Type; + + if (descriptor.PostLogoutRedirectUris.Count != 0) + { + application.PostLogoutRedirectUris = string.Join( + OpenIddictConstants.Separators.Space, + descriptor.PostLogoutRedirectUris.Select(uri => uri.OriginalString)); + } + + if (descriptor.RedirectUris.Count != 0) + { + application.RedirectUris = string.Join( + OpenIddictConstants.Separators.Space, + descriptor.RedirectUris.Select(uri => uri.OriginalString)); + } + + return Task.CompletedTask; + } } } \ No newline at end of file diff --git a/src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictAuthorizationStore.cs b/src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictAuthorizationStore.cs index de874fe3..90c0d2a3 100644 --- a/src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictAuthorizationStore.cs +++ b/src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictAuthorizationStore.cs @@ -148,30 +148,9 @@ namespace OpenIddict.EntityFrameworkCore throw new ArgumentNullException(nameof(descriptor)); } - var authorization = new TAuthorization - { - Status = descriptor.Status, - Subject = descriptor.Subject, - Type = descriptor.Type - }; - - if (descriptor.Scopes.Count != 0) - { - authorization.Scopes = string.Join(OpenIddictConstants.Separators.Space, descriptor.Scopes); - } - - // Bind the authorization to the specified application, if applicable. - if (!string.IsNullOrEmpty(descriptor.ApplicationId)) - { - var application = await Applications.FindAsync(new object[] { ConvertIdentifierFromString(descriptor.ApplicationId) }, cancellationToken); - if (application == null) - { - throw new InvalidOperationException("The application associated with the authorization cannot be found."); - } - - authorization.Application = application; - } + var authorization = new TAuthorization(); + await BindAsync(authorization, descriptor, cancellationToken); return await CreateAsync(authorization, cancellationToken); } @@ -356,5 +335,48 @@ namespace OpenIddict.EntityFrameworkCore return Context.SaveChangesAsync(cancellationToken); } + + /// + /// Sets the authorization properties based on the specified descriptor. + /// + /// The authorization to update. + /// The authorization descriptor. + /// The that can be used to abort the operation. + /// + /// A that can be used to monitor the asynchronous operation. + /// + protected virtual async Task BindAsync([NotNull] TAuthorization authorization, [NotNull] OpenIddictAuthorizationDescriptor descriptor, CancellationToken cancellationToken) + { + if (authorization == null) + { + throw new ArgumentNullException(nameof(authorization)); + } + + if (descriptor == null) + { + throw new ArgumentNullException(nameof(descriptor)); + } + + authorization.Status = descriptor.Status; + authorization.Subject = descriptor.Subject; + authorization.Type = descriptor.Type; + + if (descriptor.Scopes.Count != 0) + { + authorization.Scopes = string.Join(OpenIddictConstants.Separators.Space, descriptor.Scopes); + } + + // Bind the authorization to the specified application, if applicable. + if (!string.IsNullOrEmpty(descriptor.ApplicationId)) + { + var application = await Applications.FindAsync(new object[] { ConvertIdentifierFromString(descriptor.ApplicationId) }, cancellationToken); + if (application == null) + { + throw new InvalidOperationException("The application associated with the authorization cannot be found."); + } + + authorization.Application = application; + } + } } } \ No newline at end of file diff --git a/src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictScopeStore.cs b/src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictScopeStore.cs index 4520f532..918ed9b7 100644 --- a/src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictScopeStore.cs +++ b/src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictScopeStore.cs @@ -122,14 +122,12 @@ namespace OpenIddict.EntityFrameworkCore /// /// A that can be used to monitor the asynchronous operation, whose result returns the scope. /// - public override Task CreateAsync([NotNull] OpenIddictScopeDescriptor descriptor, CancellationToken cancellationToken) + public override async Task CreateAsync([NotNull] OpenIddictScopeDescriptor descriptor, CancellationToken cancellationToken) { - var scope = new TScope - { - Name = descriptor.Name - }; + var scope = new TScope(); - return CreateAsync(scope, cancellationToken); + await BindAsync(scope, descriptor, cancellationToken); + return await CreateAsync(scope, cancellationToken); } /// @@ -212,5 +210,32 @@ namespace OpenIddict.EntityFrameworkCore return Context.SaveChangesAsync(cancellationToken); } + + /// + /// Sets the scope properties based on the specified descriptor. + /// + /// The scope to update. + /// The scope descriptor. + /// The that can be used to abort the operation. + /// + /// A that can be used to monitor the asynchronous operation. + /// + protected virtual Task BindAsync([NotNull] TScope scope, [NotNull] OpenIddictScopeDescriptor descriptor, CancellationToken cancellationToken) + { + if (scope == null) + { + throw new ArgumentNullException(nameof(scope)); + } + + if (descriptor == null) + { + throw new ArgumentNullException(nameof(descriptor)); + } + + scope.Description = descriptor.Description; + scope.Name = descriptor.Name; + + return Task.CompletedTask; + } } } \ No newline at end of file diff --git a/src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictTokenStore.cs b/src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictTokenStore.cs index b2596619..fab5b859 100644 --- a/src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictTokenStore.cs +++ b/src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictTokenStore.cs @@ -148,41 +148,9 @@ namespace OpenIddict.EntityFrameworkCore throw new ArgumentNullException(nameof(descriptor)); } - var token = new TToken - { - Ciphertext = descriptor.Ciphertext, - CreationDate = descriptor.CreationDate, - ExpirationDate = descriptor.ExpirationDate, - Hash = descriptor.Hash, - Status = descriptor.Status, - Subject = descriptor.Subject, - Type = descriptor.Type - }; - - // Bind the token to the specified client application, if applicable. - if (!string.IsNullOrEmpty(descriptor.ApplicationId)) - { - var application = await Applications.FindAsync(new object[] { ConvertIdentifierFromString(descriptor.ApplicationId) }, cancellationToken); - if (application == null) - { - throw new InvalidOperationException("The application associated with the token cannot be found."); - } - - token.Application = application; - } - - // Bind the token to the specified authorization, if applicable. - if (!string.IsNullOrEmpty(descriptor.AuthorizationId)) - { - var authorization = await Authorizations.FindAsync(new object[] { ConvertIdentifierFromString(descriptor.AuthorizationId) }, cancellationToken); - if (authorization == null) - { - throw new InvalidOperationException("The authorization associated with the token cannot be found."); - } - - token.Authorization = authorization; - } + var token = new TToken(); + await BindAsync(token, descriptor, cancellationToken); return await CreateAsync(token, cancellationToken); } @@ -431,5 +399,59 @@ namespace OpenIddict.EntityFrameworkCore return Context.SaveChangesAsync(cancellationToken); } + + /// + /// Sets the token properties based on the specified descriptor. + /// + /// The token to update. + /// The token descriptor. + /// The that can be used to abort the operation. + /// + /// A that can be used to monitor the asynchronous operation. + /// + protected virtual async Task BindAsync([NotNull] TToken token, [NotNull] OpenIddictTokenDescriptor descriptor, CancellationToken cancellationToken) + { + if (token == null) + { + throw new ArgumentNullException(nameof(token)); + } + + if (descriptor == null) + { + throw new ArgumentNullException(nameof(descriptor)); + } + + token.Ciphertext = descriptor.Ciphertext; + token.CreationDate = descriptor.CreationDate; + token.ExpirationDate = descriptor.ExpirationDate; + token.Hash = descriptor.Hash; + token.Status = descriptor.Status; + token.Subject = descriptor.Subject; + token.Type = descriptor.Type; + + // Bind the token to the specified client application, if applicable. + if (!string.IsNullOrEmpty(descriptor.ApplicationId)) + { + var application = await Applications.FindAsync(new object[] { ConvertIdentifierFromString(descriptor.ApplicationId) }, cancellationToken); + if (application == null) + { + throw new InvalidOperationException("The application associated with the token cannot be found."); + } + + token.Application = application; + } + + // Bind the token to the specified authorization, if applicable. + if (!string.IsNullOrEmpty(descriptor.AuthorizationId)) + { + var authorization = await Authorizations.FindAsync(new object[] { ConvertIdentifierFromString(descriptor.AuthorizationId) }, cancellationToken); + if (authorization == null) + { + throw new InvalidOperationException("The authorization associated with the token cannot be found."); + } + + token.Authorization = authorization; + } + } } } \ No newline at end of file diff --git a/src/OpenIddict/OpenIddictProvider.Helpers.cs b/src/OpenIddict/OpenIddictProvider.Helpers.cs index 22cce5f8..7bc501f8 100644 --- a/src/OpenIddict/OpenIddictProvider.Helpers.cs +++ b/src/OpenIddict/OpenIddictProvider.Helpers.cs @@ -33,12 +33,18 @@ namespace OpenIddict { var descriptor = new OpenIddictAuthorizationDescriptor { + Principal = ticket.Principal, Status = OpenIddictConstants.Statuses.Valid, Subject = ticket.Principal.GetClaim(OpenIdConnectConstants.Claims.Subject), Type = OpenIddictConstants.AuthorizationTypes.AdHoc }; - foreach (var scope in request.GetScopes()) + foreach (var property in ticket.Properties.Items) + { + descriptor.Properties.Add(property); + } + + foreach (var scope in ticket.GetScopes()) { descriptor.Scopes.Add(scope); } @@ -115,11 +121,17 @@ namespace OpenIddict AuthorizationId = ticket.GetProperty(OpenIddictConstants.Properties.AuthorizationId), CreationDate = ticket.Properties.IssuedUtc, ExpirationDate = ticket.Properties.ExpiresUtc, + Principal = ticket.Principal, Status = OpenIddictConstants.Statuses.Valid, Subject = ticket.Principal.GetClaim(OpenIdConnectConstants.Claims.Subject), Type = type }; + foreach (var property in ticket.Properties.Items) + { + descriptor.Properties.Add(property); + } + string result = null; // When reference tokens are enabled or when the token is an authorization code or a From 59b29d2d23ef25bf025bb618f33619341c99cefe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Chalet?= Date: Sun, 29 Oct 2017 13:25:26 +0100 Subject: [PATCH 2/3] Optimization: update SetPostLogoutRedirectUrisAsync() and SetRedirectUrisAsync() to avoid running checks for default or empty arrays --- .../Stores/IOpenIddictApplicationStore.cs | 4 ++-- .../Stores/OpenIddictApplicationStore.cs | 20 +++++++++++-------- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/src/OpenIddict.Core/Stores/IOpenIddictApplicationStore.cs b/src/OpenIddict.Core/Stores/IOpenIddictApplicationStore.cs index b228dd2b..e4380153 100644 --- a/src/OpenIddict.Core/Stores/IOpenIddictApplicationStore.cs +++ b/src/OpenIddict.Core/Stores/IOpenIddictApplicationStore.cs @@ -276,7 +276,7 @@ namespace OpenIddict.Core /// A that can be used to monitor the asynchronous operation. /// Task SetPostLogoutRedirectUrisAsync([NotNull] TApplication application, - [NotNull] ImmutableArray addresses, CancellationToken cancellationToken); + ImmutableArray addresses, CancellationToken cancellationToken); /// /// Sets the callback addresses associated with an application. @@ -288,7 +288,7 @@ namespace OpenIddict.Core /// A that can be used to monitor the asynchronous operation. /// Task SetRedirectUrisAsync([NotNull] TApplication application, - [NotNull] ImmutableArray addresses, CancellationToken cancellationToken); + ImmutableArray addresses, CancellationToken cancellationToken); /// /// Updates an existing application. diff --git a/src/OpenIddict.Core/Stores/OpenIddictApplicationStore.cs b/src/OpenIddict.Core/Stores/OpenIddictApplicationStore.cs index d2f24866..2b9564ff 100644 --- a/src/OpenIddict.Core/Stores/OpenIddictApplicationStore.cs +++ b/src/OpenIddict.Core/Stores/OpenIddictApplicationStore.cs @@ -555,16 +555,18 @@ namespace OpenIddict.Core /// A that can be used to monitor the asynchronous operation. /// public virtual Task SetPostLogoutRedirectUrisAsync([NotNull] TApplication application, - [NotNull] ImmutableArray addresses, CancellationToken cancellationToken) + ImmutableArray addresses, CancellationToken cancellationToken) { if (application == null) { - throw new ArgumentException(nameof(application)); + throw new ArgumentNullException(nameof(application)); } - if (addresses == null) + if (addresses.IsDefaultOrEmpty) { - throw new ArgumentException(nameof(addresses)); + application.PostLogoutRedirectUris = null; + + return Task.CompletedTask; } if (addresses.Any(address => string.IsNullOrEmpty(address))) @@ -592,16 +594,18 @@ namespace OpenIddict.Core /// A that can be used to monitor the asynchronous operation. /// public virtual Task SetRedirectUrisAsync([NotNull] TApplication application, - [NotNull] ImmutableArray addresses, CancellationToken cancellationToken) + ImmutableArray addresses, CancellationToken cancellationToken) { if (application == null) { - throw new ArgumentException(nameof(application)); + throw new ArgumentNullException(nameof(application)); } - if (addresses == null) + if (addresses.IsDefaultOrEmpty) { - throw new ArgumentException(nameof(addresses)); + application.RedirectUris = null; + + return Task.CompletedTask; } if (addresses.Any(address => string.IsNullOrEmpty(address))) From 6116ba2d7d6bf020221dc478911683631b7b3691 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Chalet?= Date: Sun, 29 Oct 2017 16:57:28 +0100 Subject: [PATCH 3/3] Replace IOpenIddictApplicationStore.GetTokensAsync() by IOpenIddictTokenStore.FindByApplicationIdAsync() --- .../Managers/OpenIddictApplicationManager.cs | 33 +++++-------- .../OpenIddictAuthorizationManager.cs | 19 +++++++- .../Managers/OpenIddictTokenManager.cs | 47 +++++++++++++++++-- .../Stores/IOpenIddictApplicationStore.cs | 11 ----- .../Stores/IOpenIddictTokenStore.cs | 11 +++++ .../Stores/OpenIddictApplicationStore.cs | 40 ---------------- .../Stores/OpenIddictTokenStore.cs | 21 +++++++++ 7 files changed, 104 insertions(+), 78 deletions(-) diff --git a/src/OpenIddict.Core/Managers/OpenIddictApplicationManager.cs b/src/OpenIddict.Core/Managers/OpenIddictApplicationManager.cs index 156680b6..af2d91f1 100644 --- a/src/OpenIddict.Core/Managers/OpenIddictApplicationManager.cs +++ b/src/OpenIddict.Core/Managers/OpenIddictApplicationManager.cs @@ -244,8 +244,13 @@ namespace OpenIddict.Core /// A that can be used to monitor the asynchronous operation, /// whose result returns the client application corresponding to the identifier. /// - public virtual Task FindByIdAsync(string identifier, CancellationToken cancellationToken) + public virtual Task FindByIdAsync([NotNull] string identifier, CancellationToken cancellationToken) { + if (string.IsNullOrEmpty(identifier)) + { + throw new ArgumentException("The identifier cannot be null or empty.", nameof(identifier)); + } + return Store.FindByIdAsync(identifier, cancellationToken); } @@ -258,8 +263,13 @@ namespace OpenIddict.Core /// A that can be used to monitor the asynchronous operation, /// whose result returns the client application corresponding to the identifier. /// - public virtual Task FindByClientIdAsync(string identifier, CancellationToken cancellationToken) + public virtual Task FindByClientIdAsync([NotNull] string identifier, CancellationToken cancellationToken) { + if (string.IsNullOrEmpty(identifier)) + { + throw new ArgumentException("The identifier cannot be null or empty.", nameof(identifier)); + } + return Store.FindByClientIdAsync(identifier, cancellationToken); } @@ -408,25 +418,6 @@ namespace OpenIddict.Core return Store.GetIdAsync(application, cancellationToken); } - /// - /// Retrieves the token identifiers associated with an application. - /// - /// The application. - /// The that can be used to abort the operation. - /// - /// A that can be used to monitor the asynchronous operation, - /// whose result returns the tokens associated with the application. - /// - public virtual Task> GetTokensAsync([NotNull] TApplication application, CancellationToken cancellationToken) - { - if (application == null) - { - throw new ArgumentNullException(nameof(application)); - } - - return Store.GetTokensAsync(application, cancellationToken); - } - /// /// Determines whether an application is a confidential client. /// diff --git a/src/OpenIddict.Core/Managers/OpenIddictAuthorizationManager.cs b/src/OpenIddict.Core/Managers/OpenIddictAuthorizationManager.cs index 5b606cbe..d32ea3fe 100644 --- a/src/OpenIddict.Core/Managers/OpenIddictAuthorizationManager.cs +++ b/src/OpenIddict.Core/Managers/OpenIddictAuthorizationManager.cs @@ -182,8 +182,18 @@ namespace OpenIddict.Core /// A that can be used to monitor the asynchronous operation, /// whose result returns the authorization corresponding to the subject/client. /// - public virtual Task FindAsync(string subject, string client, CancellationToken cancellationToken) + public virtual Task FindAsync([NotNull] string subject, [NotNull] string client, CancellationToken cancellationToken) { + if (string.IsNullOrEmpty(subject)) + { + throw new ArgumentException("The subject cannot be null or empty.", nameof(subject)); + } + + if (string.IsNullOrEmpty(client)) + { + throw new ArgumentException("The client identifier cannot be null or empty.", nameof(client)); + } + return Store.FindAsync(subject, client, cancellationToken); } @@ -196,8 +206,13 @@ namespace OpenIddict.Core /// A that can be used to monitor the asynchronous operation, /// whose result returns the authorization corresponding to the identifier. /// - public virtual Task FindByIdAsync(string identifier, CancellationToken cancellationToken) + public virtual Task FindByIdAsync([NotNull] string identifier, CancellationToken cancellationToken) { + if (string.IsNullOrEmpty(identifier)) + { + throw new ArgumentException("The identifier cannot be null or empty.", nameof(identifier)); + } + return Store.FindByIdAsync(identifier, cancellationToken); } diff --git a/src/OpenIddict.Core/Managers/OpenIddictTokenManager.cs b/src/OpenIddict.Core/Managers/OpenIddictTokenManager.cs index 5ccaa461..520080d0 100644 --- a/src/OpenIddict.Core/Managers/OpenIddictTokenManager.cs +++ b/src/OpenIddict.Core/Managers/OpenIddictTokenManager.cs @@ -179,6 +179,25 @@ namespace OpenIddict.Core await UpdateAsync(token, cancellationToken); } + /// + /// Retrieves the list of tokens corresponding to the specified application identifier. + /// + /// The application identifier associated with the tokens. + /// The that can be used to abort the operation. + /// + /// A that can be used to monitor the asynchronous operation, + /// whose result returns the tokens corresponding to the specified application. + /// + public virtual Task> FindByApplicationIdAsync([NotNull] string identifier, CancellationToken cancellationToken) + { + if (string.IsNullOrEmpty(identifier)) + { + throw new ArgumentException("The identifier cannot be null or empty.", nameof(identifier)); + } + + return Store.FindByApplicationIdAsync(identifier, cancellationToken); + } + /// /// Retrieves the list of tokens corresponding to the specified authorization identifier. /// @@ -188,8 +207,13 @@ namespace OpenIddict.Core /// A that can be used to monitor the asynchronous operation, /// whose result returns the tokens corresponding to the specified authorization. /// - public virtual Task> FindByAuthorizationIdAsync(string identifier, CancellationToken cancellationToken) + public virtual Task> FindByAuthorizationIdAsync([NotNull] string identifier, CancellationToken cancellationToken) { + if (string.IsNullOrEmpty(identifier)) + { + throw new ArgumentException("The identifier cannot be null or empty.", nameof(identifier)); + } + return Store.FindByAuthorizationIdAsync(identifier, cancellationToken); } @@ -202,8 +226,13 @@ namespace OpenIddict.Core /// A that can be used to monitor the asynchronous operation, /// whose result returns the tokens corresponding to the specified hash. /// - public virtual Task FindByHashAsync(string hash, CancellationToken cancellationToken) + public virtual Task FindByHashAsync([NotNull] string hash, CancellationToken cancellationToken) { + if (string.IsNullOrEmpty(hash)) + { + throw new ArgumentException("The hash cannot be null or empty.", nameof(hash)); + } + return Store.FindByHashAsync(hash, cancellationToken); } @@ -216,8 +245,13 @@ namespace OpenIddict.Core /// A that can be used to monitor the asynchronous operation, /// whose result returns the token corresponding to the unique identifier. /// - public virtual Task FindByIdAsync(string identifier, CancellationToken cancellationToken) + public virtual Task FindByIdAsync([NotNull] string identifier, CancellationToken cancellationToken) { + if (string.IsNullOrEmpty(identifier)) + { + throw new ArgumentException("The identifier cannot be null or empty.", nameof(identifier)); + } + return Store.FindByIdAsync(identifier, cancellationToken); } @@ -230,8 +264,13 @@ namespace OpenIddict.Core /// A that can be used to monitor the asynchronous operation, /// whose result returns the tokens corresponding to the specified subject. /// - public virtual Task> FindBySubjectAsync(string subject, CancellationToken cancellationToken) + public virtual Task> FindBySubjectAsync([NotNull] string subject, CancellationToken cancellationToken) { + if (string.IsNullOrEmpty(subject)) + { + throw new ArgumentException("The subject cannot be null or empty.", nameof(subject)); + } + return Store.FindBySubjectAsync(subject, cancellationToken); } diff --git a/src/OpenIddict.Core/Stores/IOpenIddictApplicationStore.cs b/src/OpenIddict.Core/Stores/IOpenIddictApplicationStore.cs index e4380153..43157bc3 100644 --- a/src/OpenIddict.Core/Stores/IOpenIddictApplicationStore.cs +++ b/src/OpenIddict.Core/Stores/IOpenIddictApplicationStore.cs @@ -207,17 +207,6 @@ namespace OpenIddict.Core /// Task> GetRedirectUrisAsync([NotNull] TApplication application, CancellationToken cancellationToken); - /// - /// Retrieves the token identifiers associated with an application. - /// - /// The application. - /// The that can be used to abort the operation. - /// - /// A that can be used to monitor the asynchronous operation, - /// whose result returns the tokens associated with the application. - /// - Task> GetTokensAsync([NotNull] TApplication application, CancellationToken cancellationToken); - /// /// Executes the specified query. /// diff --git a/src/OpenIddict.Core/Stores/IOpenIddictTokenStore.cs b/src/OpenIddict.Core/Stores/IOpenIddictTokenStore.cs index d35402f9..56f4430b 100644 --- a/src/OpenIddict.Core/Stores/IOpenIddictTokenStore.cs +++ b/src/OpenIddict.Core/Stores/IOpenIddictTokenStore.cs @@ -69,6 +69,17 @@ namespace OpenIddict.Core /// A that can be used to monitor the asynchronous operation. Task DeleteAsync([NotNull] TToken token, CancellationToken cancellationToken); + /// + /// Retrieves the list of tokens corresponding to the specified application identifier. + /// + /// The application identifier associated with the tokens. + /// The that can be used to abort the operation. + /// + /// A that can be used to monitor the asynchronous operation, + /// whose result returns the tokens corresponding to the specified application. + /// + Task> FindByApplicationIdAsync([NotNull] string identifier, CancellationToken cancellationToken); + /// /// Retrieves the list of tokens corresponding to the specified authorization identifier. /// diff --git a/src/OpenIddict.Core/Stores/OpenIddictApplicationStore.cs b/src/OpenIddict.Core/Stores/OpenIddictApplicationStore.cs index 2b9564ff..0a3e298c 100644 --- a/src/OpenIddict.Core/Stores/OpenIddictApplicationStore.cs +++ b/src/OpenIddict.Core/Stores/OpenIddictApplicationStore.cs @@ -411,46 +411,6 @@ namespace OpenIddict.Core return Task.FromResult(ImmutableArray.Create(uris)); } - /// - /// Retrieves the token identifiers associated with an application. - /// - /// The application. - /// The that can be used to abort the operation. - /// - /// A that can be used to monitor the asynchronous operation, - /// whose result returns the tokens associated with the application. - /// - public virtual async Task> GetTokensAsync([NotNull] TApplication application, CancellationToken cancellationToken) - { - if (application == null) - { - throw new ArgumentNullException(nameof(application)); - } - - IQueryable Query(IQueryable applications) - { - return from entity in applications - where entity.Id.Equals(application.Id) - from token in entity.Tokens - select token.Id; - } - - var identifiers = await ListAsync(Query, cancellationToken); - if (identifiers.IsDefaultOrEmpty) - { - return ImmutableArray.Create(); - } - - var builder = ImmutableArray.CreateBuilder(identifiers.Length); - - foreach (var identifier in identifiers) - { - builder.Add(ConvertIdentifierToString(identifier)); - } - - return builder.ToImmutable(); - } - /// /// Executes the specified query. /// diff --git a/src/OpenIddict.Core/Stores/OpenIddictTokenStore.cs b/src/OpenIddict.Core/Stores/OpenIddictTokenStore.cs index 71dd8fe6..7b8d0754 100644 --- a/src/OpenIddict.Core/Stores/OpenIddictTokenStore.cs +++ b/src/OpenIddict.Core/Stores/OpenIddictTokenStore.cs @@ -82,6 +82,27 @@ namespace OpenIddict.Core /// A that can be used to monitor the asynchronous operation. public abstract Task DeleteAsync([NotNull] TToken token, CancellationToken cancellationToken); + /// + /// Retrieves the list of tokens corresponding to the specified application identifier. + /// + /// The application identifier associated with the tokens. + /// The that can be used to abort the operation. + /// + /// A that can be used to monitor the asynchronous operation, + /// whose result returns the tokens corresponding to the specified application. + /// + public virtual Task> FindByApplicationIdAsync([NotNull] string identifier, CancellationToken cancellationToken) + { + if (string.IsNullOrEmpty(identifier)) + { + throw new ArgumentException("The identifier cannot be null or empty.", nameof(identifier)); + } + + var key = ConvertIdentifierFromString(identifier); + + return ListAsync(tokens => tokens.Where(token => token.Application.Id.Equals(key)), cancellationToken); + } + /// /// Retrieves the list of tokens corresponding to the specified authorization identifier. ///