Browse Source

Introduce OpenIddictApplication.ConsentType and add new authorization helpers

pull/562/head
Kévin Chalet 8 years ago
parent
commit
efce0af499
  1. 5
      samples/Mvc.Server/Startup.cs
  2. 6
      src/OpenIddict.Core/Descriptors/OpenIddictApplicationDescriptor.cs
  3. 27
      src/OpenIddict.Core/Managers/OpenIddictApplicationManager.cs
  4. 131
      src/OpenIddict.Core/Managers/OpenIddictAuthorizationManager.cs
  5. 20
      src/OpenIddict.Core/Managers/OpenIddictScopeManager.cs
  6. 6
      src/OpenIddict.Core/Managers/OpenIddictTokenManager.cs
  7. 7
      src/OpenIddict.Core/OpenIddictConstants.cs
  8. 22
      src/OpenIddict.Core/Stores/IOpenIddictApplicationStore.cs
  9. 27
      src/OpenIddict.Core/Stores/IOpenIddictAuthorizationStore.cs
  10. 41
      src/OpenIddict.Core/Stores/OpenIddictApplicationStore.cs
  11. 89
      src/OpenIddict.Core/Stores/OpenIddictAuthorizationStore.cs
  12. 16
      src/OpenIddict.Core/Stores/OpenIddictTokenStore.cs
  13. 65
      src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictAuthorizationStore.cs
  14. 4
      src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictTokenStore.cs
  15. 6
      src/OpenIddict.Models/OpenIddictApplication.cs
  16. 4
      src/OpenIddict/OpenIddictExtensions.cs

5
samples/Mvc.Server/Startup.cs

@ -90,9 +90,10 @@ namespace Mvc.Server
.AllowPasswordFlow()
.AllowRefreshTokenFlow();
// Mark the "email" and "profile" scopes as supported scopes.
// Mark the "email", "profile" and "roles" scopes as supported scopes.
options.RegisterScopes(OpenIdConnectConstants.Scopes.Email,
OpenIdConnectConstants.Scopes.Profile);
OpenIdConnectConstants.Scopes.Profile,
OpenIddictConstants.Scopes.Roles);
// Make the "client_id" parameter mandatory when sending a token request.
options.RequireClientIdentification();

6
src/OpenIddict.Core/Descriptors/OpenIddictApplicationDescriptor.cs

@ -21,6 +21,12 @@ namespace OpenIddict.Core
/// </summary>
public string ClientSecret { get; set; }
/// <summary>
/// Gets or sets the consent type
/// associated with the application.
/// </summary>
public virtual string ConsentType { get; set; }
/// <summary>
/// Gets or sets the display name
/// associated with the application.

27
src/OpenIddict.Core/Managers/OpenIddictApplicationManager.cs

@ -370,6 +370,31 @@ namespace OpenIddict.Core
return type;
}
/// <summary>
/// Retrieves the consent type associated with an application.
/// </summary>
/// <param name="application">The application.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the consent type of the application (by default, "explicit").
/// </returns>
public virtual async Task<string> GetConsentTypeAsync([NotNull] TApplication application, CancellationToken cancellationToken = default)
{
if (application == null)
{
throw new ArgumentNullException(nameof(application));
}
var type = await Store.GetConsentTypeAsync(application, cancellationToken);
if (string.IsNullOrEmpty(type))
{
return OpenIddictConstants.ConsentTypes.Explicit;
}
return type;
}
/// <summary>
/// Retrieves the display name associated with an application.
/// </summary>
@ -799,6 +824,7 @@ namespace OpenIddict.Core
{
ClientId = await Store.GetClientIdAsync(application, cancellationToken),
ClientSecret = secret,
ConsentType = await Store.GetConsentTypeAsync(application, cancellationToken),
DisplayName = await Store.GetDisplayNameAsync(application, cancellationToken),
Type = await Store.GetClientTypeAsync(application, cancellationToken)
};
@ -1161,6 +1187,7 @@ namespace OpenIddict.Core
await Store.SetClientIdAsync(application, descriptor.ClientId, cancellationToken);
await Store.SetClientSecretAsync(application, descriptor.ClientSecret, cancellationToken);
await Store.SetClientTypeAsync(application, descriptor.Type, cancellationToken);
await Store.SetConsentTypeAsync(application, descriptor.ConsentType, cancellationToken);
await Store.SetDisplayNameAsync(application, descriptor.DisplayName, cancellationToken);
await Store.SetPermissionsAsync(application, ImmutableArray.CreateRange(descriptor.Permissions), cancellationToken);
await Store.SetPostLogoutRedirectUrisAsync(application, ImmutableArray.CreateRange(

131
src/OpenIddict.Core/Managers/OpenIddictAuthorizationManager.cs

@ -5,9 +5,11 @@
*/
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Security.Claims;
using System.Threading;
using System.Threading.Tasks;
using JetBrains.Annotations;
@ -88,6 +90,12 @@ namespace OpenIddict.Core
throw new ArgumentNullException(nameof(authorization));
}
// If no status was explicitly specified, assume that the authorization is valid.
if (string.IsNullOrEmpty(await Store.GetStatusAsync(authorization, cancellationToken)))
{
await Store.SetStatusAsync(authorization, OpenIddictConstants.Statuses.Valid, cancellationToken);
}
// If no type was explicitly specified, assume that the authorization is a permanent authorization.
if (string.IsNullOrEmpty(await Store.GetTypeAsync(authorization, cancellationToken)))
{
@ -131,6 +139,58 @@ namespace OpenIddict.Core
return authorization;
}
/// <summary>
/// Creates a new permanent authorization based on the specified parameters.
/// </summary>
/// <param name="principal">The principal associated with the authorization.</param>
/// <param name="subject">The subject associated with the authorization.</param>
/// <param name="client">The client associated with the authorization.</param>
/// <param name="scopes">The minimal scopes associated with the authorization.</param>
/// <param name="properties">The authentication properties associated with the authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation, whose result returns the authorization.
/// </returns>
public virtual Task<TAuthorization> CreateAsync(
[NotNull] ClaimsPrincipal principal, [NotNull] string subject,
[NotNull] string client, ImmutableArray<string> scopes,
[CanBeNull] ImmutableDictionary<string, string> properties, CancellationToken cancellationToken = default)
{
if (principal == null)
{
throw new ArgumentNullException(nameof(principal));
}
if (string.IsNullOrEmpty(subject))
{
throw new ArgumentException("The subject cannot be null or empty.", nameof(subject));
}
if (string.IsNullOrEmpty(client))
{
throw new ArgumentException("The client identifier cannot be null or empty.", nameof(client));
}
var descriptor = new OpenIddictAuthorizationDescriptor
{
ApplicationId = client,
Principal = principal,
Subject = subject
};
descriptor.Scopes.UnionWith(scopes);
if (properties != null)
{
foreach (var property in properties)
{
descriptor.Properties.Add(property);
}
}
return CreateAsync(descriptor, cancellationToken);
}
/// <summary>
/// Removes an existing authorization.
/// </summary>
@ -176,6 +236,57 @@ namespace OpenIddict.Core
return Store.FindAsync(subject, client, cancellationToken);
}
/// <summary>
/// Retrieves the authorizations matching the specified parameters.
/// </summary>
/// <param name="subject">The subject associated with the authorization.</param>
/// <param name="client">The client associated with the authorization.</param>
/// <param name="status">The status associated with the authorization.</param>
/// <param name="type">The type associated with the authorization.</param>
/// <param name="scopes">The minimal scopes associated with the authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the authorizations corresponding to the subject/client.
/// </returns>
public virtual async Task<ImmutableArray<TAuthorization>> FindAsync(
[NotNull] string subject, [NotNull] string client,
[NotNull] string status, [NotNull] string type,
ImmutableArray<string> scopes, CancellationToken cancellationToken = default)
{
if (string.IsNullOrEmpty(subject))
{
throw new ArgumentException("The subject cannot be null or empty.", nameof(subject));
}
if (string.IsNullOrEmpty(client))
{
throw new ArgumentException("The client identifier cannot be null or empty.", nameof(client));
}
if (string.IsNullOrEmpty(status))
{
throw new ArgumentException("The status cannot be null or empty.", nameof(client));
}
if (string.IsNullOrEmpty(type))
{
throw new ArgumentException("The type cannot be null or empty.", nameof(client));
}
var authorizations = ImmutableArray.CreateBuilder<TAuthorization>();
foreach (var authorization in await Store.FindAsync(subject, client, status, type, cancellationToken))
{
if (await HasScopesAsync(authorization, scopes, cancellationToken))
{
authorizations.Add(authorization);
}
}
return authorizations.ToImmutable();
}
/// <summary>
/// Retrieves an authorization using its unique identifier.
/// </summary>
@ -195,6 +306,26 @@ namespace OpenIddict.Core
return Store.FindByIdAsync(identifier, cancellationToken);
}
/// <summary>
/// Retrieves all the authorizations corresponding to the specified subject.
/// </summary>
/// <param name="subject">The subject associated with the authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the authorizations corresponding to the specified subject.
/// </returns>
public virtual Task<ImmutableArray<TAuthorization>> FindBySubjectAsync(
[NotNull] string subject, CancellationToken cancellationToken = default)
{
if (string.IsNullOrEmpty(subject))
{
throw new ArgumentException("The subject cannot be null or empty.", nameof(subject));
}
return Store.FindBySubjectAsync(subject, cancellationToken);
}
/// <summary>
/// Retrieves the optional application identifier associated with an authorization.
/// </summary>

20
src/OpenIddict.Core/Managers/OpenIddictScopeManager.cs

@ -501,11 +501,29 @@ namespace OpenIddict.Core
var results = ImmutableArray.CreateBuilder<ValidationResult>();
if (string.IsNullOrEmpty(await Store.GetNameAsync(scope, cancellationToken)))
var name = await Store.GetNameAsync(scope, cancellationToken);
if (string.IsNullOrEmpty(name))
{
results.Add(new ValidationResult("The scope name cannot be null or empty."));
}
else if (name.Contains(OpenIddictConstants.Separators.Space))
{
results.Add(new ValidationResult("The scope name cannot contain spaces."));
}
else
{
// Ensure the name is not already used for a different name.
var other = await Store.FindByNameAsync(name, cancellationToken);
if (other != null && !string.Equals(
await Store.GetIdAsync(other, cancellationToken),
await Store.GetIdAsync(scope, cancellationToken), StringComparison.Ordinal))
{
results.Add(new ValidationResult("A scope with the same name already exists."));
}
}
return results.ToImmutable();
}

6
src/OpenIddict.Core/Managers/OpenIddictTokenManager.cs

@ -90,6 +90,12 @@ namespace OpenIddict.Core
throw new ArgumentNullException(nameof(token));
}
// If no status was explicitly specified, assume that the token is valid.
if (string.IsNullOrEmpty(await Store.GetStatusAsync(token, cancellationToken)))
{
await Store.SetStatusAsync(token, OpenIddictConstants.Statuses.Valid, cancellationToken);
}
var results = await ValidateAsync(token, cancellationToken);
if (results.Any(result => result != ValidationResult.Success))
{

7
src/OpenIddict.Core/OpenIddictConstants.cs

@ -26,6 +26,13 @@ namespace OpenIddict.Core
public const string Public = "public";
}
public static class ConsentTypes
{
public const string Explicit = "explicit";
public const string External = "external";
public const string Implicit = "implicit";
}
public static class Environment
{
public const string AuthorizationRequest = "openiddict-authorization-request:";

22
src/OpenIddict.Core/Stores/IOpenIddictApplicationStore.cs

@ -157,6 +157,17 @@ namespace OpenIddict.Core
/// </returns>
Task<string> GetClientTypeAsync([NotNull] TApplication application, CancellationToken cancellationToken);
/// <summary>
/// Retrieves the consent type associated with an application.
/// </summary>
/// <param name="application">The application.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the consent type of the application (by default, "explicit").
/// </returns>
Task<string> GetConsentTypeAsync([NotNull] TApplication application, CancellationToken cancellationToken);
/// <summary>
/// Retrieves the display name associated with an application.
/// </summary>
@ -296,6 +307,17 @@ namespace OpenIddict.Core
/// </returns>
Task SetClientTypeAsync([NotNull] TApplication application, [CanBeNull] string type, CancellationToken cancellationToken);
/// <summary>
/// Sets the consent type associated with an application.
/// </summary>
/// <param name="application">The application.</param>
/// <param name="type">The consent type associated with the application.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
Task SetConsentTypeAsync([NotNull] TApplication application, [CanBeNull] string type, CancellationToken cancellationToken);
/// <summary>
/// Sets the display name associated with an application.
/// </summary>

27
src/OpenIddict.Core/Stores/IOpenIddictAuthorizationStore.cs

@ -75,6 +75,22 @@ namespace OpenIddict.Core
/// </returns>
Task<ImmutableArray<TAuthorization>> FindAsync([NotNull] string subject, [NotNull] string client, CancellationToken cancellationToken);
/// <summary>
/// Retrieves the authorizations matching the specified parameters.
/// </summary>
/// <param name="subject">The subject associated with the authorization.</param>
/// <param name="client">The client associated with the authorization.</param>
/// <param name="status">The status associated with the authorization.</param>
/// <param name="type">The type associated with the authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the authorizations corresponding to the subject/client.
/// </returns>
Task<ImmutableArray<TAuthorization>> FindAsync(
[NotNull] string subject, [NotNull] string client,
[NotNull] string status, [NotNull] string type, CancellationToken cancellationToken);
/// <summary>
/// Retrieves an authorization using its unique identifier.
/// </summary>
@ -86,6 +102,17 @@ namespace OpenIddict.Core
/// </returns>
Task<TAuthorization> FindByIdAsync([NotNull] string identifier, CancellationToken cancellationToken);
/// <summary>
/// Retrieves all the authorizations corresponding to the specified subject.
/// </summary>
/// <param name="subject">The subject associated with the authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the authorizations corresponding to the specified subject.
/// </returns>
Task<ImmutableArray<TAuthorization>> FindBySubjectAsync([NotNull] string subject, CancellationToken cancellationToken);
/// <summary>
/// Retrieves the optional application identifier associated with an authorization.
/// </summary>

41
src/OpenIddict.Core/Stores/OpenIddictApplicationStore.cs

@ -307,6 +307,25 @@ namespace OpenIddict.Core
return Task.FromResult(application.Type);
}
/// <summary>
/// Retrieves the consent type associated with an application.
/// </summary>
/// <param name="application">The application.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the consent type of the application (by default, "explicit").
/// </returns>
public virtual Task<string> GetConsentTypeAsync([NotNull] TApplication application, CancellationToken cancellationToken)
{
if (application == null)
{
throw new ArgumentNullException(nameof(application));
}
return Task.FromResult(application.ConsentType);
}
/// <summary>
/// Retrieves the display name associated with an application.
/// </summary>
@ -603,6 +622,28 @@ namespace OpenIddict.Core
return Task.CompletedTask;
}
/// <summary>
/// Sets the consent type associated with an application.
/// </summary>
/// <param name="application">The application.</param>
/// <param name="type">The consent type associated with the application.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetConsentTypeAsync([NotNull] TApplication application,
[CanBeNull] string type, CancellationToken cancellationToken)
{
if (application == null)
{
throw new ArgumentNullException(nameof(application));
}
application.ConsentType = type;
return Task.CompletedTask;
}
/// <summary>
/// Sets the display name associated with an application.
/// </summary>

89
src/OpenIddict.Core/Stores/OpenIddictAuthorizationStore.cs

@ -104,7 +104,8 @@ namespace OpenIddict.Core
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the authorizations corresponding to the subject/client.
/// </returns>
public virtual Task<ImmutableArray<TAuthorization>> FindAsync([NotNull] string subject, [NotNull] string client, CancellationToken cancellationToken)
public virtual Task<ImmutableArray<TAuthorization>> FindAsync(
[NotNull] string subject, [NotNull] string client, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(subject))
{
@ -118,9 +119,9 @@ namespace OpenIddict.Core
IQueryable<TAuthorization> Query(IQueryable<TAuthorization> authorizations, TKey key, string principal)
=> from authorization in authorizations
where authorization.Application != null
where authorization.Application.Id.Equals(key)
where authorization.Subject == principal
where authorization.Application != null &&
authorization.Application.Id.Equals(key) &&
authorization.Subject == principal
select authorization;
return ListAsync(
@ -128,6 +129,57 @@ namespace OpenIddict.Core
(key: ConvertIdentifierFromString(client), principal: subject), cancellationToken);
}
/// <summary>
/// Retrieves the authorizations matching the specified parameters.
/// </summary>
/// <param name="subject">The subject associated with the authorization.</param>
/// <param name="client">The client associated with the authorization.</param>
/// <param name="status">The status associated with the authorization.</param>
/// <param name="type">The type associated with the authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the authorizations corresponding to the subject/client.
/// </returns>
public virtual Task<ImmutableArray<TAuthorization>> FindAsync(
[NotNull] string subject, [NotNull] string client,
[NotNull] string status, [NotNull] string type, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(subject))
{
throw new ArgumentException("The subject cannot be null or empty.", nameof(subject));
}
if (string.IsNullOrEmpty(client))
{
throw new ArgumentException("The client identifier cannot be null or empty.", nameof(client));
}
if (string.IsNullOrEmpty(status))
{
throw new ArgumentException("The status cannot be null or empty.", nameof(client));
}
if (string.IsNullOrEmpty(type))
{
throw new ArgumentException("The type cannot be null or empty.", nameof(client));
}
IQueryable<TAuthorization> Query(IQueryable<TAuthorization> authorizations,
TKey key, string principal, string state, string kind)
=> from authorization in authorizations
where authorization.Application != null &&
authorization.Application.Id.Equals(key) &&
authorization.Subject == principal &&
authorization.Status == state &&
authorization.Type == kind
select authorization;
return ListAsync(
(authorizations, state) => Query(authorizations, state.key, state.principal, state.state, state.kind),
(key: ConvertIdentifierFromString(client), principal: subject, state: status, kind: type), cancellationToken);
}
/// <summary>
/// Retrieves an authorization using its unique identifier.
/// </summary>
@ -152,6 +204,31 @@ namespace OpenIddict.Core
return GetAsync((authorizations, key) => Query(authorizations, key), ConvertIdentifierFromString(identifier), cancellationToken);
}
/// <summary>
/// Retrieves all the authorizations corresponding to the specified subject.
/// </summary>
/// <param name="subject">The subject associated with the authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the authorizations corresponding to the specified subject.
/// </returns>
public virtual Task<ImmutableArray<TAuthorization>> FindBySubjectAsync(
[NotNull] string subject, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(subject))
{
throw new ArgumentException("The subject cannot be null or empty.", nameof(subject));
}
IQueryable<TAuthorization> Query(IQueryable<TAuthorization> authorizations, string principal)
=> from authorization in authorizations
where authorization.Subject == principal
select authorization;
return ListAsync((authorizations, principal) => Query(authorizations, principal), subject, cancellationToken);
}
/// <summary>
/// Retrieves the optional application identifier associated with an authorization.
/// </summary>
@ -175,8 +252,8 @@ namespace OpenIddict.Core
IQueryable<TKey> Query(IQueryable<TAuthorization> authorizations, TKey key)
=> from element in authorizations
where element.Id.Equals(key)
where element.Application != null
where element.Id.Equals(key) &&
element.Application != null
select element.Application.Id;
return ConvertIdentifierToString(await GetAsync(

16
src/OpenIddict.Core/Stores/OpenIddictTokenStore.cs

@ -108,8 +108,8 @@ namespace OpenIddict.Core
IQueryable<TToken> Query(IQueryable<TToken> tokens, TKey key)
=> from token in tokens
where token.Application != null
where token.Application.Id.Equals(key)
where token.Application != null &&
token.Application.Id.Equals(key)
select token;
return ListAsync((tokens, key) => Query(tokens, key), ConvertIdentifierFromString(identifier), cancellationToken);
@ -133,8 +133,8 @@ namespace OpenIddict.Core
IQueryable<TToken> Query(IQueryable<TToken> tokens, TKey key)
=> from token in tokens
where token.Authorization != null
where token.Authorization.Id.Equals(key)
where token.Authorization != null &&
token.Authorization.Id.Equals(key)
select token;
return ListAsync((tokens, key) => Query(tokens, key), ConvertIdentifierFromString(identifier), cancellationToken);
@ -252,8 +252,8 @@ namespace OpenIddict.Core
IQueryable<TKey> Query(IQueryable<TToken> tokens, TKey key)
=> from element in tokens
where element.Id.Equals(key)
where element.Application != null
where element.Id.Equals(key) &&
element.Application != null
select element.Application.Id;
return ConvertIdentifierToString(await GetAsync((tokens, key) => Query(tokens, key), token.Id, cancellationToken));
@ -282,8 +282,8 @@ namespace OpenIddict.Core
IQueryable<TKey> Query(IQueryable<TToken> tokens, TKey key)
=> from element in tokens
where element.Id.Equals(key)
where element.Authorization != null
where element.Id.Equals(key) &&
element.Authorization != null
select element.Authorization.Id;
return ConvertIdentifierToString(await GetAsync((tokens, key) => Query(tokens, key), token.Id, cancellationToken));

65
src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictAuthorizationStore.cs

@ -188,7 +188,8 @@ namespace OpenIddict.EntityFrameworkCore
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the authorizations corresponding to the subject/client.
/// </returns>
public override async Task<ImmutableArray<TAuthorization>> FindAsync([NotNull] string subject, [NotNull] string client, CancellationToken cancellationToken)
public override async Task<ImmutableArray<TAuthorization>> FindAsync(
[NotNull] string subject, [NotNull] string client, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(subject))
{
@ -205,7 +206,8 @@ namespace OpenIddict.EntityFrameworkCore
// this method is overriden to use an explicit join before applying the equality check.
// See https://github.com/openiddict/openiddict-core/issues/499 for more information.
IQueryable<TAuthorization> Query(IQueryable<TAuthorization> authorizations, IQueryable<TApplication> applications, TKey key, string principal)
IQueryable<TAuthorization> Query(IQueryable<TAuthorization> authorizations,
IQueryable<TApplication> applications, TKey key, string principal)
=> from authorization in authorizations.Include(authorization => authorization.Application)
where authorization.Subject == principal
join application in applications on authorization.Application.Id equals application.Id
@ -216,6 +218,61 @@ namespace OpenIddict.EntityFrameworkCore
Authorizations, Applications, ConvertIdentifierFromString(client), subject).ToListAsync(cancellationToken));
}
/// <summary>
/// Retrieves the authorizations matching the specified parameters.
/// </summary>
/// <param name="subject">The subject associated with the authorization.</param>
/// <param name="client">The client associated with the authorization.</param>
/// <param name="status">The status associated with the authorization.</param>
/// <param name="type">The type associated with the authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the authorizations corresponding to the subject/client.
/// </returns>
public override async Task<ImmutableArray<TAuthorization>> FindAsync(
[NotNull] string subject, [NotNull] string client,
[NotNull] string status, [NotNull] string type, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(subject))
{
throw new ArgumentException("The subject cannot be null or empty.", nameof(subject));
}
if (string.IsNullOrEmpty(client))
{
throw new ArgumentException("The client identifier cannot be null or empty.", nameof(client));
}
if (string.IsNullOrEmpty(status))
{
throw new ArgumentException("The status cannot be null or empty.", nameof(client));
}
if (string.IsNullOrEmpty(type))
{
throw new ArgumentException("The type cannot be null or empty.", nameof(client));
}
// Note: due to a bug in Entity Framework Core's query visitor, the authorizations can't be
// filtered using authorization.Application.Id.Equals(key). To work around this issue,
// this method is overriden to use an explicit join before applying the equality check.
// See https://github.com/openiddict/openiddict-core/issues/499 for more information.
IQueryable<TAuthorization> Query(IQueryable<TAuthorization> authorizations,
IQueryable<TApplication> applications, TKey key, string principal, string state, string kind)
=> from authorization in authorizations.Include(authorization => authorization.Application)
where authorization.Subject == principal &&
authorization.Status == state &&
authorization.Type == kind
join application in applications on authorization.Application.Id equals application.Id
where application.Id.Equals(key)
select authorization;
return ImmutableArray.CreateRange(await Query(
Authorizations, Applications, ConvertIdentifierFromString(client), subject, status, type).ToListAsync(cancellationToken));
}
/// <summary>
/// Retrieves an authorization using its unique identifier.
/// </summary>
@ -233,8 +290,8 @@ namespace OpenIddict.EntityFrameworkCore
}
var authorization = (from entry in Context.ChangeTracker.Entries<TAuthorization>()
where entry.Entity != null
where entry.Entity.Id.Equals(ConvertIdentifierFromString(identifier))
where entry.Entity != null &&
entry.Entity.Id.Equals(ConvertIdentifierFromString(identifier))
select entry.Entity).FirstOrDefault();
if (authorization != null)

4
src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictTokenStore.cs

@ -242,8 +242,8 @@ namespace OpenIddict.EntityFrameworkCore
}
var token = (from entry in Context.ChangeTracker.Entries<TToken>()
where entry.Entity != null
where entry.Entity.Id.Equals(ConvertIdentifierFromString(identifier))
where entry.Entity != null &&
entry.Entity.Id.Equals(ConvertIdentifierFromString(identifier))
select entry.Entity).FirstOrDefault();
if (token != null)

6
src/OpenIddict.Models/OpenIddictApplication.cs

@ -56,6 +56,12 @@ namespace OpenIddict.Models
/// </summary>
public virtual string ConcurrencyToken { get; set; } = Guid.NewGuid().ToString();
/// <summary>
/// Gets or sets the consent type
/// associated with the current application.
/// </summary>
public virtual string ConsentType { get; set; }
/// <summary>
/// Gets or sets the display name
/// associated with the current application.

4
src/OpenIddict/OpenIddictExtensions.cs

@ -690,8 +690,8 @@ namespace Microsoft.Extensions.DependencyInjection
/// <summary>
/// Rejects authorization and token requests that specify scopes that have not been
/// registered in the database using <see cref="RegisterScopes(OpenIddictBuilder, string[])"/>
/// or <see cref="OpenIddictScopeManager{TScope}.CreateAsync(TScope, CancellationToken)"/>.
/// registered using <see cref="RegisterScopes(OpenIddictBuilder, string[])"/> or
/// <see cref="OpenIddictScopeManager{TScope}.CreateAsync(TScope, CancellationToken)"/>.
/// </summary>
/// <param name="builder">The services builder used by OpenIddict to register new services.</param>
public static OpenIddictBuilder EnableScopeValidation([NotNull] this OpenIddictBuilder builder)

Loading…
Cancel
Save