From 1bddda9cdb6c3ac853214d4a933e70df92816e8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Chalet?= Date: Sat, 14 Oct 2017 19:28:00 +0200 Subject: [PATCH] Add new GetApplicationIdAsync()/SetApplicationIdAsync() methods in the authorization/token managers/stores --- .../OpenIddictAuthorizationManager.cs | 39 ++++++ .../Managers/OpenIddictTokenManager.cs | 35 ++++-- .../Stores/IOpenIddictAuthorizationStore.cs | 22 ++++ .../Stores/IOpenIddictTokenStore.cs | 23 +++- .../Stores/OpenIddictAuthorizationStore.cs | 40 ++++++ .../Stores/OpenIddictTokenStore.cs | 37 +++++- .../Stores/OpenIddictAuthorizationStore.cs | 73 +++++++++++ .../Stores/OpenIddictTokenStore.cs | 112 +++++++++++++---- .../Stores/OpenIddictAuthorizationStore.cs | 73 +++++++++++ .../Stores/OpenIddictTokenStore.cs | 116 ++++++++++++++---- src/OpenIddict/OpenIddictProvider.Helpers.cs | 7 +- src/OpenIddict/OpenIddictProvider.Signin.cs | 4 +- 12 files changed, 507 insertions(+), 74 deletions(-) diff --git a/src/OpenIddict.Core/Managers/OpenIddictAuthorizationManager.cs b/src/OpenIddict.Core/Managers/OpenIddictAuthorizationManager.cs index b43f7049..5b606cbe 100644 --- a/src/OpenIddict.Core/Managers/OpenIddictAuthorizationManager.cs +++ b/src/OpenIddict.Core/Managers/OpenIddictAuthorizationManager.cs @@ -201,6 +201,25 @@ namespace OpenIddict.Core return Store.FindByIdAsync(identifier, cancellationToken); } + /// + /// Retrieves the optional application identifier associated with an authorization. + /// + /// 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 application identifier associated with the authorization. + /// + public virtual Task GetApplicationIdAsync([NotNull] TAuthorization authorization, CancellationToken cancellationToken) + { + if (authorization == null) + { + throw new ArgumentNullException(nameof(authorization)); + } + + return Store.GetApplicationIdAsync(authorization, cancellationToken); + } + /// /// Executes the specified query. /// @@ -376,6 +395,26 @@ namespace OpenIddict.Core } } + /// + /// Sets the application identifier associated with an authorization. + /// + /// The authorization. + /// The unique identifier associated with the client application. + /// The that can be used to abort the operation. + /// + /// A that can be used to monitor the asynchronous operation. + /// + public virtual async Task SetApplicationIdAsync([NotNull] TAuthorization authorization, [CanBeNull] string identifier, CancellationToken cancellationToken) + { + if (authorization == null) + { + throw new ArgumentNullException(nameof(authorization)); + } + + await Store.SetApplicationIdAsync(authorization, identifier, cancellationToken); + await UpdateAsync(authorization, cancellationToken); + } + /// /// Updates an existing authorization. /// diff --git a/src/OpenIddict.Core/Managers/OpenIddictTokenManager.cs b/src/OpenIddict.Core/Managers/OpenIddictTokenManager.cs index ea012aa1..646e4acb 100644 --- a/src/OpenIddict.Core/Managers/OpenIddictTokenManager.cs +++ b/src/OpenIddict.Core/Managers/OpenIddictTokenManager.cs @@ -236,6 +236,25 @@ namespace OpenIddict.Core return Store.FindBySubjectAsync(subject, cancellationToken); } + /// + /// Retrieves the optional application identifier associated with a token. + /// + /// The token. + /// The that can be used to abort the operation. + /// + /// A that can be used to monitor the asynchronous operation, + /// whose result returns the application identifier associated with the token. + /// + public virtual Task GetApplicationIdAsync([NotNull] TToken token, CancellationToken cancellationToken) + { + if (token == null) + { + throw new ArgumentNullException(nameof(token)); + } + + return Store.GetApplicationIdAsync(token, cancellationToken); + } + /// /// Executes the specified query. /// @@ -549,42 +568,42 @@ namespace OpenIddict.Core } /// - /// Sets the authorization associated with a token. + /// Sets the application identifier associated with a token. /// /// The token. - /// The unique identifier associated with the authorization. + /// The unique identifier associated with the client application. /// The that can be used to abort the operation. /// /// A that can be used to monitor the asynchronous operation. /// - public virtual async Task SetAuthorizationAsync([NotNull] TToken token, [CanBeNull] string identifier, CancellationToken cancellationToken) + public virtual async Task SetApplicationIdAsync([NotNull] TToken token, [CanBeNull] string identifier, CancellationToken cancellationToken) { if (token == null) { throw new ArgumentNullException(nameof(token)); } - await Store.SetAuthorizationAsync(token, identifier, cancellationToken); + await Store.SetApplicationIdAsync(token, identifier, cancellationToken); await UpdateAsync(token, cancellationToken); } /// - /// Sets the client application associated with a token. + /// Sets the authorization identifier associated with a token. /// /// The token. - /// The unique identifier associated with the client application. + /// The unique identifier associated with the authorization. /// The that can be used to abort the operation. /// /// A that can be used to monitor the asynchronous operation. /// - public virtual async Task SetClientAsync([NotNull] TToken token, [CanBeNull] string identifier, CancellationToken cancellationToken) + public virtual async Task SetAuthorizationIdAsync([NotNull] TToken token, [CanBeNull] string identifier, CancellationToken cancellationToken) { if (token == null) { throw new ArgumentNullException(nameof(token)); } - await Store.SetClientAsync(token, identifier, cancellationToken); + await Store.SetAuthorizationIdAsync(token, identifier, cancellationToken); await UpdateAsync(token, cancellationToken); } diff --git a/src/OpenIddict.Core/Stores/IOpenIddictAuthorizationStore.cs b/src/OpenIddict.Core/Stores/IOpenIddictAuthorizationStore.cs index 09bee76f..d4fb16d8 100644 --- a/src/OpenIddict.Core/Stores/IOpenIddictAuthorizationStore.cs +++ b/src/OpenIddict.Core/Stores/IOpenIddictAuthorizationStore.cs @@ -94,6 +94,17 @@ namespace OpenIddict.Core /// Task FindByIdAsync([NotNull] string identifier, CancellationToken cancellationToken); + /// + /// Retrieves the optional application identifier associated with an authorization. + /// + /// 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 application identifier associated with the authorization. + /// + Task GetApplicationIdAsync([NotNull] TAuthorization authorization, CancellationToken cancellationToken); + /// /// Executes the specified query. /// @@ -187,6 +198,17 @@ namespace OpenIddict.Core /// Task> ListInvalidAsync([CanBeNull] int? count, [CanBeNull] int? offset, CancellationToken cancellationToken); + /// + /// Sets the application identifier associated with an authorization. + /// + /// The authorization. + /// The unique identifier associated with the client application. + /// The that can be used to abort the operation. + /// + /// A that can be used to monitor the asynchronous operation. + /// + Task SetApplicationIdAsync([NotNull] TAuthorization authorization, [CanBeNull] string identifier, CancellationToken cancellationToken); + /// /// Sets the status associated with an authorization. /// diff --git a/src/OpenIddict.Core/Stores/IOpenIddictTokenStore.cs b/src/OpenIddict.Core/Stores/IOpenIddictTokenStore.cs index 91d09f81..d35402f9 100644 --- a/src/OpenIddict.Core/Stores/IOpenIddictTokenStore.cs +++ b/src/OpenIddict.Core/Stores/IOpenIddictTokenStore.cs @@ -113,6 +113,17 @@ namespace OpenIddict.Core /// Task> FindBySubjectAsync([NotNull] string subject, CancellationToken cancellationToken); + /// + /// Retrieves the optional application identifier associated with a token. + /// + /// The token. + /// The that can be used to abort the operation. + /// + /// A that can be used to monitor the asynchronous operation, + /// whose result returns the application identifier associated with the token. + /// + Task GetApplicationIdAsync([NotNull] TToken token, CancellationToken cancellationToken); + /// /// Executes the specified query. /// @@ -262,26 +273,26 @@ namespace OpenIddict.Core Task> ListInvalidAsync([CanBeNull] int? count, [CanBeNull] int? offset, CancellationToken cancellationToken); /// - /// Sets the authorization associated with a token. + /// Sets the application identifier associated with a token. /// /// The token. - /// The unique identifier associated with the authorization. + /// The unique identifier associated with the client application. /// The that can be used to abort the operation. /// /// A that can be used to monitor the asynchronous operation. /// - Task SetAuthorizationAsync([NotNull] TToken token, [CanBeNull] string identifier, CancellationToken cancellationToken); + Task SetApplicationIdAsync([NotNull] TToken token, [CanBeNull] string identifier, CancellationToken cancellationToken); /// - /// Sets the client application associated with a token. + /// Sets the authorization identifier associated with a token. /// /// The token. - /// The unique identifier associated with the client application. + /// The unique identifier associated with the authorization. /// The that can be used to abort the operation. /// /// A that can be used to monitor the asynchronous operation. /// - Task SetClientAsync([NotNull] TToken token, [CanBeNull] string identifier, CancellationToken cancellationToken); + Task SetAuthorizationIdAsync([NotNull] TToken token, [CanBeNull] string identifier, CancellationToken cancellationToken); /// /// Sets the expiration date associated with a token. diff --git a/src/OpenIddict.Core/Stores/OpenIddictAuthorizationStore.cs b/src/OpenIddict.Core/Stores/OpenIddictAuthorizationStore.cs index d272f4ca..0d08b0ff 100644 --- a/src/OpenIddict.Core/Stores/OpenIddictAuthorizationStore.cs +++ b/src/OpenIddict.Core/Stores/OpenIddictAuthorizationStore.cs @@ -136,6 +136,35 @@ namespace OpenIddict.Core return GetAsync(authorizations => authorizations.Where(authorization => authorization.Id.Equals(key)), cancellationToken); } + /// + /// Retrieves the optional application identifier associated with an authorization. + /// + /// 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 application identifier associated with the authorization. + /// + public virtual async Task GetApplicationIdAsync([NotNull] TAuthorization authorization, CancellationToken cancellationToken) + { + if (authorization == null) + { + throw new ArgumentNullException(nameof(authorization)); + } + + if (authorization.Application != null) + { + return ConvertIdentifierToString(authorization.Application.Id); + } + + var key = await GetAsync(authorizations => + from element in authorizations + where element.Id.Equals(authorization.Id) + select element.Application.Id, cancellationToken); + + return ConvertIdentifierToString(key); + } + /// /// Executes the specified query. /// @@ -301,6 +330,17 @@ namespace OpenIddict.Core return ListAsync(Query, cancellationToken); } + /// + /// Sets the application identifier associated with an authorization. + /// + /// The authorization. + /// The unique identifier associated with the client application. + /// The that can be used to abort the operation. + /// + /// A that can be used to monitor the asynchronous operation. + /// + public abstract Task SetApplicationIdAsync([NotNull] TAuthorization authorization, [CanBeNull] string identifier, CancellationToken cancellationToken); + /// /// Sets the status associated with an authorization. /// diff --git a/src/OpenIddict.Core/Stores/OpenIddictTokenStore.cs b/src/OpenIddict.Core/Stores/OpenIddictTokenStore.cs index 80584071..71dd8fe6 100644 --- a/src/OpenIddict.Core/Stores/OpenIddictTokenStore.cs +++ b/src/OpenIddict.Core/Stores/OpenIddictTokenStore.cs @@ -174,6 +174,35 @@ namespace OpenIddict.Core /// public abstract Task GetAsync([NotNull] Func, IQueryable> query, CancellationToken cancellationToken); + /// + /// Retrieves the optional application identifier associated with a token. + /// + /// The token. + /// The that can be used to abort the operation. + /// + /// A that can be used to monitor the asynchronous operation, + /// whose result returns the application identifier associated with the token. + /// + public virtual async Task GetApplicationIdAsync([NotNull] TToken token, CancellationToken cancellationToken) + { + if (token == null) + { + throw new ArgumentNullException(nameof(token)); + } + + if (token.Application != null) + { + return ConvertIdentifierToString(token.Application.Id); + } + + var key = await GetAsync(tokens => + from element in tokens + where element.Id.Equals(token.Id) + select element.Application.Id, cancellationToken); + + return ConvertIdentifierToString(key); + } + /// /// Retrieves the optional authorization identifier associated with a token. /// @@ -437,7 +466,7 @@ namespace OpenIddict.Core } /// - /// Sets the authorization associated with a token. + /// Sets the authorization identifier associated with a token. /// /// The token. /// The unique identifier associated with the authorization. @@ -445,10 +474,10 @@ namespace OpenIddict.Core /// /// A that can be used to monitor the asynchronous operation. /// - public abstract Task SetAuthorizationAsync([NotNull] TToken token, [CanBeNull] string identifier, CancellationToken cancellationToken); + public abstract Task SetAuthorizationIdAsync([NotNull] TToken token, [CanBeNull] string identifier, CancellationToken cancellationToken); /// - /// Sets the client application associated with a token. + /// Sets the application identifier associated with a token. /// /// The token. /// The unique identifier associated with the client application. @@ -456,7 +485,7 @@ namespace OpenIddict.Core /// /// A that can be used to monitor the asynchronous operation. /// - public abstract Task SetClientAsync([NotNull] TToken token, [CanBeNull] string identifier, CancellationToken cancellationToken); + public abstract Task SetApplicationIdAsync([NotNull] TToken token, [CanBeNull] string identifier, CancellationToken cancellationToken); /// /// Sets the expiration date associated with a token. diff --git a/src/OpenIddict.EntityFramework/Stores/OpenIddictAuthorizationStore.cs b/src/OpenIddict.EntityFramework/Stores/OpenIddictAuthorizationStore.cs index d40f511f..7cbd4857 100644 --- a/src/OpenIddict.EntityFramework/Stores/OpenIddictAuthorizationStore.cs +++ b/src/OpenIddict.EntityFramework/Stores/OpenIddictAuthorizationStore.cs @@ -209,6 +209,38 @@ namespace OpenIddict.EntityFramework return Authorizations.FindAsync(cancellationToken, ConvertIdentifierFromString(identifier)); } + /// + /// Retrieves the optional application identifier associated with an authorization. + /// + /// 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 application identifier associated with the authorization. + /// + public override async Task GetApplicationIdAsync([NotNull] TAuthorization authorization, CancellationToken cancellationToken) + { + if (authorization == null) + { + throw new ArgumentNullException(nameof(authorization)); + } + + // If the application is not attached to the authorization instance (which is expected + // if the token was retrieved using the default FindBy*Async APIs as they don't + // eagerly load the application from the database), try to load it manually. + if (authorization.Application == null) + { + return ConvertIdentifierToString( + await Context.Entry(authorization) + .Reference(entry => entry.Application) + .Query() + .Select(application => application.Id) + .FirstOrDefaultAsync()); + } + + return ConvertIdentifierToString(authorization.Application.Id); + } + /// /// Executes the specified query. /// @@ -249,6 +281,47 @@ namespace OpenIddict.EntityFramework return ImmutableArray.Create(await query.Invoke(Authorizations).ToArrayAsync(cancellationToken)); } + /// + /// Sets the application identifier associated with an authorization. + /// + /// The authorization. + /// The unique identifier associated with the client application. + /// The that can be used to abort the operation. + /// + /// A that can be used to monitor the asynchronous operation. + /// + public override async Task SetApplicationIdAsync([NotNull] TAuthorization authorization, [CanBeNull] string identifier, CancellationToken cancellationToken) + { + if (authorization == null) + { + throw new ArgumentNullException(nameof(authorization)); + } + + if (!string.IsNullOrEmpty(identifier)) + { + var application = await Applications.FindAsync(cancellationToken, ConvertIdentifierFromString(identifier)); + if (application == null) + { + throw new InvalidOperationException("The application associated with the authorization cannot be found."); + } + + authorization.Application = application; + } + + else + { + var key = await GetIdAsync(authorization, cancellationToken); + + // Try to retrieve the application associated with the authorization. + // If none can be found, assume that no application is attached. + var application = await Applications.FirstOrDefaultAsync(element => element.Tokens.Any(t => t.Id.Equals(key))); + if (application != null) + { + application.Authorizations.Remove(authorization); + } + } + } + /// /// Updates an existing authorization. /// diff --git a/src/OpenIddict.EntityFramework/Stores/OpenIddictTokenStore.cs b/src/OpenIddict.EntityFramework/Stores/OpenIddictTokenStore.cs index ad4c2474..5d7c4f06 100644 --- a/src/OpenIddict.EntityFramework/Stores/OpenIddictTokenStore.cs +++ b/src/OpenIddict.EntityFramework/Stores/OpenIddictTokenStore.cs @@ -223,6 +223,38 @@ namespace OpenIddict.EntityFramework return Tokens.FindAsync(cancellationToken, ConvertIdentifierFromString(identifier)); } + /// + /// Retrieves the optional application identifier associated with a token. + /// + /// The token. + /// The that can be used to abort the operation. + /// + /// A that can be used to monitor the asynchronous operation, + /// whose result returns the application identifier associated with the token. + /// + public override async Task GetApplicationIdAsync([NotNull] TToken token, CancellationToken cancellationToken) + { + if (token == null) + { + throw new ArgumentNullException(nameof(token)); + } + + // If the application is not attached to the token instance (which is expected + // if the token was retrieved using the default FindBy*Async APIs as they don't + // eagerly load the application from the database), try to load it manually. + if (token.Application == null) + { + return ConvertIdentifierToString( + await Context.Entry(token) + .Reference(entry => entry.Application) + .Query() + .Select(application => application.Id) + .FirstOrDefaultAsync()); + } + + return ConvertIdentifierToString(token.Application.Id); + } + /// /// Executes the specified query. /// @@ -243,6 +275,38 @@ namespace OpenIddict.EntityFramework return query.Invoke(Tokens).SingleOrDefaultAsync(cancellationToken); } + /// + /// Retrieves the optional authorization identifier associated with a token. + /// + /// The token. + /// The that can be used to abort the operation. + /// + /// A that can be used to monitor the asynchronous operation, + /// whose result returns the authorization identifier associated with the token. + /// + public override async Task GetAuthorizationIdAsync([NotNull] TToken token, CancellationToken cancellationToken) + { + if (token == null) + { + throw new ArgumentNullException(nameof(token)); + } + + // If the authorization is not attached to the token instance (which is expected + // if the token was retrieved using the default FindBy*Async APIs as they don't + // eagerly load the authorization from the database), try to load it manually. + if (token.Authorization == null) + { + return ConvertIdentifierToString( + await Context.Entry(token) + .Reference(entry => entry.Authorization) + .Query() + .Select(authorization => authorization.Id) + .FirstOrDefaultAsync()); + } + + return ConvertIdentifierToString(token.Authorization.Id); + } + /// /// Executes the specified query. /// @@ -264,15 +328,15 @@ namespace OpenIddict.EntityFramework } /// - /// Sets the authorization associated with a token. + /// Sets the application identifier associated with a token. /// /// The token. - /// The unique identifier associated with the authorization. + /// The unique identifier associated with the client application. /// The that can be used to abort the operation. /// /// A that can be used to monitor the asynchronous operation. /// - public override async Task SetAuthorizationAsync([NotNull] TToken token, [CanBeNull] string identifier, CancellationToken cancellationToken) + public override async Task SetApplicationIdAsync([NotNull] TToken token, [CanBeNull] string identifier, CancellationToken cancellationToken) { if (token == null) { @@ -281,39 +345,39 @@ namespace OpenIddict.EntityFramework if (!string.IsNullOrEmpty(identifier)) { - var authorization = await Authorizations.FindAsync(cancellationToken, ConvertIdentifierFromString(identifier)); - if (authorization == null) + var application = await Applications.FindAsync(cancellationToken, ConvertIdentifierFromString(identifier)); + if (application == null) { - throw new InvalidOperationException("The authorization associated with the token cannot be found."); + throw new InvalidOperationException("The application associated with the token cannot be found."); } - token.Authorization = authorization; + token.Application = application; } else { var key = await GetIdAsync(token, cancellationToken); - // Try to retrieve the authorization associated with the token. - // If none can be found, assume that no authorization is attached. - var authorization = await Authorizations.FirstOrDefaultAsync(element => element.Tokens.Any(t => t.Id.Equals(key))); - if (authorization != null) + // Try to retrieve the application associated with the token. + // If none can be found, assume that no application is attached. + var application = await Applications.FirstOrDefaultAsync(element => element.Tokens.Any(t => t.Id.Equals(key))); + if (application != null) { - authorization.Tokens.Remove(token); + application.Tokens.Remove(token); } } } /// - /// Sets the client application associated with a token. + /// Sets the authorization identifier associated with a token. /// /// The token. - /// The unique identifier associated with the client application. + /// The unique identifier associated with the authorization. /// The that can be used to abort the operation. /// /// A that can be used to monitor the asynchronous operation. /// - public override async Task SetClientAsync([NotNull] TToken token, [CanBeNull] string identifier, CancellationToken cancellationToken) + public override async Task SetAuthorizationIdAsync([NotNull] TToken token, [CanBeNull] string identifier, CancellationToken cancellationToken) { if (token == null) { @@ -322,25 +386,25 @@ namespace OpenIddict.EntityFramework if (!string.IsNullOrEmpty(identifier)) { - var application = await Applications.FindAsync(cancellationToken, ConvertIdentifierFromString(identifier)); - if (application == null) + var authorization = await Authorizations.FindAsync(cancellationToken, ConvertIdentifierFromString(identifier)); + if (authorization == null) { - throw new InvalidOperationException("The application associated with the token cannot be found."); + throw new InvalidOperationException("The authorization associated with the token cannot be found."); } - token.Application = application; + token.Authorization = authorization; } else { var key = await GetIdAsync(token, cancellationToken); - // Try to retrieve the application associated with the token. - // If none can be found, assume that no application is attached. - var application = await Applications.FirstOrDefaultAsync(element => element.Tokens.Any(t => t.Id.Equals(key))); - if (application != null) + // Try to retrieve the authorization associated with the token. + // If none can be found, assume that no authorization is attached. + var authorization = await Authorizations.FirstOrDefaultAsync(element => element.Tokens.Any(t => t.Id.Equals(key))); + if (authorization != null) { - application.Tokens.Remove(token); + authorization.Tokens.Remove(token); } } } diff --git a/src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictAuthorizationStore.cs b/src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictAuthorizationStore.cs index b261dd4a..4e92ac93 100644 --- a/src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictAuthorizationStore.cs +++ b/src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictAuthorizationStore.cs @@ -209,6 +209,38 @@ namespace OpenIddict.EntityFrameworkCore return Authorizations.FindAsync(new object[] { ConvertIdentifierFromString(identifier) }, cancellationToken); } + /// + /// Retrieves the optional application identifier associated with an authorization. + /// + /// 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 application identifier associated with the authorization. + /// + public override async Task GetApplicationIdAsync([NotNull] TAuthorization authorization, CancellationToken cancellationToken) + { + if (authorization == null) + { + throw new ArgumentNullException(nameof(authorization)); + } + + // If the application is not attached to the authorization instance (which is expected + // if the token was retrieved using the default FindBy*Async APIs as they don't + // eagerly load the application from the database), try to load it manually. + if (authorization.Application == null) + { + return ConvertIdentifierToString( + await Context.Entry(authorization) + .Reference(entry => entry.Application) + .Query() + .Select(application => application.Id) + .FirstOrDefaultAsync()); + } + + return ConvertIdentifierToString(authorization.Application.Id); + } + /// /// Executes the specified query. /// @@ -249,6 +281,47 @@ namespace OpenIddict.EntityFrameworkCore return ImmutableArray.Create(await query.Invoke(Authorizations).ToArrayAsync(cancellationToken)); } + /// + /// Sets the application identifier associated with an authorization. + /// + /// The authorization. + /// The unique identifier associated with the client application. + /// The that can be used to abort the operation. + /// + /// A that can be used to monitor the asynchronous operation. + /// + public override async Task SetApplicationIdAsync([NotNull] TAuthorization authorization, [CanBeNull] string identifier, CancellationToken cancellationToken) + { + if (authorization == null) + { + throw new ArgumentNullException(nameof(authorization)); + } + + if (!string.IsNullOrEmpty(identifier)) + { + var application = await Applications.FindAsync(cancellationToken, ConvertIdentifierFromString(identifier)); + if (application == null) + { + throw new InvalidOperationException("The application associated with the authorization cannot be found."); + } + + authorization.Application = application; + } + + else + { + var key = await GetIdAsync(authorization, cancellationToken); + + // Try to retrieve the application associated with the authorization. + // If none can be found, assume that no application is attached. + var application = await Applications.FirstOrDefaultAsync(element => element.Tokens.Any(t => t.Id.Equals(key))); + if (application != null) + { + application.Authorizations.Remove(authorization); + } + } + } + /// /// Updates an existing authorization. /// diff --git a/src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictTokenStore.cs b/src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictTokenStore.cs index 2dd5186d..b2596619 100644 --- a/src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictTokenStore.cs +++ b/src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictTokenStore.cs @@ -223,6 +223,38 @@ namespace OpenIddict.EntityFrameworkCore return Tokens.FindAsync(new object[] { ConvertIdentifierFromString(identifier) }, cancellationToken); } + /// + /// Retrieves the optional application identifier associated with a token. + /// + /// The token. + /// The that can be used to abort the operation. + /// + /// A that can be used to monitor the asynchronous operation, + /// whose result returns the application identifier associated with the token. + /// + public override async Task GetApplicationIdAsync([NotNull] TToken token, CancellationToken cancellationToken) + { + if (token == null) + { + throw new ArgumentNullException(nameof(token)); + } + + // If the application is not attached to the token instance (which is expected + // if the token was retrieved using the default FindBy*Async APIs as they don't + // eagerly load the application from the database), try to load it manually. + if (token.Application == null) + { + return ConvertIdentifierToString( + await Context.Entry(token) + .Reference(entry => entry.Application) + .Query() + .Select(application => application.Id) + .FirstOrDefaultAsync()); + } + + return ConvertIdentifierToString(token.Application.Id); + } + /// /// Executes the specified query. /// @@ -243,6 +275,38 @@ namespace OpenIddict.EntityFrameworkCore return query.Invoke(Tokens).SingleOrDefaultAsync(cancellationToken); } + /// + /// Retrieves the optional authorization identifier associated with a token. + /// + /// The token. + /// The that can be used to abort the operation. + /// + /// A that can be used to monitor the asynchronous operation, + /// whose result returns the authorization identifier associated with the token. + /// + public override async Task GetAuthorizationIdAsync([NotNull] TToken token, CancellationToken cancellationToken) + { + if (token == null) + { + throw new ArgumentNullException(nameof(token)); + } + + // If the authorization is not attached to the token instance (which is expected + // if the token was retrieved using the default FindBy*Async APIs as they don't + // eagerly load the authorization from the database), try to load it manually. + if (token.Authorization == null) + { + return ConvertIdentifierToString( + await Context.Entry(token) + .Reference(entry => entry.Authorization) + .Query() + .Select(authorization => authorization.Id) + .FirstOrDefaultAsync()); + } + + return ConvertIdentifierToString(token.Authorization.Id); + } + /// /// Executes the specified query. /// @@ -264,15 +328,15 @@ namespace OpenIddict.EntityFrameworkCore } /// - /// Sets the authorization associated with a token. + /// Sets the application identifier associated with a token. /// /// The token. - /// The unique identifier associated with the authorization. + /// The unique identifier associated with the client application. /// The that can be used to abort the operation. /// /// A that can be used to monitor the asynchronous operation. /// - public override async Task SetAuthorizationAsync([NotNull] TToken token, [CanBeNull] string identifier, CancellationToken cancellationToken) + public override async Task SetApplicationIdAsync([NotNull] TToken token, [CanBeNull] string identifier, CancellationToken cancellationToken) { if (token == null) { @@ -281,39 +345,41 @@ namespace OpenIddict.EntityFrameworkCore if (!string.IsNullOrEmpty(identifier)) { - var authorization = await Authorizations.FindAsync(new object[] { ConvertIdentifierFromString(identifier) }, cancellationToken); - if (authorization == null) + var key = ConvertIdentifierFromString(identifier); + + var application = await Applications.FindAsync(new object[] { ConvertIdentifierFromString(identifier) }, cancellationToken); + if (application == null) { - throw new InvalidOperationException("The authorization associated with the token cannot be found."); + throw new InvalidOperationException("The application associated with the token cannot be found."); } - token.Authorization = authorization; + token.Application = application; } else { var key = await GetIdAsync(token, cancellationToken); - // Try to retrieve the authorization associated with the token. - // If none can be found, assume that no authorization is attached. - var authorization = await Authorizations.FirstOrDefaultAsync(element => element.Tokens.Any(t => t.Id.Equals(key))); - if (authorization != null) + // Try to retrieve the application associated with the token. + // If none can be found, assume that no application is attached. + var application = await Applications.FirstOrDefaultAsync(element => element.Tokens.Any(t => t.Id.Equals(key))); + if (application != null) { - authorization.Tokens.Remove(token); + application.Tokens.Remove(token); } } } /// - /// Sets the client application associated with a token. + /// Sets the authorization identifier associated with a token. /// /// The token. - /// The unique identifier associated with the client application. + /// The unique identifier associated with the authorization. /// The that can be used to abort the operation. /// /// A that can be used to monitor the asynchronous operation. /// - public override async Task SetClientAsync([NotNull] TToken token, [CanBeNull] string identifier, CancellationToken cancellationToken) + public override async Task SetAuthorizationIdAsync([NotNull] TToken token, [CanBeNull] string identifier, CancellationToken cancellationToken) { if (token == null) { @@ -322,27 +388,25 @@ namespace OpenIddict.EntityFrameworkCore if (!string.IsNullOrEmpty(identifier)) { - var key = ConvertIdentifierFromString(identifier); - - var application = await Applications.FindAsync(new object[] { ConvertIdentifierFromString(identifier) }, cancellationToken); - if (application == null) + var authorization = await Authorizations.FindAsync(new object[] { ConvertIdentifierFromString(identifier) }, cancellationToken); + if (authorization == null) { - throw new InvalidOperationException("The application associated with the token cannot be found."); + throw new InvalidOperationException("The authorization associated with the token cannot be found."); } - token.Application = application; + token.Authorization = authorization; } else { var key = await GetIdAsync(token, cancellationToken); - // Try to retrieve the application associated with the token. - // If none can be found, assume that no application is attached. - var application = await Applications.FirstOrDefaultAsync(element => element.Tokens.Any(t => t.Id.Equals(key))); - if (application != null) + // Try to retrieve the authorization associated with the token. + // If none can be found, assume that no authorization is attached. + var authorization = await Authorizations.FirstOrDefaultAsync(element => element.Tokens.Any(t => t.Id.Equals(key))); + if (authorization != null) { - application.Tokens.Remove(token); + authorization.Tokens.Remove(token); } } } diff --git a/src/OpenIddict/OpenIddictProvider.Helpers.cs b/src/OpenIddict/OpenIddictProvider.Helpers.cs index 34eb6ab0..c7613c06 100644 --- a/src/OpenIddict/OpenIddictProvider.Helpers.cs +++ b/src/OpenIddict/OpenIddictProvider.Helpers.cs @@ -197,12 +197,11 @@ namespace OpenIddict ticket.SetTokenId(identifier); // Dynamically set the creation and expiration dates. - ticket.Properties.IssuedUtc = await Tokens.GetCreationDateAsync(token, context.RequestAborted); - ticket.Properties.ExpiresUtc = await Tokens.GetExpirationDateAsync(token, context.RequestAborted); + ticket.Properties.IssuedUtc = descriptor.CreationDate; + ticket.Properties.ExpiresUtc = descriptor.ExpirationDate; // Restore the authorization identifier using the identifier attached with the database entry. - ticket.SetProperty(OpenIddictConstants.Properties.AuthorizationId, - await Tokens.GetAuthorizationIdAsync(token, context.RequestAborted)); + ticket.SetProperty(OpenIddictConstants.Properties.AuthorizationId, descriptor.AuthorizationId); if (!string.IsNullOrEmpty(result)) { diff --git a/src/OpenIddict/OpenIddictProvider.Signin.cs b/src/OpenIddict/OpenIddictProvider.Signin.cs index 72c38136..ef04be79 100644 --- a/src/OpenIddict/OpenIddictProvider.Signin.cs +++ b/src/OpenIddict/OpenIddictProvider.Signin.cs @@ -29,8 +29,8 @@ namespace OpenIddict // the OpenID Connect server middleware allows creating authentication tickets // that are completely disconnected from the original code or refresh token ticket. // This scenario is deliberately not supported in OpenIddict and all the tickets - // must be linked. To ensure the properties are preserved from an authorization code - // or a refresh token to the new ticket, they are manually restored if necessary. + // must be linked. To ensure the properties are flowed from the authorization code + // or the refresh token to the new ticket, they are manually restored if necessary. // Retrieve the original authentication ticket from the request properties. var ticket = context.Request.GetProperty(