11 changed files with 1396 additions and 1 deletions
@ -0,0 +1,7 @@ |
|||
<Project> |
|||
|
|||
<ItemGroup> |
|||
<ExcludeFromTest Include="$(RepositoryRoot)test\OpenIddict.EntityFramework.Tests\*.csproj" Condition="'$(OS)' != 'Windows_NT'"/> |
|||
</ItemGroup> |
|||
|
|||
</Project> |
|||
@ -0,0 +1,24 @@ |
|||
<Project Sdk="Microsoft.NET.Sdk"> |
|||
|
|||
<Import Project="..\..\build\packages.props" /> |
|||
|
|||
<PropertyGroup> |
|||
<TargetFramework>net461</TargetFramework> |
|||
</PropertyGroup> |
|||
|
|||
<PropertyGroup> |
|||
<Description>Entity Framework 6.x stores for OpenIddict.</Description> |
|||
<Authors>Kévin Chalet</Authors> |
|||
<PackageTags>aspnetcore;authentication;jwt;openidconnect;openiddict;security</PackageTags> |
|||
</PropertyGroup> |
|||
|
|||
<ItemGroup> |
|||
<ProjectReference Include="..\OpenIddict.Core\OpenIddict.Core.csproj" /> |
|||
</ItemGroup> |
|||
|
|||
<ItemGroup> |
|||
<PackageReference Include="EntityFramework" Version="$(EntityFrameworkVersion)" /> |
|||
<PackageReference Include="JetBrains.Annotations" Version="$(JetBrainsVersion)" PrivateAssets="All" /> |
|||
</ItemGroup> |
|||
|
|||
</Project> |
|||
@ -0,0 +1,264 @@ |
|||
/* |
|||
* Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
|
|||
* See https://github.com/openiddict/openiddict-core for more information concerning
|
|||
* the license and the contributors participating to this project. |
|||
*/ |
|||
|
|||
using System; |
|||
using System.ComponentModel; |
|||
using System.ComponentModel.DataAnnotations.Schema; |
|||
using System.Data.Entity; |
|||
using System.Data.Entity.Infrastructure.Annotations; |
|||
using System.Diagnostics; |
|||
using System.Reflection; |
|||
using JetBrains.Annotations; |
|||
using Microsoft.Extensions.DependencyInjection.Extensions; |
|||
using OpenIddict.Core; |
|||
using OpenIddict.EntityFramework; |
|||
using OpenIddict.Models; |
|||
|
|||
namespace Microsoft.Extensions.DependencyInjection |
|||
{ |
|||
public static class OpenIddictExtensions |
|||
{ |
|||
/// <summary>
|
|||
/// Registers the Entity Framework 6.x stores. Note: when using the Entity Framework stores,
|
|||
/// the application <see cref="DbContext"/> MUST be manually registered in the DI container and
|
|||
/// the entities MUST be derived from the models contained in the OpenIddict.Models package.
|
|||
/// </summary>
|
|||
/// <param name="builder">The services builder used by OpenIddict to register new services.</param>
|
|||
/// <returns>The <see cref="OpenIddictBuilder"/>.</returns>
|
|||
public static OpenIddictBuilder AddEntityFrameworkStores<TContext>([NotNull] this OpenIddictBuilder builder) |
|||
where TContext : DbContext |
|||
{ |
|||
if (builder == null) |
|||
{ |
|||
throw new ArgumentNullException(nameof(builder)); |
|||
} |
|||
|
|||
Debug.Assert(builder.ApplicationType != null && |
|||
builder.AuthorizationType != null && |
|||
builder.ScopeType != null && |
|||
builder.TokenType != null, "The entity types exposed by OpenIddictBuilder shouldn't be null."); |
|||
|
|||
var application = FindGenericBaseType(builder.ApplicationType, typeof(OpenIddictApplication<,,>)); |
|||
if (application == null) |
|||
{ |
|||
throw new InvalidOperationException("The Entity Framework stores can only be used " + |
|||
"with the built-in OpenIddictApplication entity."); |
|||
} |
|||
|
|||
var authorization = FindGenericBaseType(builder.AuthorizationType, typeof(OpenIddictAuthorization<,,>)); |
|||
if (authorization == null) |
|||
{ |
|||
throw new InvalidOperationException("The Entity Framework stores can only be used " + |
|||
"with the built-in OpenIddictAuthorization entity."); |
|||
} |
|||
|
|||
var scope = FindGenericBaseType(builder.ScopeType, typeof(OpenIddictScope<>)); |
|||
if (scope == null) |
|||
{ |
|||
throw new InvalidOperationException("The Entity Framework stores can only be used " + |
|||
"with the built-in OpenIddictScope entity."); |
|||
} |
|||
|
|||
var token = FindGenericBaseType(builder.TokenType, typeof(OpenIddictToken<,,>)); |
|||
if (token == null) |
|||
{ |
|||
throw new InvalidOperationException("The Entity Framework stores can only be used " + |
|||
"with the built-in OpenIddictToken entity."); |
|||
} |
|||
|
|||
var converter = TypeDescriptor.GetConverter(application.GenericTypeArguments[0]); |
|||
if (converter == null || !converter.CanConvertFrom(typeof(string)) || |
|||
!converter.CanConvertTo(typeof(string))) |
|||
{ |
|||
throw new InvalidOperationException("The specified entity key type is not supported."); |
|||
} |
|||
|
|||
// Register the application store in the DI container.
|
|||
builder.Services.TryAddScoped( |
|||
typeof(IOpenIddictApplicationStore<>).MakeGenericType(builder.ApplicationType), |
|||
typeof(OpenIddictApplicationStore<,,,,>).MakeGenericType( |
|||
/* TApplication: */ builder.ApplicationType, |
|||
/* TAuthorization: */ builder.AuthorizationType, |
|||
/* TToken: */ builder.TokenType, |
|||
/* TContext: */ typeof(TContext), |
|||
/* TKey: */ application.GenericTypeArguments[0])); |
|||
|
|||
// Register the authorization store in the DI container.
|
|||
builder.Services.TryAddScoped( |
|||
typeof(IOpenIddictAuthorizationStore<>).MakeGenericType(builder.AuthorizationType), |
|||
typeof(OpenIddictAuthorizationStore<,,,,>).MakeGenericType( |
|||
/* TAuthorization: */ builder.AuthorizationType, |
|||
/* TApplication: */ builder.ApplicationType, |
|||
/* TToken: */ builder.TokenType, |
|||
/* TContext: */ typeof(TContext), |
|||
/* TKey: */ authorization.GenericTypeArguments[0])); |
|||
|
|||
// Register the scope store in the DI container.
|
|||
builder.Services.TryAddScoped( |
|||
typeof(IOpenIddictScopeStore<>).MakeGenericType(builder.ScopeType), |
|||
typeof(OpenIddictScopeStore<,,>).MakeGenericType( |
|||
/* TScope: */ builder.ScopeType, |
|||
/* TContext: */ typeof(TContext), |
|||
/* TKey: */ scope.GenericTypeArguments[0])); |
|||
|
|||
// Register the token store in the DI container.
|
|||
builder.Services.TryAddScoped( |
|||
typeof(IOpenIddictTokenStore<>).MakeGenericType(builder.TokenType), |
|||
typeof(OpenIddictTokenStore<,,,,>).MakeGenericType( |
|||
/* TToken: */ builder.TokenType, |
|||
/* TApplication: */ builder.ApplicationType, |
|||
/* TAuthorization: */ builder.AuthorizationType, |
|||
/* TContext: */ typeof(TContext), |
|||
/* TKey: */ token.GenericTypeArguments[0])); |
|||
|
|||
return builder; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Registers the OpenIddict entity sets in the Entity Framework context
|
|||
/// using the default OpenIddict models and the default key type (string).
|
|||
/// </summary>
|
|||
/// <param name="builder">The builder used to configure the Entity Framework context.</param>
|
|||
/// <returns>The Entity Framework context builder.</returns>
|
|||
public static DbModelBuilder UseOpenIddict([NotNull] this DbModelBuilder builder) |
|||
{ |
|||
return builder.UseOpenIddict<OpenIddictApplication, |
|||
OpenIddictAuthorization, |
|||
OpenIddictScope, |
|||
OpenIddictToken, string>(); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Registers the OpenIddict entity sets in the Entity Framework context
|
|||
/// using the specified entities and the specified key type.
|
|||
/// Note: using this method requires creating non-generic derived classes
|
|||
/// for all the OpenIddict entities (application, authorization, scope, token).
|
|||
/// </summary>
|
|||
/// <param name="builder">The builder used to configure the Entity Framework context.</param>
|
|||
/// <returns>The Entity Framework context builder.</returns>
|
|||
public static DbModelBuilder UseOpenIddict<TApplication, TAuthorization, TScope, TToken, TKey>([NotNull] this DbModelBuilder builder) |
|||
where TApplication : OpenIddictApplication<TKey, TAuthorization, TToken>, new() |
|||
where TAuthorization : OpenIddictAuthorization<TKey, TApplication, TToken>, new() |
|||
where TScope : OpenIddictScope<TKey>, new() |
|||
where TToken : OpenIddictToken<TKey, TApplication, TAuthorization>, new() |
|||
where TKey : IEquatable<TKey> |
|||
{ |
|||
if (builder == null) |
|||
{ |
|||
throw new ArgumentNullException(nameof(builder)); |
|||
} |
|||
|
|||
// Note: unlike Entity Framework Core 1.x/2.x, Entity Framework 6.x
|
|||
// always throws an exception when using generic types as entity types.
|
|||
// To ensure a better exception is thrown, a manual check is made here.
|
|||
if (typeof(TApplication).GetTypeInfo().IsGenericType) |
|||
{ |
|||
throw new InvalidOperationException("The application entity cannot be a generic type. " + |
|||
"Consider creating a non-generic derived class."); |
|||
} |
|||
|
|||
if (typeof(TAuthorization).GetTypeInfo().IsGenericType) |
|||
{ |
|||
throw new InvalidOperationException("The authorization entity cannot be a generic type. " + |
|||
"Consider creating a non-generic derived class."); |
|||
} |
|||
|
|||
if (typeof(TScope).GetTypeInfo().IsGenericType) |
|||
{ |
|||
throw new InvalidOperationException("The scope entity cannot be a generic type. " + |
|||
"Consider creating a non-generic derived class."); |
|||
} |
|||
|
|||
if (typeof(TToken).GetTypeInfo().IsGenericType) |
|||
{ |
|||
throw new InvalidOperationException("The scope entity cannot be a generic type. " + |
|||
"Consider creating a non-generic derived class."); |
|||
} |
|||
|
|||
// Warning: optional foreign keys MUST NOT be added as CLR properties because
|
|||
// Entity Framework would throw an exception due to the TKey generic parameter
|
|||
// being non-nullable when using value types like short, int, long or Guid.
|
|||
|
|||
// Configure the TApplication entity.
|
|||
builder.Entity<TApplication>() |
|||
.HasKey(application => application.Id); |
|||
|
|||
builder.Entity<TApplication>() |
|||
.Property(application => application.ClientId) |
|||
.HasMaxLength(450) |
|||
.HasColumnAnnotation(IndexAnnotation.AnnotationName, new IndexAnnotation(new IndexAttribute())); |
|||
|
|||
builder.Entity<TApplication>() |
|||
.HasMany(application => application.Authorizations) |
|||
.WithOptional(authorization => authorization.Application) |
|||
.Map(association => association.MapKey("ApplicationId")); |
|||
|
|||
builder.Entity<TApplication>() |
|||
.HasMany(application => application.Tokens) |
|||
.WithOptional(token => token.Application) |
|||
.Map(association => association.MapKey("ApplicationId")); |
|||
|
|||
builder.Entity<TApplication>() |
|||
.ToTable("OpenIddictApplications"); |
|||
|
|||
// Configure the TAuthorization entity.
|
|||
builder.Entity<TAuthorization>() |
|||
.HasKey(authorization => authorization.Id); |
|||
|
|||
builder.Entity<TAuthorization>() |
|||
.HasMany(application => application.Tokens) |
|||
.WithOptional(token => token.Authorization) |
|||
.Map(association => association.MapKey("AuthorizationId")); |
|||
|
|||
builder.Entity<TAuthorization>() |
|||
.ToTable("OpenIddictAuthorizations"); |
|||
|
|||
// Configure the TScope entity.
|
|||
builder.Entity<TScope>() |
|||
.HasKey(scope => scope.Id); |
|||
|
|||
builder.Entity<TScope>() |
|||
.ToTable("OpenIddictScopes"); |
|||
|
|||
// Configure the TToken entity.
|
|||
builder.Entity<TToken>() |
|||
.HasKey(token => token.Id); |
|||
|
|||
builder.Entity<TToken>() |
|||
.Property(token => token.Hash) |
|||
.HasMaxLength(450) |
|||
.HasColumnAnnotation(IndexAnnotation.AnnotationName, new IndexAnnotation(new IndexAttribute())); |
|||
|
|||
builder.Entity<TToken>() |
|||
.ToTable("OpenIddictTokens"); |
|||
|
|||
return builder; |
|||
} |
|||
|
|||
private static TypeInfo FindGenericBaseType(Type type, Type definition) |
|||
{ |
|||
if (type == null) |
|||
{ |
|||
throw new ArgumentNullException(nameof(type)); |
|||
} |
|||
|
|||
if (definition == null) |
|||
{ |
|||
throw new ArgumentNullException(nameof(definition)); |
|||
} |
|||
|
|||
for (var candidate = type.GetTypeInfo(); candidate != null; candidate = candidate.BaseType?.GetTypeInfo()) |
|||
{ |
|||
if (candidate.IsGenericType && candidate.GetGenericTypeDefinition() == definition) |
|||
{ |
|||
return candidate; |
|||
} |
|||
} |
|||
|
|||
return null; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,225 @@ |
|||
/* |
|||
* Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
|
|||
* See https://github.com/openiddict/openiddict-core for more information concerning
|
|||
* the license and the contributors participating to this project. |
|||
*/ |
|||
|
|||
using System; |
|||
using System.Data.Entity; |
|||
using System.Data.Entity.Infrastructure; |
|||
using System.Linq; |
|||
using System.Threading; |
|||
using System.Threading.Tasks; |
|||
using JetBrains.Annotations; |
|||
using OpenIddict.Core; |
|||
using OpenIddict.Models; |
|||
|
|||
namespace OpenIddict.EntityFramework |
|||
{ |
|||
/// <summary>
|
|||
/// Provides methods allowing to manage the applications stored in a database.
|
|||
/// Note: this class can only be used with the default OpenIddict entities.
|
|||
/// </summary>
|
|||
/// <typeparam name="TContext">The type of the Entity Framework database context.</typeparam>
|
|||
public class OpenIddictApplicationStore<TContext> : OpenIddictApplicationStore<OpenIddictApplication, |
|||
OpenIddictAuthorization, |
|||
OpenIddictToken, TContext, string> |
|||
where TContext : DbContext |
|||
{ |
|||
public OpenIddictApplicationStore([NotNull] TContext context) : base(context) { } |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Provides methods allowing to manage the applications stored in a database.
|
|||
/// Note: this class can only be used with the default OpenIddict entities.
|
|||
/// </summary>
|
|||
/// <typeparam name="TContext">The type of the Entity Framework database context.</typeparam>
|
|||
/// <typeparam name="TKey">The type of the entity primary keys.</typeparam>
|
|||
public class OpenIddictApplicationStore<TContext, TKey> : OpenIddictApplicationStore<OpenIddictApplication<TKey>, |
|||
OpenIddictAuthorization<TKey>, |
|||
OpenIddictToken<TKey>, TContext, TKey> |
|||
where TContext : DbContext |
|||
where TKey : IEquatable<TKey> |
|||
{ |
|||
public OpenIddictApplicationStore([NotNull] TContext context) : base(context) { } |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Provides methods allowing to manage the applications stored in a database.
|
|||
/// Note: this class can only be used with the default OpenIddict entities.
|
|||
/// </summary>
|
|||
/// <typeparam name="TApplication">The type of the Application entity.</typeparam>
|
|||
/// <typeparam name="TAuthorization">The type of the Authorization entity.</typeparam>
|
|||
/// <typeparam name="TToken">The type of the Token entity.</typeparam>
|
|||
/// <typeparam name="TContext">The type of the Entity Framework database context.</typeparam>
|
|||
/// <typeparam name="TKey">The type of the entity primary keys.</typeparam>
|
|||
public class OpenIddictApplicationStore<TApplication, TAuthorization, TToken, TContext, TKey> : |
|||
OpenIddictApplicationStore<TApplication, TAuthorization, TToken, TKey> |
|||
where TApplication : OpenIddictApplication<TKey, TAuthorization, TToken>, new() |
|||
where TAuthorization : OpenIddictAuthorization<TKey, TApplication, TToken>, new() |
|||
where TToken : OpenIddictToken<TKey, TApplication, TAuthorization>, new() |
|||
where TContext : DbContext |
|||
where TKey : IEquatable<TKey> |
|||
{ |
|||
public OpenIddictApplicationStore([NotNull] TContext context) |
|||
{ |
|||
if (context == null) |
|||
{ |
|||
throw new ArgumentNullException(nameof(context)); |
|||
} |
|||
|
|||
Context = context; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the database context associated with the current store.
|
|||
/// </summary>
|
|||
protected virtual TContext Context { get; } |
|||
|
|||
/// <summary>
|
|||
/// Gets the database set corresponding to the <typeparamref name="TApplication"/> entity.
|
|||
/// </summary>
|
|||
protected DbSet<TApplication> Applications => Context.Set<TApplication>(); |
|||
|
|||
/// <summary>
|
|||
/// Creates a new application.
|
|||
/// </summary>
|
|||
/// <param name="application">The application to create.</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 application.
|
|||
/// </returns>
|
|||
public override async Task<TApplication> CreateAsync([NotNull] TApplication application, CancellationToken cancellationToken) |
|||
{ |
|||
if (application == null) |
|||
{ |
|||
throw new ArgumentNullException(nameof(application)); |
|||
} |
|||
|
|||
Applications.Add(application); |
|||
|
|||
await Context.SaveChangesAsync(cancellationToken); |
|||
|
|||
return application; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Creates a new application.
|
|||
/// </summary>
|
|||
/// <param name="descriptor">The application descriptor.</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 application.
|
|||
/// </returns>
|
|||
public override Task<TApplication> CreateAsync([NotNull] OpenIddictApplicationDescriptor descriptor, CancellationToken cancellationToken) |
|||
{ |
|||
if (descriptor == null) |
|||
{ |
|||
throw new ArgumentNullException(nameof(descriptor)); |
|||
} |
|||
|
|||
var application = new TApplication |
|||
{ |
|||
ClientId = descriptor.ClientId, |
|||
ClientSecret = descriptor.ClientSecret, |
|||
DisplayName = descriptor.DisplayName, |
|||
LogoutRedirectUri = descriptor.LogoutRedirectUri, |
|||
RedirectUri = descriptor.RedirectUri, |
|||
Type = descriptor.Type |
|||
}; |
|||
|
|||
return CreateAsync(application, cancellationToken); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Removes an existing application.
|
|||
/// </summary>
|
|||
/// <param name="application">The application to delete.</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 override async Task DeleteAsync([NotNull] TApplication application, CancellationToken cancellationToken) |
|||
{ |
|||
if (application == null) |
|||
{ |
|||
throw new ArgumentNullException(nameof(application)); |
|||
} |
|||
|
|||
Applications.Remove(application); |
|||
|
|||
try |
|||
{ |
|||
await Context.SaveChangesAsync(cancellationToken); |
|||
} |
|||
|
|||
catch (DbUpdateConcurrencyException) { } |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Executes the specified query.
|
|||
/// </summary>
|
|||
/// <typeparam name="TResult">The result type.</typeparam>
|
|||
/// <param name="query">The query to execute.</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 single element returned when executing the specified query.
|
|||
/// </returns>
|
|||
public override Task<TResult> GetAsync<TResult>([NotNull] Func<IQueryable<TApplication>, IQueryable<TResult>> query, CancellationToken cancellationToken) |
|||
{ |
|||
if (query == null) |
|||
{ |
|||
throw new ArgumentNullException(nameof(query)); |
|||
} |
|||
|
|||
return query.Invoke(Applications).SingleOrDefaultAsync(cancellationToken); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Executes the specified query.
|
|||
/// </summary>
|
|||
/// <typeparam name="TResult">The result type.</typeparam>
|
|||
/// <param name="query">The query to execute.</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 all the elements returned when executing the specified query.
|
|||
/// </returns>
|
|||
public override Task<TResult[]> ListAsync<TResult>([NotNull] Func<IQueryable<TApplication>, IQueryable<TResult>> query, CancellationToken cancellationToken) |
|||
{ |
|||
if (query == null) |
|||
{ |
|||
throw new ArgumentNullException(nameof(query)); |
|||
} |
|||
|
|||
return query.Invoke(Applications).ToArrayAsync(cancellationToken); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Updates an existing application.
|
|||
/// </summary>
|
|||
/// <param name="application">The application to update.</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 override async Task UpdateAsync([NotNull] TApplication application, CancellationToken cancellationToken) |
|||
{ |
|||
if (application == null) |
|||
{ |
|||
throw new ArgumentNullException(nameof(application)); |
|||
} |
|||
|
|||
Applications.Attach(application); |
|||
Context.Entry(application).State = EntityState.Modified; |
|||
|
|||
try |
|||
{ |
|||
await Context.SaveChangesAsync(cancellationToken); |
|||
} |
|||
|
|||
catch (DbUpdateConcurrencyException) { } |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,211 @@ |
|||
/* |
|||
* Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
|
|||
* See https://github.com/openiddict/openiddict-core for more information concerning
|
|||
* the license and the contributors participating to this project. |
|||
*/ |
|||
|
|||
using System; |
|||
using System.Data.Entity; |
|||
using System.Data.Entity.Infrastructure; |
|||
using System.Linq; |
|||
using System.Threading; |
|||
using System.Threading.Tasks; |
|||
using JetBrains.Annotations; |
|||
using OpenIddict.Core; |
|||
using OpenIddict.Models; |
|||
|
|||
namespace OpenIddict.EntityFramework |
|||
{ |
|||
/// <summary>
|
|||
/// Provides methods allowing to manage the authorizations stored in a database.
|
|||
/// Note: this class can only be used with the default OpenIddict entities.
|
|||
/// </summary>
|
|||
/// <typeparam name="TContext">The type of the Entity Framework database context.</typeparam>
|
|||
public class OpenIddictAuthorizationStore<TContext> : OpenIddictAuthorizationStore<OpenIddictAuthorization, |
|||
OpenIddictApplication, |
|||
OpenIddictToken, TContext, string> |
|||
where TContext : DbContext |
|||
{ |
|||
public OpenIddictAuthorizationStore([NotNull] TContext context) : base(context) { } |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Provides methods allowing to manage the authorizations stored in a database.
|
|||
/// Note: this class can only be used with the default OpenIddict entities.
|
|||
/// </summary>
|
|||
/// <typeparam name="TContext">The type of the Entity Framework database context.</typeparam>
|
|||
/// <typeparam name="TKey">The type of the entity primary keys.</typeparam>
|
|||
public class OpenIddictAuthorizationStore<TContext, TKey> : OpenIddictAuthorizationStore<OpenIddictAuthorization<TKey>, |
|||
OpenIddictApplication<TKey>, |
|||
OpenIddictToken<TKey>, TContext, TKey> |
|||
where TContext : DbContext |
|||
where TKey : IEquatable<TKey> |
|||
{ |
|||
public OpenIddictAuthorizationStore([NotNull] TContext context) : base(context) { } |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Provides methods allowing to manage the authorizations stored in a database.
|
|||
/// Note: this class can only be used with the default OpenIddict entities.
|
|||
/// </summary>
|
|||
/// <typeparam name="TAuthorization">The type of the Authorization entity.</typeparam>
|
|||
/// <typeparam name="TApplication">The type of the Application entity.</typeparam>
|
|||
/// <typeparam name="TToken">The type of the Token entity.</typeparam>
|
|||
/// <typeparam name="TContext">The type of the Entity Framework database context.</typeparam>
|
|||
/// <typeparam name="TKey">The type of the entity primary keys.</typeparam>
|
|||
public class OpenIddictAuthorizationStore<TAuthorization, TApplication, TToken, TContext, TKey> : |
|||
OpenIddictAuthorizationStore<TAuthorization, TApplication, TToken, TKey> |
|||
where TAuthorization : OpenIddictAuthorization<TKey, TApplication, TToken>, new() |
|||
where TApplication : OpenIddictApplication<TKey, TAuthorization, TToken>, new() |
|||
where TToken : OpenIddictToken<TKey, TApplication, TAuthorization>, new() |
|||
where TContext : DbContext |
|||
where TKey : IEquatable<TKey> |
|||
{ |
|||
public OpenIddictAuthorizationStore([NotNull] TContext context) |
|||
{ |
|||
if (context == null) |
|||
{ |
|||
throw new ArgumentNullException(nameof(context)); |
|||
} |
|||
|
|||
Context = context; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the database context associated with the current store.
|
|||
/// </summary>
|
|||
protected virtual TContext Context { get; } |
|||
|
|||
/// <summary>
|
|||
/// Gets the database set corresponding to the <typeparamref name="TApplication"/> entity.
|
|||
/// </summary>
|
|||
protected DbSet<TApplication> Applications => Context.Set<TApplication>(); |
|||
|
|||
/// <summary>
|
|||
/// Gets the database set corresponding to the <typeparamref name="TAuthorization"/> entity.
|
|||
/// </summary>
|
|||
protected DbSet<TAuthorization> Authorizations => Context.Set<TAuthorization>(); |
|||
|
|||
/// <summary>
|
|||
/// Creates a new authorization.
|
|||
/// </summary>
|
|||
/// <param name="authorization">The authorization to create.</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 override async Task<TAuthorization> CreateAsync([NotNull] TAuthorization authorization, CancellationToken cancellationToken) |
|||
{ |
|||
if (authorization == null) |
|||
{ |
|||
throw new ArgumentNullException(nameof(authorization)); |
|||
} |
|||
|
|||
Authorizations.Add(authorization); |
|||
|
|||
await Context.SaveChangesAsync(cancellationToken); |
|||
|
|||
return authorization; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Creates a new authorization.
|
|||
/// </summary>
|
|||
/// <param name="descriptor">The authorization descriptor.</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 override async Task<TAuthorization> CreateAsync([NotNull] OpenIddictAuthorizationDescriptor descriptor, CancellationToken cancellationToken) |
|||
{ |
|||
if (descriptor == null) |
|||
{ |
|||
throw new ArgumentNullException(nameof(descriptor)); |
|||
} |
|||
|
|||
var authorization = new TAuthorization |
|||
{ |
|||
Scope = string.Join(" ", descriptor.Scopes), |
|||
Subject = descriptor.Subject |
|||
}; |
|||
|
|||
// 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; |
|||
} |
|||
|
|||
return await CreateAsync(authorization, cancellationToken); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Executes the specified query.
|
|||
/// </summary>
|
|||
/// <typeparam name="TResult">The result type.</typeparam>
|
|||
/// <param name="query">The query to execute.</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 single element returned when executing the specified query.
|
|||
/// </returns>
|
|||
public override Task<TResult> GetAsync<TResult>([NotNull] Func<IQueryable<TAuthorization>, IQueryable<TResult>> query, CancellationToken cancellationToken) |
|||
{ |
|||
if (query == null) |
|||
{ |
|||
throw new ArgumentNullException(nameof(query)); |
|||
} |
|||
|
|||
return query.Invoke(Authorizations).SingleOrDefaultAsync(cancellationToken); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Executes the specified query.
|
|||
/// </summary>
|
|||
/// <typeparam name="TResult">The result type.</typeparam>
|
|||
/// <param name="query">The query to execute.</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 all the elements returned when executing the specified query.
|
|||
/// </returns>
|
|||
public override Task<TResult[]> ListAsync<TResult>([NotNull] Func<IQueryable<TAuthorization>, IQueryable<TResult>> query, CancellationToken cancellationToken) |
|||
{ |
|||
if (query == null) |
|||
{ |
|||
throw new ArgumentNullException(nameof(query)); |
|||
} |
|||
|
|||
return query.Invoke(Authorizations).ToArrayAsync(cancellationToken); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Updates an existing authorization.
|
|||
/// </summary>
|
|||
/// <param name="authorization">The authorization to update.</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 override async Task UpdateAsync([NotNull] TAuthorization authorization, CancellationToken cancellationToken) |
|||
{ |
|||
|
|||
Authorizations.Attach(authorization); |
|||
Context.Entry(authorization).State = EntityState.Modified; |
|||
|
|||
try |
|||
{ |
|||
await Context.SaveChangesAsync(cancellationToken); |
|||
} |
|||
|
|||
catch (DbUpdateConcurrencyException) { } |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,113 @@ |
|||
/* |
|||
* Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
|
|||
* See https://github.com/openiddict/openiddict-core for more information concerning
|
|||
* the license and the contributors participating to this project. |
|||
*/ |
|||
|
|||
using System; |
|||
using System.Data.Entity; |
|||
using System.Linq; |
|||
using System.Threading; |
|||
using System.Threading.Tasks; |
|||
using JetBrains.Annotations; |
|||
using OpenIddict.Models; |
|||
|
|||
namespace OpenIddict.EntityFramework |
|||
{ |
|||
/// <summary>
|
|||
/// Provides methods allowing to manage the scopes stored in a database.
|
|||
/// Note: this class can only be used with the default OpenIddict entities.
|
|||
/// </summary>
|
|||
/// <typeparam name="TContext">The type of the Entity Framework database context.</typeparam>
|
|||
public class OpenIddictScopeStore<TContext> : OpenIddictScopeStore<OpenIddictScope, TContext, string> |
|||
where TContext : DbContext |
|||
{ |
|||
public OpenIddictScopeStore([NotNull] TContext context) : base(context) { } |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Provides methods allowing to manage the scopes stored in a database.
|
|||
/// Note: this class can only be used with the default OpenIddict entities.
|
|||
/// </summary>
|
|||
/// <typeparam name="TContext">The type of the Entity Framework database context.</typeparam>
|
|||
/// <typeparam name="TKey">The type of the entity primary keys.</typeparam>
|
|||
public class OpenIddictScopeStore<TContext, TKey> : OpenIddictScopeStore<OpenIddictScope<TKey>, TContext, TKey> |
|||
where TContext : DbContext |
|||
where TKey : IEquatable<TKey> |
|||
{ |
|||
public OpenIddictScopeStore([NotNull] TContext context) : base(context) { } |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Provides methods allowing to manage the scopes stored in a database.
|
|||
/// Note: this class can only be used with the default OpenIddict entities.
|
|||
/// </summary>
|
|||
/// <typeparam name="TScope">The type of the Scope entity.</typeparam>
|
|||
/// <typeparam name="TContext">The type of the Entity Framework database context.</typeparam>
|
|||
/// <typeparam name="TKey">The type of the entity primary keys.</typeparam>
|
|||
public class OpenIddictScopeStore<TScope, TContext, TKey> : Core.OpenIddictScopeStore<TScope, TKey> |
|||
where TScope : OpenIddictScope<TKey>, new() |
|||
where TContext : DbContext |
|||
where TKey : IEquatable<TKey> |
|||
{ |
|||
public OpenIddictScopeStore([NotNull] TContext context) |
|||
{ |
|||
if (context == null) |
|||
{ |
|||
throw new ArgumentNullException(nameof(context)); |
|||
} |
|||
|
|||
Context = context; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the database context associated with the current store.
|
|||
/// </summary>
|
|||
protected virtual TContext Context { get; } |
|||
|
|||
/// <summary>
|
|||
/// Gets the database set corresponding to the <typeparamref name="TScope"/> entity.
|
|||
/// </summary>
|
|||
protected DbSet<TScope> Scopes => Context.Set<TScope>(); |
|||
|
|||
/// <summary>
|
|||
/// Executes the specified query.
|
|||
/// </summary>
|
|||
/// <typeparam name="TResult">The result type.</typeparam>
|
|||
/// <param name="query">The query to execute.</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 single element returned when executing the specified query.
|
|||
/// </returns>
|
|||
public override Task<TResult> GetAsync<TResult>([NotNull] Func<IQueryable<TScope>, IQueryable<TResult>> query, CancellationToken cancellationToken) |
|||
{ |
|||
if (query == null) |
|||
{ |
|||
throw new ArgumentNullException(nameof(query)); |
|||
} |
|||
|
|||
return query.Invoke(Scopes).SingleOrDefaultAsync(cancellationToken); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Executes the specified query.
|
|||
/// </summary>
|
|||
/// <typeparam name="TResult">The result type.</typeparam>
|
|||
/// <param name="query">The query to execute.</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 all the elements returned when executing the specified query.
|
|||
/// </returns>
|
|||
public override Task<TResult[]> ListAsync<TResult>([NotNull] Func<IQueryable<TScope>, IQueryable<TResult>> query, CancellationToken cancellationToken) |
|||
{ |
|||
if (query == null) |
|||
{ |
|||
throw new ArgumentNullException(nameof(query)); |
|||
} |
|||
|
|||
return query.Invoke(Scopes).ToArrayAsync(cancellationToken); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,347 @@ |
|||
/* |
|||
* Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
|
|||
* See https://github.com/openiddict/openiddict-core for more information concerning
|
|||
* the license and the contributors participating to this project. |
|||
*/ |
|||
|
|||
using System; |
|||
using System.Data.Entity; |
|||
using System.Data.Entity.Infrastructure; |
|||
using System.Linq; |
|||
using System.Threading; |
|||
using System.Threading.Tasks; |
|||
using JetBrains.Annotations; |
|||
using OpenIddict.Core; |
|||
using OpenIddict.Models; |
|||
|
|||
namespace OpenIddict.EntityFramework |
|||
{ |
|||
/// <summary>
|
|||
/// Provides methods allowing to manage the tokens stored in a database.
|
|||
/// Note: this class can only be used with the default OpenIddict entities.
|
|||
/// </summary>
|
|||
/// <typeparam name="TContext">The type of the Entity Framework database context.</typeparam>
|
|||
public class OpenIddictTokenStore<TContext> : OpenIddictTokenStore<OpenIddictToken, |
|||
OpenIddictApplication, |
|||
OpenIddictAuthorization, TContext, string> |
|||
where TContext : DbContext |
|||
{ |
|||
public OpenIddictTokenStore([NotNull] TContext context) : base(context) { } |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Provides methods allowing to manage the tokens stored in a database.
|
|||
/// Note: this class can only be used with the default OpenIddict entities.
|
|||
/// </summary>
|
|||
/// <typeparam name="TContext">The type of the Entity Framework database context.</typeparam>
|
|||
/// <typeparam name="TKey">The type of the entity primary keys.</typeparam>
|
|||
public class OpenIddictTokenStore<TContext, TKey> : OpenIddictTokenStore<OpenIddictToken<TKey>, |
|||
OpenIddictApplication<TKey>, |
|||
OpenIddictAuthorization<TKey>, TContext, TKey> |
|||
where TContext : DbContext |
|||
where TKey : IEquatable<TKey> |
|||
{ |
|||
public OpenIddictTokenStore([NotNull] TContext context) : base(context) { } |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Provides methods allowing to manage the tokens stored in a database.
|
|||
/// Note: this class can only be used with the default OpenIddict entities.
|
|||
/// </summary>
|
|||
/// <typeparam name="TToken">The type of the Token entity.</typeparam>
|
|||
/// <typeparam name="TApplication">The type of the Application entity.</typeparam>
|
|||
/// <typeparam name="TAuthorization">The type of the Authorization entity.</typeparam>
|
|||
/// <typeparam name="TContext">The type of the Entity Framework database context.</typeparam>
|
|||
/// <typeparam name="TKey">The type of the entity primary keys.</typeparam>
|
|||
public class OpenIddictTokenStore<TToken, TApplication, TAuthorization, TContext, TKey> : |
|||
OpenIddictTokenStore<TToken, TApplication, TAuthorization, TKey> |
|||
where TToken : OpenIddictToken<TKey, TApplication, TAuthorization>, new() |
|||
where TApplication : OpenIddictApplication<TKey, TAuthorization, TToken>, new() |
|||
where TAuthorization : OpenIddictAuthorization<TKey, TApplication, TToken>, new() |
|||
where TContext : DbContext |
|||
where TKey : IEquatable<TKey> |
|||
{ |
|||
public OpenIddictTokenStore([NotNull] TContext context) |
|||
{ |
|||
if (context == null) |
|||
{ |
|||
throw new ArgumentNullException(nameof(context)); |
|||
} |
|||
|
|||
Context = context; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the database context associated with the current store.
|
|||
/// </summary>
|
|||
protected virtual TContext Context { get; } |
|||
|
|||
/// <summary>
|
|||
/// Gets the database set corresponding to the <typeparamref name="TApplication"/> entity.
|
|||
/// </summary>
|
|||
protected DbSet<TApplication> Applications => Context.Set<TApplication>(); |
|||
|
|||
/// <summary>
|
|||
/// Gets the database set corresponding to the <typeparamref name="TAuthorization"/> entity.
|
|||
/// </summary>
|
|||
protected DbSet<TAuthorization> Authorizations => Context.Set<TAuthorization>(); |
|||
|
|||
/// <summary>
|
|||
/// Gets the database set corresponding to the <typeparamref name="TToken"/> entity.
|
|||
/// </summary>
|
|||
protected DbSet<TToken> Tokens => Context.Set<TToken>(); |
|||
|
|||
/// <summary>
|
|||
/// Creates a new token.
|
|||
/// </summary>
|
|||
/// <param name="token">The token to create.</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 token.
|
|||
/// </returns>
|
|||
public override async Task<TToken> CreateAsync([NotNull] TToken token, CancellationToken cancellationToken) |
|||
{ |
|||
if (token == null) |
|||
{ |
|||
throw new ArgumentNullException(nameof(token)); |
|||
} |
|||
|
|||
Tokens.Add(token); |
|||
|
|||
await Context.SaveChangesAsync(cancellationToken); |
|||
|
|||
return token; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Creates a new token, which is associated with a particular subject.
|
|||
/// </summary>
|
|||
/// <param name="descriptor">The token descriptor.</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 token.
|
|||
/// </returns>
|
|||
public override async Task<TToken> CreateAsync([NotNull] OpenIddictTokenDescriptor descriptor, CancellationToken cancellationToken) |
|||
{ |
|||
if (descriptor == null) |
|||
{ |
|||
throw new ArgumentNullException(nameof(descriptor)); |
|||
} |
|||
|
|||
var token = new TToken |
|||
{ |
|||
Ciphertext = descriptor.Ciphertext, |
|||
CreationDate = descriptor.CreationDate, |
|||
ExpirationDate = descriptor.ExpirationDate, |
|||
Hash = descriptor.Hash, |
|||
Subject = descriptor.Subject, |
|||
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; |
|||
} |
|||
|
|||
return await CreateAsync(token, cancellationToken); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Removes a token.
|
|||
/// </summary>
|
|||
/// <param name="token">The token to delete.</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 override async Task DeleteAsync([NotNull] TToken token, CancellationToken cancellationToken) |
|||
{ |
|||
if (token == null) |
|||
{ |
|||
throw new ArgumentNullException(nameof(token)); |
|||
} |
|||
|
|||
Tokens.Remove(token); |
|||
|
|||
try |
|||
{ |
|||
await Context.SaveChangesAsync(cancellationToken); |
|||
} |
|||
|
|||
catch (DbUpdateConcurrencyException) { } |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Executes the specified query.
|
|||
/// </summary>
|
|||
/// <typeparam name="TResult">The result type.</typeparam>
|
|||
/// <param name="query">The query to execute.</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 single element returned when executing the specified query.
|
|||
/// </returns>
|
|||
public override Task<TResult> GetAsync<TResult>([NotNull] Func<IQueryable<TToken>, IQueryable<TResult>> query, CancellationToken cancellationToken) |
|||
{ |
|||
if (query == null) |
|||
{ |
|||
throw new ArgumentNullException(nameof(query)); |
|||
} |
|||
|
|||
return query.Invoke(Tokens).SingleOrDefaultAsync(cancellationToken); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Executes the specified query.
|
|||
/// </summary>
|
|||
/// <typeparam name="TResult">The result type.</typeparam>
|
|||
/// <param name="query">The query to execute.</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 all the elements returned when executing the specified query.
|
|||
/// </returns>
|
|||
public override Task<TResult[]> ListAsync<TResult>([NotNull] Func<IQueryable<TToken>, IQueryable<TResult>> query, CancellationToken cancellationToken) |
|||
{ |
|||
if (query == null) |
|||
{ |
|||
throw new ArgumentNullException(nameof(query)); |
|||
} |
|||
|
|||
return query.Invoke(Tokens).ToArrayAsync(cancellationToken); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Sets the authorization associated with a token.
|
|||
/// </summary>
|
|||
/// <param name="token">The token.</param>
|
|||
/// <param name="identifier">The unique identifier 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.
|
|||
/// </returns>
|
|||
public override async Task SetAuthorizationAsync([NotNull] TToken token, [CanBeNull] string identifier, CancellationToken cancellationToken) |
|||
{ |
|||
if (token == null) |
|||
{ |
|||
throw new ArgumentNullException(nameof(token)); |
|||
} |
|||
|
|||
if (!string.IsNullOrEmpty(identifier)) |
|||
{ |
|||
var key = ConvertIdentifierFromString(identifier); |
|||
|
|||
var authorization = await Authorizations.SingleOrDefaultAsync(element => element.Id.Equals(key)); |
|||
if (authorization == null) |
|||
{ |
|||
throw new InvalidOperationException("The authorization associated with the token cannot be found."); |
|||
} |
|||
|
|||
authorization.Tokens.Add(token); |
|||
} |
|||
|
|||
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.SingleOrDefaultAsync(element => element.Tokens.Any(t => t.Id.Equals(key))); |
|||
if (authorization != null) |
|||
{ |
|||
authorization.Tokens.Remove(token); |
|||
} |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Sets the client application associated with a token.
|
|||
/// </summary>
|
|||
/// <param name="token">The token.</param>
|
|||
/// <param name="identifier">The unique identifier associated with the client 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 override async Task SetClientAsync([NotNull] TToken token, [CanBeNull] string identifier, CancellationToken cancellationToken) |
|||
{ |
|||
if (token == null) |
|||
{ |
|||
throw new ArgumentNullException(nameof(token)); |
|||
} |
|||
|
|||
if (!string.IsNullOrEmpty(identifier)) |
|||
{ |
|||
var key = ConvertIdentifierFromString(identifier); |
|||
|
|||
var application = await Applications.SingleOrDefaultAsync(element => element.Id.Equals(key)); |
|||
if (application == null) |
|||
{ |
|||
throw new InvalidOperationException("The application associated with the token cannot be found."); |
|||
} |
|||
|
|||
application.Tokens.Add(token); |
|||
} |
|||
|
|||
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.SingleOrDefaultAsync(element => element.Tokens.Any(t => t.Id.Equals(key))); |
|||
if (application != null) |
|||
{ |
|||
application.Tokens.Remove(token); |
|||
} |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Updates an existing token.
|
|||
/// </summary>
|
|||
/// <param name="token">The token to update.</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 override async Task UpdateAsync([NotNull] TToken token, CancellationToken cancellationToken) |
|||
{ |
|||
if (token == null) |
|||
{ |
|||
throw new ArgumentNullException(nameof(token)); |
|||
} |
|||
|
|||
Tokens.Attach(token); |
|||
Context.Entry(token).State = EntityState.Modified; |
|||
|
|||
try |
|||
{ |
|||
await Context.SaveChangesAsync(cancellationToken); |
|||
} |
|||
|
|||
catch (DbUpdateConcurrencyException) { } |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,25 @@ |
|||
<Project Sdk="Microsoft.NET.Sdk"> |
|||
|
|||
<Import Project="..\..\build\tests.props" /> |
|||
|
|||
<PropertyGroup> |
|||
<TargetFramework>net461</TargetFramework> |
|||
</PropertyGroup> |
|||
|
|||
<ItemGroup> |
|||
<ProjectReference Include="..\..\src\OpenIddict.EntityFramework\OpenIddict.EntityFramework.csproj" /> |
|||
</ItemGroup> |
|||
|
|||
<ItemGroup> |
|||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="$(AspNetCoreVersion)" /> |
|||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="$(TestSdkVersion)" /> |
|||
<PackageReference Include="Moq" Version="$(MoqVersion)" /> |
|||
<PackageReference Include="xunit" Version="$(XunitVersion)" /> |
|||
<PackageReference Include="xunit.runner.visualstudio" Version="$(XunitVersion)" /> |
|||
</ItemGroup> |
|||
|
|||
<ItemGroup> |
|||
<Service Include="{82a7f48d-3b50-4b1e-b82e-3ada8210c358}" /> |
|||
</ItemGroup> |
|||
|
|||
</Project> |
|||
@ -0,0 +1,161 @@ |
|||
using System; |
|||
using System.Data.Entity; |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using OpenIddict.EntityFramework; |
|||
using OpenIddict.Models; |
|||
using Xunit; |
|||
|
|||
namespace OpenIddict.EntityFrameworkCore.Tests |
|||
{ |
|||
public class OpenIddictExtensionsTests |
|||
{ |
|||
[Fact] |
|||
public void AddEntityFrameworkStores_ThrowsAnExceptionForInvalidApplicationEntity() |
|||
{ |
|||
// Arrange
|
|||
var builder = new OpenIddictBuilder(new ServiceCollection()) |
|||
{ |
|||
ApplicationType = typeof(object) |
|||
}; |
|||
|
|||
// Act and assert
|
|||
var exception = Assert.Throws<InvalidOperationException>(delegate |
|||
{ |
|||
builder.AddEntityFrameworkStores<DbContext>(); |
|||
}); |
|||
|
|||
Assert.Equal("The Entity Framework stores can only be used " + |
|||
"with the built-in OpenIddictApplication entity.", exception.Message); |
|||
} |
|||
|
|||
[Fact] |
|||
public void AddEntityFrameworkStores_ThrowsAnExceptionForInvalidAuthorizationEntity() |
|||
{ |
|||
// Arrange
|
|||
var builder = new OpenIddictBuilder(new ServiceCollection()) |
|||
{ |
|||
AuthorizationType = typeof(object) |
|||
}; |
|||
|
|||
// Act and assert
|
|||
var exception = Assert.Throws<InvalidOperationException>(delegate |
|||
{ |
|||
builder.AddEntityFrameworkStores<DbContext>(); |
|||
}); |
|||
|
|||
Assert.Equal("The Entity Framework stores can only be used " + |
|||
"with the built-in OpenIddictAuthorization entity.", exception.Message); |
|||
} |
|||
|
|||
[Fact] |
|||
public void AddEntityFrameworkStores_ThrowsAnExceptionForInvalidScopeEntity() |
|||
{ |
|||
// Arrange
|
|||
var builder = new OpenIddictBuilder(new ServiceCollection()) |
|||
{ |
|||
ScopeType = typeof(object) |
|||
}; |
|||
|
|||
// Act and assert
|
|||
var exception = Assert.Throws<InvalidOperationException>(delegate |
|||
{ |
|||
builder.AddEntityFrameworkStores<DbContext>(); |
|||
}); |
|||
|
|||
Assert.Equal("The Entity Framework stores can only be used " + |
|||
"with the built-in OpenIddictScope entity.", exception.Message); |
|||
} |
|||
|
|||
[Fact] |
|||
public void AddEntityFrameworkStores_ThrowsAnExceptionForInvalidTokenEntity() |
|||
{ |
|||
// Arrange
|
|||
var builder = new OpenIddictBuilder(new ServiceCollection()) |
|||
{ |
|||
TokenType = typeof(object) |
|||
}; |
|||
|
|||
// Act and assert
|
|||
var exception = Assert.Throws<InvalidOperationException>(delegate |
|||
{ |
|||
builder.AddEntityFrameworkStores<DbContext>(); |
|||
}); |
|||
|
|||
Assert.Equal("The Entity Framework stores can only be used " + |
|||
"with the built-in OpenIddictToken entity.", exception.Message); |
|||
} |
|||
|
|||
[Theory] |
|||
[InlineData(typeof(OpenIddictApplicationStore<OpenIddictApplication, OpenIddictAuthorization, OpenIddictToken, DbContext, string>))] |
|||
[InlineData(typeof(OpenIddictAuthorizationStore<OpenIddictAuthorization, OpenIddictApplication, OpenIddictToken, DbContext, string>))] |
|||
[InlineData(typeof(OpenIddictScopeStore<OpenIddictScope, DbContext, string>))] |
|||
[InlineData(typeof(OpenIddictTokenStore<OpenIddictToken, OpenIddictApplication, OpenIddictAuthorization, DbContext, string>))] |
|||
public void AddEntityFrameworkStores_RegistersEntityFrameworkStores(Type type) |
|||
{ |
|||
// Arrange
|
|||
var services = new ServiceCollection(); |
|||
var builder = new OpenIddictBuilder(services); |
|||
|
|||
// Act
|
|||
builder.AddEntityFrameworkStores<DbContext>(); |
|||
|
|||
// Assert
|
|||
Assert.Contains(services, service => service.ImplementationType == type); |
|||
} |
|||
|
|||
[Theory] |
|||
[InlineData(typeof(OpenIddictApplicationStore<OpenIddictApplication<Guid>, OpenIddictAuthorization<Guid>, OpenIddictToken<Guid>, DbContext, Guid>))] |
|||
[InlineData(typeof(OpenIddictAuthorizationStore<OpenIddictAuthorization<Guid>, OpenIddictApplication<Guid>, OpenIddictToken<Guid>, DbContext, Guid>))] |
|||
[InlineData(typeof(OpenIddictScopeStore<OpenIddictScope<Guid>, DbContext, Guid>))] |
|||
[InlineData(typeof(OpenIddictTokenStore<OpenIddictToken<Guid>, OpenIddictApplication<Guid>, OpenIddictAuthorization<Guid>, DbContext, Guid>))] |
|||
public void AddEntityFrameworkStores_KeyTypeIsInferredFromEntities(Type type) |
|||
{ |
|||
// Arrange
|
|||
var services = new ServiceCollection(); |
|||
|
|||
var builder = new OpenIddictBuilder(services) |
|||
{ |
|||
ApplicationType = typeof(OpenIddictApplication<Guid>), |
|||
AuthorizationType = typeof(OpenIddictAuthorization<Guid>), |
|||
ScopeType = typeof(OpenIddictScope<Guid>), |
|||
TokenType = typeof(OpenIddictToken<Guid>) |
|||
}; |
|||
|
|||
// Act
|
|||
builder.AddEntityFrameworkStores<DbContext>(); |
|||
|
|||
// Assert
|
|||
Assert.Contains(services, service => service.ImplementationType == type); |
|||
} |
|||
|
|||
[Theory] |
|||
[InlineData(typeof(OpenIddictApplicationStore<CustomApplication, CustomAuthorization, CustomToken, DbContext, long>))] |
|||
[InlineData(typeof(OpenIddictAuthorizationStore<CustomAuthorization, CustomApplication, CustomToken, DbContext, long>))] |
|||
[InlineData(typeof(OpenIddictScopeStore<CustomScope, DbContext, long>))] |
|||
[InlineData(typeof(OpenIddictTokenStore<CustomToken, CustomApplication, CustomAuthorization, DbContext, long>))] |
|||
public void AddEntityFrameworkStores_DefaultEntitiesCanBeReplaced(Type type) |
|||
{ |
|||
// Arrange
|
|||
var services = new ServiceCollection(); |
|||
|
|||
var builder = new OpenIddictBuilder(services) |
|||
{ |
|||
ApplicationType = typeof(CustomApplication), |
|||
AuthorizationType = typeof(CustomAuthorization), |
|||
ScopeType = typeof(CustomScope), |
|||
TokenType = typeof(CustomToken) |
|||
}; |
|||
|
|||
// Act
|
|||
builder.AddEntityFrameworkStores<DbContext>(); |
|||
|
|||
// Assert
|
|||
Assert.Contains(services, service => service.ImplementationType == type); |
|||
} |
|||
|
|||
public class CustomApplication : OpenIddictApplication<long, CustomAuthorization, CustomToken> { } |
|||
public class CustomAuthorization : OpenIddictAuthorization<long, CustomApplication, CustomToken> { } |
|||
public class CustomScope : OpenIddictScope<long> { } |
|||
public class CustomToken : OpenIddictToken<long, CustomApplication, CustomAuthorization> { } |
|||
} |
|||
} |
|||
Loading…
Reference in new issue