diff --git a/src/OpenIddict.Core/Managers/OpenIddictApplicationManager.cs b/src/OpenIddict.Core/Managers/OpenIddictApplicationManager.cs
index 2fa5a4db..4ebdbed8 100644
--- a/src/OpenIddict.Core/Managers/OpenIddictApplicationManager.cs
+++ b/src/OpenIddict.Core/Managers/OpenIddictApplicationManager.cs
@@ -129,6 +129,7 @@ namespace OpenIddict.Core
"a confidential or hybrid application.");
}
+ // If a client secret was provided, obfuscate it.
if (!string.IsNullOrEmpty(secret))
{
secret = await ObfuscateClientSecretAsync(secret, cancellationToken);
@@ -151,7 +152,7 @@ namespace OpenIddict.Core
}
///
- /// Creates a new application.
+ /// Creates a new application based on the specified descriptor.
/// Note: the default implementation automatically hashes the client
/// secret before storing it in the database, for security reasons.
///
@@ -168,43 +169,23 @@ namespace OpenIddict.Core
throw new ArgumentNullException(nameof(descriptor));
}
- // If no client type was specified, assume it's a
- // public application if no secret was provided.
- if (string.IsNullOrEmpty(descriptor.Type))
- {
- descriptor.Type = string.IsNullOrEmpty(descriptor.ClientSecret) ?
- OpenIddictConstants.ClientTypes.Public :
- OpenIddictConstants.ClientTypes.Confidential;
- }
-
- // If the client is not a public application, throw an
- // exception as the client secret is required in this case.
- if (string.IsNullOrEmpty(descriptor.ClientSecret) &&
- !string.Equals(descriptor.Type, OpenIddictConstants.ClientTypes.Public, StringComparison.OrdinalIgnoreCase))
- {
- throw new InvalidOperationException("A client secret must be provided when creating " +
- "a confidential or hybrid application.");
- }
-
- // Obfuscate the provided client secret.
- if (!string.IsNullOrEmpty(descriptor.ClientSecret))
+ var application = await Store.InstantiateAsync(cancellationToken);
+ if (application == null)
{
- descriptor.ClientSecret = await ObfuscateClientSecretAsync(descriptor.ClientSecret, cancellationToken);
+ throw new InvalidOperationException("An error occurred while trying to create a new application");
}
- await ValidateAsync(descriptor, cancellationToken);
+ await PopulateAsync(application, descriptor, cancellationToken);
- try
+ var secret = await Store.GetClientSecretAsync(application, cancellationToken);
+ if (!string.IsNullOrEmpty(secret))
{
- return await Store.CreateAsync(descriptor, cancellationToken);
+ await Store.SetClientSecretAsync(application, /* secret: */ null, cancellationToken);
+ return await CreateAsync(application, secret, cancellationToken);
}
- catch (Exception exception)
- {
- Logger.LogError(0, exception, "An exception occurred while trying to create a new application.");
- throw;
- }
+ return await CreateAsync(application, cancellationToken);
}
///
@@ -584,6 +565,83 @@ namespace OpenIddict.Core
await UpdateAsync(application, cancellationToken);
}
+ ///
+ /// Updates an existing application.
+ ///
+ /// The application to update.
+ /// The delegate used to update the application based on the given descriptor.
+ /// The that can be used to abort the operation.
+ ///
+ /// A that can be used to monitor the asynchronous operation.
+ ///
+ public virtual async Task UpdateAsync([NotNull] TApplication application,
+ [NotNull] Func operation, CancellationToken cancellationToken)
+ {
+ if (operation == null)
+ {
+ throw new ArgumentNullException(nameof(operation));
+ }
+
+ // Store the original client secret for later comparison.
+ var secret = await Store.GetClientSecretAsync(application, cancellationToken);
+
+ var descriptor = new OpenIddictApplicationDescriptor
+ {
+ ClientId = await Store.GetClientIdAsync(application, cancellationToken),
+ ClientSecret = secret,
+ DisplayName = await Store.GetDisplayNameAsync(application, cancellationToken),
+ Type = await Store.GetClientTypeAsync(application, cancellationToken)
+ };
+
+ foreach (var address in await Store.GetPostLogoutRedirectUrisAsync(application, cancellationToken))
+ {
+ // Ensure the address is not null or empty.
+ if (string.IsNullOrEmpty(address))
+ {
+ throw new ArgumentException("Callback URLs cannot be null or empty.");
+ }
+
+ // Ensure the address is a valid absolute URL.
+ if (!Uri.TryCreate(address, UriKind.Absolute, out Uri uri) || !uri.IsWellFormedOriginalString())
+ {
+ throw new ArgumentException("Callback URLs must be valid absolute URLs.");
+ }
+
+ descriptor.PostLogoutRedirectUris.Add(uri);
+ }
+
+ foreach (var address in await Store.GetRedirectUrisAsync(application, cancellationToken))
+ {
+ // Ensure the address is not null or empty.
+ if (string.IsNullOrEmpty(address))
+ {
+ throw new ArgumentException("Callback URLs cannot be null or empty.");
+ }
+
+ // Ensure the address is a valid absolute URL.
+ if (!Uri.TryCreate(address, UriKind.Absolute, out Uri uri) || !uri.IsWellFormedOriginalString())
+ {
+ throw new ArgumentException("Callback URLs must be valid absolute URLs.");
+ }
+
+ descriptor.RedirectUris.Add(uri);
+ }
+
+ await operation(descriptor);
+ await PopulateAsync(application, descriptor, cancellationToken);
+
+ // If the client secret was updated, re-obfuscate it before persisting the changes.
+ var comparand = await Store.GetClientSecretAsync(application, cancellationToken);
+ if (!string.Equals(secret, comparand, StringComparison.Ordinal))
+ {
+ await UpdateAsync(application, comparand, cancellationToken);
+
+ return;
+ }
+
+ await UpdateAsync(application, cancellationToken);
+ }
+
///
/// Validates the client_secret associated with an application.
///
@@ -639,8 +697,7 @@ namespace OpenIddict.Core
/// A that can be used to monitor the asynchronous operation, whose result
/// returns a boolean indicating whether the post_logout_redirect_uri was valid.
///
- public virtual async Task ValidatePostLogoutRedirectUriAsync(
- [NotNull] string address, CancellationToken cancellationToken)
+ public virtual async Task ValidatePostLogoutRedirectUriAsync([NotNull] string address, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(address))
{
@@ -707,120 +764,96 @@ namespace OpenIddict.Core
}
///
- /// Validates the application to ensure it's in a consistent state.
+ /// Populates the application using the specified descriptor.
///
/// The application.
+ /// The descriptor.
/// The that can be used to abort the operation.
///
/// A that can be used to monitor the asynchronous operation.
///
- protected virtual async Task ValidateAsync([NotNull] TApplication application, CancellationToken cancellationToken)
+ protected virtual async Task PopulateAsync([NotNull] TApplication application,
+ [NotNull] OpenIddictApplicationDescriptor descriptor, CancellationToken cancellationToken)
{
- var descriptor = new OpenIddictApplicationDescriptor
- {
- ClientId = await Store.GetClientIdAsync(application, cancellationToken),
- ClientSecret = await Store.GetClientSecretAsync(application, cancellationToken),
- DisplayName = await Store.GetDisplayNameAsync(application, cancellationToken),
- Type = await Store.GetClientTypeAsync(application, cancellationToken)
- };
-
- foreach (var address in await Store.GetPostLogoutRedirectUrisAsync(application, cancellationToken))
+ if (application == null)
{
- // Ensure the address is not null or empty.
- if (string.IsNullOrEmpty(address))
- {
- throw new ArgumentException("Callback URLs cannot be null or empty.");
- }
-
- // Ensure the address is a valid absolute URL.
- if (!Uri.TryCreate(address, UriKind.Absolute, out Uri uri) || !uri.IsWellFormedOriginalString())
- {
- throw new ArgumentException("Callback URLs must be valid absolute URLs.");
- }
-
- descriptor.PostLogoutRedirectUris.Add(uri);
+ throw new ArgumentNullException(nameof(application));
}
- foreach (var address in await Store.GetRedirectUrisAsync(application, cancellationToken))
+ if (descriptor == null)
{
- // Ensure the address is not null or empty.
- if (string.IsNullOrEmpty(address))
- {
- throw new ArgumentException("Callback URLs cannot be null or empty.");
- }
-
- // Ensure the address is a valid absolute URL.
- if (!Uri.TryCreate(address, UriKind.Absolute, out Uri uri) || !uri.IsWellFormedOriginalString())
- {
- throw new ArgumentException("Callback URLs must be valid absolute URLs.");
- }
-
- descriptor.RedirectUris.Add(uri);
+ throw new ArgumentNullException(nameof(descriptor));
}
- await ValidateAsync(descriptor, cancellationToken);
+ await Store.SetClientIdAsync(application, descriptor.ClientId, cancellationToken);
+ await Store.SetClientSecretAsync(application, descriptor.ClientSecret, cancellationToken);
+ await Store.SetClientTypeAsync(application, descriptor.Type, cancellationToken);
+ await Store.SetDisplayNameAsync(application, descriptor.DisplayName, cancellationToken);
+ await Store.SetPostLogoutRedirectUrisAsync(application, ImmutableArray.CreateRange(
+ descriptor.PostLogoutRedirectUris.Select(address => address.OriginalString)), cancellationToken);
+ await Store.SetRedirectUrisAsync(application, ImmutableArray.CreateRange(
+ descriptor.RedirectUris.Select(address => address.OriginalString)), cancellationToken);
}
///
- /// Validates the application descriptor to ensure it's in a consistent state.
+ /// Validates the application to ensure it's in a consistent state.
///
- /// The application descriptor.
+ /// The application.
/// The that can be used to abort the operation.
///
/// A that can be used to monitor the asynchronous operation.
///
- protected virtual Task ValidateAsync([NotNull] OpenIddictApplicationDescriptor descriptor, CancellationToken cancellationToken)
+ protected virtual async Task ValidateAsync([NotNull] TApplication application, CancellationToken cancellationToken)
{
- if (descriptor == null)
+ if (string.IsNullOrEmpty(await Store.GetClientIdAsync(application, cancellationToken)))
{
- throw new ArgumentNullException(nameof(descriptor));
+ throw new ArgumentException("The client identifier cannot be null or empty.", nameof(application));
}
- if (string.IsNullOrEmpty(descriptor.ClientId))
- {
- throw new ArgumentException("The client identifier cannot be null or empty.", nameof(descriptor));
- }
-
- if (string.IsNullOrEmpty(descriptor.Type))
+ var type = await Store.GetClientTypeAsync(application, cancellationToken);
+ if (string.IsNullOrEmpty(type))
{
- throw new ArgumentException("The client type cannot be null or empty.", nameof(descriptor));
+ throw new ArgumentException("The client type cannot be null or empty.", nameof(application));
}
// Ensure the application type is supported by the manager.
- if (!string.Equals(descriptor.Type, OpenIddictConstants.ClientTypes.Confidential, StringComparison.OrdinalIgnoreCase) &&
- !string.Equals(descriptor.Type, OpenIddictConstants.ClientTypes.Hybrid, StringComparison.OrdinalIgnoreCase) &&
- !string.Equals(descriptor.Type, OpenIddictConstants.ClientTypes.Public, StringComparison.OrdinalIgnoreCase))
+ if (!string.Equals(type, OpenIddictConstants.ClientTypes.Confidential, StringComparison.OrdinalIgnoreCase) &&
+ !string.Equals(type, OpenIddictConstants.ClientTypes.Hybrid, StringComparison.OrdinalIgnoreCase) &&
+ !string.Equals(type, OpenIddictConstants.ClientTypes.Public, StringComparison.OrdinalIgnoreCase))
{
throw new ArgumentException("Only 'confidential', 'hybrid' or 'public' applications are " +
- "supported by the default application manager.", nameof(descriptor));
+ "supported by the default application manager.", nameof(application));
}
// Ensure a client secret was specified if the client is a confidential application.
- if (string.IsNullOrEmpty(descriptor.ClientSecret) &&
- string.Equals(descriptor.Type, OpenIddictConstants.ClientTypes.Confidential, StringComparison.OrdinalIgnoreCase))
+ var secret = await Store.GetClientSecretAsync(application, cancellationToken);
+ if (string.IsNullOrEmpty(secret) &&
+ string.Equals(type, OpenIddictConstants.ClientTypes.Confidential, StringComparison.OrdinalIgnoreCase))
{
- throw new ArgumentException("The client secret cannot be null or empty for a confidential application.", nameof(descriptor));
+ throw new ArgumentException("The client secret cannot be null or empty for a confidential application.", nameof(application));
}
// Ensure no client secret was specified if the client is a public application.
- else if (!string.IsNullOrEmpty(descriptor.ClientSecret) &&
- string.Equals(descriptor.Type, OpenIddictConstants.ClientTypes.Public, StringComparison.OrdinalIgnoreCase))
+ else if (!string.IsNullOrEmpty(secret) &&
+ string.Equals(type, OpenIddictConstants.ClientTypes.Public, StringComparison.OrdinalIgnoreCase))
{
- throw new ArgumentException("A client secret cannot be associated with a public application.", nameof(descriptor));
+ throw new ArgumentException("A client secret cannot be associated with a public application.", nameof(application));
}
// When callback URLs are specified, ensure they are valid and spec-compliant.
// See https://tools.ietf.org/html/rfc6749#section-3.1 for more information.
- foreach (var uri in descriptor.PostLogoutRedirectUris.Concat(descriptor.RedirectUris))
+ foreach (var address in ImmutableArray.Create()
+ .AddRange(await Store.GetPostLogoutRedirectUrisAsync(application, cancellationToken))
+ .AddRange(await Store.GetRedirectUrisAsync(application, cancellationToken)))
{
- // Ensure the address is not null.
- if (uri == null)
+ // Ensure the address is not null or empty.
+ if (string.IsNullOrEmpty(address))
{
- throw new ArgumentException("Callback URLs cannot be null.");
+ throw new ArgumentException("Callback URLs cannot be null or empty.");
}
- // Ensure the address is a valid and absolute URL.
- if (!uri.IsAbsoluteUri || !uri.IsWellFormedOriginalString())
+ // Ensure the address is a valid absolute URL.
+ if (!Uri.TryCreate(address, UriKind.Absolute, out Uri uri) || !uri.IsWellFormedOriginalString())
{
throw new ArgumentException("Callback URLs must be valid absolute URLs.");
}
@@ -831,8 +864,6 @@ namespace OpenIddict.Core
throw new ArgumentException("Callback URLs cannot contain a fragment.");
}
}
-
- return Task.FromResult(0);
}
///
diff --git a/src/OpenIddict.Core/Managers/OpenIddictAuthorizationManager.cs b/src/OpenIddict.Core/Managers/OpenIddictAuthorizationManager.cs
index f718916c..02bd5ff6 100644
--- a/src/OpenIddict.Core/Managers/OpenIddictAuthorizationManager.cs
+++ b/src/OpenIddict.Core/Managers/OpenIddictAuthorizationManager.cs
@@ -108,7 +108,7 @@ namespace OpenIddict.Core
}
///
- /// Creates a new authorization.
+ /// Creates a new authorization based on the specified descriptor.
///
/// The authorization descriptor.
/// The that can be used to abort the operation.
@@ -122,26 +122,14 @@ namespace OpenIddict.Core
throw new ArgumentNullException(nameof(descriptor));
}
- // If no type was explicitly specified, assume that
- // the authorization is a permanent authorization.
- if (string.IsNullOrEmpty(descriptor.Type))
- {
- descriptor.Type = OpenIddictConstants.AuthorizationTypes.Permanent;
- }
-
- await ValidateAsync(descriptor, cancellationToken);
-
- try
+ var authorization = await Store.InstantiateAsync(cancellationToken);
+ if (authorization == null)
{
- return await Store.CreateAsync(descriptor, cancellationToken);
+ throw new InvalidOperationException("An error occurred while trying to create a new authorization.");
}
- catch (Exception exception)
- {
- Logger.LogError(0, exception, "An exception occurred while trying to create a new authorization.");
-
- throw;
- }
+ await PopulateAsync(authorization, descriptor, cancellationToken);
+ return await CreateAsync(authorization, cancellationToken);
}
///
@@ -462,81 +450,119 @@ namespace OpenIddict.Core
}
///
- /// Validates the authorization to ensure it's in a consistent state.
+ /// Updates an existing authorization.
///
- /// The authorization.
+ /// The authorization to update.
+ /// The delegate used to update the authorization based on the given descriptor.
/// The that can be used to abort the operation.
///
/// A that can be used to monitor the asynchronous operation.
///
- protected virtual async Task ValidateAsync([NotNull] TAuthorization authorization, CancellationToken cancellationToken)
+ public virtual async Task UpdateAsync([NotNull] TAuthorization authorization,
+ [NotNull] Func operation, CancellationToken cancellationToken)
{
- if (authorization == null)
+ if (operation == null)
{
- throw new ArgumentNullException(nameof(authorization));
+ throw new ArgumentNullException(nameof(operation));
}
var descriptor = new OpenIddictAuthorizationDescriptor
{
+ ApplicationId = await Store.GetApplicationIdAsync(authorization, cancellationToken),
Status = await Store.GetStatusAsync(authorization, cancellationToken),
Subject = await Store.GetSubjectAsync(authorization, cancellationToken),
Type = await Store.GetTypeAsync(authorization, cancellationToken)
};
- await ValidateAsync(descriptor, cancellationToken);
+ foreach (var scope in await Store.GetScopesAsync(authorization, cancellationToken))
+ {
+ descriptor.Scopes.Add(scope);
+ }
+
+ await operation(descriptor);
+ await PopulateAsync(authorization, descriptor, cancellationToken);
+ await UpdateAsync(authorization, cancellationToken);
}
///
- /// Validates the authorization descriptor to ensure it's in a consistent state.
+ /// Populates the authorization using the specified descriptor.
///
- /// The authorization descriptor.
+ /// The authorization.
+ /// The descriptor.
/// The that can be used to abort the operation.
///
/// A that can be used to monitor the asynchronous operation.
///
- protected virtual Task ValidateAsync([NotNull] OpenIddictAuthorizationDescriptor descriptor, CancellationToken cancellationToken)
+ protected virtual async Task PopulateAsync([NotNull] TAuthorization authorization,
+ [NotNull] OpenIddictAuthorizationDescriptor descriptor, CancellationToken cancellationToken)
{
+ if (authorization == null)
+ {
+ throw new ArgumentNullException(nameof(authorization));
+ }
+
if (descriptor == null)
{
throw new ArgumentNullException(nameof(descriptor));
}
- if (string.IsNullOrEmpty(descriptor.Type))
+ await Store.SetApplicationIdAsync(authorization, descriptor.ApplicationId, cancellationToken);
+ await Store.SetScopesAsync(authorization, ImmutableArray.CreateRange(descriptor.Scopes), cancellationToken);
+ await Store.SetStatusAsync(authorization, descriptor.Status, cancellationToken);
+ await Store.SetSubjectAsync(authorization, descriptor.Subject, cancellationToken);
+ await Store.SetTypeAsync(authorization, descriptor.Type, cancellationToken);
+ }
+
+ ///
+ /// Validates the authorization to ensure it's in a consistent state.
+ ///
+ /// The authorization.
+ /// The that can be used to abort the operation.
+ ///
+ /// A that can be used to monitor the asynchronous operation.
+ ///
+ protected virtual async Task ValidateAsync([NotNull] TAuthorization authorization, CancellationToken cancellationToken)
+ {
+ if (authorization == null)
+ {
+ throw new ArgumentNullException(nameof(authorization));
+ }
+
+ var type = await Store.GetTypeAsync(authorization, cancellationToken);
+ if (string.IsNullOrEmpty(type))
{
- throw new ArgumentException("The authorization type cannot be null or empty.", nameof(descriptor));
+ throw new ArgumentException("The authorization type cannot be null or empty.", nameof(authorization));
}
- if (!string.Equals(descriptor.Type, OpenIddictConstants.AuthorizationTypes.AdHoc, StringComparison.OrdinalIgnoreCase) &&
- !string.Equals(descriptor.Type, OpenIddictConstants.AuthorizationTypes.Permanent, StringComparison.OrdinalIgnoreCase))
+ if (!string.Equals(type, OpenIddictConstants.AuthorizationTypes.AdHoc, StringComparison.OrdinalIgnoreCase) &&
+ !string.Equals(type, OpenIddictConstants.AuthorizationTypes.Permanent, StringComparison.OrdinalIgnoreCase))
{
- throw new ArgumentException("The specified authorization type is not supported by the default token manager.");
+ throw new ArgumentException("The specified authorization type is not supported by the default token manager.", nameof(authorization));
}
- if (string.IsNullOrEmpty(descriptor.Status))
+ if (string.IsNullOrEmpty(await Store.GetStatusAsync(authorization, cancellationToken)))
{
- throw new ArgumentException("The status cannot be null or empty.");
+ throw new ArgumentException("The status cannot be null or empty.", nameof(authorization));
}
- if (string.IsNullOrEmpty(descriptor.Subject))
+ if (string.IsNullOrEmpty(await Store.GetSubjectAsync(authorization, cancellationToken)))
{
- throw new ArgumentException("The subject cannot be null or empty.");
+ throw new ArgumentException("The subject cannot be null or empty.", nameof(authorization));
}
// Ensure that the scopes are not null or empty and do not contain spaces.
- foreach (var scope in descriptor.Scopes)
+ foreach (var scope in await Store.GetScopesAsync(authorization, cancellationToken))
{
if (string.IsNullOrEmpty(scope))
{
- throw new ArgumentException("Scopes cannot be null or empty.", nameof(descriptor));
+ throw new ArgumentException("Scopes cannot be null or empty.", nameof(authorization));
}
if (scope.Contains(OpenIddictConstants.Separators.Space))
{
- throw new ArgumentException("Scopes cannot contain spaces.", nameof(descriptor));
+ throw new ArgumentException("Scopes cannot contain spaces.", nameof(authorization));
}
}
-
- return Task.FromResult(0);
}
}
}
\ No newline at end of file
diff --git a/src/OpenIddict.Core/Managers/OpenIddictScopeManager.cs b/src/OpenIddict.Core/Managers/OpenIddictScopeManager.cs
index 84b7fa2f..0a39576d 100644
--- a/src/OpenIddict.Core/Managers/OpenIddictScopeManager.cs
+++ b/src/OpenIddict.Core/Managers/OpenIddictScopeManager.cs
@@ -100,7 +100,7 @@ namespace OpenIddict.Core
}
///
- /// Creates a new scope.
+ /// Creates a new scope based on the specified descriptor.
///
/// The scope descriptor.
/// The that can be used to abort the operation.
@@ -114,17 +114,14 @@ namespace OpenIddict.Core
throw new ArgumentNullException(nameof(descriptor));
}
- try
+ var scope = await Store.InstantiateAsync(cancellationToken);
+ if (scope == null)
{
- return await Store.CreateAsync(descriptor, cancellationToken);
+ throw new InvalidOperationException("An error occurred while trying to create a new scope.");
}
- catch (Exception exception)
- {
- Logger.LogError(0, exception, "An exception occurred while trying to create a new scope.");
-
- throw;
- }
+ await PopulateAsync(scope, descriptor, cancellationToken);
+ return await CreateAsync(scope, cancellationToken);
}
///
@@ -237,5 +234,59 @@ namespace OpenIddict.Core
throw;
}
}
+
+ ///
+ /// Updates an existing scope.
+ ///
+ /// The scope to update.
+ /// The delegate used to update the scope based on the given descriptor.
+ /// The that can be used to abort the operation.
+ ///
+ /// A that can be used to monitor the asynchronous operation.
+ ///
+ public virtual async Task UpdateAsync([NotNull] TScope scope,
+ [NotNull] Func operation, CancellationToken cancellationToken)
+ {
+ if (operation == null)
+ {
+ throw new ArgumentNullException(nameof(operation));
+ }
+
+ var descriptor = new OpenIddictScopeDescriptor
+ {
+ Description = await Store.GetDescriptionAsync(scope, cancellationToken),
+ Name = await Store.GetNameAsync(scope, cancellationToken)
+ };
+
+ await operation(descriptor);
+ await PopulateAsync(scope, descriptor, cancellationToken);
+ await UpdateAsync(scope, cancellationToken);
+ }
+
+ ///
+ /// Populates the scope using the specified descriptor.
+ ///
+ /// The scope.
+ /// The descriptor.
+ /// The that can be used to abort the operation.
+ ///
+ /// A that can be used to monitor the asynchronous operation.
+ ///
+ protected virtual async Task PopulateAsync([NotNull] TScope scope,
+ [NotNull] OpenIddictScopeDescriptor descriptor, CancellationToken cancellationToken)
+ {
+ if (scope == null)
+ {
+ throw new ArgumentNullException(nameof(scope));
+ }
+
+ if (descriptor == null)
+ {
+ throw new ArgumentNullException(nameof(descriptor));
+ }
+
+ await Store.SetDescriptionAsync(scope, descriptor.Description, cancellationToken);
+ await Store.SetNameAsync(scope, descriptor.Description, cancellationToken);
+ }
}
}
\ No newline at end of file
diff --git a/src/OpenIddict.Core/Managers/OpenIddictTokenManager.cs b/src/OpenIddict.Core/Managers/OpenIddictTokenManager.cs
index f97de828..cf3f8277 100644
--- a/src/OpenIddict.Core/Managers/OpenIddictTokenManager.cs
+++ b/src/OpenIddict.Core/Managers/OpenIddictTokenManager.cs
@@ -102,7 +102,7 @@ namespace OpenIddict.Core
}
///
- /// Creates a new token, which is associated with a particular subject.
+ /// Creates a new token based on the specified descriptor.
///
/// The token descriptor.
/// The that can be used to abort the operation.
@@ -116,19 +116,14 @@ namespace OpenIddict.Core
throw new ArgumentNullException(nameof(descriptor));
}
- await ValidateAsync(descriptor, cancellationToken);
-
- try
+ var token = await Store.InstantiateAsync(cancellationToken);
+ if (token == null)
{
- return await Store.CreateAsync(descriptor, cancellationToken);
+ throw new InvalidOperationException("An error occurred while trying to create a new token");
}
- catch (Exception exception)
- {
- Logger.LogError(0, exception, "An exception occurred while trying to create a new token.");
-
- throw;
- }
+ await PopulateAsync(token, descriptor, cancellationToken);
+ return await CreateAsync(token, cancellationToken);
}
///
@@ -674,68 +669,110 @@ namespace OpenIddict.Core
}
///
- /// Validates the token to ensure it's in a consistent state.
+ /// Updates an existing token.
///
- /// The token.
+ /// The token to update.
+ /// The delegate used to update the token based on the given descriptor.
/// The that can be used to abort the operation.
///
/// A that can be used to monitor the asynchronous operation.
///
- protected virtual async Task ValidateAsync([NotNull] TToken token, CancellationToken cancellationToken)
+ public virtual async Task UpdateAsync([NotNull] TToken token,
+ [NotNull] Func operation, CancellationToken cancellationToken)
{
- if (token == null)
+ if (operation == null)
{
- throw new ArgumentNullException(nameof(token));
+ throw new ArgumentNullException(nameof(operation));
}
var descriptor = new OpenIddictTokenDescriptor
{
+ ApplicationId = await Store.GetApplicationIdAsync(token, cancellationToken),
+ AuthorizationId = await Store.GetAuthorizationIdAsync(token, cancellationToken),
+ Ciphertext = await Store.GetCiphertextAsync(token, cancellationToken),
+ CreationDate = await Store.GetCreationDateAsync(token, cancellationToken),
+ ExpirationDate = await Store.GetExpirationDateAsync(token, cancellationToken),
+ Hash = await Store.GetHashAsync(token, cancellationToken),
Status = await Store.GetStatusAsync(token, cancellationToken),
Subject = await Store.GetSubjectAsync(token, cancellationToken),
Type = await Store.GetTokenTypeAsync(token, cancellationToken)
};
- await ValidateAsync(descriptor, cancellationToken);
+ await operation(descriptor);
+ await PopulateAsync(token, descriptor, cancellationToken);
+ await UpdateAsync(token, cancellationToken);
}
///
- /// Validates the token descriptor to ensure it's in a consistent state.
+ /// Populates the token using the specified descriptor.
///
- /// The token descriptor.
+ /// The token.
+ /// The descriptor.
/// The that can be used to abort the operation.
///
/// A that can be used to monitor the asynchronous operation.
///
- protected virtual Task ValidateAsync([NotNull] OpenIddictTokenDescriptor descriptor, CancellationToken cancellationToken)
+ protected virtual async Task PopulateAsync([NotNull] TToken token,
+ [NotNull] OpenIddictTokenDescriptor descriptor, CancellationToken cancellationToken)
{
+ if (token == null)
+ {
+ throw new ArgumentNullException(nameof(token));
+ }
+
if (descriptor == null)
{
throw new ArgumentNullException(nameof(descriptor));
}
- if (string.IsNullOrEmpty(descriptor.Type))
+ await Store.SetApplicationIdAsync(token, descriptor.ApplicationId, cancellationToken);
+ await Store.SetAuthorizationIdAsync(token, descriptor.AuthorizationId, cancellationToken);
+ await Store.SetCiphertextAsync(token, descriptor.Ciphertext, cancellationToken);
+ await Store.SetCreationDateAsync(token, descriptor.CreationDate, cancellationToken);
+ await Store.SetExpirationDateAsync(token, descriptor.ExpirationDate, cancellationToken);
+ await Store.SetHashAsync(token, descriptor.Hash, cancellationToken);
+ await Store.SetStatusAsync(token, descriptor.Status, cancellationToken);
+ await Store.SetSubjectAsync(token, descriptor.Subject, cancellationToken);
+ await Store.SetTokenTypeAsync(token, descriptor.Type, cancellationToken);
+ }
+
+ ///
+ /// Validates the token to ensure it's in a consistent state.
+ ///
+ /// The token.
+ /// The that can be used to abort the operation.
+ ///
+ /// A that can be used to monitor the asynchronous operation.
+ ///
+ protected virtual async Task ValidateAsync([NotNull] TToken token, CancellationToken cancellationToken)
+ {
+ if (token == null)
{
- throw new ArgumentException("The token type cannot be null or empty.", nameof(descriptor));
+ throw new ArgumentNullException(nameof(token));
}
- if (!string.Equals(descriptor.Type, OpenIddictConstants.TokenTypes.AccessToken, StringComparison.OrdinalIgnoreCase) &&
- !string.Equals(descriptor.Type, OpenIddictConstants.TokenTypes.AuthorizationCode, StringComparison.OrdinalIgnoreCase) &&
- !string.Equals(descriptor.Type, OpenIddictConstants.TokenTypes.RefreshToken, StringComparison.OrdinalIgnoreCase))
+ var type = await Store.GetTokenTypeAsync(token, cancellationToken);
+ if (string.IsNullOrEmpty(type))
{
- throw new ArgumentException("The specified token type is not supported by the default token manager.");
+ throw new ArgumentException("The token type cannot be null or empty.", nameof(token));
}
- if (string.IsNullOrEmpty(descriptor.Status))
+ if (!string.Equals(type, OpenIddictConstants.TokenTypes.AccessToken, StringComparison.OrdinalIgnoreCase) &&
+ !string.Equals(type, OpenIddictConstants.TokenTypes.AuthorizationCode, StringComparison.OrdinalIgnoreCase) &&
+ !string.Equals(type, OpenIddictConstants.TokenTypes.RefreshToken, StringComparison.OrdinalIgnoreCase))
{
- throw new ArgumentException("The status cannot be null or empty.");
+ throw new ArgumentException("The specified token type is not supported by the default token manager.", nameof(token));
}
- if (string.IsNullOrEmpty(descriptor.Subject))
+ if (string.IsNullOrEmpty(await Store.GetStatusAsync(token, cancellationToken)))
{
- throw new ArgumentException("The subject cannot be null or empty.");
+ throw new ArgumentException("The status cannot be null or empty.", nameof(token));
}
- return Task.FromResult(0);
+ if (string.IsNullOrEmpty(await Store.GetSubjectAsync(token, cancellationToken)))
+ {
+ throw new ArgumentException("The subject cannot be null or empty.", nameof(token));
+ }
}
}
}
\ No newline at end of file
diff --git a/src/OpenIddict.Core/Stores/IOpenIddictApplicationStore.cs b/src/OpenIddict.Core/Stores/IOpenIddictApplicationStore.cs
index c8a2a055..ea5f5645 100644
--- a/src/OpenIddict.Core/Stores/IOpenIddictApplicationStore.cs
+++ b/src/OpenIddict.Core/Stores/IOpenIddictApplicationStore.cs
@@ -52,16 +52,6 @@ namespace OpenIddict.Core
///
Task CreateAsync([NotNull] TApplication application, CancellationToken cancellationToken);
- ///
- /// Creates a new application.
- ///
- /// The application descriptor.
- /// The that can be used to abort the operation.
- ///
- /// A that can be used to monitor the asynchronous operation, whose result returns the application.
- ///
- Task CreateAsync([NotNull] OpenIddictApplicationDescriptor descriptor, CancellationToken cancellationToken);
-
///
/// Removes an existing application.
///
@@ -207,6 +197,16 @@ namespace OpenIddict.Core
///
Task> GetRedirectUrisAsync([NotNull] TApplication application, CancellationToken cancellationToken);
+ ///
+ /// Instantiates a new application.
+ ///
+ /// The that can be used to abort the operation.
+ ///
+ /// A that can be used to monitor the asynchronous operation, whose result
+ /// returns the instantiated application, that can be persisted in the database.
+ ///
+ Task InstantiateAsync(CancellationToken cancellationToken);
+
///
/// Executes the specified query and returns all the corresponding elements.
///
@@ -231,6 +231,17 @@ namespace OpenIddict.Core
///
Task> ListAsync([NotNull] Func, IQueryable> query, CancellationToken cancellationToken);
+ ///
+ /// Sets the client identifier associated with an application.
+ ///
+ /// The application.
+ /// The client identifier associated with the application.
+ /// The that can be used to abort the operation.
+ ///
+ /// A that can be used to monitor the asynchronous operation.
+ ///
+ Task SetClientIdAsync([NotNull] TApplication application, [CanBeNull] string identifier, CancellationToken cancellationToken);
+
///
/// Sets the client secret associated with an application.
/// Note: depending on the manager used to create the application,
@@ -253,7 +264,18 @@ namespace OpenIddict.Core
///
/// A that can be used to monitor the asynchronous operation.
///
- Task SetClientTypeAsync([NotNull] TApplication application, [NotNull] string type, CancellationToken cancellationToken);
+ Task SetClientTypeAsync([NotNull] TApplication application, [CanBeNull] string type, CancellationToken cancellationToken);
+
+ ///
+ /// Sets the display name associated with an application.
+ ///
+ /// The application.
+ /// The display name associated with the application.
+ /// The that can be used to abort the operation.
+ ///
+ /// A that can be used to monitor the asynchronous operation.
+ ///
+ Task SetDisplayNameAsync([NotNull] TApplication application, [CanBeNull] string name, CancellationToken cancellationToken);
///
/// Sets the logout callback addresses associated with an application.
diff --git a/src/OpenIddict.Core/Stores/IOpenIddictAuthorizationStore.cs b/src/OpenIddict.Core/Stores/IOpenIddictAuthorizationStore.cs
index 7d02ddc6..1310b146 100644
--- a/src/OpenIddict.Core/Stores/IOpenIddictAuthorizationStore.cs
+++ b/src/OpenIddict.Core/Stores/IOpenIddictAuthorizationStore.cs
@@ -51,16 +51,6 @@ namespace OpenIddict.Core
///
Task CreateAsync([NotNull] TAuthorization authorization, CancellationToken cancellationToken);
- ///
- /// Creates a new authorization.
- ///
- /// The authorization descriptor.
- /// The that can be used to abort the operation.
- ///
- /// A that can be used to monitor the asynchronous operation, whose result returns the authorization.
- ///
- Task CreateAsync([NotNull] OpenIddictAuthorizationDescriptor descriptor, CancellationToken cancellationToken);
-
///
/// Removes an existing authorization.
///
@@ -129,6 +119,17 @@ namespace OpenIddict.Core
///
Task GetIdAsync([NotNull] TAuthorization authorization, CancellationToken cancellationToken);
+ ///
+ /// Retrieves the scopes 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 scopes associated with the specified authorization.
+ ///
+ Task> GetScopesAsync([NotNull] TAuthorization authorization, CancellationToken cancellationToken);
+
///
/// Retrieves the status associated with an authorization.
///
@@ -162,6 +163,16 @@ namespace OpenIddict.Core
///
Task GetTypeAsync([NotNull] TAuthorization authorization, CancellationToken cancellationToken);
+ ///
+ /// Instantiates a new authorization.
+ ///
+ /// The that can be used to abort the operation.
+ ///
+ /// A that can be used to monitor the asynchronous operation, whose result
+ /// returns the instantiated authorization, that can be persisted in the database.
+ ///
+ Task InstantiateAsync(CancellationToken cancellationToken);
+
///
/// Executes the specified query and returns all the corresponding elements.
///
@@ -208,7 +219,20 @@ namespace OpenIddict.Core
///
/// A that can be used to monitor the asynchronous operation.
///
- Task SetApplicationIdAsync([NotNull] TAuthorization authorization, [CanBeNull] string identifier, CancellationToken cancellationToken);
+ Task SetApplicationIdAsync([NotNull] TAuthorization authorization,
+ [CanBeNull] string identifier, CancellationToken cancellationToken);
+
+ ///
+ /// Sets the scopes associated with an authorization.
+ ///
+ /// The authorization.
+ /// The scopes associated with the authorization.
+ /// The that can be used to abort the operation.
+ ///
+ /// A that can be used to monitor the asynchronous operation.
+ ///
+ Task SetScopesAsync([NotNull] TAuthorization authorization,
+ ImmutableArray scopes, CancellationToken cancellationToken);
///
/// Sets the status associated with an authorization.
@@ -219,7 +243,20 @@ namespace OpenIddict.Core
///
/// A that can be used to monitor the asynchronous operation.
///
- Task SetStatusAsync([NotNull] TAuthorization authorization, [NotNull] string status, CancellationToken cancellationToken);
+ Task SetStatusAsync([NotNull] TAuthorization authorization,
+ [CanBeNull] string status, CancellationToken cancellationToken);
+
+ ///
+ /// Sets the subject associated with an authorization.
+ ///
+ /// The authorization.
+ /// The subject associated with the authorization.
+ /// The that can be used to abort the operation.
+ ///
+ /// A that can be used to monitor the asynchronous operation.
+ ///
+ Task SetSubjectAsync([NotNull] TAuthorization authorization,
+ [CanBeNull] string subject, CancellationToken cancellationToken);
///
/// Sets the type associated with an authorization.
@@ -230,7 +267,8 @@ namespace OpenIddict.Core
///
/// A that can be used to monitor the asynchronous operation.
///
- Task SetTypeAsync([NotNull] TAuthorization authorization, [NotNull] string type, CancellationToken cancellationToken);
+ Task SetTypeAsync([NotNull] TAuthorization authorization,
+ [CanBeNull] string type, CancellationToken cancellationToken);
///
/// Updates an existing authorization.
diff --git a/src/OpenIddict.Core/Stores/IOpenIddictScopeStore.cs b/src/OpenIddict.Core/Stores/IOpenIddictScopeStore.cs
index 22b3d760..f71c1afd 100644
--- a/src/OpenIddict.Core/Stores/IOpenIddictScopeStore.cs
+++ b/src/OpenIddict.Core/Stores/IOpenIddictScopeStore.cs
@@ -51,16 +51,6 @@ namespace OpenIddict.Core
///
Task CreateAsync([NotNull] TScope scope, CancellationToken cancellationToken);
- ///
- /// Creates a new scope.
- ///
- /// The scope descriptor.
- /// The that can be used to abort the operation.
- ///
- /// A that can be used to monitor the asynchronous operation, whose result returns the scope.
- ///
- Task CreateAsync([NotNull] OpenIddictScopeDescriptor descriptor, CancellationToken cancellationToken);
-
///
/// Removes an existing scope.
///
@@ -83,6 +73,38 @@ namespace OpenIddict.Core
///
Task GetAsync([NotNull] Func, IQueryable> query, CancellationToken cancellationToken);
+ ///
+ /// Retrieves the description associated with a scope.
+ ///
+ /// The scope.
+ /// The that can be used to abort the operation.
+ ///
+ /// A that can be used to monitor the asynchronous operation,
+ /// whose result returns the description associated with the specified scope.
+ ///
+ Task GetDescriptionAsync([NotNull] TScope scope, CancellationToken cancellationToken);
+
+ ///
+ /// Retrieves the name associated with a scope.
+ ///
+ /// The scope.
+ /// The that can be used to abort the operation.
+ ///
+ /// A that can be used to monitor the asynchronous operation,
+ /// whose result returns the name associated with the specified scope.
+ ///
+ Task GetNameAsync([NotNull] TScope scope, CancellationToken cancellationToken);
+
+ ///
+ /// Instantiates a new scope.
+ ///
+ /// The that can be used to abort the operation.
+ ///
+ /// A that can be used to monitor the asynchronous operation,
+ /// whose result returns the instantiated scope, that can be persisted in the database.
+ ///
+ Task InstantiateAsync(CancellationToken cancellationToken);
+
///
/// Executes the specified query and returns all the corresponding elements.
///
@@ -107,6 +129,28 @@ namespace OpenIddict.Core
///
Task> ListAsync([NotNull] Func, IQueryable> query, CancellationToken cancellationToken);
+ ///
+ /// Sets the description associated with a scope.
+ ///
+ /// The scope.
+ /// The description associated with the authorization.
+ /// The that can be used to abort the operation.
+ ///
+ /// A that can be used to monitor the asynchronous operation.
+ ///
+ Task SetDescriptionAsync([NotNull] TScope scope, [CanBeNull] string description, CancellationToken cancellationToken);
+
+ ///
+ /// Sets the name associated with a scope.
+ ///
+ /// The scope.
+ /// The name associated with the authorization.
+ /// The that can be used to abort the operation.
+ ///
+ /// A that can be used to monitor the asynchronous operation.
+ ///
+ Task SetNameAsync([NotNull] TScope scope, [CanBeNull] string name, CancellationToken cancellationToken);
+
///
/// Updates an existing scope.
///
diff --git a/src/OpenIddict.Core/Stores/IOpenIddictTokenStore.cs b/src/OpenIddict.Core/Stores/IOpenIddictTokenStore.cs
index 51c871c0..75007225 100644
--- a/src/OpenIddict.Core/Stores/IOpenIddictTokenStore.cs
+++ b/src/OpenIddict.Core/Stores/IOpenIddictTokenStore.cs
@@ -51,16 +51,6 @@ namespace OpenIddict.Core
///
Task CreateAsync([NotNull] TToken token, CancellationToken cancellationToken);
- ///
- /// Creates a new token.
- ///
- /// The token descriptor.
- /// The that can be used to abort the operation.
- ///
- /// A that can be used to monitor the asynchronous operation, whose result returns the token.
- ///
- Task CreateAsync([NotNull] OpenIddictTokenDescriptor descriptor, CancellationToken cancellationToken);
-
///
/// Removes a token.
///
@@ -103,7 +93,7 @@ namespace OpenIddict.Core
Task FindByHashAsync([NotNull] string hash, CancellationToken cancellationToken);
///
- /// Retrieves an token using its unique identifier.
+ /// Retrieves a token using its unique identifier.
///
/// The unique identifier associated with the token.
/// The that can be used to abort the operation.
@@ -246,6 +236,16 @@ namespace OpenIddict.Core
///
Task GetTokenTypeAsync([NotNull] TToken token, CancellationToken cancellationToken);
+ ///
+ /// Instantiates a new token.
+ ///
+ /// The that can be used to abort the operation.
+ ///
+ /// A that can be used to monitor the asynchronous operation,
+ /// whose result returns the instantiated token, that can be persisted in the database.
+ ///
+ Task InstantiateAsync(CancellationToken cancellationToken);
+
///
/// Executes the specified query and returns all the corresponding elements.
///
@@ -287,7 +287,7 @@ namespace OpenIddict.Core
/// Sets the application identifier associated with a token.
///
/// The token.
- /// The unique identifier associated with the client application.
+ /// The unique identifier associated with the token.
/// The that can be used to abort the operation.
///
/// A that can be used to monitor the asynchronous operation.
@@ -298,24 +298,57 @@ namespace OpenIddict.Core
/// Sets the authorization identifier associated with a token.
///
/// The token.
- /// The unique identifier associated with the authorization.
+ /// The unique identifier associated with the token.
/// The that can be used to abort the operation.
///
/// A that can be used to monitor the asynchronous operation.
///
Task SetAuthorizationIdAsync([NotNull] TToken token, [CanBeNull] string identifier, CancellationToken cancellationToken);
+ ///
+ /// Sets the ciphertext associated with a token.
+ ///
+ /// The token.
+ /// The ciphertext associated with the token.
+ /// The that can be used to abort the operation.
+ ///
+ /// A that can be used to monitor the asynchronous operation.
+ ///
+ Task SetCiphertextAsync([NotNull] TToken token, [CanBeNull] string ciphertext, CancellationToken cancellationToken);
+
+ ///
+ /// Sets the creation date associated with a token.
+ ///
+ /// The token.
+ /// The creation date.
+ /// The that can be used to abort the operation.
+ ///
+ /// A that can be used to monitor the asynchronous operation.
+ ///
+ Task SetCreationDateAsync([NotNull] TToken token, [CanBeNull] DateTimeOffset? date, CancellationToken cancellationToken);
+
///
/// Sets the expiration date associated with a token.
///
/// The token.
- /// The date on which the token will no longer be considered valid.
+ /// The expiration date.
/// The that can be used to abort the operation.
///
/// A that can be used to monitor the asynchronous operation.
///
Task SetExpirationDateAsync([NotNull] TToken token, [CanBeNull] DateTimeOffset? date, CancellationToken cancellationToken);
+ ///
+ /// Sets the hash associated with a token.
+ ///
+ /// The token.
+ /// The hash associated with the token.
+ /// The that can be used to abort the operation.
+ ///
+ /// A that can be used to monitor the asynchronous operation.
+ ///
+ Task SetHashAsync([NotNull] TToken token, [CanBeNull] string hash, CancellationToken cancellationToken);
+
///
/// Sets the status associated with a token.
///
@@ -325,7 +358,29 @@ namespace OpenIddict.Core
///
/// A that can be used to monitor the asynchronous operation.
///
- Task SetStatusAsync([NotNull] TToken token, [NotNull] string status, CancellationToken cancellationToken);
+ Task SetStatusAsync([NotNull] TToken token, [CanBeNull] string status, CancellationToken cancellationToken);
+
+ ///
+ /// Sets the subject associated with a token.
+ ///
+ /// The token.
+ /// The subject associated with the token.
+ /// The that can be used to abort the operation.
+ ///
+ /// A that can be used to monitor the asynchronous operation.
+ ///
+ Task SetSubjectAsync([NotNull] TToken token, [CanBeNull] string subject, CancellationToken cancellationToken);
+
+ ///
+ /// Sets the token type associated with a token.
+ ///
+ /// The token.
+ /// The token type associated with the token.
+ /// The that can be used to abort the operation.
+ ///
+ /// A that can be used to monitor the asynchronous operation.
+ ///
+ Task SetTokenTypeAsync([NotNull] TToken token, [CanBeNull] string type, CancellationToken cancellationToken);
///
/// Updates an existing token.
diff --git a/src/OpenIddict.Core/Stores/OpenIddictApplicationStore.cs b/src/OpenIddict.Core/Stores/OpenIddictApplicationStore.cs
index 25c02062..ccc0725f 100644
--- a/src/OpenIddict.Core/Stores/OpenIddictApplicationStore.cs
+++ b/src/OpenIddict.Core/Stores/OpenIddictApplicationStore.cs
@@ -64,16 +64,6 @@ namespace OpenIddict.Core
///
public abstract Task CreateAsync([NotNull] TApplication application, CancellationToken cancellationToken);
- ///
- /// Creates a new application.
- ///
- /// The application descriptor.
- /// The that can be used to abort the operation.
- ///
- /// A that can be used to monitor the asynchronous operation, whose result returns the application.
- ///
- public abstract Task CreateAsync([NotNull] OpenIddictApplicationDescriptor descriptor, CancellationToken cancellationToken);
-
///
/// Removes an existing application.
///
@@ -425,6 +415,16 @@ namespace OpenIddict.Core
return Task.FromResult(ImmutableArray.Create(uris));
}
+ ///
+ /// Instantiates a new application.
+ ///
+ /// The that can be used to abort the operation.
+ ///
+ /// A that can be used to monitor the asynchronous operation, whose result
+ /// returns the instantiated application, that can be persisted in the database.
+ ///
+ public virtual Task InstantiateAsync(CancellationToken cancellationToken) => Task.FromResult(new TApplication());
+
///
/// Executes the specified query and returns all the corresponding elements.
///
@@ -469,6 +469,28 @@ namespace OpenIddict.Core
///
public abstract Task> ListAsync([NotNull] Func, IQueryable> query, CancellationToken cancellationToken);
+ ///
+ /// Sets the client identifier associated with an application.
+ ///
+ /// The application.
+ /// The client identifier associated with the application.
+ /// The that can be used to abort the operation.
+ ///
+ /// A that can be used to monitor the asynchronous operation.
+ ///
+ public virtual Task SetClientIdAsync([NotNull] TApplication application,
+ [CanBeNull] string identifier, CancellationToken cancellationToken)
+ {
+ if (application == null)
+ {
+ throw new ArgumentNullException(nameof(application));
+ }
+
+ application.ClientId = identifier;
+
+ return Task.FromResult(0);
+ }
+
///
/// Sets the client secret associated with an application.
/// Note: depending on the manager used to create the application,
@@ -502,19 +524,37 @@ namespace OpenIddict.Core
///
/// A that can be used to monitor the asynchronous operation.
///
- public virtual Task SetClientTypeAsync([NotNull] TApplication application, [NotNull] string type, CancellationToken cancellationToken)
+ public virtual Task SetClientTypeAsync([NotNull] TApplication application,
+ [CanBeNull] string type, CancellationToken cancellationToken)
{
if (application == null)
{
throw new ArgumentNullException(nameof(application));
}
- if (string.IsNullOrEmpty(type))
+ application.Type = type;
+
+ return Task.FromResult(0);
+ }
+
+ ///
+ /// Sets the display name associated with an application.
+ ///
+ /// The application.
+ /// The display name associated with the application.
+ /// The that can be used to abort the operation.
+ ///
+ /// A that can be used to monitor the asynchronous operation.
+ ///
+ public virtual Task SetDisplayNameAsync([NotNull] TApplication application,
+ [CanBeNull] string name, CancellationToken cancellationToken)
+ {
+ if (application == null)
{
- throw new ArgumentException("The client type cannot be null or empty.", nameof(type));
+ throw new ArgumentNullException(nameof(application));
}
- application.Type = type;
+ application.DisplayName = name;
return Task.FromResult(0);
}
diff --git a/src/OpenIddict.Core/Stores/OpenIddictAuthorizationStore.cs b/src/OpenIddict.Core/Stores/OpenIddictAuthorizationStore.cs
index 0d7ec91c..4c020296 100644
--- a/src/OpenIddict.Core/Stores/OpenIddictAuthorizationStore.cs
+++ b/src/OpenIddict.Core/Stores/OpenIddictAuthorizationStore.cs
@@ -64,16 +64,6 @@ namespace OpenIddict.Core
///
public abstract Task CreateAsync([NotNull] TAuthorization authorization, CancellationToken cancellationToken);
- ///
- /// Creates a new authorization.
- ///
- /// The authorization descriptor.
- /// 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 abstract Task CreateAsync([NotNull] OpenIddictAuthorizationDescriptor descriptor, CancellationToken cancellationToken);
-
///
/// Removes an existing authorization.
///
@@ -170,12 +160,15 @@ namespace OpenIddict.Core
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);
+ IQueryable Query(IQueryable authorizations)
+ {
+ return from element in authorizations
+ where element.Id.Equals(authorization.Id)
+ where element.Application != null
+ select element.Application.Id;
+ }
- return ConvertIdentifierToString(key);
+ return ConvertIdentifierToString(await GetAsync(Query, cancellationToken));
}
///
@@ -209,6 +202,34 @@ namespace OpenIddict.Core
return Task.FromResult(ConvertIdentifierToString(authorization.Id));
}
+ ///
+ /// Retrieves the scopes 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 scopes associated with the specified authorization.
+ ///
+ public virtual Task> GetScopesAsync([NotNull] TAuthorization authorization, CancellationToken cancellationToken)
+ {
+ if (authorization == null)
+ {
+ throw new ArgumentNullException(nameof(authorization));
+ }
+
+ if (string.IsNullOrEmpty(authorization.Scopes))
+ {
+ return Task.FromResult(ImmutableArray.Create());
+ }
+
+ var scopes = authorization.Scopes.Split(
+ new[] { OpenIddictConstants.Separators.Space },
+ StringSplitOptions.RemoveEmptyEntries);
+
+ return Task.FromResult(ImmutableArray.Create(scopes));
+ }
+
///
/// Retrieves the status associated with an authorization.
///
@@ -261,6 +282,16 @@ namespace OpenIddict.Core
return Task.FromResult(authorization.Type);
}
+ ///
+ /// Instantiates a new authorization.
+ ///
+ /// The that can be used to abort the operation.
+ ///
+ /// A that can be used to monitor the asynchronous operation, whose result
+ /// returns the instantiated authorization, that can be persisted in the database.
+ ///
+ public virtual Task InstantiateAsync(CancellationToken cancellationToken) => Task.FromResult(new TAuthorization());
+
///
/// Executes the specified query and returns all the corresponding elements.
///
@@ -352,7 +383,47 @@ namespace OpenIddict.Core
///
/// A that can be used to monitor the asynchronous operation.
///
- public abstract Task SetApplicationIdAsync([NotNull] TAuthorization authorization, [CanBeNull] string identifier, CancellationToken cancellationToken);
+ public abstract Task SetApplicationIdAsync([NotNull] TAuthorization authorization,
+ [CanBeNull] string identifier, CancellationToken cancellationToken);
+
+ ///
+ /// Sets the scopes associated with an authorization.
+ ///
+ /// The authorization.
+ /// The scopes 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 Task SetScopesAsync([NotNull] TAuthorization authorization,
+ ImmutableArray scopes, CancellationToken cancellationToken)
+ {
+ if (authorization == null)
+ {
+ throw new ArgumentNullException(nameof(authorization));
+ }
+
+ if (scopes.IsDefaultOrEmpty)
+ {
+ authorization.Scopes = null;
+
+ return Task.FromResult(0);
+ }
+
+ if (scopes.Any(scope => string.IsNullOrEmpty(scope)))
+ {
+ throw new ArgumentException("Scopes cannot be null or empty.", nameof(authorization));
+ }
+
+ if (scopes.Any(scope => scope.Contains(OpenIddictConstants.Separators.Space)))
+ {
+ throw new ArgumentException("Scopes cannot contain spaces.", nameof(authorization));
+ }
+
+ authorization.Scopes = string.Join(OpenIddictConstants.Separators.Space, scopes);
+
+ return Task.FromResult(0);
+ }
///
/// Sets the status associated with an authorization.
@@ -363,7 +434,8 @@ namespace OpenIddict.Core
///
/// A that can be used to monitor the asynchronous operation.
///
- public virtual Task SetStatusAsync([NotNull] TAuthorization authorization, [NotNull] string status, CancellationToken cancellationToken)
+ public virtual Task SetStatusAsync([NotNull] TAuthorization authorization,
+ [CanBeNull] string status, CancellationToken cancellationToken)
{
if (authorization == null)
{
@@ -375,6 +447,28 @@ namespace OpenIddict.Core
return Task.FromResult(0);
}
+ ///
+ /// Sets the subject associated with an authorization.
+ ///
+ /// The authorization.
+ /// The subject 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 Task SetSubjectAsync([NotNull] TAuthorization authorization,
+ [CanBeNull] string subject, CancellationToken cancellationToken)
+ {
+ if (authorization == null)
+ {
+ throw new ArgumentNullException(nameof(authorization));
+ }
+
+ authorization.Subject = subject;
+
+ return Task.FromResult(0);
+ }
+
///
/// Sets the type associated with an authorization.
///
@@ -384,7 +478,8 @@ namespace OpenIddict.Core
///
/// A that can be used to monitor the asynchronous operation.
///
- public virtual Task SetTypeAsync([NotNull] TAuthorization authorization, [NotNull] string type, CancellationToken cancellationToken)
+ public virtual Task SetTypeAsync([NotNull] TAuthorization authorization,
+ [CanBeNull] string type, CancellationToken cancellationToken)
{
if (authorization == null)
{
diff --git a/src/OpenIddict.Core/Stores/OpenIddictScopeStore.cs b/src/OpenIddict.Core/Stores/OpenIddictScopeStore.cs
index 7600a95b..1596f9d8 100644
--- a/src/OpenIddict.Core/Stores/OpenIddictScopeStore.cs
+++ b/src/OpenIddict.Core/Stores/OpenIddictScopeStore.cs
@@ -60,16 +60,6 @@ namespace OpenIddict.Core
///
public abstract Task CreateAsync([NotNull] TScope scope, CancellationToken cancellationToken);
- ///
- /// Creates a new scope.
- ///
- /// The scope descriptor.
- /// The that can be used to abort the operation.
- ///
- /// A that can be used to monitor the asynchronous operation, whose result returns the scope.
- ///
- public abstract Task CreateAsync([NotNull] OpenIddictScopeDescriptor descriptor, CancellationToken cancellationToken);
-
///
/// Removes an existing scope.
///
@@ -92,6 +82,54 @@ namespace OpenIddict.Core
///
public abstract Task GetAsync([NotNull] Func, IQueryable> query, CancellationToken cancellationToken);
+ ///
+ /// Retrieves the description associated with a scope.
+ ///
+ /// The scope.
+ /// The that can be used to abort the operation.
+ ///
+ /// A that can be used to monitor the asynchronous operation,
+ /// whose result returns the description associated with the specified scope.
+ ///
+ public virtual Task GetDescriptionAsync([NotNull] TScope scope, CancellationToken cancellationToken)
+ {
+ if (scope == null)
+ {
+ throw new ArgumentNullException(nameof(scope));
+ }
+
+ return Task.FromResult(scope.Description);
+ }
+
+ ///
+ /// Retrieves the name associated with a scope.
+ ///
+ /// The scope.
+ /// The that can be used to abort the operation.
+ ///
+ /// A that can be used to monitor the asynchronous operation,
+ /// whose result returns the name associated with the specified scope.
+ ///
+ public virtual Task GetNameAsync([NotNull] TScope scope, CancellationToken cancellationToken)
+ {
+ if (scope == null)
+ {
+ throw new ArgumentNullException(nameof(scope));
+ }
+
+ return Task.FromResult(scope.Name);
+ }
+
+ ///
+ /// Instantiates a new scope.
+ ///
+ /// The that can be used to abort the operation.
+ ///
+ /// A that can be used to monitor the asynchronous operation,
+ /// whose result returns the instantiated scope, that can be persisted in the database.
+ ///
+ public virtual Task InstantiateAsync(CancellationToken cancellationToken) => Task.FromResult(new TScope());
+
///
/// Executes the specified query and returns all the corresponding elements.
///
@@ -136,6 +174,48 @@ namespace OpenIddict.Core
///
public abstract Task> ListAsync([NotNull] Func, IQueryable> query, CancellationToken cancellationToken);
+ ///
+ /// Sets the description associated with a scope.
+ ///
+ /// The scope.
+ /// The description 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 Task SetDescriptionAsync([NotNull] TScope scope, [CanBeNull] string description, CancellationToken cancellationToken)
+ {
+ if (scope == null)
+ {
+ throw new ArgumentNullException(nameof(scope));
+ }
+
+ scope.Description = description;
+
+ return Task.FromResult(0);
+ }
+
+ ///
+ /// Sets the name associated with a scope.
+ ///
+ /// The scope.
+ /// The name 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 Task SetNameAsync([NotNull] TScope scope, [CanBeNull] string name, CancellationToken cancellationToken)
+ {
+ if (scope == null)
+ {
+ throw new ArgumentNullException(nameof(scope));
+ }
+
+ scope.Name = name;
+
+ return Task.FromResult(0);
+ }
+
///
/// Updates an existing scope.
///
diff --git a/src/OpenIddict.Core/Stores/OpenIddictTokenStore.cs b/src/OpenIddict.Core/Stores/OpenIddictTokenStore.cs
index b60738a9..7e4b651c 100644
--- a/src/OpenIddict.Core/Stores/OpenIddictTokenStore.cs
+++ b/src/OpenIddict.Core/Stores/OpenIddictTokenStore.cs
@@ -64,16 +64,6 @@ namespace OpenIddict.Core
///
public abstract Task CreateAsync([NotNull] TToken token, CancellationToken cancellationToken);
- ///
- /// Creates a new token.
- ///
- /// The token descriptor.
- /// The that can be used to abort the operation.
- ///
- /// A that can be used to monitor the asynchronous operation, whose result returns the token.
- ///
- public abstract Task CreateAsync([NotNull] OpenIddictTokenDescriptor descriptor, CancellationToken cancellationToken);
-
///
/// Removes a token.
///
@@ -167,7 +157,7 @@ namespace OpenIddict.Core
}
///
- /// Retrieves an token using its unique identifier.
+ /// Retrieves a token using its unique identifier.
///
/// The unique identifier associated with the token.
/// The that can be used to abort the operation.
@@ -253,12 +243,15 @@ namespace OpenIddict.Core
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);
+ IQueryable Query(IQueryable tokens)
+ {
+ return from element in tokens
+ where element.Id.Equals(token.Id)
+ where element.Application != null
+ select element.Application.Id;
+ }
- return ConvertIdentifierToString(key);
+ return ConvertIdentifierToString(await GetAsync(Query, cancellationToken));
}
///
@@ -282,12 +275,15 @@ namespace OpenIddict.Core
return ConvertIdentifierToString(token.Authorization.Id);
}
- var key = await GetAsync(tokens =>
- from element in tokens
- where element.Id.Equals(token.Id)
- select element.Authorization.Id, cancellationToken);
+ IQueryable Query(IQueryable tokens)
+ {
+ return from element in tokens
+ where element.Id.Equals(token.Id)
+ where element.Authorization != null
+ select element.Authorization.Id;
+ }
- return ConvertIdentifierToString(key);
+ return ConvertIdentifierToString(await GetAsync(Query, cancellationToken));
}
///
@@ -442,6 +438,16 @@ namespace OpenIddict.Core
return Task.FromResult(token.Type);
}
+ ///
+ /// Instantiates a new token.
+ ///
+ /// The that can be used to abort the operation.
+ ///
+ /// A that can be used to monitor the asynchronous operation,
+ /// whose result returns the instantiated token, that can be persisted in the database.
+ ///
+ public virtual Task InstantiateAsync(CancellationToken cancellationToken) => Task.FromResult(new TToken());
+
///
/// Executes the specified query and returns all the corresponding elements.
///
@@ -527,7 +533,7 @@ namespace OpenIddict.Core
/// Sets the authorization identifier associated with a token.
///
/// The token.
- /// The unique identifier associated with the authorization.
+ /// The unique identifier associated with the token.
/// The that can be used to abort the operation.
///
/// A that can be used to monitor the asynchronous operation.
@@ -538,18 +544,61 @@ namespace OpenIddict.Core
/// Sets the application identifier associated with a token.
///
/// The token.
- /// The unique identifier associated with the client application.
+ /// The unique identifier associated with the token.
/// The that can be used to abort the operation.
///
/// A that can be used to monitor the asynchronous operation.
///
public abstract Task SetApplicationIdAsync([NotNull] TToken token, [CanBeNull] string identifier, CancellationToken cancellationToken);
+ ///
+ /// Sets the ciphertext associated with a token.
+ ///
+ /// The token.
+ /// The ciphertext associated with the token.
+ /// The that can be used to abort the operation.
+ ///
+ /// A that can be used to monitor the asynchronous operation.
+ ///
+ public virtual Task SetCiphertextAsync([NotNull] TToken token, [CanBeNull] string ciphertext, CancellationToken cancellationToken)
+ {
+ if (token == null)
+ {
+ throw new ArgumentNullException(nameof(token));
+ }
+
+ token.Ciphertext = ciphertext;
+
+ return Task.FromResult(0);
+ }
+
+ ///
+ /// Sets the creation date associated with a token.
+ ///
+ /// The token.
+ /// The creation date.
+ /// The that can be used to abort the operation.
+ ///
+ /// A that can be used to monitor the asynchronous operation.
+ ///
+ public virtual Task SetCreationDateAsync([NotNull] TToken token,
+ [CanBeNull] DateTimeOffset? date, CancellationToken cancellationToken)
+ {
+ if (token == null)
+ {
+ throw new ArgumentNullException(nameof(token));
+ }
+
+ token.CreationDate = date;
+
+ return Task.FromResult(0);
+ }
+
///
/// Sets the expiration date associated with a token.
///
/// The token.
- /// The date on which the token will no longer be considered valid.
+ /// The expiration date.
/// The that can be used to abort the operation.
///
/// A that can be used to monitor the asynchronous operation.
@@ -567,6 +616,27 @@ namespace OpenIddict.Core
return Task.FromResult(0);
}
+ ///
+ /// Sets the hash associated with a token.
+ ///
+ /// The token.
+ /// The hash associated with the token.
+ /// The that can be used to abort the operation.
+ ///
+ /// A that can be used to monitor the asynchronous operation.
+ ///
+ public virtual Task SetHashAsync([NotNull] TToken token, [CanBeNull] string hash, CancellationToken cancellationToken)
+ {
+ if (token == null)
+ {
+ throw new ArgumentNullException(nameof(token));
+ }
+
+ token.Hash = hash;
+
+ return Task.FromResult(0);
+ }
+
///
/// Sets the status associated with a token.
///
@@ -576,18 +646,75 @@ namespace OpenIddict.Core
///
/// A that can be used to monitor the asynchronous operation.
///
- public virtual Task SetStatusAsync([NotNull] TToken token, [NotNull] string status, CancellationToken cancellationToken)
+ public virtual Task SetStatusAsync([NotNull] TToken token, [CanBeNull] string status, CancellationToken cancellationToken)
{
if (token == null)
{
throw new ArgumentNullException(nameof(token));
}
+ if (string.IsNullOrEmpty(status))
+ {
+ throw new ArgumentException("The status cannot be null or empty.", nameof(status));
+ }
+
token.Status = status;
return Task.FromResult(0);
}
+ ///
+ /// Sets the subject associated with a token.
+ ///
+ /// The token.
+ /// The subject associated with the token.
+ /// The that can be used to abort the operation.
+ ///
+ /// A that can be used to monitor the asynchronous operation.
+ ///
+ public virtual Task SetSubjectAsync([NotNull] TToken token, [CanBeNull] string subject, CancellationToken cancellationToken)
+ {
+ if (token == null)
+ {
+ throw new ArgumentNullException(nameof(token));
+ }
+
+ if (string.IsNullOrEmpty(subject))
+ {
+ throw new ArgumentException("The subject cannot be null or empty.", nameof(subject));
+ }
+
+ token.Subject = subject;
+
+ return Task.FromResult(0);
+ }
+
+ ///
+ /// Sets the token type associated with a token.
+ ///
+ /// The token.
+ /// The token type associated with the token.
+ /// The that can be used to abort the operation.
+ ///
+ /// A that can be used to monitor the asynchronous operation.
+ ///
+ public virtual Task SetTokenTypeAsync([NotNull] TToken token, [CanBeNull] string type, CancellationToken cancellationToken)
+ {
+ if (token == null)
+ {
+ throw new ArgumentNullException(nameof(token));
+ }
+
+ if (string.IsNullOrEmpty(type))
+ {
+ throw new ArgumentException("The token type cannot be null or empty.", nameof(type));
+ }
+
+ token.Type = type;
+
+ return Task.FromResult(0);
+ }
+
///
/// Updates an existing token.
///
diff --git a/src/OpenIddict.EntityFramework/OpenIddictExtensions.cs b/src/OpenIddict.EntityFramework/OpenIddictExtensions.cs
index 402d68e5..f215c10e 100644
--- a/src/OpenIddict.EntityFramework/OpenIddictExtensions.cs
+++ b/src/OpenIddict.EntityFramework/OpenIddictExtensions.cs
@@ -208,8 +208,7 @@ namespace Microsoft.Extensions.DependencyInjection
builder.Entity()
.HasMany(application => application.Tokens)
.WithOptional(token => token.Application)
- .Map(association => association.MapKey("ApplicationId"))
- .WillCascadeOnDelete();
+ .Map(association => association.MapKey("ApplicationId"));
builder.Entity()
.ToTable("OpenIddictApplications");
@@ -237,8 +236,7 @@ namespace Microsoft.Extensions.DependencyInjection
builder.Entity()
.HasMany(application => application.Tokens)
.WithOptional(token => token.Authorization)
- .Map(association => association.MapKey("AuthorizationId"))
- .WillCascadeOnDelete();
+ .Map(association => association.MapKey("AuthorizationId"));
builder.Entity()
.ToTable("OpenIddictAuthorizations");
diff --git a/src/OpenIddict.EntityFramework/Stores/OpenIddictApplicationStore.cs b/src/OpenIddict.EntityFramework/Stores/OpenIddictApplicationStore.cs
index ae1e81df..98646dfc 100644
--- a/src/OpenIddict.EntityFramework/Stores/OpenIddictApplicationStore.cs
+++ b/src/OpenIddict.EntityFramework/Stores/OpenIddictApplicationStore.cs
@@ -134,27 +134,6 @@ namespace OpenIddict.EntityFramework
return application;
}
- ///
- /// Creates a new application.
- ///
- /// The application descriptor.
- /// The that can be used to abort the operation.
- ///
- /// A that can be used to monitor the asynchronous operation, whose result returns the application.
- ///
- public override async Task CreateAsync([NotNull] OpenIddictApplicationDescriptor descriptor, CancellationToken cancellationToken)
- {
- if (descriptor == null)
- {
- throw new ArgumentNullException(nameof(descriptor));
- }
-
- var application = new TApplication();
-
- await BindAsync(application, descriptor, cancellationToken);
- return await CreateAsync(application, cancellationToken);
- }
-
///
/// Removes an existing application.
///
@@ -291,48 +270,5 @@ 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.FromResult(0);
- }
}
}
\ No newline at end of file
diff --git a/src/OpenIddict.EntityFramework/Stores/OpenIddictAuthorizationStore.cs b/src/OpenIddict.EntityFramework/Stores/OpenIddictAuthorizationStore.cs
index a081f839..efdb3847 100644
--- a/src/OpenIddict.EntityFramework/Stores/OpenIddictAuthorizationStore.cs
+++ b/src/OpenIddict.EntityFramework/Stores/OpenIddictAuthorizationStore.cs
@@ -134,27 +134,6 @@ namespace OpenIddict.EntityFramework
return authorization;
}
- ///
- /// Creates a new authorization.
- ///
- /// The authorization descriptor.
- /// 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 override async Task CreateAsync([NotNull] OpenIddictAuthorizationDescriptor descriptor, CancellationToken cancellationToken)
- {
- if (descriptor == null)
- {
- throw new ArgumentNullException(nameof(descriptor));
- }
-
- var authorization = new TAuthorization();
-
- await BindAsync(authorization, descriptor, cancellationToken);
- return await CreateAsync(authorization, cancellationToken);
- }
-
///
/// Removes an existing authorization.
///
@@ -204,7 +183,17 @@ namespace OpenIddict.EntityFramework
throw new ArgumentException("The identifier cannot be null or empty.", nameof(identifier));
}
- return Authorizations.FindAsync(cancellationToken, ConvertIdentifierFromString(identifier));
+ var authorization = (from entry in Context.ChangeTracker.Entries()
+ where entry.Entity != null
+ where entry.Entity.Id.Equals(ConvertIdentifierFromString(identifier))
+ select entry.Entity).FirstOrDefault();
+
+ if (authorization != null)
+ {
+ return Task.FromResult(authorization);
+ }
+
+ return base.FindByIdAsync(identifier, cancellationToken);
}
///
@@ -223,17 +212,21 @@ namespace OpenIddict.EntityFramework
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 the application is not attached to the authorization, try to load it manually.
+ if (authorization.Application == null)
+ {
+ var reference = Context.Entry(authorization).Reference(entry => entry.Application);
+ if (reference.EntityEntry.State == EntityState.Detached)
+ {
+ return null;
+ }
+
+ await reference.LoadAsync(cancellationToken);
+ }
+
if (authorization.Application == null)
{
- return ConvertIdentifierToString(
- await Context.Entry(authorization)
- .Reference(entry => entry.Application)
- .Query()
- .Select(application => application.Id)
- .FirstOrDefaultAsync());
+ return null;
}
return ConvertIdentifierToString(authorization.Application.Id);
@@ -256,7 +249,7 @@ namespace OpenIddict.EntityFramework
throw new ArgumentNullException(nameof(query));
}
- return query(Authorizations).FirstOrDefaultAsync(cancellationToken);
+ return query(Authorizations.Include(authorization => authorization.Application)).FirstOrDefaultAsync(cancellationToken);
}
///
@@ -276,7 +269,8 @@ namespace OpenIddict.EntityFramework
throw new ArgumentNullException(nameof(query));
}
- return ImmutableArray.CreateRange(await query(Authorizations).ToListAsync(cancellationToken));
+ return ImmutableArray.CreateRange(await query(
+ Authorizations.Include(authorization => authorization.Application)).ToListAsync(cancellationToken));
}
///
@@ -308,15 +302,19 @@ namespace OpenIddict.EntityFramework
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.Authorizations.Any(t => t.Id.Equals(key)));
- if (application != null)
+ // If the application is not attached to the authorization, try to load it manually.
+ if (authorization.Application == null)
{
- application.Authorizations.Remove(authorization);
+ var reference = Context.Entry(authorization).Reference(entry => entry.Application);
+ if (reference.EntityEntry.State == EntityState.Detached)
+ {
+ return;
+ }
+
+ await reference.LoadAsync(cancellationToken);
}
+
+ authorization.Application = null;
}
}
@@ -345,48 +343,5 @@ 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(cancellationToken, ConvertIdentifierFromString(descriptor.ApplicationId));
- 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 56997071..7cd7492f 100644
--- a/src/OpenIddict.EntityFramework/Stores/OpenIddictScopeStore.cs
+++ b/src/OpenIddict.EntityFramework/Stores/OpenIddictScopeStore.cs
@@ -114,22 +114,6 @@ namespace OpenIddict.EntityFramework
return scope;
}
- ///
- /// Creates a new scope.
- ///
- /// The scope descriptor.
- /// The that can be used to abort the operation.
- ///
- /// A that can be used to monitor the asynchronous operation, whose result returns the scope.
- ///
- public override async Task CreateAsync([NotNull] OpenIddictScopeDescriptor descriptor, CancellationToken cancellationToken)
- {
- var scope = new TScope();
-
- await BindAsync(scope, descriptor, cancellationToken);
- return await CreateAsync(scope, cancellationToken);
- }
-
///
/// Removes an existing scope.
///
@@ -215,32 +199,5 @@ 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.FromResult(0);
- }
}
}
\ No newline at end of file
diff --git a/src/OpenIddict.EntityFramework/Stores/OpenIddictTokenStore.cs b/src/OpenIddict.EntityFramework/Stores/OpenIddictTokenStore.cs
index ccd7c221..69cfe996 100644
--- a/src/OpenIddict.EntityFramework/Stores/OpenIddictTokenStore.cs
+++ b/src/OpenIddict.EntityFramework/Stores/OpenIddictTokenStore.cs
@@ -133,27 +133,6 @@ namespace OpenIddict.EntityFramework
return token;
}
- ///
- /// Creates a new token.
- ///
- /// The token descriptor.
- /// The that can be used to abort the operation.
- ///
- /// A that can be used to monitor the asynchronous operation, whose result returns the token.
- ///
- public override async Task CreateAsync([NotNull] OpenIddictTokenDescriptor descriptor, CancellationToken cancellationToken)
- {
- if (descriptor == null)
- {
- throw new ArgumentNullException(nameof(descriptor));
- }
-
- var token = new TToken();
-
- await BindAsync(token, descriptor, cancellationToken);
- return await CreateAsync(token, cancellationToken);
- }
-
///
/// Removes a token.
///
@@ -173,7 +152,7 @@ namespace OpenIddict.EntityFramework
}
///
- /// Retrieves an token using its unique identifier.
+ /// Retrieves a token using its unique identifier.
///
/// The unique identifier associated with the token.
/// The that can be used to abort the operation.
@@ -188,7 +167,17 @@ namespace OpenIddict.EntityFramework
throw new ArgumentException("The identifier cannot be null or empty.", nameof(identifier));
}
- return Tokens.FindAsync(cancellationToken, ConvertIdentifierFromString(identifier));
+ var token = (from entry in Context.ChangeTracker.Entries()
+ where entry.Entity != null
+ where entry.Entity.Id.Equals(ConvertIdentifierFromString(identifier))
+ select entry.Entity).FirstOrDefault();
+
+ if (token != null)
+ {
+ return Task.FromResult(token);
+ }
+
+ return base.FindByIdAsync(identifier, cancellationToken);
}
///
@@ -207,17 +196,21 @@ namespace OpenIddict.EntityFramework
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 the application is not attached to the token, 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());
+ var reference = Context.Entry(token).Reference(entry => entry.Application);
+ if (reference.EntityEntry.State == EntityState.Detached)
+ {
+ return null;
+ }
+
+ await reference.LoadAsync(cancellationToken);
+ }
+
+ if (token.Application == null)
+ {
+ return null;
}
return ConvertIdentifierToString(token.Application.Id);
@@ -240,7 +233,9 @@ namespace OpenIddict.EntityFramework
throw new ArgumentNullException(nameof(query));
}
- return query(Tokens).FirstOrDefaultAsync(cancellationToken);
+ return query(
+ Tokens.Include(token => token.Application)
+ .Include(token => token.Authorization)).FirstOrDefaultAsync(cancellationToken);
}
///
@@ -259,17 +254,21 @@ namespace OpenIddict.EntityFramework
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 the authorization is not attached to the token, try to load it manually.
+ if (token.Authorization == null)
+ {
+ var reference = Context.Entry(token).Reference(entry => entry.Authorization);
+ if (reference.EntityEntry.State == EntityState.Detached)
+ {
+ return null;
+ }
+
+ await reference.LoadAsync(cancellationToken);
+ }
+
if (token.Authorization == null)
{
- return ConvertIdentifierToString(
- await Context.Entry(token)
- .Reference(entry => entry.Authorization)
- .Query()
- .Select(authorization => authorization.Id)
- .FirstOrDefaultAsync());
+ return null;
}
return ConvertIdentifierToString(token.Authorization.Id);
@@ -292,7 +291,9 @@ namespace OpenIddict.EntityFramework
throw new ArgumentNullException(nameof(query));
}
- return ImmutableArray.CreateRange(await query(Tokens).ToListAsync(cancellationToken));
+ return ImmutableArray.CreateRange(await query(
+ Tokens.Include(token => token.Application)
+ .Include(token => token.Authorization)).ToListAsync(cancellationToken));
}
///
@@ -324,15 +325,19 @@ namespace OpenIddict.EntityFramework
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)
+ // If the application is not attached to the token, try to load it manually.
+ if (token.Application == null)
{
- application.Tokens.Remove(token);
+ var reference = Context.Entry(token).Reference(entry => entry.Application);
+ if (reference.EntityEntry.State == EntityState.Detached)
+ {
+ return;
+ }
+
+ await reference.LoadAsync(cancellationToken);
}
+
+ token.Application = null;
}
}
@@ -365,15 +370,19 @@ namespace OpenIddict.EntityFramework
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)
+ // If the authorization is not attached to the token, try to load it manually.
+ if (token.Authorization == null)
{
- authorization.Tokens.Remove(token);
+ var reference = Context.Entry(token).Reference(entry => entry.Authorization);
+ if (reference.EntityEntry.State == EntityState.Detached)
+ {
+ return;
+ }
+
+ await reference.LoadAsync(cancellationToken);
}
+
+ token.Authorization = null;
}
}
@@ -402,59 +411,5 @@ 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(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;
- }
- }
}
}
\ No newline at end of file
diff --git a/src/OpenIddict.EntityFrameworkCore/OpenIddictExtensions.cs b/src/OpenIddict.EntityFrameworkCore/OpenIddictExtensions.cs
index fca70808..7bd1793a 100644
--- a/src/OpenIddict.EntityFrameworkCore/OpenIddictExtensions.cs
+++ b/src/OpenIddict.EntityFrameworkCore/OpenIddictExtensions.cs
@@ -243,8 +243,7 @@ namespace Microsoft.Extensions.DependencyInjection
entity.HasMany(application => application.Tokens)
.WithOne(token => token.Application)
.HasForeignKey("ApplicationId")
- .IsRequired(required: false)
- .OnDelete(DeleteBehavior.Cascade);
+ .IsRequired(required: false);
entity.ToTable("OpenIddictApplications");
});
@@ -269,8 +268,7 @@ namespace Microsoft.Extensions.DependencyInjection
entity.HasMany(authorization => authorization.Tokens)
.WithOne(token => token.Authorization)
.HasForeignKey("AuthorizationId")
- .IsRequired(required: false)
- .OnDelete(DeleteBehavior.Cascade);
+ .IsRequired(required: false);
entity.ToTable("OpenIddictAuthorizations");
});
diff --git a/src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictApplicationStore.cs b/src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictApplicationStore.cs
index 95d47f64..d1e3ee69 100644
--- a/src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictApplicationStore.cs
+++ b/src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictApplicationStore.cs
@@ -134,27 +134,6 @@ namespace OpenIddict.EntityFrameworkCore
return application;
}
- ///
- /// Creates a new application.
- ///
- /// The application descriptor.
- /// The that can be used to abort the operation.
- ///
- /// A that can be used to monitor the asynchronous operation, whose result returns the application.
- ///
- public override async Task CreateAsync([NotNull] OpenIddictApplicationDescriptor descriptor, CancellationToken cancellationToken)
- {
- if (descriptor == null)
- {
- throw new ArgumentNullException(nameof(descriptor));
- }
-
- var application = new TApplication();
-
- await BindAsync(application, descriptor, cancellationToken);
- return await CreateAsync(application, cancellationToken);
- }
-
///
/// Removes an existing application.
///
@@ -272,48 +251,5 @@ 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.FromResult(0);
- }
}
}
\ No newline at end of file
diff --git a/src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictAuthorizationStore.cs b/src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictAuthorizationStore.cs
index 1982c00e..855f93e9 100644
--- a/src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictAuthorizationStore.cs
+++ b/src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictAuthorizationStore.cs
@@ -134,27 +134,6 @@ namespace OpenIddict.EntityFrameworkCore
return authorization;
}
- ///
- /// Creates a new authorization.
- ///
- /// The authorization descriptor.
- /// 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 override async Task CreateAsync([NotNull] OpenIddictAuthorizationDescriptor descriptor, CancellationToken cancellationToken)
- {
- if (descriptor == null)
- {
- throw new ArgumentNullException(nameof(descriptor));
- }
-
- var authorization = new TAuthorization();
-
- await BindAsync(authorization, descriptor, cancellationToken);
- return await CreateAsync(authorization, cancellationToken);
- }
-
///
/// Removes an existing authorization.
///
@@ -220,7 +199,7 @@ namespace OpenIddict.EntityFrameworkCore
{
var key = ConvertIdentifierFromString(client);
- return from authorization in authorizations
+ return from authorization in authorizations.Include(authorization => authorization.Application)
where authorization.Subject == subject
join application in applications on authorization.Application.Id equals application.Id
where application.Id.Equals(key)
@@ -230,6 +209,35 @@ namespace OpenIddict.EntityFrameworkCore
return ImmutableArray.CreateRange(await Query(Authorizations, Applications).ToListAsync(cancellationToken));
}
+ ///
+ /// Retrieves an authorization using its unique identifier.
+ ///
+ /// 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,
+ /// whose result returns the authorization corresponding to the identifier.
+ ///
+ public override Task FindByIdAsync([NotNull] string identifier, CancellationToken cancellationToken)
+ {
+ if (string.IsNullOrEmpty(identifier))
+ {
+ throw new ArgumentException("The identifier cannot be null or empty.", nameof(identifier));
+ }
+
+ var authorization = (from entry in Context.ChangeTracker.Entries()
+ where entry.Entity != null
+ where entry.Entity.Id.Equals(ConvertIdentifierFromString(identifier))
+ select entry.Entity).FirstOrDefault();
+
+ if (authorization != null)
+ {
+ return Task.FromResult(authorization);
+ }
+
+ return base.FindByIdAsync(identifier, cancellationToken);
+ }
+
///
/// Executes the specified query and returns the first element.
///
@@ -247,7 +255,7 @@ namespace OpenIddict.EntityFrameworkCore
throw new ArgumentNullException(nameof(query));
}
- return query(Authorizations).FirstOrDefaultAsync(cancellationToken);
+ return query(Authorizations.Include(authorization => authorization.Application)).FirstOrDefaultAsync(cancellationToken);
}
///
@@ -267,7 +275,8 @@ namespace OpenIddict.EntityFrameworkCore
throw new ArgumentNullException(nameof(query));
}
- return ImmutableArray.CreateRange(await query(Authorizations).ToListAsync(cancellationToken));
+ return ImmutableArray.CreateRange(await query(
+ Authorizations.Include(authorization => authorization.Application)).ToListAsync(cancellationToken));
}
///
@@ -338,50 +347,5 @@ 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 key = ConvertIdentifierFromString(descriptor.ApplicationId);
-
- var application = await Applications.SingleOrDefaultAsync(entity => entity.Id.Equals(key));
- 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 16e07e8b..abe7cca1 100644
--- a/src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictScopeStore.cs
+++ b/src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictScopeStore.cs
@@ -114,22 +114,6 @@ namespace OpenIddict.EntityFrameworkCore
return scope;
}
- ///
- /// Creates a new scope.
- ///
- /// The scope descriptor.
- /// The that can be used to abort the operation.
- ///
- /// A that can be used to monitor the asynchronous operation, whose result returns the scope.
- ///
- public override async Task CreateAsync([NotNull] OpenIddictScopeDescriptor descriptor, CancellationToken cancellationToken)
- {
- var scope = new TScope();
-
- await BindAsync(scope, descriptor, cancellationToken);
- return await CreateAsync(scope, cancellationToken);
- }
-
///
/// Removes an existing scope.
///
@@ -215,32 +199,5 @@ 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.FromResult(0);
- }
}
}
\ No newline at end of file
diff --git a/src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictTokenStore.cs b/src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictTokenStore.cs
index f421aff7..a3a2e8dc 100644
--- a/src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictTokenStore.cs
+++ b/src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictTokenStore.cs
@@ -133,27 +133,6 @@ namespace OpenIddict.EntityFrameworkCore
return token;
}
- ///
- /// Creates a new token.
- ///
- /// The token descriptor.
- /// The that can be used to abort the operation.
- ///
- /// A that can be used to monitor the asynchronous operation, whose result returns the token.
- ///
- public override async Task CreateAsync([NotNull] OpenIddictTokenDescriptor descriptor, CancellationToken cancellationToken)
- {
- if (descriptor == null)
- {
- throw new ArgumentNullException(nameof(descriptor));
- }
-
- var token = new TToken();
-
- await BindAsync(token, descriptor, cancellationToken);
- return await CreateAsync(token, cancellationToken);
- }
-
///
/// Removes a token.
///
@@ -197,7 +176,7 @@ namespace OpenIddict.EntityFrameworkCore
{
var key = ConvertIdentifierFromString(identifier);
- return from token in tokens
+ return from token in tokens.Include(token => token.Application).Include(token => token.Authorization)
join application in applications on token.Application.Id equals application.Id
where application.Id.Equals(key)
select token;
@@ -231,7 +210,7 @@ namespace OpenIddict.EntityFrameworkCore
{
var key = ConvertIdentifierFromString(identifier);
- return from token in tokens
+ return from token in tokens.Include(token => token.Application).Include(token => token.Authorization)
join authorization in authorizations on token.Authorization.Id equals authorization.Id
where authorization.Id.Equals(key)
select token;
@@ -240,6 +219,35 @@ namespace OpenIddict.EntityFrameworkCore
return ImmutableArray.CreateRange(await Query(Authorizations, Tokens).ToListAsync(cancellationToken));
}
+ ///
+ /// Retrieves a token using its unique identifier.
+ ///
+ /// The unique identifier associated with 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 token corresponding to the unique identifier.
+ ///
+ public override Task FindByIdAsync([NotNull] string identifier, CancellationToken cancellationToken)
+ {
+ if (string.IsNullOrEmpty(identifier))
+ {
+ throw new ArgumentException("The identifier cannot be null or empty.", nameof(identifier));
+ }
+
+ var token = (from entry in Context.ChangeTracker.Entries()
+ where entry.Entity != null
+ where entry.Entity.Id.Equals(ConvertIdentifierFromString(identifier))
+ select entry.Entity).FirstOrDefault();
+
+ if (token != null)
+ {
+ return Task.FromResult(token);
+ }
+
+ return base.FindByIdAsync(identifier, cancellationToken);
+ }
+
///
/// Executes the specified query and returns the first element.
///
@@ -257,7 +265,9 @@ namespace OpenIddict.EntityFrameworkCore
throw new ArgumentNullException(nameof(query));
}
- return query(Tokens).FirstOrDefaultAsync(cancellationToken);
+ return query(
+ Tokens.Include(token => token.Application)
+ .Include(token => token.Authorization)).FirstOrDefaultAsync(cancellationToken);
}
///
@@ -277,7 +287,9 @@ namespace OpenIddict.EntityFrameworkCore
throw new ArgumentNullException(nameof(query));
}
- return ImmutableArray.CreateRange(await query(Tokens).ToListAsync(cancellationToken));
+ return ImmutableArray.CreateRange(await query(
+ Tokens.Include(token => token.Application)
+ .Include(token => token.Authorization)).ToListAsync(cancellationToken));
}
///
@@ -391,63 +403,5 @@ 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 key = ConvertIdentifierFromString(descriptor.ApplicationId);
-
- var application = await Applications.SingleOrDefaultAsync(entity => entity.Id.Equals(key));
- 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 key = ConvertIdentifierFromString(descriptor.AuthorizationId);
-
- var authorization = await Authorizations.SingleOrDefaultAsync(entity => entity.Id.Equals(key));
- if (authorization == null)
- {
- throw new InvalidOperationException("The authorization associated with the token cannot be found.");
- }
-
- token.Authorization = authorization;
- }
- }
}
}
\ No newline at end of file