Browse Source

Revamp the OpenIddict services registration process and introduce new builders to separate the server APIs from the core APIs

pull/590/head
Kévin Chalet 8 years ago
parent
commit
7bca2c06ed
  1. 9
      OpenIddict.sln
  2. 4
      samples/Mvc.Server/Controllers/AuthorizationController.cs
  3. 2
      samples/Mvc.Server/Controllers/UserinfoController.cs
  4. 112
      samples/Mvc.Server/Startup.cs
  5. 23
      src/OpenIddict.Abstractions/OpenIddict.Abstractions.csproj
  6. 38
      src/OpenIddict.Abstractions/OpenIddictBuilder.cs
  7. 2
      src/OpenIddict.Abstractions/OpenIddictConstants.cs
  8. 56
      src/OpenIddict.Abstractions/OpenIddictExtensions.cs
  9. 18
      src/OpenIddict.Abstractions/Resolvers/IOpenIddictApplicationStoreResolver.cs
  10. 18
      src/OpenIddict.Abstractions/Resolvers/IOpenIddictAuthorizationStoreResolver.cs
  11. 18
      src/OpenIddict.Abstractions/Resolvers/IOpenIddictScopeStoreResolver.cs
  12. 18
      src/OpenIddict.Abstractions/Resolvers/IOpenIddictTokenStoreResolver.cs
  13. 2
      src/OpenIddict.Abstractions/Stores/IOpenIddictApplicationStore.cs
  14. 2
      src/OpenIddict.Abstractions/Stores/IOpenIddictAuthorizationStore.cs
  15. 2
      src/OpenIddict.Abstractions/Stores/IOpenIddictScopeStore.cs
  16. 2
      src/OpenIddict.Abstractions/Stores/IOpenIddictTokenStore.cs
  17. 15
      src/OpenIddict.Core/Managers/OpenIddictApplicationManager.cs
  18. 16
      src/OpenIddict.Core/Managers/OpenIddictAuthorizationManager.cs
  19. 15
      src/OpenIddict.Core/Managers/OpenIddictScopeManager.cs
  20. 16
      src/OpenIddict.Core/Managers/OpenIddictTokenManager.cs
  21. 4
      src/OpenIddict.Core/OpenIddict.Core.csproj
  22. 327
      src/OpenIddict.Core/OpenIddictBuilder.cs
  23. 628
      src/OpenIddict.Core/OpenIddictCoreBuilder.cs
  24. 73
      src/OpenIddict.Core/OpenIddictCoreExtensions.cs
  25. 67
      src/OpenIddict.Core/OpenIddictCoreHelpers.cs
  26. 33
      src/OpenIddict.Core/OpenIddictCoreOptions.cs
  27. 89
      src/OpenIddict.Core/OpenIddictExtensions.cs
  28. 44
      src/OpenIddict.Core/Resolvers/OpenIddictApplicationStoreResolver.cs
  29. 44
      src/OpenIddict.Core/Resolvers/OpenIddictAuthorizationStoreResolver.cs
  30. 44
      src/OpenIddict.Core/Resolvers/OpenIddictScopeStoreResolver.cs
  31. 44
      src/OpenIddict.Core/Resolvers/OpenIddictTokenStoreResolver.cs
  32. 1
      src/OpenIddict.EntityFramework/OpenIddict.EntityFramework.csproj
  33. 161
      src/OpenIddict.EntityFramework/OpenIddictExtensions.cs
  34. 65
      src/OpenIddict.EntityFramework/Resolvers/OpenIddictApplicationStoreResolver.cs
  35. 65
      src/OpenIddict.EntityFramework/Resolvers/OpenIddictAuthorizationStoreResolver.cs
  36. 63
      src/OpenIddict.EntityFramework/Resolvers/OpenIddictScopeStoreResolver.cs
  37. 65
      src/OpenIddict.EntityFramework/Resolvers/OpenIddictTokenStoreResolver.cs
  38. 2
      src/OpenIddict.EntityFramework/Stores/OpenIddictAuthorizationStore.cs
  39. 2
      src/OpenIddict.EntityFramework/Stores/OpenIddictTokenStore.cs
  40. 1
      src/OpenIddict.EntityFrameworkCore/OpenIddict.EntityFrameworkCore.csproj
  41. 161
      src/OpenIddict.EntityFrameworkCore/OpenIddictExtensions.cs
  42. 65
      src/OpenIddict.EntityFrameworkCore/Resolvers/OpenIddictApplicationStoreResolver.cs
  43. 65
      src/OpenIddict.EntityFrameworkCore/Resolvers/OpenIddictAuthorizationStoreResolver.cs
  44. 63
      src/OpenIddict.EntityFrameworkCore/Resolvers/OpenIddictScopeStoreResolver.cs
  45. 65
      src/OpenIddict.EntityFrameworkCore/Resolvers/OpenIddictTokenStoreResolver.cs
  46. 2
      src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictAuthorizationStore.cs
  47. 1
      src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictTokenStore.cs
  48. 5
      src/OpenIddict.Mvc/OpenIddictExtensions.cs
  49. 8
      src/OpenIddict.Server/Internal/OpenIddictServerHandler.cs
  50. 36
      src/OpenIddict.Server/Internal/OpenIddictServerInitializer.cs
  51. 14
      src/OpenIddict.Server/Internal/OpenIddictServerProvider.Authentication.cs
  52. 8
      src/OpenIddict.Server/Internal/OpenIddictServerProvider.Discovery.cs
  53. 11
      src/OpenIddict.Server/Internal/OpenIddictServerProvider.Exchange.cs
  54. 14
      src/OpenIddict.Server/Internal/OpenIddictServerProvider.Helpers.cs
  55. 8
      src/OpenIddict.Server/Internal/OpenIddictServerProvider.Introspection.cs
  56. 10
      src/OpenIddict.Server/Internal/OpenIddictServerProvider.Revocation.cs
  57. 16
      src/OpenIddict.Server/Internal/OpenIddictServerProvider.Serialization.cs
  58. 12
      src/OpenIddict.Server/Internal/OpenIddictServerProvider.Session.cs
  59. 4
      src/OpenIddict.Server/Internal/OpenIddictServerProvider.Userinfo.cs
  60. 13
      src/OpenIddict.Server/Internal/OpenIddictServerProvider.cs
  61. 1008
      src/OpenIddict.Server/OpenIddictExtensions.cs
  62. 653
      src/OpenIddict.Server/OpenIddictServerBuilder.cs
  63. 123
      src/OpenIddict.Server/OpenIddictServerExtensions.cs
  64. 28
      src/OpenIddict.Server/OpenIddictServerOptions.cs
  65. 3
      src/OpenIddict.Stores/OpenIddict.Stores.csproj
  66. 2
      src/OpenIddict.Stores/Stores/OpenIddictApplicationStore.cs
  67. 2
      src/OpenIddict.Stores/Stores/OpenIddictAuthorizationStore.cs
  68. 2
      src/OpenIddict.Stores/Stores/OpenIddictScopeStore.cs
  69. 2
      src/OpenIddict.Stores/Stores/OpenIddictTokenStore.cs
  70. 84
      src/OpenIddict/OpenIddictExtensions.cs
  71. 329
      test/OpenIddict.Core.Tests/OpenIddictBuilderTests.cs
  72. 487
      test/OpenIddict.Core.Tests/OpenIddictCoreBuilderTests.cs
  73. 48
      test/OpenIddict.Core.Tests/OpenIddictExtensionsTests.cs
  74. 162
      test/OpenIddict.EntityFramework.Tests/OpenIddictExtensionsTests.cs
  75. 162
      test/OpenIddict.EntityFrameworkCore.Tests/OpenIddictExtensionsTests.cs
  76. 1
      test/OpenIddict.Mvc.Tests/OpenIddict.Mvc.Tests.csproj
  77. 2
      test/OpenIddict.Mvc.Tests/OpenIddictExtensionsTests.cs
  78. 10
      test/OpenIddict.Server.Tests/Internal/OpenIddictServerInitializerTests.cs
  79. 6
      test/OpenIddict.Server.Tests/Internal/OpenIddictServerProviderTests.Authentication.cs
  80. 7
      test/OpenIddict.Server.Tests/Internal/OpenIddictServerProviderTests.Discovery.cs
  81. 5
      test/OpenIddict.Server.Tests/Internal/OpenIddictServerProviderTests.Exchange.cs
  82. 5
      test/OpenIddict.Server.Tests/Internal/OpenIddictServerProviderTests.Introspection.cs
  83. 5
      test/OpenIddict.Server.Tests/Internal/OpenIddictServerProviderTests.Revocation.cs
  84. 5
      test/OpenIddict.Server.Tests/Internal/OpenIddictServerProviderTests.Serialization.cs
  85. 5
      test/OpenIddict.Server.Tests/Internal/OpenIddictServerProviderTests.Session.cs
  86. 4
      test/OpenIddict.Server.Tests/Internal/OpenIddictServerProviderTests.Userinfo.cs
  87. 113
      test/OpenIddict.Server.Tests/Internal/OpenIddictServerProviderTests.cs
  88. 44
      test/OpenIddict.Server.Tests/OpenIddictServerBuilderTests.cs
  89. 36
      test/OpenIddict.Tests/OpenIddictExtensionsTests.cs

9
OpenIddict.sln

@ -50,7 +50,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenIddict.Stores", "src\Op
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenIddict.Server", "src\OpenIddict.Server\OpenIddict.Server.csproj", "{21A7F241-CBE7-4F5C-9787-F2C50D135AEA}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenIddict.Server.Tests", "test\OpenIddict.Server.Tests\OpenIddict.Server.Tests.csproj", "{07B02B98-8A68-432D-A932-48E6D52B221A}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenIddict.Server.Tests", "test\OpenIddict.Server.Tests\OpenIddict.Server.Tests.csproj", "{07B02B98-8A68-432D-A932-48E6D52B221A}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenIddict.Abstractions", "src\OpenIddict.Abstractions\OpenIddict.Abstractions.csproj", "{886A16DA-C9CF-4979-9B38-D06DF8A714B6}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@ -122,6 +124,10 @@ Global
{07B02B98-8A68-432D-A932-48E6D52B221A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{07B02B98-8A68-432D-A932-48E6D52B221A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{07B02B98-8A68-432D-A932-48E6D52B221A}.Release|Any CPU.Build.0 = Release|Any CPU
{886A16DA-C9CF-4979-9B38-D06DF8A714B6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{886A16DA-C9CF-4979-9B38-D06DF8A714B6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{886A16DA-C9CF-4979-9B38-D06DF8A714B6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{886A16DA-C9CF-4979-9B38-D06DF8A714B6}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -143,6 +149,7 @@ Global
{275D888A-B4C8-4E93-AC4B-B1AA25D98159} = {D544447C-D701-46BB-9A5B-C76C612A596B}
{21A7F241-CBE7-4F5C-9787-F2C50D135AEA} = {D544447C-D701-46BB-9A5B-C76C612A596B}
{07B02B98-8A68-432D-A932-48E6D52B221A} = {5FC71D6A-A994-4F62-977F-88A7D25379D7}
{886A16DA-C9CF-4979-9B38-D06DF8A714B6} = {D544447C-D701-46BB-9A5B-C76C612A596B}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {A710059F-0466-4D48-9B3A-0EF4F840B616}

4
samples/Mvc.Server/Controllers/AuthorizationController.cs

@ -5,7 +5,6 @@
*/
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Security.Claims;
using System.Threading.Tasks;
@ -20,6 +19,7 @@ using Mvc.Server.Helpers;
using Mvc.Server.Models;
using Mvc.Server.ViewModels.Authorization;
using Mvc.Server.ViewModels.Shared;
using OpenIddict.Abstractions;
using OpenIddict.Core;
using OpenIddict.Models;
@ -67,7 +67,7 @@ namespace Mvc.Server
// the original authorization request from the cache.
return View(new AuthorizeViewModel
{
ApplicationName = application.DisplayName,
ApplicationName = await _applicationManager.GetDisplayNameAsync(application),
RequestId = request.RequestId,
Scope = request.Scope
});

2
samples/Mvc.Server/Controllers/UserinfoController.cs

@ -6,7 +6,7 @@ using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Mvc.Server.Models;
using Newtonsoft.Json.Linq;
using OpenIddict.Core;
using OpenIddict.Abstractions;
namespace Mvc.Server.Controllers
{

112
samples/Mvc.Server/Startup.cs

@ -8,6 +8,7 @@ using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Mvc.Server.Models;
using Mvc.Server.Services;
using OpenIddict.Abstractions;
using OpenIddict.Core;
using OpenIddict.Models;
@ -67,57 +68,66 @@ namespace Mvc.Server
.AddOAuthValidation();
// Register the OpenIddict services.
services.AddOpenIddict(options =>
{
// Register the Entity Framework stores.
options.AddEntityFrameworkCoreStores<ApplicationDbContext>();
// Register the ASP.NET Core MVC binder used by OpenIddict.
// Note: if you don't call this method, you won't be able to
// bind OpenIdConnectRequest or OpenIdConnectResponse parameters.
options.AddMvcBinders();
// Enable the authorization, logout, token and userinfo endpoints.
options.EnableAuthorizationEndpoint("/connect/authorize")
.EnableLogoutEndpoint("/connect/logout")
.EnableTokenEndpoint("/connect/token")
.EnableUserinfoEndpoint("/api/userinfo");
// Note: the Mvc.Client sample only uses the code flow and the password flow, but you
// can enable the other flows if you need to support implicit or client credentials.
options.AllowAuthorizationCodeFlow()
.AllowPasswordFlow()
.AllowRefreshTokenFlow();
// Mark the "email", "profile" and "roles" scopes as supported scopes.
options.RegisterScopes(OpenIdConnectConstants.Scopes.Email,
OpenIdConnectConstants.Scopes.Profile,
OpenIddictConstants.Scopes.Roles);
// Make the "client_id" parameter mandatory when sending a token request.
options.RequireClientIdentification();
// When request caching is enabled, authorization and logout requests
// are stored in the distributed cache by OpenIddict and the user agent
// is redirected to the same page with a single parameter (request_id).
// This allows flowing large OpenID Connect requests even when using
// an external authentication provider like Google, Facebook or Twitter.
options.EnableRequestCaching();
// Enable scope validation, so that authorization and token requests
// that specify unregistered scopes are automatically rejected.
options.EnableScopeValidation();
// During development, you can disable the HTTPS requirement.
options.DisableHttpsRequirement();
// Note: to use JWT access tokens instead of the default
// encrypted format, the following lines are required:
//
// options.UseJsonWebTokens();
// options.AddEphemeralSigningKey();
});
services.AddOpenIddict()
// Register the OpenIddict core services.
.AddCore(options =>
{
// Configure OpenIddict to use the default models.
options.UseDefaultModels();
// Register the Entity Framework stores.
options.AddEntityFrameworkCoreStores<ApplicationDbContext>();
})
// Register the OpenIddict server handler.
.AddServer(options =>
{
// Register the ASP.NET Core MVC binder used by OpenIddict.
// Note: if you don't call this method, you won't be able to
// bind OpenIdConnectRequest or OpenIdConnectResponse parameters.
options.AddMvcBinders();
// Enable the authorization, logout, token and userinfo endpoints.
options.EnableAuthorizationEndpoint("/connect/authorize")
.EnableLogoutEndpoint("/connect/logout")
.EnableTokenEndpoint("/connect/token")
.EnableUserinfoEndpoint("/api/userinfo");
// Note: the Mvc.Client sample only uses the code flow and the password flow, but you
// can enable the other flows if you need to support implicit or client credentials.
options.AllowAuthorizationCodeFlow()
.AllowPasswordFlow()
.AllowRefreshTokenFlow();
// Mark the "email", "profile" and "roles" scopes as supported scopes.
options.RegisterScopes(OpenIdConnectConstants.Scopes.Email,
OpenIdConnectConstants.Scopes.Profile,
OpenIddictConstants.Scopes.Roles);
// Make the "client_id" parameter mandatory when sending a token request.
options.RequireClientIdentification();
// When request caching is enabled, authorization and logout requests
// are stored in the distributed cache by OpenIddict and the user agent
// is redirected to the same page with a single parameter (request_id).
// This allows flowing large OpenID Connect requests even when using
// an external authentication provider like Google, Facebook or Twitter.
options.EnableRequestCaching();
// Enable scope validation, so that authorization and token requests
// that specify unregistered scopes are automatically rejected.
options.EnableScopeValidation();
// During development, you can disable the HTTPS requirement.
options.DisableHttpsRequirement();
// Note: to use JWT access tokens instead of the default
// encrypted format, the following lines are required:
//
// options.UseJsonWebTokens();
// options.AddEphemeralSigningKey();
});
services.AddTransient<IEmailSender, AuthMessageSender>();
services.AddTransient<ISmsSender, AuthMessageSender>();

23
src/OpenIddict.Abstractions/OpenIddict.Abstractions.csproj

@ -0,0 +1,23 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\build\packages.props" />
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>
<PropertyGroup>
<Description>OpenIddict's abstractions.</Description>
<Authors>Kévin Chalet</Authors>
<PackageTags>aspnetcore;authentication;jwt;openidconnect;openiddict;security</PackageTags>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="JetBrains.Annotations" Version="$(JetBrainsVersion)" PrivateAssets="All" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="$(AspNetCoreVersion)" />
<PackageReference Include="Newtonsoft.Json" Version="$(JsonNetVersion)" />
<PackageReference Include="System.Collections.Immutable" Version="$(ImmutableCollectionsVersion)" />
<PackageReference Include="System.Threading.Tasks.Extensions" Version="$(TasksExtensionsVersion)" />
</ItemGroup>
</Project>

38
src/OpenIddict.Abstractions/OpenIddictBuilder.cs

@ -0,0 +1,38 @@
/*
* 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 JetBrains.Annotations;
namespace Microsoft.Extensions.DependencyInjection
{
/// <summary>
/// Provides a shared entry point allowing to configure the OpenIddict services.
/// </summary>
public class OpenIddictBuilder
{
/// <summary>
/// Initializes a new instance of <see cref="OpenIddictBuilder"/>.
/// </summary>
/// <param name="services">The services collection.</param>
public OpenIddictBuilder([NotNull] IServiceCollection services)
{
if (services == null)
{
throw new ArgumentNullException(nameof(services));
}
Services = services;
}
/// <summary>
/// Gets the services collection.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
public IServiceCollection Services { get; }
}
}

2
src/OpenIddict.Core/OpenIddictConstants.cs → src/OpenIddict.Abstractions/OpenIddictConstants.cs

@ -4,7 +4,7 @@
* the license and the contributors participating to this project.
*/
namespace OpenIddict.Core
namespace OpenIddict.Abstractions
{
public static class OpenIddictConstants
{

56
src/OpenIddict.Abstractions/OpenIddictExtensions.cs

@ -0,0 +1,56 @@
/*
* 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 JetBrains.Annotations;
namespace Microsoft.Extensions.DependencyInjection
{
public static class OpenIddictExtensions
{
/// <summary>
/// Provides a common entry point for registering the OpenIddict services.
/// </summary>
/// <param name="services">The services collection.</param>
/// <remarks>This extension can be safely called multiple times.</remarks>
/// <returns>The <see cref="OpenIddictBuilder"/>.</returns>
public static OpenIddictBuilder AddOpenIddict([NotNull] this IServiceCollection services)
{
if (services == null)
{
throw new ArgumentNullException(nameof(services));
}
return new OpenIddictBuilder(services);
}
/// <summary>
/// Provides a common entry point for registering the OpenIddict services.
/// </summary>
/// <param name="services">The services collection.</param>
/// <param name="configuration">The configuration delegate used to register new services.</param>
/// <remarks>This extension can be safely called multiple times.</remarks>
/// <returns>The <see cref="OpenIddictBuilder"/>.</returns>
public static IServiceCollection AddOpenIddict(
[NotNull] this IServiceCollection services,
[NotNull] Action<OpenIddictBuilder> configuration)
{
if (services == null)
{
throw new ArgumentNullException(nameof(services));
}
if (configuration == null)
{
throw new ArgumentNullException(nameof(configuration));
}
configuration(services.AddOpenIddict());
return services;
}
}
}

18
src/OpenIddict.Abstractions/Resolvers/IOpenIddictApplicationStoreResolver.cs

@ -0,0 +1,18 @@
using System;
namespace OpenIddict.Abstractions
{
/// <summary>
/// Exposes a method allowing to resolve an application store.
/// </summary>
public interface IOpenIddictApplicationStoreResolver
{
/// <summary>
/// Returns an application store compatible with the specified application type or throws an
/// <see cref="InvalidOperationException"/> if no store can be built using the specified type.
/// </summary>
/// <typeparam name="TApplication">The type of the Application entity.</typeparam>
/// <returns>An <see cref="IOpenIddictApplicationStore{TApplication}"/>.</returns>
IOpenIddictApplicationStore<TApplication> Get<TApplication>() where TApplication : class;
}
}

18
src/OpenIddict.Abstractions/Resolvers/IOpenIddictAuthorizationStoreResolver.cs

@ -0,0 +1,18 @@
using System;
namespace OpenIddict.Abstractions
{
/// <summary>
/// Exposes a method allowing to resolve an authorization store.
/// </summary>
public interface IOpenIddictAuthorizationStoreResolver
{
/// <summary>
/// Returns an authorization store compatible with the specified authorization type or throws an
/// <see cref="InvalidOperationException"/> if no store can be built using the specified type.
/// </summary>
/// <typeparam name="TAuthorization">The type of the Authorization entity.</typeparam>
/// <returns>An <see cref="IOpenIddictAuthorizationStore{TAuthorization}"/>.</returns>
IOpenIddictAuthorizationStore<TAuthorization> Get<TAuthorization>() where TAuthorization : class;
}
}

18
src/OpenIddict.Abstractions/Resolvers/IOpenIddictScopeStoreResolver.cs

@ -0,0 +1,18 @@
using System;
namespace OpenIddict.Abstractions
{
/// <summary>
/// Exposes a method allowing to resolve a scope store.
/// </summary>
public interface IOpenIddictScopeStoreResolver
{
/// <summary>
/// Returns a scope store compatible with the specified scope type or throws an
/// <see cref="InvalidOperationException"/> if no store can be built using the specified type.
/// </summary>
/// <typeparam name="TScope">The type of the Scope entity.</typeparam>
/// <returns>An <see cref="IOpenIddictScopeStore{TScope}"/>.</returns>
IOpenIddictScopeStore<TScope> Get<TScope>() where TScope : class;
}
}

18
src/OpenIddict.Abstractions/Resolvers/IOpenIddictTokenStoreResolver.cs

@ -0,0 +1,18 @@
using System;
namespace OpenIddict.Abstractions
{
/// <summary>
/// Exposes a method allowing to resolve a token store.
/// </summary>
public interface IOpenIddictTokenStoreResolver
{
/// <summary>
/// Returns a token store compatible with the specified token type or throws an
/// <see cref="InvalidOperationException"/> if no store can be built using the specified type.
/// </summary>
/// <typeparam name="TToken">The type of the Token entity.</typeparam>
/// <returns>An <see cref="IOpenIddictTokenStore{TToken}"/>.</returns>
IOpenIddictTokenStore<TToken> Get<TToken>() where TToken : class;
}
}

2
src/OpenIddict.Core/Stores/IOpenIddictApplicationStore.cs → src/OpenIddict.Abstractions/Stores/IOpenIddictApplicationStore.cs

@ -12,7 +12,7 @@ using System.Threading.Tasks;
using JetBrains.Annotations;
using Newtonsoft.Json.Linq;
namespace OpenIddict.Core
namespace OpenIddict.Abstractions
{
/// <summary>
/// Provides methods allowing to manage the applications stored in a database.

2
src/OpenIddict.Core/Stores/IOpenIddictAuthorizationStore.cs → src/OpenIddict.Abstractions/Stores/IOpenIddictAuthorizationStore.cs

@ -12,7 +12,7 @@ using System.Threading.Tasks;
using JetBrains.Annotations;
using Newtonsoft.Json.Linq;
namespace OpenIddict.Core
namespace OpenIddict.Abstractions
{
/// <summary>
/// Provides methods allowing to manage the authorizations stored in a database.

2
src/OpenIddict.Core/Stores/IOpenIddictScopeStore.cs → src/OpenIddict.Abstractions/Stores/IOpenIddictScopeStore.cs

@ -12,7 +12,7 @@ using System.Threading.Tasks;
using JetBrains.Annotations;
using Newtonsoft.Json.Linq;
namespace OpenIddict.Core
namespace OpenIddict.Abstractions
{
/// <summary>
/// Provides methods allowing to manage the scopes stored in a database.

2
src/OpenIddict.Core/Stores/IOpenIddictTokenStore.cs → src/OpenIddict.Abstractions/Stores/IOpenIddictTokenStore.cs

@ -12,7 +12,7 @@ using System.Threading.Tasks;
using JetBrains.Annotations;
using Newtonsoft.Json.Linq;
namespace OpenIddict.Core
namespace OpenIddict.Abstractions
{
/// <summary>
/// Provides methods allowing to manage the tokens stored in a database.

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

@ -13,6 +13,8 @@ using System.Threading.Tasks;
using CryptoHelper;
using JetBrains.Annotations;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using OpenIddict.Abstractions;
namespace OpenIddict.Core
{
@ -23,11 +25,13 @@ namespace OpenIddict.Core
public class OpenIddictApplicationManager<TApplication> where TApplication : class
{
public OpenIddictApplicationManager(
[NotNull] IOpenIddictApplicationStore<TApplication> store,
[NotNull] ILogger<OpenIddictApplicationManager<TApplication>> logger)
[NotNull] IOpenIddictApplicationStoreResolver resolver,
[NotNull] ILogger<OpenIddictApplicationManager<TApplication>> logger,
[NotNull] IOptionsMonitor<OpenIddictCoreOptions> options)
{
Store = store;
Store = resolver.Get<TApplication>();
Logger = logger;
Options = options;
}
/// <summary>
@ -35,6 +39,11 @@ namespace OpenIddict.Core
/// </summary>
protected ILogger Logger { get; }
/// <summary>
/// Gets the options associated with the current manager.
/// </summary>
protected IOptionsMonitor<OpenIddictCoreOptions> Options { get; }
/// <summary>
/// Gets the store associated with the current manager.
/// </summary>

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

@ -5,7 +5,6 @@
*/
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.ComponentModel.DataAnnotations;
using System.Linq;
@ -14,6 +13,8 @@ using System.Threading;
using System.Threading.Tasks;
using JetBrains.Annotations;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using OpenIddict.Abstractions;
namespace OpenIddict.Core
{
@ -24,11 +25,13 @@ namespace OpenIddict.Core
public class OpenIddictAuthorizationManager<TAuthorization> where TAuthorization : class
{
public OpenIddictAuthorizationManager(
[NotNull] IOpenIddictAuthorizationStore<TAuthorization> store,
[NotNull] ILogger<OpenIddictAuthorizationManager<TAuthorization>> logger)
[NotNull] IOpenIddictAuthorizationStoreResolver resolver,
[NotNull] ILogger<OpenIddictAuthorizationManager<TAuthorization>> logger,
[NotNull] IOptionsMonitor<OpenIddictCoreOptions> options)
{
Store = resolver.Get<TAuthorization>();
Logger = logger;
Store = store;
Options = options;
}
/// <summary>
@ -36,6 +39,11 @@ namespace OpenIddict.Core
/// </summary>
protected ILogger Logger { get; }
/// <summary>
/// Gets the options associated with the current manager.
/// </summary>
protected IOptionsMonitor<OpenIddictCoreOptions> Options { get; }
/// <summary>
/// Gets the store associated with the current manager.
/// </summary>

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

@ -13,6 +13,8 @@ using System.Threading;
using System.Threading.Tasks;
using JetBrains.Annotations;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using OpenIddict.Abstractions;
namespace OpenIddict.Core
{
@ -23,11 +25,13 @@ namespace OpenIddict.Core
public class OpenIddictScopeManager<TScope> where TScope : class
{
public OpenIddictScopeManager(
[NotNull] IOpenIddictScopeStore<TScope> store,
[NotNull] ILogger<OpenIddictScopeManager<TScope>> logger)
[NotNull] IOpenIddictScopeStoreResolver resolver,
[NotNull] ILogger<OpenIddictScopeManager<TScope>> logger,
[NotNull] IOptionsMonitor<OpenIddictCoreOptions> options)
{
Store = resolver.Get<TScope>();
Logger = logger;
Store = store;
Options = options;
}
/// <summary>
@ -35,6 +39,11 @@ namespace OpenIddict.Core
/// </summary>
protected ILogger Logger { get; }
/// <summary>
/// Gets the options associated with the current manager.
/// </summary>
protected IOptionsMonitor<OpenIddictCoreOptions> Options { get; }
/// <summary>
/// Gets the store associated with the current manager.
/// </summary>

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

@ -5,7 +5,6 @@
*/
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.ComponentModel.DataAnnotations;
using System.Linq;
@ -15,6 +14,8 @@ using System.Threading;
using System.Threading.Tasks;
using JetBrains.Annotations;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using OpenIddict.Abstractions;
namespace OpenIddict.Core
{
@ -25,11 +26,13 @@ namespace OpenIddict.Core
public class OpenIddictTokenManager<TToken> where TToken : class
{
public OpenIddictTokenManager(
[NotNull] IOpenIddictTokenStore<TToken> store,
[NotNull] ILogger<OpenIddictTokenManager<TToken>> logger)
[NotNull] IOpenIddictTokenStoreResolver resolver,
[NotNull] ILogger<OpenIddictTokenManager<TToken>> logger,
[NotNull] IOptionsMonitor<OpenIddictCoreOptions> options)
{
Store = resolver.Get<TToken>();
Logger = logger;
Store = store;
Options = options;
}
/// <summary>
@ -37,6 +40,11 @@ namespace OpenIddict.Core
/// </summary>
protected ILogger Logger { get; }
/// <summary>
/// Gets the options associated with the current manager.
/// </summary>
protected IOptionsMonitor<OpenIddictCoreOptions> Options { get; }
/// <summary>
/// Gets the store associated with the current manager.
/// </summary>

4
src/OpenIddict.Core/OpenIddict.Core.csproj

@ -12,6 +12,10 @@
<PackageTags>aspnetcore;authentication;jwt;openidconnect;openiddict;security</PackageTags>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\OpenIddict.Abstractions\OpenIddict.Abstractions.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="CryptoHelper" Version="$(CryptoHelperVersion)" />
<PackageReference Include="JetBrains.Annotations" Version="$(JetBrainsVersion)" PrivateAssets="All" />

327
src/OpenIddict.Core/OpenIddictBuilder.cs

@ -1,327 +0,0 @@
/*
* 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 JetBrains.Annotations;
using OpenIddict.Core;
namespace Microsoft.Extensions.DependencyInjection
{
/// <summary>
/// Exposes the necessary methods required to configure OpenIddict.
/// </summary>
public class OpenIddictBuilder
{
/// <summary>
/// Initializes a new instance of <see cref="OpenIddictBuilder"/>.
/// </summary>
/// <param name="services">The services collection.</param>
public OpenIddictBuilder([NotNull] IServiceCollection services)
{
if (services == null)
{
throw new ArgumentNullException(nameof(services));
}
Services = services;
}
/// <summary>
/// Gets or sets the type corresponding to the Application entity.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
public Type ApplicationType { get; set; }
/// <summary>
/// Gets or sets the type corresponding to the Authorization entity.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
public Type AuthorizationType { get; set; }
/// <summary>
/// Gets or sets the type corresponding to the Scope entity.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
public Type ScopeType { get; set; }
/// <summary>
/// Gets or sets the type corresponding to the Token entity.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
public Type TokenType { get; set; }
/// <summary>
/// Gets the services collection.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
public IServiceCollection Services { get; }
/// <summary>
/// Adds a custom application manager derived from
/// <see cref="OpenIddictApplicationManager{TApplication}"/>.
/// </summary>
/// <typeparam name="TManager">The type of the custom manager.</typeparam>
/// <returns>The <see cref="OpenIddictBuilder"/>.</returns>
public OpenIddictBuilder AddApplicationManager<TManager>() where TManager : class
=> AddApplicationManager(typeof(TManager));
/// <summary>
/// Adds a custom application manager derived from
/// <see cref="OpenIddictApplicationManager{TApplication}"/>.
/// </summary>
/// <param name="type">The type of the custom manager.</param>
/// <returns>The <see cref="OpenIddictBuilder"/>.</returns>
public virtual OpenIddictBuilder AddApplicationManager([NotNull] Type type)
{
if (type == null)
{
throw new ArgumentNullException(nameof(type));
}
var contract = typeof(OpenIddictApplicationManager<>).MakeGenericType(ApplicationType);
if (!contract.IsAssignableFrom(type))
{
throw new InvalidOperationException("The specified type is invalid.");
}
Services.AddScoped(contract, type);
return this;
}
/// <summary>
/// Adds a custom application store derived from
/// <see cref="IOpenIddictApplicationStore{TApplication}"/>.
/// </summary>
/// <typeparam name="TStore">The type of the custom store.</typeparam>
/// <returns>The <see cref="OpenIddictBuilder"/>.</returns>
public OpenIddictBuilder AddApplicationStore<TStore>() where TStore : class
=> AddApplicationStore(typeof(TStore));
/// <summary>
/// Adds a custom application store derived from
/// <see cref="IOpenIddictApplicationStore{TApplication}"/>.
/// </summary>
/// <param name="type">The type of the custom store.</param>
/// <returns>The <see cref="OpenIddictBuilder"/>.</returns>
public virtual OpenIddictBuilder AddApplicationStore([NotNull] Type type)
{
if (type == null)
{
throw new ArgumentNullException(nameof(type));
}
var contract = typeof(IOpenIddictApplicationStore<>).MakeGenericType(ApplicationType);
if (!contract.IsAssignableFrom(type))
{
throw new InvalidOperationException("The specified type is invalid.");
}
Services.AddScoped(contract, type);
return this;
}
/// <summary>
/// Adds a custom authorization manager derived from
/// <see cref="OpenIddictAuthorizationManager{TAuthorization}"/>.
/// </summary>
/// <typeparam name="TManager">The type of the custom manager.</typeparam>
/// <returns>The <see cref="OpenIddictBuilder"/>.</returns>
public OpenIddictBuilder AddAuthorizationManager<TManager>() where TManager : class
=> AddAuthorizationManager(typeof(TManager));
/// <summary>
/// Adds a custom authorization manager derived from
/// <see cref="OpenIddictAuthorizationManager{TAuthorization}"/>.
/// </summary>
/// <param name="type">The type of the custom manager.</param>
/// <returns>The <see cref="OpenIddictBuilder"/>.</returns>
public virtual OpenIddictBuilder AddAuthorizationManager([NotNull] Type type)
{
if (type == null)
{
throw new ArgumentNullException(nameof(type));
}
var contract = typeof(OpenIddictAuthorizationManager<>).MakeGenericType(AuthorizationType);
if (!contract.IsAssignableFrom(type))
{
throw new InvalidOperationException("The specified type is invalid.");
}
Services.AddScoped(contract, type);
return this;
}
/// <summary>
/// Adds a custom authorization store derived from
/// <see cref="IOpenIddictAuthorizationStore{TAuthorization}"/>.
/// </summary>
/// <typeparam name="TStore">The type of the custom store.</typeparam>
/// <returns>The <see cref="OpenIddictBuilder"/>.</returns>
public OpenIddictBuilder AddAuthorizationStore<TStore>() where TStore : class
=> AddAuthorizationStore(typeof(TStore));
/// <summary>
/// Adds a custom authorization store derived from
/// <see cref="IOpenIddictAuthorizationStore{TAuthorization}"/>.
/// </summary>
/// <param name="type">The type of the custom store.</param>
/// <returns>The <see cref="OpenIddictBuilder"/>.</returns>
public virtual OpenIddictBuilder AddAuthorizationStore([NotNull] Type type)
{
if (type == null)
{
throw new ArgumentNullException(nameof(type));
}
var contract = typeof(IOpenIddictAuthorizationStore<>).MakeGenericType(AuthorizationType);
if (!contract.IsAssignableFrom(type))
{
throw new InvalidOperationException("The specified type is invalid.");
}
Services.AddScoped(contract, type);
return this;
}
/// <summary>
/// Adds a custom scope manager derived from
/// <see cref="OpenIddictScopeManager{TScope}"/>.
/// </summary>
/// <typeparam name="TManager">The type of the custom manager.</typeparam>
/// <returns>The <see cref="OpenIddictBuilder"/>.</returns>
public OpenIddictBuilder AddScopeManager<TManager>() where TManager : class
=> AddScopeManager(typeof(TManager));
/// <summary>
/// Adds a custom scope manager derived from
/// <see cref="OpenIddictScopeManager{TScope}"/>.
/// </summary>
/// <param name="type">The type of the custom manager.</param>
/// <returns>The <see cref="OpenIddictBuilder"/>.</returns>
public virtual OpenIddictBuilder AddScopeManager([NotNull] Type type)
{
if (type == null)
{
throw new ArgumentNullException(nameof(type));
}
var contract = typeof(OpenIddictScopeManager<>).MakeGenericType(ScopeType);
if (!contract.IsAssignableFrom(type))
{
throw new InvalidOperationException("The specified type is invalid.");
}
Services.AddScoped(contract, type);
return this;
}
/// <summary>
/// Adds a custom scope store derived from
/// <see cref="IOpenIddictScopeStore{TScope}"/>.
/// </summary>
/// <typeparam name="TStore">The type of the custom store.</typeparam>
/// <returns>The <see cref="OpenIddictBuilder"/>.</returns>
public OpenIddictBuilder AddScopeStore<TStore>() where TStore : class
=> AddScopeStore(typeof(TStore));
/// <summary>
/// Adds a custom scope store derived from
/// <see cref="IOpenIddictScopeStore{TScope}"/>.
/// </summary>
/// <param name="type">The type of the custom store.</param>
/// <returns>The <see cref="OpenIddictBuilder"/>.</returns>
public virtual OpenIddictBuilder AddScopeStore([NotNull] Type type)
{
if (type == null)
{
throw new ArgumentNullException(nameof(type));
}
var contract = typeof(IOpenIddictScopeStore<>).MakeGenericType(ScopeType);
if (!contract.IsAssignableFrom(type))
{
throw new InvalidOperationException("The specified type is invalid.");
}
Services.AddScoped(contract, type);
return this;
}
/// <summary>
/// Adds a custom token manager derived from
/// <see cref="OpenIddictTokenManager{TToken}"/>.
/// </summary>
/// <typeparam name="TManager">The type of the custom manager.</typeparam>
/// <returns>The <see cref="OpenIddictBuilder"/>.</returns>
public OpenIddictBuilder AddTokenManager<TManager>() where TManager : class
=> AddTokenManager(typeof(TManager));
/// <summary>
/// Adds a custom token manager derived from
/// <see cref="OpenIddictTokenManager{TToken}"/>.
/// </summary>
/// <param name="type">The type of the custom manager.</param>
/// <returns>The <see cref="OpenIddictBuilder"/>.</returns>
public virtual OpenIddictBuilder AddTokenManager([NotNull] Type type)
{
if (type == null)
{
throw new ArgumentNullException(nameof(type));
}
var contract = typeof(OpenIddictTokenManager<>).MakeGenericType(TokenType);
if (!contract.IsAssignableFrom(type))
{
throw new InvalidOperationException("The specified type is invalid.");
}
Services.AddScoped(contract, type);
return this;
}
/// <summary>
/// Adds a custom token store derived from
/// <see cref="IOpenIddictTokenStore{TToken}"/>.
/// </summary>
/// <typeparam name="TStore">The type of the custom store.</typeparam>
/// <returns>The <see cref="OpenIddictBuilder"/>.</returns>
public OpenIddictBuilder AddTokenStore<TStore>() where TStore : class
=> AddTokenStore(typeof(TStore));
/// <summary>
/// Adds a custom token store derived from
/// <see cref="IOpenIddictTokenStore{TToken}"/>.
/// </summary>
/// <param name="type">The type of the custom store.</param>
/// <returns>The <see cref="OpenIddictBuilder"/>.</returns>
public virtual OpenIddictBuilder AddTokenStore([NotNull] Type type)
{
if (type == null)
{
throw new ArgumentNullException(nameof(type));
}
var contract = typeof(IOpenIddictTokenStore<>).MakeGenericType(TokenType);
if (!contract.IsAssignableFrom(type))
{
throw new InvalidOperationException("The specified type is invalid.");
}
Services.AddScoped(contract, type);
return this;
}
}
}

628
src/OpenIddict.Core/OpenIddictCoreBuilder.cs

@ -0,0 +1,628 @@
/*
* 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 JetBrains.Annotations;
using Microsoft.Extensions.DependencyInjection.Extensions;
using OpenIddict.Abstractions;
using OpenIddict.Core;
namespace Microsoft.Extensions.DependencyInjection
{
/// <summary>
/// Exposes the necessary methods required to configure the OpenIddict core services.
/// </summary>
public class OpenIddictCoreBuilder
{
/// <summary>
/// Initializes a new instance of <see cref="OpenIddictCoreBuilder"/>.
/// </summary>
/// <param name="services">The services collection.</param>
public OpenIddictCoreBuilder([NotNull] IServiceCollection services)
{
if (services == null)
{
throw new ArgumentNullException(nameof(services));
}
Services = services;
}
/// <summary>
/// Gets the services collection.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
public IServiceCollection Services { get; }
/// <summary>
/// Amends the default OpenIddict core configuration.
/// </summary>
/// <param name="configuration">The delegate used to configure the OpenIddict options.</param>
/// <remarks>This extension can be safely called multiple times.</remarks>
/// <returns>The <see cref="OpenIddictCoreBuilder"/>.</returns>
public OpenIddictCoreBuilder Configure([NotNull] Action<OpenIddictCoreOptions> configuration)
{
if (configuration == null)
{
throw new ArgumentNullException(nameof(configuration));
}
Services.Configure(configuration);
return this;
}
/// <summary>
/// Adds a custom application store by a custom implementation derived
/// from <see cref="IOpenIddictApplicationStore{TApplication}"/>.
/// Note: when using this overload, the application store
/// must be either a non-generic or closed generic service.
/// </summary>
/// <typeparam name="TStore">The type of the custom store.</typeparam>
/// <returns>The <see cref="OpenIddictCoreBuilder"/>.</returns>
public OpenIddictCoreBuilder AddApplicationStore<TStore>() where TStore : class
=> AddApplicationStore(typeof(TStore));
/// <summary>
/// Adds a custom application store by a custom implementation derived
/// from <see cref="IOpenIddictApplicationStore{TApplication}"/>.
/// Note: when using this overload, the application store can be
/// either a non-generic, a closed or an open generic service.
/// </summary>
/// <param name="type">The type of the custom store.</param>
/// <returns>The <see cref="OpenIddictCoreBuilder"/>.</returns>
public OpenIddictCoreBuilder AddApplicationStore([NotNull] Type type)
{
if (type == null)
{
throw new ArgumentNullException(nameof(type));
}
var root = OpenIddictCoreHelpers.FindGenericBaseType(type, typeof(IOpenIddictApplicationStore<>));
if (root == null)
{
throw new ArgumentException("The specified type is invalid.", nameof(type));
}
// Note: managers can be either open generics (e.g OpenIddictApplicationStore<>)
// or closed generics (e.g OpenIddictApplicationStore<OpenIddictApplication>).
if (type.IsGenericTypeDefinition)
{
if (type.GetGenericArguments().Length != 1)
{
throw new ArgumentException("The specified type is invalid.", nameof(type));
}
Services.Replace(ServiceDescriptor.Scoped(typeof(IOpenIddictApplicationStore<>), type));
}
else
{
Services.Replace(ServiceDescriptor.Scoped(typeof(IOpenIddictApplicationStore<>)
.MakeGenericType(root.GenericTypeArguments[0]), type));
}
return this;
}
/// <summary>
/// Adds a custom authorization store by a custom implementation derived
/// from <see cref="IOpenIddictAuthorizationStore{TAuthorization}"/>.
/// Note: when using this overload, the authorization store
/// must be either a non-generic or closed generic service.
/// </summary>
/// <typeparam name="TStore">The type of the custom store.</typeparam>
/// <returns>The <see cref="OpenIddictCoreBuilder"/>.</returns>
public OpenIddictCoreBuilder AddAuthorizationStore<TStore>() where TStore : class
=> AddAuthorizationStore(typeof(TStore));
/// <summary>
/// Adds a custom authorization store by a custom implementation derived
/// from <see cref="IOpenIddictAuthorizationStore{TAuthorization}"/>.
/// Note: when using this overload, the authorization store can be
/// either a non-generic, a closed or an open generic service.
/// </summary>
/// <param name="type">The type of the custom store.</param>
/// <returns>The <see cref="OpenIddictCoreBuilder"/>.</returns>
public OpenIddictCoreBuilder AddAuthorizationStore([NotNull] Type type)
{
if (type == null)
{
throw new ArgumentNullException(nameof(type));
}
var root = OpenIddictCoreHelpers.FindGenericBaseType(type, typeof(IOpenIddictAuthorizationStore<>));
if (root == null)
{
throw new ArgumentException("The specified type is invalid.", nameof(type));
}
// Note: managers can be either open generics (e.g OpenIddictAuthorizationStore<>)
// or closed generics (e.g OpenIddictAuthorizationStore<OpenIddictAuthorization>).
if (type.IsGenericTypeDefinition)
{
if (type.GetGenericArguments().Length != 1)
{
throw new ArgumentException("The specified type is invalid.", nameof(type));
}
Services.Replace(ServiceDescriptor.Scoped(typeof(IOpenIddictAuthorizationStore<>), type));
}
else
{
Services.Replace(ServiceDescriptor.Scoped(typeof(IOpenIddictAuthorizationStore<>)
.MakeGenericType(root.GenericTypeArguments[0]), type));
}
return this;
}
/// <summary>
/// Adds a custom scope store by a custom implementation derived
/// from <see cref="IOpenIddictScopeStore{TScope}"/>.
/// Note: when using this overload, the scope store
/// must be either a non-generic or closed generic service.
/// </summary>
/// <typeparam name="TStore">The type of the custom store.</typeparam>
/// <returns>The <see cref="OpenIddictCoreBuilder"/>.</returns>
public OpenIddictCoreBuilder AddScopeStore<TStore>() where TStore : class
=> AddScopeStore(typeof(TStore));
/// <summary>
/// Adds a custom scope store by a custom implementation derived
/// from <see cref="IOpenIddictScopeStore{TScope}"/>.
/// Note: when using this overload, the scope store can be
/// either a non-generic, a closed or an open generic service.
/// </summary>
/// <param name="type">The type of the custom store.</param>
/// <returns>The <see cref="OpenIddictCoreBuilder"/>.</returns>
public OpenIddictCoreBuilder AddScopeStore([NotNull] Type type)
{
if (type == null)
{
throw new ArgumentNullException(nameof(type));
}
var root = OpenIddictCoreHelpers.FindGenericBaseType(type, typeof(IOpenIddictScopeStore<>));
if (root == null)
{
throw new ArgumentException("The specified type is invalid.", nameof(type));
}
// Note: managers can be either open generics (e.g OpenIddictScopeStore<>)
// or closed generics (e.g OpenIddictScopeStore<OpenIddictScope>).
if (type.IsGenericTypeDefinition)
{
if (type.GetGenericArguments().Length != 1)
{
throw new ArgumentException("The specified type is invalid.", nameof(type));
}
Services.Replace(ServiceDescriptor.Scoped(typeof(IOpenIddictScopeStore<>), type));
}
else
{
Services.Replace(ServiceDescriptor.Scoped(typeof(IOpenIddictScopeStore<>)
.MakeGenericType(root.GenericTypeArguments[0]), type));
}
return this;
}
/// <summary>
/// Adds a custom token store by a custom implementation derived
/// from <see cref="IOpenIddictTokenStore{TToken}"/>.
/// Note: when using this overload, the token store
/// must be either a non-generic or closed generic service.
/// </summary>
/// <typeparam name="TStore">The type of the custom store.</typeparam>
/// <returns>The <see cref="OpenIddictCoreBuilder"/>.</returns>
public OpenIddictCoreBuilder AddTokenStore<TStore>() where TStore : class
=> AddTokenStore(typeof(TStore));
/// <summary>
/// Adds a custom token store by a custom implementation derived
/// from <see cref="IOpenIddictTokenStore{TToken}"/>.
/// Note: when using this overload, the token store can be
/// either a non-generic, a closed or an open generic service.
/// </summary>
/// <param name="type">The type of the custom store.</param>
/// <returns>The <see cref="OpenIddictCoreBuilder"/>.</returns>
public OpenIddictCoreBuilder AddTokenStore([NotNull] Type type)
{
if (type == null)
{
throw new ArgumentNullException(nameof(type));
}
var root = OpenIddictCoreHelpers.FindGenericBaseType(type, typeof(IOpenIddictTokenStore<>));
if (root == null)
{
throw new ArgumentException("The specified type is invalid.", nameof(type));
}
// Note: managers can be either open generics (e.g OpenIddictTokenStore<>)
// or closed generics (e.g OpenIddictTokenStore<OpenIddictToken>).
if (type.IsGenericTypeDefinition)
{
if (type.GetGenericArguments().Length != 1)
{
throw new ArgumentException("The specified type is invalid.", nameof(type));
}
Services.Replace(ServiceDescriptor.Scoped(typeof(IOpenIddictTokenStore<>), type));
}
else
{
Services.Replace(ServiceDescriptor.Scoped(typeof(IOpenIddictTokenStore<>)
.MakeGenericType(root.GenericTypeArguments[0]), type));
}
return this;
}
/// <summary>
/// Replace the default application manager by a custom manager derived
/// from <see cref="OpenIddictApplicationManager{TApplication}"/>.
/// Note: when using this overload, the application manager can be
/// either a non-generic, a closed or an open generic service.
/// </summary>
/// <param name="type">The type of the custom manager.</param>
/// <returns>The <see cref="OpenIddictCoreBuilder"/>.</returns>
public OpenIddictCoreBuilder ReplaceApplicationManager([NotNull] Type type)
{
if (type == null)
{
throw new ArgumentNullException(nameof(type));
}
var root = OpenIddictCoreHelpers.FindGenericBaseType(type, typeof(OpenIddictApplicationManager<>));
if (root == null)
{
throw new ArgumentException("The specified type is invalid.", nameof(type));
}
// Note: managers can be either open generics (e.g OpenIddictApplicationManager<>)
// or closed generics (e.g OpenIddictApplicationManager<OpenIddictApplication>).
if (type.IsGenericTypeDefinition)
{
if (type.GetGenericArguments().Length != 1)
{
throw new ArgumentException("The specified type is invalid.", nameof(type));
}
Services.Replace(ServiceDescriptor.Scoped(typeof(OpenIddictApplicationManager<>), type));
}
else
{
Services.Replace(ServiceDescriptor.Scoped(typeof(OpenIddictApplicationManager<>)
.MakeGenericType(root.GenericTypeArguments[0]), type));
}
return this;
}
/// <summary>
/// Replaces the default application store resolver by a custom implementation.
/// </summary>
/// <typeparam name="TResolver">The type of the custom store.</typeparam>
/// <returns>The <see cref="OpenIddictCoreBuilder"/>.</returns>
public OpenIddictCoreBuilder ReplaceApplicationStoreResolver<TResolver>()
where TResolver : IOpenIddictApplicationStoreResolver
=> ReplaceApplicationStoreResolver(typeof(TResolver));
/// <summary>
/// Replaces the default application store resolver by a custom implementation.
/// </summary>
/// <param name="type">The type of the custom store.</param>
/// <returns>The <see cref="OpenIddictCoreBuilder"/>.</returns>
public OpenIddictCoreBuilder ReplaceApplicationStoreResolver([NotNull] Type type)
{
if (type == null)
{
throw new ArgumentNullException(nameof(type));
}
if (!typeof(IOpenIddictApplicationStoreResolver).IsAssignableFrom(type))
{
throw new ArgumentException("The specified type is invalid.", nameof(type));
}
Services.Replace(ServiceDescriptor.Scoped(typeof(IOpenIddictApplicationStoreResolver), type));
return this;
}
/// <summary>
/// Replace the default application manager by a custom manager derived
/// from <see cref="OpenIddictApplicationManager{TApplication}"/>.
/// Note: when using this overload, the application manager
/// must be either a non-generic or closed generic service.
/// </summary>
/// <typeparam name="TManager">The type of the custom manager.</typeparam>
/// <returns>The <see cref="OpenIddictCoreBuilder"/>.</returns>
public OpenIddictCoreBuilder ReplaceApplicationManager<TManager>() where TManager : class
=> ReplaceApplicationManager(typeof(TManager));
/// <summary>
/// Replace the default authorization manager by a custom manager derived
/// from <see cref="OpenIddictAuthorizationManager{TAuthorization}"/>.
/// Note: when using this overload, the authorization manager
/// must be either a non-generic or closed generic service.
/// </summary>
/// <typeparam name="TManager">The type of the custom manager.</typeparam>
/// <returns>The <see cref="OpenIddictCoreBuilder"/>.</returns>
public OpenIddictCoreBuilder ReplaceAuthorizationManager<TManager>() where TManager : class
=> ReplaceAuthorizationManager(typeof(TManager));
/// <summary>
/// Replace the default authorization manager by a custom manager derived
/// from <see cref="OpenIddictAuthorizationManager{TAuthorization}"/>.
/// Note: when using this overload, the authorization manager can be
/// either a non-generic, a closed or an open generic service.
/// </summary>
/// <param name="type">The type of the custom manager.</param>
/// <returns>The <see cref="OpenIddictCoreBuilder"/>.</returns>
public OpenIddictCoreBuilder ReplaceAuthorizationManager([NotNull] Type type)
{
if (type == null)
{
throw new ArgumentNullException(nameof(type));
}
var root = OpenIddictCoreHelpers.FindGenericBaseType(type, typeof(OpenIddictAuthorizationManager<>));
if (root == null)
{
throw new ArgumentException("The specified type is invalid.", nameof(type));
}
// Note: managers can be either open generics (e.g OpenIddictAuthorizationManager<>)
// or closed generics (e.g OpenIddictAuthorizationManager<OpenIddictAuthorization>).
if (type.IsGenericTypeDefinition)
{
if (type.GetGenericArguments().Length != 1)
{
throw new ArgumentException("The specified type is invalid.", nameof(type));
}
Services.Replace(ServiceDescriptor.Scoped(typeof(OpenIddictAuthorizationManager<>), type));
}
else
{
Services.Replace(ServiceDescriptor.Scoped(typeof(OpenIddictAuthorizationManager<>)
.MakeGenericType(root.GenericTypeArguments[0]), type));
}
return this;
}
/// <summary>
/// Replaces the default authorization store resolver by a custom implementation.
/// </summary>
/// <typeparam name="TResolver">The type of the custom store.</typeparam>
/// <returns>The <see cref="OpenIddictCoreBuilder"/>.</returns>
public OpenIddictCoreBuilder ReplaceAuthorizationStoreResolver<TResolver>()
where TResolver : IOpenIddictAuthorizationStoreResolver
=> ReplaceAuthorizationStoreResolver(typeof(TResolver));
/// <summary>
/// Replaces the default authorization store resolver by a custom implementation.
/// </summary>
/// <param name="type">The type of the custom store.</param>
/// <returns>The <see cref="OpenIddictCoreBuilder"/>.</returns>
public OpenIddictCoreBuilder ReplaceAuthorizationStoreResolver([NotNull] Type type)
{
if (type == null)
{
throw new ArgumentNullException(nameof(type));
}
if (!typeof(IOpenIddictAuthorizationStoreResolver).IsAssignableFrom(type))
{
throw new ArgumentException("The specified type is invalid.", nameof(type));
}
Services.Replace(ServiceDescriptor.Scoped(typeof(IOpenIddictAuthorizationStoreResolver), type));
return this;
}
/// <summary>
/// Replace the default scope manager by a custom manager
/// derived from <see cref="OpenIddictScopeManager{TScope}"/>.
/// Note: when using this overload, the scope manager
/// must be either a non-generic or closed generic service.
/// </summary>
/// <typeparam name="TManager">The type of the custom manager.</typeparam>
/// <returns>The <see cref="OpenIddictCoreBuilder"/>.</returns>
public OpenIddictCoreBuilder ReplaceScopeManager<TManager>() where TManager : class
=> ReplaceScopeManager(typeof(TManager));
/// <summary>
/// Replace the default scope manager by a custom manager
/// derived from <see cref="OpenIddictScopeManager{TScope}"/>.
/// Note: when using this overload, the scope manager can be
/// either a non-generic, a closed or an open generic service.
/// </summary>
/// <param name="type">The type of the custom manager.</param>
/// <returns>The <see cref="OpenIddictCoreBuilder"/>.</returns>
public OpenIddictCoreBuilder ReplaceScopeManager([NotNull] Type type)
{
if (type == null)
{
throw new ArgumentNullException(nameof(type));
}
var root = OpenIddictCoreHelpers.FindGenericBaseType(type, typeof(OpenIddictScopeManager<>));
if (root == null)
{
throw new ArgumentException("The specified type is invalid.", nameof(type));
}
// Note: managers can be either open generics (e.g OpenIddictScopeManager<>)
// or closed generics (e.g OpenIddictScopeManager<OpenIddictScope>).
if (type.IsGenericTypeDefinition)
{
if (type.GetGenericArguments().Length != 1)
{
throw new ArgumentException("The specified type is invalid.", nameof(type));
}
Services.Replace(ServiceDescriptor.Scoped(typeof(OpenIddictScopeManager<>), type));
}
else
{
Services.Replace(ServiceDescriptor.Scoped(typeof(OpenIddictScopeManager<>)
.MakeGenericType(root.GenericTypeArguments[0]), type));
}
return this;
}
/// <summary>
/// Replaces the default scope store resolver by a custom implementation.
/// </summary>
/// <typeparam name="TResolver">The type of the custom store.</typeparam>
/// <returns>The <see cref="OpenIddictCoreBuilder"/>.</returns>
public OpenIddictCoreBuilder ReplaceScopeStoreResolver<TResolver>()
where TResolver : IOpenIddictScopeStoreResolver
=> ReplaceScopeStoreResolver(typeof(TResolver));
/// <summary>
/// Replaces the default scope store resolver by a custom implementation.
/// </summary>
/// <param name="type">The type of the custom store.</param>
/// <returns>The <see cref="OpenIddictCoreBuilder"/>.</returns>
public OpenIddictCoreBuilder ReplaceScopeStoreResolver([NotNull] Type type)
{
if (type == null)
{
throw new ArgumentNullException(nameof(type));
}
if (!typeof(IOpenIddictScopeStoreResolver).IsAssignableFrom(type))
{
throw new ArgumentException("The specified type is invalid.", nameof(type));
}
Services.Replace(ServiceDescriptor.Scoped(typeof(IOpenIddictScopeStoreResolver), type));
return this;
}
/// <summary>
/// Replace the default token manager by a custom manager
/// derived from <see cref="OpenIddictTokenManager{TToken}"/>.
/// Note: when using this overload, the token manager
/// must be either a non-generic or closed generic service.
/// </summary>
/// <typeparam name="TManager">The type of the custom manager.</typeparam>
/// <returns>The <see cref="OpenIddictCoreBuilder"/>.</returns>
public OpenIddictCoreBuilder ReplaceTokenManager<TManager>() where TManager : class
=> ReplaceTokenManager(typeof(TManager));
/// <summary>
/// Replace the default token manager by a custom manager
/// derived from <see cref="OpenIddictTokenManager{TToken}"/>.
/// Note: when using this overload, the token manager can be
/// either a non-generic, a closed or an open generic service.
/// </summary>
/// <param name="type">The type of the custom manager.</param>
/// <returns>The <see cref="OpenIddictCoreBuilder"/>.</returns>
public OpenIddictCoreBuilder ReplaceTokenManager([NotNull] Type type)
{
if (type == null)
{
throw new ArgumentNullException(nameof(type));
}
var root = OpenIddictCoreHelpers.FindGenericBaseType(type, typeof(OpenIddictTokenManager<>));
if (root == null)
{
throw new ArgumentException("The specified type is invalid.", nameof(type));
}
// Note: managers can be either open generics (e.g OpenIddictTokenManager<>)
// or closed generics (e.g OpenIddictTokenManager<OpenIddictToken>).
if (type.IsGenericTypeDefinition)
{
if (type.GetGenericArguments().Length != 1)
{
throw new ArgumentException("The specified type is invalid.", nameof(type));
}
Services.Replace(ServiceDescriptor.Scoped(typeof(OpenIddictTokenManager<>), type));
}
else
{
Services.Replace(ServiceDescriptor.Scoped(typeof(OpenIddictTokenManager<>)
.MakeGenericType(root.GenericTypeArguments[0]), type));
}
return this;
}
/// <summary>
/// Replaces the default token store resolver by a custom implementation.
/// </summary>
/// <typeparam name="TResolver">The type of the custom store.</typeparam>
/// <returns>The <see cref="OpenIddictCoreBuilder"/>.</returns>
public OpenIddictCoreBuilder ReplaceTokenStoreResolver<TResolver>()
where TResolver : IOpenIddictTokenStoreResolver
=> ReplaceTokenStoreResolver(typeof(TResolver));
/// <summary>
/// Replaces the default token store resolver by a custom implementation.
/// </summary>
/// <param name="type">The type of the custom store.</param>
/// <returns>The <see cref="OpenIddictCoreBuilder"/>.</returns>
public OpenIddictCoreBuilder ReplaceTokenStoreResolver([NotNull] Type type)
{
if (type == null)
{
throw new ArgumentNullException(nameof(type));
}
if (!typeof(IOpenIddictTokenStoreResolver).IsAssignableFrom(type))
{
throw new ArgumentException("The specified type is invalid.", nameof(type));
}
Services.Replace(ServiceDescriptor.Scoped(typeof(IOpenIddictTokenStoreResolver), type));
return this;
}
/// <summary>
/// Configures OpenIddict to use the specified entities.
/// </summary>
/// <typeparam name="TApplication">The type corresponding to the Application entity.</typeparam>
/// <typeparam name="TAuthorization">The type corresponding to the Authorization entity.</typeparam>
/// <typeparam name="TScope">The type corresponding to the Scope entity.</typeparam>
/// <typeparam name="TToken">The type corresponding to the Token entity.</typeparam>
/// <returns>The <see cref="OpenIddictCoreBuilder"/>.</returns>
public OpenIddictCoreBuilder UseCustomModels<TApplication, TAuthorization, TScope, TToken>()
where TApplication : class
where TAuthorization : class
where TScope : class
where TToken : class
=> Configure(options =>
{
options.DefaultApplicationType = typeof(TApplication);
options.DefaultAuthorizationType = typeof(TAuthorization);
options.DefaultScopeType = typeof(TScope);
options.DefaultTokenType = typeof(TToken);
});
}
}

73
src/OpenIddict.Core/OpenIddictCoreExtensions.cs

@ -0,0 +1,73 @@
/*
* 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 JetBrains.Annotations;
using Microsoft.Extensions.DependencyInjection.Extensions;
using OpenIddict.Abstractions;
using OpenIddict.Core;
namespace Microsoft.Extensions.DependencyInjection
{
public static class OpenIddictCoreExtensions
{
/// <summary>
/// Registers the OpenIddict core services in the DI container.
/// </summary>
/// <param name="builder">The services builder used by OpenIddict to register new services.</param>
/// <remarks>This extension can be safely called multiple times.</remarks>
/// <returns>The <see cref="OpenIddictBuilder"/>.</returns>
public static OpenIddictCoreBuilder AddCore([NotNull] this OpenIddictBuilder builder)
{
if (builder == null)
{
throw new ArgumentNullException(nameof(builder));
}
builder.Services.AddDistributedMemoryCache();
builder.Services.AddMemoryCache();
builder.Services.AddOptions();
builder.Services.TryAddScoped(typeof(OpenIddictApplicationManager<>));
builder.Services.TryAddScoped(typeof(OpenIddictAuthorizationManager<>));
builder.Services.TryAddScoped(typeof(OpenIddictScopeManager<>));
builder.Services.TryAddScoped(typeof(OpenIddictTokenManager<>));
builder.Services.TryAddScoped<IOpenIddictApplicationStoreResolver, OpenIddictApplicationStoreResolver>();
builder.Services.TryAddScoped<IOpenIddictAuthorizationStoreResolver, OpenIddictAuthorizationStoreResolver>();
builder.Services.TryAddScoped<IOpenIddictScopeStoreResolver, OpenIddictScopeStoreResolver>();
builder.Services.TryAddScoped<IOpenIddictTokenStoreResolver, OpenIddictTokenStoreResolver>();
return new OpenIddictCoreBuilder(builder.Services);
}
/// <summary>
/// Registers the OpenIddict core services in the DI container.
/// </summary>
/// <param name="builder">The services builder used by OpenIddict to register new services.</param>
/// <param name="configuration">The configuration delegate used to configure the core services.</param>
/// <remarks>This extension can be safely called multiple times.</remarks>
/// <returns>The <see cref="OpenIddictBuilder"/>.</returns>
public static OpenIddictBuilder AddCore(
[NotNull] this OpenIddictBuilder builder,
[NotNull] Action<OpenIddictCoreBuilder> configuration)
{
if (builder == null)
{
throw new ArgumentNullException(nameof(builder));
}
if (configuration == null)
{
throw new ArgumentNullException(nameof(configuration));
}
configuration(builder.AddCore());
return builder;
}
}
}

67
src/OpenIddict.Core/OpenIddictCoreHelpers.cs

@ -0,0 +1,67 @@
using System;
using System.ComponentModel;
namespace OpenIddict.Core
{
/// <summary>
/// Exposes common helpers used by the OpenIddict assemblies.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
public static class OpenIddictCoreHelpers
{
/// <summary>
/// Finds the base type that matches the specified generic type definition.
/// </summary>
/// <param name="type">The type to introspect.</param>
/// <param name="definition">The generic type definition.</param>
/// <returns>A <see cref="Type"/> instance if the base type was found, <c>null</c> otherwise.</returns>
public static Type FindGenericBaseType(Type type, Type definition)
{
if (type == null)
{
throw new ArgumentNullException(nameof(type));
}
if (definition == null)
{
throw new ArgumentNullException(nameof(definition));
}
if (!definition.IsGenericTypeDefinition)
{
throw new ArgumentException("The second parameter must be a generic type definition.", nameof(definition));
}
for (var candidate = type; candidate != null; candidate = candidate.BaseType)
{
if (!candidate.IsGenericType && !candidate.IsConstructedGenericType)
{
continue;
}
if (candidate.GetGenericTypeDefinition() == definition)
{
return candidate;
}
if (definition.IsInterface)
{
foreach (var contract in candidate.GetInterfaces())
{
if (!contract.IsGenericType && !contract.IsConstructedGenericType)
{
continue;
}
if (contract.GetGenericTypeDefinition() == definition)
{
return contract;
}
}
}
}
return null;
}
}
}

33
src/OpenIddict.Core/OpenIddictCoreOptions.cs

@ -0,0 +1,33 @@
/*
* 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;
namespace OpenIddict.Core
{
public class OpenIddictCoreOptions
{
/// <summary>
/// Gets or sets the type corresponding to the Application entity.
/// </summary>
public Type DefaultApplicationType { get; set; }
/// <summary>
/// Gets or sets the type corresponding to the Authorization entity.
/// </summary>
public Type DefaultAuthorizationType { get; set; }
/// <summary>
/// Gets or sets the type corresponding to the Scope entity.
/// </summary>
public Type DefaultScopeType { get; set; }
/// <summary>
/// Gets or sets the type corresponding to the Token entity.
/// </summary>
public Type DefaultTokenType { get; set; }
}
}

89
src/OpenIddict.Core/OpenIddictExtensions.cs

@ -1,89 +0,0 @@
/*
* 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 JetBrains.Annotations;
using Microsoft.Extensions.DependencyInjection.Extensions;
using OpenIddict.Core;
namespace Microsoft.Extensions.DependencyInjection
{
public static class OpenIddictExtensions
{
/// <summary>
/// Registers the default OpenIddict services in the DI container, using the specified entities.
/// </summary>
/// <typeparam name="TApplication">The type of the Application entity.</typeparam>
/// <typeparam name="TAuthorization">The type of the Authorization entity.</typeparam>
/// <typeparam name="TScope">The type of the Scope entity.</typeparam>
/// <typeparam name="TToken">The type of the Token entity.</typeparam>
/// <param name="services">The services collection.</param>
/// <returns>The <see cref="OpenIddictBuilder"/>.</returns>
public static OpenIddictBuilder AddOpenIddict<TApplication, TAuthorization, TScope, TToken>([NotNull] this IServiceCollection services)
where TApplication : class
where TAuthorization : class
where TScope : class
where TToken : class
{
if (services == null)
{
throw new ArgumentNullException(nameof(services));
}
services.AddDistributedMemoryCache();
services.AddMemoryCache();
services.AddOptions();
// Register the OpenIddict core services in the DI container.
services.TryAddScoped<OpenIddictApplicationManager<TApplication>>();
services.TryAddScoped<OpenIddictAuthorizationManager<TAuthorization>>();
services.TryAddScoped<OpenIddictScopeManager<TScope>>();
services.TryAddScoped<OpenIddictTokenManager<TToken>>();
return new OpenIddictBuilder(services)
{
ApplicationType = typeof(TApplication),
AuthorizationType = typeof(TAuthorization),
ScopeType = typeof(TScope),
TokenType = typeof(TToken)
};
}
/// <summary>
/// Registers the default OpenIddict services in the DI container, using the specified entities.
/// </summary>
/// <typeparam name="TApplication">The type of the Application entity.</typeparam>
/// <typeparam name="TAuthorization">The type of the Authorization entity.</typeparam>
/// <typeparam name="TScope">The type of the Scope entity.</typeparam>
/// <typeparam name="TToken">The type of the Token entity.</typeparam>
/// <param name="services">The services collection.</param>
/// <param name="configuration">The configuration delegate used to register new services.</param>
/// <returns>The <see cref="IServiceCollection"/>.</returns>
public static IServiceCollection AddOpenIddict<TApplication, TAuthorization, TScope, TToken>(
[NotNull] this IServiceCollection services,
[NotNull] Action<OpenIddictBuilder> configuration)
where TApplication : class
where TAuthorization : class
where TScope : class
where TToken : class
{
if (services == null)
{
throw new ArgumentNullException(nameof(services));
}
if (configuration == null)
{
throw new ArgumentNullException(nameof(configuration));
}
// Register the OpenIddict core services and invoke the configuration delegate.
configuration(services.AddOpenIddict<TApplication, TAuthorization, TScope, TToken>());
return services;
}
}
}

44
src/OpenIddict.Core/Resolvers/OpenIddictApplicationStoreResolver.cs

@ -0,0 +1,44 @@
using System;
using System.Text;
using JetBrains.Annotations;
using Microsoft.Extensions.DependencyInjection;
using OpenIddict.Abstractions;
namespace OpenIddict.Core
{
/// <summary>
/// Exposes a method allowing to resolve an application store.
/// </summary>
public class OpenIddictApplicationStoreResolver : IOpenIddictApplicationStoreResolver
{
private readonly IServiceProvider _provider;
public OpenIddictApplicationStoreResolver([NotNull] IServiceProvider provider)
{
_provider = provider;
}
/// <summary>
/// Returns an application store compatible with the specified application type or throws an
/// <see cref="InvalidOperationException"/> if no store can be built using the specified type.
/// </summary>
/// <typeparam name="TApplication">The type of the Application entity.</typeparam>
/// <returns>An <see cref="IOpenIddictApplicationStore{TApplication}"/>.</returns>
public IOpenIddictApplicationStore<TApplication> Get<TApplication>() where TApplication : class
{
var store = _provider.GetService<IOpenIddictApplicationStore<TApplication>>();
if (store == null)
{
throw new InvalidOperationException(new StringBuilder()
.AppendLine("No application store has been registered in the dependency injection container.")
.Append("To register the Entity Framework Core stores, reference the 'OpenIddict.EntityFrameworkCore' ")
.AppendLine("package and call 'services.AddOpenIddict().AddCore().AddEntityFrameworkCoreStores()'.")
.Append("To register a custom store, create an implementation of 'IOpenIddictApplicationStore' and ")
.Append("use 'services.AddOpenIddict().AddCore().AddApplicationStore()' to add it to the DI container.")
.ToString());
}
return store;
}
}
}

44
src/OpenIddict.Core/Resolvers/OpenIddictAuthorizationStoreResolver.cs

@ -0,0 +1,44 @@
using System;
using System.Text;
using JetBrains.Annotations;
using Microsoft.Extensions.DependencyInjection;
using OpenIddict.Abstractions;
namespace OpenIddict.Core
{
/// <summary>
/// Exposes a method allowing to resolve an authorization store.
/// </summary>
public class OpenIddictAuthorizationStoreResolver : IOpenIddictAuthorizationStoreResolver
{
private readonly IServiceProvider _provider;
public OpenIddictAuthorizationStoreResolver([NotNull] IServiceProvider provider)
{
_provider = provider;
}
/// <summary>
/// Returns an authorization store compatible with the specified authorization type or throws an
/// <see cref="InvalidOperationException"/> if no store can be built using the specified type.
/// </summary>
/// <typeparam name="TAuthorization">The type of the Authorization entity.</typeparam>
/// <returns>An <see cref="IOpenIddictAuthorizationStore{TAuthorization}"/>.</returns>
public IOpenIddictAuthorizationStore<TAuthorization> Get<TAuthorization>() where TAuthorization : class
{
var store = _provider.GetService<IOpenIddictAuthorizationStore<TAuthorization>>();
if (store == null)
{
throw new InvalidOperationException(new StringBuilder()
.AppendLine("No authorization store has been registered in the dependency injection container.")
.Append("To register the Entity Framework Core stores, reference the 'OpenIddict.EntityFrameworkCore' ")
.AppendLine("package and call 'services.AddOpenIddict().AddCore().AddEntityFrameworkCoreStores()'.")
.Append("To register a custom store, create an implementation of 'IOpenIddictAuthorizationStore' and ")
.Append("use 'services.AddOpenIddict().AddCore().AddAuthorizationStore()' to add it to the DI container.")
.ToString());
}
return store;
}
}
}

44
src/OpenIddict.Core/Resolvers/OpenIddictScopeStoreResolver.cs

@ -0,0 +1,44 @@
using System;
using System.Text;
using JetBrains.Annotations;
using Microsoft.Extensions.DependencyInjection;
using OpenIddict.Abstractions;
namespace OpenIddict.Core
{
/// <summary>
/// Exposes a method allowing to resolve a scope store.
/// </summary>
public class OpenIddictScopeStoreResolver : IOpenIddictScopeStoreResolver
{
private readonly IServiceProvider _provider;
public OpenIddictScopeStoreResolver([NotNull] IServiceProvider provider)
{
_provider = provider;
}
/// <summary>
/// Returns a scope store compatible with the specified scope type or throws an
/// <see cref="InvalidOperationException"/> if no store can be built using the specified type.
/// </summary>
/// <typeparam name="TScope">The type of the Scope entity.</typeparam>
/// <returns>An <see cref="IOpenIddictScopeStore{TScope}"/>.</returns>
public IOpenIddictScopeStore<TScope> Get<TScope>() where TScope : class
{
var store = _provider.GetService<IOpenIddictScopeStore<TScope>>();
if (store == null)
{
throw new InvalidOperationException(new StringBuilder()
.AppendLine("No scope store has been registered in the dependency injection container.")
.Append("To register the Entity Framework Core stores, reference the 'OpenIddict.EntityFrameworkCore' ")
.AppendLine("package and call 'services.AddOpenIddict().AddCore().AddEntityFrameworkCoreStores()'.")
.Append("To register a custom store, create an implementation of 'IOpenIddictScopeStore' and ")
.Append("use 'services.AddOpenIddict().AddCore().AddScopeStore()' to add it to the DI container.")
.ToString());
}
return store;
}
}
}

44
src/OpenIddict.Core/Resolvers/OpenIddictTokenStoreResolver.cs

@ -0,0 +1,44 @@
using System;
using System.Text;
using JetBrains.Annotations;
using Microsoft.Extensions.DependencyInjection;
using OpenIddict.Abstractions;
namespace OpenIddict.Core
{
/// <summary>
/// Exposes a method allowing to resolve a token store.
/// </summary>
public class OpenIddictTokenStoreResolver : IOpenIddictTokenStoreResolver
{
private readonly IServiceProvider _provider;
public OpenIddictTokenStoreResolver([NotNull] IServiceProvider provider)
{
_provider = provider;
}
/// <summary>
/// Returns a token store compatible with the specified token type or throws an
/// <see cref="InvalidOperationException"/> if no store can be built using the specified type.
/// </summary>
/// <typeparam name="TToken">The type of the Token entity.</typeparam>
/// <returns>An <see cref="IOpenIddictTokenStore{TToken}"/>.</returns>
public IOpenIddictTokenStore<TToken> Get<TToken>() where TToken : class
{
var store = _provider.GetService<IOpenIddictTokenStore<TToken>>();
if (store == null)
{
throw new InvalidOperationException(new StringBuilder()
.AppendLine("No token store factory has been registered in the dependency injection container.")
.Append("To register the Entity Framework Core stores, reference the 'OpenIddict.EntityFrameworkCore' ")
.AppendLine("package and call 'services.AddOpenIddict().AddCore().AddEntityFrameworkCoreStores()'.")
.Append("To register a custom store, create an implementation of 'IOpenIddictTokenStore' and ")
.Append("use 'services.AddOpenIddict().AddCore().AddTokenStore()' to add it to the DI container.")
.ToString());
}
return store;
}
}
}

1
src/OpenIddict.EntityFramework/OpenIddict.EntityFramework.csproj

@ -13,6 +13,7 @@
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\OpenIddict.Core\OpenIddict.Core.csproj" />
<ProjectReference Include="..\OpenIddict.Stores\OpenIddict.Stores.csproj" />
</ItemGroup>

161
src/OpenIddict.EntityFramework/OpenIddictExtensions.cs

@ -5,15 +5,12 @@
*/
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 System.Text;
using JetBrains.Annotations;
using Microsoft.Extensions.DependencyInjection.Extensions;
using OpenIddict.Core;
using OpenIddict.EntityFramework;
using OpenIddict.Models;
@ -27,8 +24,9 @@ namespace Microsoft.Extensions.DependencyInjection
/// 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)
/// <remarks>This extension can be safely called multiple times.</remarks>
/// <returns>The <see cref="OpenIddictCoreBuilder"/>.</returns>
public static OpenIddictCoreBuilder AddEntityFrameworkStores<TContext>([NotNull] this OpenIddictCoreBuilder builder)
where TContext : DbContext
{
if (builder == null)
@ -36,85 +34,15 @@ namespace Microsoft.Extensions.DependencyInjection
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.");
builder.Services.TryAddScoped(typeof(OpenIddictApplicationStore<,,,,>));
builder.Services.TryAddScoped(typeof(OpenIddictAuthorizationStore<,,,,>));
builder.Services.TryAddScoped(typeof(OpenIddictScopeStore<,,>));
builder.Services.TryAddScoped(typeof(OpenIddictTokenStore<,,,,>));
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;
return builder.ReplaceApplicationStoreResolver<OpenIddictApplicationStoreResolver<TContext>>()
.ReplaceAuthorizationStoreResolver<OpenIddictAuthorizationStoreResolver<TContext>>()
.ReplaceScopeStoreResolver<OpenIddictScopeStoreResolver<TContext>>()
.ReplaceTokenStoreResolver<OpenIddictTokenStoreResolver<TContext>>();
}
/// <summary>
@ -124,12 +52,10 @@ namespace Microsoft.Extensions.DependencyInjection
/// <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>();
}
=> builder.UseOpenIddict<OpenIddictApplication,
OpenIddictAuthorization,
OpenIddictScope,
OpenIddictToken, string>();
/// <summary>
/// Registers the OpenIddict entity sets in the Entity Framework context
@ -154,28 +80,36 @@ namespace Microsoft.Extensions.DependencyInjection
// 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)
if (typeof(TApplication).IsGenericType)
{
throw new InvalidOperationException("The application entity cannot be a generic type. " +
"Consider creating a non-generic derived class.");
throw new InvalidOperationException(new StringBuilder()
.AppendLine("The application entity cannot be a generic type.")
.Append("Consider creating a non-generic derived class.")
.ToString());
}
if (typeof(TAuthorization).GetTypeInfo().IsGenericType)
if (typeof(TAuthorization).IsGenericType)
{
throw new InvalidOperationException("The authorization entity cannot be a generic type. " +
"Consider creating a non-generic derived class.");
throw new InvalidOperationException(new StringBuilder()
.AppendLine("The authorization entity cannot be a generic type.")
.Append("Consider creating a non-generic derived class.")
.ToString());
}
if (typeof(TScope).GetTypeInfo().IsGenericType)
if (typeof(TScope).IsGenericType)
{
throw new InvalidOperationException("The scope entity cannot be a generic type. " +
"Consider creating a non-generic derived class.");
throw new InvalidOperationException(new StringBuilder()
.AppendLine("The scope entity cannot be a generic type.")
.Append("Consider creating a non-generic derived class.")
.ToString());
}
if (typeof(TToken).GetTypeInfo().IsGenericType)
if (typeof(TToken).IsGenericType)
{
throw new InvalidOperationException("The scope entity cannot be a generic type. " +
"Consider creating a non-generic derived class.");
throw new InvalidOperationException(new StringBuilder()
.AppendLine("The token entity cannot be a generic type.")
.Append("Consider creating a non-generic derived class.")
.ToString());
}
// Warning: optional foreign keys MUST NOT be added as CLR properties because
@ -285,28 +219,5 @@ namespace Microsoft.Extensions.DependencyInjection
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;
}
}
}

65
src/OpenIddict.EntityFramework/Resolvers/OpenIddictApplicationStoreResolver.cs

@ -0,0 +1,65 @@
using System;
using System.Collections.Concurrent;
using System.Data.Entity;
using System.Text;
using JetBrains.Annotations;
using Microsoft.Extensions.DependencyInjection;
using OpenIddict.Abstractions;
using OpenIddict.Core;
using OpenIddict.Models;
namespace OpenIddict.EntityFramework
{
/// <summary>
/// Exposes a method allowing to resolve an application store.
/// </summary>
public class OpenIddictApplicationStoreResolver<TContext> : IOpenIddictApplicationStoreResolver
where TContext : DbContext
{
private static readonly ConcurrentDictionary<Type, Type> _cache = new ConcurrentDictionary<Type, Type>();
private readonly IServiceProvider _provider;
public OpenIddictApplicationStoreResolver([NotNull] IServiceProvider provider)
{
_provider = provider;
}
/// <summary>
/// Returns an application store compatible with the specified application type or throws an
/// <see cref="InvalidOperationException"/> if no store can be built using the specified type.
/// </summary>
/// <typeparam name="TApplication">The type of the Application entity.</typeparam>
/// <returns>An <see cref="IOpenIddictApplicationStore{TApplication}"/>.</returns>
public IOpenIddictApplicationStore<TApplication> Get<TApplication>() where TApplication : class
{
var store = _provider.GetService<IOpenIddictApplicationStore<TApplication>>();
if (store != null)
{
return store;
}
var type = _cache.GetOrAdd(typeof(TApplication), key =>
{
var root = OpenIddictCoreHelpers.FindGenericBaseType(key, typeof(OpenIddictApplication<,,>));
if (root == null)
{
throw new InvalidOperationException(new StringBuilder()
.AppendLine("The specified application type is not compatible with the Entity Framework 6.x stores.")
.Append("When enabling the Entity Framework 6.x stores, make sure you use the built-in generic ")
.Append("'OpenIddictApplication' entity (from the 'OpenIddict.Models' package) or a custom entity ")
.Append("that inherits from the generic 'OpenIddictApplication' entity.")
.ToString());
}
return typeof(OpenIddictApplicationStore<,,,,>).MakeGenericType(
/* TApplication: */ key,
/* TAuthorization: */ root.GenericTypeArguments[1],
/* TToken: */ root.GenericTypeArguments[2],
/* TContext: */ typeof(TContext),
/* TKey: */ root.GenericTypeArguments[0]);
});
return (IOpenIddictApplicationStore<TApplication>) _provider.GetRequiredService(type);
}
}
}

65
src/OpenIddict.EntityFramework/Resolvers/OpenIddictAuthorizationStoreResolver.cs

@ -0,0 +1,65 @@
using System;
using System.Collections.Concurrent;
using System.Data.Entity;
using System.Text;
using JetBrains.Annotations;
using Microsoft.Extensions.DependencyInjection;
using OpenIddict.Abstractions;
using OpenIddict.Core;
using OpenIddict.Models;
namespace OpenIddict.EntityFramework
{
/// <summary>
/// Exposes a method allowing to resolve an authorization store.
/// </summary>
public class OpenIddictAuthorizationStoreResolver<TContext> : IOpenIddictAuthorizationStoreResolver
where TContext : DbContext
{
private static readonly ConcurrentDictionary<Type, Type> _cache = new ConcurrentDictionary<Type, Type>();
private readonly IServiceProvider _provider;
public OpenIddictAuthorizationStoreResolver([NotNull] IServiceProvider provider)
{
_provider = provider;
}
/// <summary>
/// Returns an authorization store compatible with the specified authorization type or throws an
/// <see cref="InvalidOperationException"/> if no store can be built using the specified type.
/// </summary>
/// <typeparam name="TAuthorization">The type of the Authorization entity.</typeparam>
/// <returns>An <see cref="IOpenIddictAuthorizationStore{TAuthorization}"/>.</returns>
public IOpenIddictAuthorizationStore<TAuthorization> Get<TAuthorization>() where TAuthorization : class
{
var store = _provider.GetService<IOpenIddictAuthorizationStore<TAuthorization>>();
if (store != null)
{
return store;
}
var type = _cache.GetOrAdd(typeof(TAuthorization), key =>
{
var root = OpenIddictCoreHelpers.FindGenericBaseType(key, typeof(OpenIddictAuthorization<,,>));
if (root == null)
{
throw new InvalidOperationException(new StringBuilder()
.AppendLine("The specified authorization type is not compatible with the Entity Framework 6.x stores.")
.Append("When enabling the Entity Framework 6.x stores, make sure you use the built-in generic ")
.Append("'OpenIddictAuthorization' entity (from the 'OpenIddict.Models' package) or a custom entity ")
.Append("that inherits from the generic 'OpenIddictAuthorization' entity.")
.ToString());
}
return typeof(OpenIddictAuthorizationStore<,,,,>).MakeGenericType(
/* TAuthorization: */ key,
/* TApplication: */ root.GenericTypeArguments[1],
/* TToken: */ root.GenericTypeArguments[2],
/* TContext: */ typeof(TContext),
/* TKey: */ root.GenericTypeArguments[0]);
});
return (IOpenIddictAuthorizationStore<TAuthorization>) _provider.GetRequiredService(type);
}
}
}

63
src/OpenIddict.EntityFramework/Resolvers/OpenIddictScopeStoreResolver.cs

@ -0,0 +1,63 @@
using System;
using System.Collections.Concurrent;
using System.Data.Entity;
using System.Text;
using JetBrains.Annotations;
using Microsoft.Extensions.DependencyInjection;
using OpenIddict.Abstractions;
using OpenIddict.Core;
using OpenIddict.Models;
namespace OpenIddict.EntityFramework
{
/// <summary>
/// Exposes a method allowing to resolve a scope store.
/// </summary>
public class OpenIddictScopeStoreResolver<TContext> : IOpenIddictScopeStoreResolver
where TContext : DbContext
{
private static readonly ConcurrentDictionary<Type, Type> _cache = new ConcurrentDictionary<Type, Type>();
private readonly IServiceProvider _provider;
public OpenIddictScopeStoreResolver([NotNull] IServiceProvider provider)
{
_provider = provider;
}
/// <summary>
/// Returns a scope store compatible with the specified scope type or throws an
/// <see cref="InvalidOperationException"/> if no store can be built using the specified type.
/// </summary>
/// <typeparam name="TScope">The type of the Scope entity.</typeparam>
/// <returns>An <see cref="IOpenIddictScopeStore{TScope}"/>.</returns>
public IOpenIddictScopeStore<TScope> Get<TScope>() where TScope : class
{
var store = _provider.GetService<IOpenIddictScopeStore<TScope>>();
if (store != null)
{
return store;
}
var type = _cache.GetOrAdd(typeof(TScope), key =>
{
var root = OpenIddictCoreHelpers.FindGenericBaseType(key, typeof(OpenIddictScope<>));
if (root == null)
{
throw new InvalidOperationException(new StringBuilder()
.AppendLine("The specified scope type is not compatible with the Entity Framework 6.x stores.")
.Append("When enabling the Entity Framework 6.x stores, make sure you use the built-in generic ")
.Append("'OpenIdScope' entity (from the 'OpenIddict.Models' package) or a custom entity ")
.Append("that inherits from the generic 'OpenIddictScope' entity.")
.ToString());
}
return typeof(OpenIddictScopeStore<,,>).MakeGenericType(
/* TScope: */ key,
/* TContext: */ typeof(TContext),
/* TKey: */ root.GenericTypeArguments[0]);
});
return (IOpenIddictScopeStore<TScope>) _provider.GetRequiredService(type);
}
}
}

65
src/OpenIddict.EntityFramework/Resolvers/OpenIddictTokenStoreResolver.cs

@ -0,0 +1,65 @@
using System;
using System.Collections.Concurrent;
using System.Data.Entity;
using System.Text;
using JetBrains.Annotations;
using Microsoft.Extensions.DependencyInjection;
using OpenIddict.Abstractions;
using OpenIddict.Core;
using OpenIddict.Models;
namespace OpenIddict.EntityFramework
{
/// <summary>
/// Exposes a method allowing to resolve a token store.
/// </summary>
public class OpenIddictTokenStoreResolver<TContext> : IOpenIddictTokenStoreResolver
where TContext : DbContext
{
private static readonly ConcurrentDictionary<Type, Type> _cache = new ConcurrentDictionary<Type, Type>();
private readonly IServiceProvider _provider;
public OpenIddictTokenStoreResolver([NotNull] IServiceProvider provider)
{
_provider = provider;
}
/// <summary>
/// Returns a token store compatible with the specified token type or throws an
/// <see cref="InvalidOperationException"/> if no store can be built using the specified type.
/// </summary>
/// <typeparam name="TToken">The type of the Token entity.</typeparam>
/// <returns>An <see cref="IOpenIddictTokenStore{TToken}"/>.</returns>
public IOpenIddictTokenStore<TToken> Get<TToken>() where TToken : class
{
var store = _provider.GetService<IOpenIddictTokenStore<TToken>>();
if (store != null)
{
return store;
}
var type = _cache.GetOrAdd(typeof(TToken), key =>
{
var root = OpenIddictCoreHelpers.FindGenericBaseType(key, typeof(OpenIddictToken<,,>));
if (root == null)
{
throw new InvalidOperationException(new StringBuilder()
.AppendLine("The specified token type is not compatible with the Entity Framework 6.x stores.")
.Append("When enabling the Entity Framework 6.x stores, make sure you use the built-in generic ")
.Append("'OpenIddictToken' entity (from the 'OpenIddict.Models' package) or a custom entity ")
.Append("that inherits from the generic 'OpenIddictToken' entity.")
.ToString());
}
return typeof(OpenIddictTokenStore<,,,,>).MakeGenericType(
/* TToken: */ key,
/* TApplication: */ root.GenericTypeArguments[1],
/* TAuthorization: */ root.GenericTypeArguments[2],
/* TContext: */ typeof(TContext),
/* TKey: */ root.GenericTypeArguments[0]);
});
return (IOpenIddictTokenStore<TToken>) _provider.GetRequiredService(type);
}
}
}

2
src/OpenIddict.EntityFramework/Stores/OpenIddictAuthorizationStore.cs

@ -14,7 +14,7 @@ using System.Threading;
using System.Threading.Tasks;
using JetBrains.Annotations;
using Microsoft.Extensions.Caching.Memory;
using OpenIddict.Core;
using OpenIddict.Abstractions;
using OpenIddict.Models;
using OpenIddict.Stores;

2
src/OpenIddict.EntityFramework/Stores/OpenIddictTokenStore.cs

@ -14,7 +14,7 @@ using System.Threading;
using System.Threading.Tasks;
using JetBrains.Annotations;
using Microsoft.Extensions.Caching.Memory;
using OpenIddict.Core;
using OpenIddict.Abstractions;
using OpenIddict.Models;
using OpenIddict.Stores;

1
src/OpenIddict.EntityFrameworkCore/OpenIddict.EntityFrameworkCore.csproj

@ -13,6 +13,7 @@
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\OpenIddict.Core\OpenIddict.Core.csproj" />
<ProjectReference Include="..\OpenIddict.Stores\OpenIddict.Stores.csproj" />
</ItemGroup>

161
src/OpenIddict.EntityFrameworkCore/OpenIddictExtensions.cs

@ -5,14 +5,10 @@
*/
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Reflection;
using JetBrains.Annotations;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.Extensions.DependencyInjection.Extensions;
using OpenIddict.Core;
using OpenIddict.EntityFrameworkCore;
using OpenIddict.Models;
@ -25,8 +21,9 @@ namespace Microsoft.Extensions.DependencyInjection
/// 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 AddEntityFrameworkCoreStores<TContext>([NotNull] this OpenIddictBuilder builder)
/// <remarks>This extension can be safely called multiple times.</remarks>
/// <returns>The <see cref="OpenIddictCoreBuilder"/>.</returns>
public static OpenIddictCoreBuilder AddEntityFrameworkCoreStores<TContext>([NotNull] this OpenIddictCoreBuilder builder)
where TContext : DbContext
{
if (builder == null)
@ -34,85 +31,15 @@ namespace Microsoft.Extensions.DependencyInjection
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.");
builder.Services.TryAddScoped(typeof(OpenIddictApplicationStore<,,,,>));
builder.Services.TryAddScoped(typeof(OpenIddictAuthorizationStore<,,,,>));
builder.Services.TryAddScoped(typeof(OpenIddictScopeStore<,,>));
builder.Services.TryAddScoped(typeof(OpenIddictTokenStore<,,,,>));
var application = FindGenericBaseType(builder.ApplicationType, typeof(OpenIddictApplication<,,>));
if (application == null)
{
throw new InvalidOperationException("The Entity Framework Core 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 Core 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 Core 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 Core 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;
return builder.ReplaceApplicationStoreResolver<OpenIddictApplicationStoreResolver<TContext>>()
.ReplaceAuthorizationStoreResolver<OpenIddictAuthorizationStoreResolver<TContext>>()
.ReplaceScopeStoreResolver<OpenIddictScopeStoreResolver<TContext>>()
.ReplaceTokenStoreResolver<OpenIddictTokenStoreResolver<TContext>>();
}
/// <summary>
@ -122,12 +49,10 @@ namespace Microsoft.Extensions.DependencyInjection
/// <param name="builder">The builder used to configure the Entity Framework context.</param>
/// <returns>The Entity Framework context builder.</returns>
public static DbContextOptionsBuilder UseOpenIddict([NotNull] this DbContextOptionsBuilder builder)
{
return builder.UseOpenIddict<OpenIddictApplication,
OpenIddictAuthorization,
OpenIddictScope,
OpenIddictToken, string>();
}
=> builder.UseOpenIddict<OpenIddictApplication,
OpenIddictAuthorization,
OpenIddictScope,
OpenIddictToken, string>();
/// <summary>
/// Registers the OpenIddict entity sets in the Entity Framework context
@ -135,13 +60,12 @@ namespace Microsoft.Extensions.DependencyInjection
/// </summary>
/// <param name="builder">The builder used to configure the Entity Framework context.</param>
/// <returns>The Entity Framework context builder.</returns>
public static DbContextOptionsBuilder UseOpenIddict<TKey>([NotNull] this DbContextOptionsBuilder builder) where TKey : IEquatable<TKey>
{
return builder.UseOpenIddict<OpenIddictApplication<TKey>,
OpenIddictAuthorization<TKey>,
OpenIddictScope<TKey>,
OpenIddictToken<TKey>, TKey>();
}
public static DbContextOptionsBuilder UseOpenIddict<TKey>([NotNull] this DbContextOptionsBuilder builder)
where TKey : IEquatable<TKey>
=> builder.UseOpenIddict<OpenIddictApplication<TKey>,
OpenIddictAuthorization<TKey>,
OpenIddictScope<TKey>,
OpenIddictToken<TKey>, TKey>();
/// <summary>
/// Registers the OpenIddict entity sets in the Entity Framework context
@ -171,12 +95,10 @@ namespace Microsoft.Extensions.DependencyInjection
/// <param name="builder">The builder used to configure the Entity Framework context.</param>
/// <returns>The Entity Framework context builder.</returns>
public static ModelBuilder UseOpenIddict([NotNull] this ModelBuilder builder)
{
return builder.UseOpenIddict<OpenIddictApplication,
OpenIddictAuthorization,
OpenIddictScope,
OpenIddictToken, string>();
}
=> builder.UseOpenIddict<OpenIddictApplication,
OpenIddictAuthorization,
OpenIddictScope,
OpenIddictToken, string>();
/// <summary>
/// Registers the OpenIddict entity sets in the Entity Framework context
@ -185,12 +107,10 @@ namespace Microsoft.Extensions.DependencyInjection
/// <param name="builder">The builder used to configure the Entity Framework context.</param>
/// <returns>The Entity Framework context builder.</returns>
public static ModelBuilder UseOpenIddict<TKey>([NotNull] this ModelBuilder builder) where TKey : IEquatable<TKey>
{
return builder.UseOpenIddict<OpenIddictApplication<TKey>,
OpenIddictAuthorization<TKey>,
OpenIddictScope<TKey>,
OpenIddictToken<TKey>, TKey>();
}
=> builder.UseOpenIddict<OpenIddictApplication<TKey>,
OpenIddictAuthorization<TKey>,
OpenIddictScope<TKey>,
OpenIddictToken<TKey>, TKey>();
/// <summary>
/// Registers the OpenIddict entity sets in the Entity Framework context
@ -309,28 +229,5 @@ namespace Microsoft.Extensions.DependencyInjection
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;
}
}
}

65
src/OpenIddict.EntityFrameworkCore/Resolvers/OpenIddictApplicationStoreResolver.cs

@ -0,0 +1,65 @@
using System;
using System.Collections.Concurrent;
using System.Text;
using JetBrains.Annotations;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using OpenIddict.Abstractions;
using OpenIddict.Core;
using OpenIddict.Models;
namespace OpenIddict.EntityFrameworkCore
{
/// <summary>
/// Exposes a method allowing to resolve an application store.
/// </summary>
public class OpenIddictApplicationStoreResolver<TContext> : IOpenIddictApplicationStoreResolver
where TContext : DbContext
{
private static readonly ConcurrentDictionary<Type, Type> _cache = new ConcurrentDictionary<Type, Type>();
private readonly IServiceProvider _provider;
public OpenIddictApplicationStoreResolver([NotNull] IServiceProvider provider)
{
_provider = provider;
}
/// <summary>
/// Returns an application store compatible with the specified application type or throws an
/// <see cref="InvalidOperationException"/> if no store can be built using the specified type.
/// </summary>
/// <typeparam name="TApplication">The type of the Application entity.</typeparam>
/// <returns>An <see cref="IOpenIddictApplicationStore{TApplication}"/>.</returns>
public IOpenIddictApplicationStore<TApplication> Get<TApplication>() where TApplication : class
{
var store = _provider.GetService<IOpenIddictApplicationStore<TApplication>>();
if (store != null)
{
return store;
}
var type = _cache.GetOrAdd(typeof(TApplication), key =>
{
var root = OpenIddictCoreHelpers.FindGenericBaseType(key, typeof(OpenIddictApplication<,,>));
if (root == null)
{
throw new InvalidOperationException(new StringBuilder()
.AppendLine("The specified application type is not compatible with the Entity Framework Core stores.")
.Append("When enabling the Entity Framework Core stores, make sure you use the built-in generic ")
.Append("'OpenIddictApplication' entity (from the 'OpenIddict.Models' package) or a custom entity ")
.Append("that inherits from the generic 'OpenIddictApplication' entity.")
.ToString());
}
return typeof(OpenIddictApplicationStore<,,,,>).MakeGenericType(
/* TApplication: */ key,
/* TAuthorization: */ root.GenericTypeArguments[1],
/* TToken: */ root.GenericTypeArguments[2],
/* TContext: */ typeof(TContext),
/* TKey: */ root.GenericTypeArguments[0]);
});
return (IOpenIddictApplicationStore<TApplication>) _provider.GetRequiredService(type);
}
}
}

65
src/OpenIddict.EntityFrameworkCore/Resolvers/OpenIddictAuthorizationStoreResolver.cs

@ -0,0 +1,65 @@
using System;
using System.Collections.Concurrent;
using System.Text;
using JetBrains.Annotations;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using OpenIddict.Abstractions;
using OpenIddict.Core;
using OpenIddict.Models;
namespace OpenIddict.EntityFrameworkCore
{
/// <summary>
/// Exposes a method allowing to resolve an authorization store.
/// </summary>
public class OpenIddictAuthorizationStoreResolver<TContext> : IOpenIddictAuthorizationStoreResolver
where TContext : DbContext
{
private static readonly ConcurrentDictionary<Type, Type> _cache = new ConcurrentDictionary<Type, Type>();
private readonly IServiceProvider _provider;
public OpenIddictAuthorizationStoreResolver([NotNull] IServiceProvider provider)
{
_provider = provider;
}
/// <summary>
/// Returns an authorization store compatible with the specified authorization type or throws an
/// <see cref="InvalidOperationException"/> if no store can be built using the specified type.
/// </summary>
/// <typeparam name="TAuthorization">The type of the Authorization entity.</typeparam>
/// <returns>An <see cref="IOpenIddictAuthorizationStore{TAuthorization}"/>.</returns>
public IOpenIddictAuthorizationStore<TAuthorization> Get<TAuthorization>() where TAuthorization : class
{
var store = _provider.GetService<IOpenIddictAuthorizationStore<TAuthorization>>();
if (store != null)
{
return store;
}
var type = _cache.GetOrAdd(typeof(TAuthorization), key =>
{
var root = OpenIddictCoreHelpers.FindGenericBaseType(key, typeof(OpenIddictAuthorization<,,>));
if (root == null)
{
throw new InvalidOperationException(new StringBuilder()
.AppendLine("The specified authorization type is not compatible with the Entity Framework Core stores.")
.Append("When enabling the Entity Framework Core stores, make sure you use the built-in generic ")
.Append("'OpenIddictAuthorization' entity (from the 'OpenIddict.Models' package) or a custom entity ")
.Append("that inherits from the generic 'OpenIddictAuthorization' entity.")
.ToString());
}
return typeof(OpenIddictAuthorizationStore<,,,,>).MakeGenericType(
/* TAuthorization: */ key,
/* TApplication: */ root.GenericTypeArguments[1],
/* TToken: */ root.GenericTypeArguments[2],
/* TContext: */ typeof(TContext),
/* TKey: */ root.GenericTypeArguments[0]);
});
return (IOpenIddictAuthorizationStore<TAuthorization>) _provider.GetRequiredService(type);
}
}
}

63
src/OpenIddict.EntityFrameworkCore/Resolvers/OpenIddictScopeStoreResolver.cs

@ -0,0 +1,63 @@
using System;
using System.Collections.Concurrent;
using System.Text;
using JetBrains.Annotations;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using OpenIddict.Abstractions;
using OpenIddict.Core;
using OpenIddict.Models;
namespace OpenIddict.EntityFrameworkCore
{
/// <summary>
/// Exposes a method allowing to resolve a scope store.
/// </summary>
public class OpenIddictScopeStoreResolver<TContext> : IOpenIddictScopeStoreResolver
where TContext : DbContext
{
private static readonly ConcurrentDictionary<Type, Type> _cache = new ConcurrentDictionary<Type, Type>();
private readonly IServiceProvider _provider;
public OpenIddictScopeStoreResolver([NotNull] IServiceProvider provider)
{
_provider = provider;
}
/// <summary>
/// Returns a scope store compatible with the specified scope type or throws an
/// <see cref="InvalidOperationException"/> if no store can be built using the specified type.
/// </summary>
/// <typeparam name="TScope">The type of the Scope entity.</typeparam>
/// <returns>An <see cref="IOpenIddictScopeStore{TScope}"/>.</returns>
public IOpenIddictScopeStore<TScope> Get<TScope>() where TScope : class
{
var store = _provider.GetService<IOpenIddictScopeStore<TScope>>();
if (store != null)
{
return store;
}
var type = _cache.GetOrAdd(typeof(TScope), key =>
{
var root = OpenIddictCoreHelpers.FindGenericBaseType(key, typeof(OpenIddictScope<>));
if (root == null)
{
throw new InvalidOperationException(new StringBuilder()
.AppendLine("The specified scope type is not compatible with the Entity Framework Core stores.")
.Append("When enabling the Entity Framework Core stores, make sure you use the built-in generic ")
.Append("'OpenIdScope' entity (from the 'OpenIddict.Models' package) or a custom entity ")
.Append("that inherits from the generic 'OpenIddictScope' entity.")
.ToString());
}
return typeof(OpenIddictScopeStore<,,>).MakeGenericType(
/* TScope: */ key,
/* TContext: */ typeof(TContext),
/* TKey: */ root.GenericTypeArguments[0]);
});
return (IOpenIddictScopeStore<TScope>) _provider.GetRequiredService(type);
}
}
}

65
src/OpenIddict.EntityFrameworkCore/Resolvers/OpenIddictTokenStoreResolver.cs

@ -0,0 +1,65 @@
using System;
using System.Collections.Concurrent;
using System.Text;
using JetBrains.Annotations;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using OpenIddict.Abstractions;
using OpenIddict.Core;
using OpenIddict.Models;
namespace OpenIddict.EntityFrameworkCore
{
/// <summary>
/// Exposes a method allowing to resolve a token store.
/// </summary>
public class OpenIddictTokenStoreResolver<TContext> : IOpenIddictTokenStoreResolver
where TContext : DbContext
{
private static readonly ConcurrentDictionary<Type, Type> _cache = new ConcurrentDictionary<Type, Type>();
private readonly IServiceProvider _provider;
public OpenIddictTokenStoreResolver([NotNull] IServiceProvider provider)
{
_provider = provider;
}
/// <summary>
/// Returns a token store compatible with the specified token type or throws an
/// <see cref="InvalidOperationException"/> if no store can be built using the specified type.
/// </summary>
/// <typeparam name="TToken">The type of the Token entity.</typeparam>
/// <returns>An <see cref="IOpenIddictTokenStore{TToken}"/>.</returns>
public IOpenIddictTokenStore<TToken> Get<TToken>() where TToken : class
{
var store = _provider.GetService<IOpenIddictTokenStore<TToken>>();
if (store != null)
{
return store;
}
var type = _cache.GetOrAdd(typeof(TToken), key =>
{
var root = OpenIddictCoreHelpers.FindGenericBaseType(key, typeof(OpenIddictToken<,,>));
if (root == null)
{
throw new InvalidOperationException(new StringBuilder()
.AppendLine("The specified token type is not compatible with the Entity Framework Core stores.")
.Append("When enabling the Entity Framework Core stores, make sure you use the built-in generic ")
.Append("'OpenIddictToken' entity (from the 'OpenIddict.Models' package) or a custom entity ")
.Append("that inherits from the generic 'OpenIddictToken' entity.")
.ToString());
}
return typeof(OpenIddictTokenStore<,,,,>).MakeGenericType(
/* TToken: */ key,
/* TApplication: */ root.GenericTypeArguments[1],
/* TAuthorization: */ root.GenericTypeArguments[2],
/* TContext: */ typeof(TContext),
/* TKey: */ root.GenericTypeArguments[0]);
});
return (IOpenIddictTokenStore<TToken>) _provider.GetRequiredService(type);
}
}
}

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

@ -16,7 +16,7 @@ using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Storage;
using Microsoft.Extensions.Caching.Memory;
using OpenIddict.Core;
using OpenIddict.Abstractions;
using OpenIddict.Models;
using OpenIddict.Stores;

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

@ -16,6 +16,7 @@ using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Storage;
using Microsoft.Extensions.Caching.Memory;
using OpenIddict.Abstractions;
using OpenIddict.Core;
using OpenIddict.Models;
using OpenIddict.Stores;

5
src/OpenIddict.Mvc/OpenIddictExtensions.cs

@ -17,8 +17,9 @@ namespace Microsoft.Extensions.DependencyInjection
/// Registers the ASP.NET Core MVC model binders used by OpenIddict.
/// </summary>
/// <param name="builder">The services builder used by OpenIddict to register new services.</param>
/// <returns>The <see cref="OpenIddictBuilder"/>.</returns>
public static OpenIddictBuilder AddMvcBinders([NotNull] this OpenIddictBuilder builder)
/// <remarks>This extension can be safely called multiple times.</remarks>
/// <returns>The <see cref="OpenIddictServerBuilder"/>.</returns>
public static OpenIddictServerBuilder AddMvcBinders([NotNull] this OpenIddictServerBuilder builder)
{
if (builder == null)
{

8
src/OpenIddict.Server/Internal/OpenIddictHandler.cs → src/OpenIddict.Server/Internal/OpenIddictServerHandler.cs

@ -6,13 +6,13 @@ using Microsoft.AspNetCore.Authentication;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
namespace OpenIddict
namespace OpenIddict.Server
{
[EditorBrowsable(EditorBrowsableState.Never)]
public class OpenIddictHandler : OpenIdConnectServerHandler
public class OpenIddictServerHandler : OpenIdConnectServerHandler
{
public OpenIddictHandler(
[NotNull] IOptionsMonitor<OpenIddictOptions> options,
public OpenIddictServerHandler(
[NotNull] IOptionsMonitor<OpenIddictServerOptions> options,
[NotNull] ILoggerFactory logger,
[NotNull] UrlEncoder encoder,
[NotNull] ISystemClock clock)

36
src/OpenIddict.Server/Internal/OpenIddictInitializer.cs → src/OpenIddict.Server/Internal/OpenIddictServerInitializer.cs

@ -15,28 +15,32 @@ using Microsoft.AspNetCore.DataProtection;
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using OpenIddict.Core;
namespace OpenIddict
namespace OpenIddict.Server
{
/// <summary>
/// Contains the methods required to ensure that the configuration
/// used by OpenIddict is in a consistent and valid state.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
public class OpenIddictInitializer : IPostConfigureOptions<OpenIddictOptions>
public class OpenIddictServerInitializer : IPostConfigureOptions<OpenIddictServerOptions>
{
private readonly IDistributedCache _cache;
private readonly IDataProtectionProvider _dataProtectionProvider;
private readonly IOptionsMonitor<OpenIddictCoreOptions> _options;
/// <summary>
/// Creates a new instance of the <see cref="OpenIddictInitializer"/> class.
/// Creates a new instance of the <see cref="OpenIddictServerInitializer"/> class.
/// </summary>
public OpenIddictInitializer(
public OpenIddictServerInitializer(
[NotNull] IDistributedCache cache,
[NotNull] IDataProtectionProvider dataProtectionProvider)
[NotNull] IDataProtectionProvider dataProtectionProvider,
[NotNull] IOptionsMonitor<OpenIddictCoreOptions> options)
{
_cache = cache;
_dataProtectionProvider = dataProtectionProvider;
_options = options;
}
/// <summary>
@ -45,7 +49,7 @@ namespace OpenIddict
/// </summary>
/// <param name="name">The authentication scheme associated with the handler instance.</param>
/// <param name="options">The options instance to initialize.</param>
public void PostConfigure([NotNull] string name, [NotNull] OpenIddictOptions options)
public void PostConfigure([NotNull] string name, [NotNull] OpenIddictServerOptions options)
{
if (options == null)
{
@ -189,6 +193,26 @@ namespace OpenIddict
{
options.Scopes.Add(OpenIdConnectConstants.Scopes.OfflineAccess);
}
if (options.ApplicationType == null)
{
options.ApplicationType = _options.CurrentValue.DefaultApplicationType;
}
if (options.AuthorizationType == null)
{
options.AuthorizationType = _options.CurrentValue.DefaultAuthorizationType;
}
if (options.ScopeType == null)
{
options.ScopeType = _options.CurrentValue.DefaultScopeType;
}
if (options.TokenType == null)
{
options.TokenType = _options.CurrentValue.DefaultTokenType;
}
}
}
}

14
src/OpenIddict.Server/Internal/OpenIddictProvider.Authentication.cs → src/OpenIddict.Server/Internal/OpenIddictServerProvider.Authentication.cs

@ -19,16 +19,16 @@ using Microsoft.IdentityModel.Tokens;
using Newtonsoft.Json;
using Newtonsoft.Json.Bson;
using Newtonsoft.Json.Linq;
using OpenIddict.Core;
using OpenIddict.Abstractions;
namespace OpenIddict
namespace OpenIddict.Server
{
public partial class OpenIddictProvider<TApplication, TAuthorization, TScope, TToken> : OpenIdConnectServerProvider
public partial class OpenIddictServerProvider<TApplication, TAuthorization, TScope, TToken> : OpenIdConnectServerProvider
where TApplication : class where TAuthorization : class where TScope : class where TToken : class
{
public override async Task ExtractAuthorizationRequest([NotNull] ExtractAuthorizationRequestContext context)
{
var options = (OpenIddictOptions) context.Options;
var options = (OpenIddictServerOptions) context.Options;
// Reject requests using the unsupported request parameter.
if (!string.IsNullOrEmpty(context.Request.Request))
@ -109,7 +109,7 @@ namespace OpenIddict
public override async Task ValidateAuthorizationRequest([NotNull] ValidateAuthorizationRequestContext context)
{
var options = (OpenIddictOptions) context.Options;
var options = (OpenIddictServerOptions) context.Options;
// Note: the OpenID Connect server middleware supports authorization code, implicit, hybrid,
// none and custom flows but OpenIddict uses a stricter policy rejecting none and custum flows.
@ -414,7 +414,7 @@ namespace OpenIddict
public override async Task HandleAuthorizationRequest([NotNull] HandleAuthorizationRequestContext context)
{
var options = (OpenIddictOptions) context.Options;
var options = (OpenIddictServerOptions) context.Options;
// If no request_id parameter can be found in the current request, assume the OpenID Connect request
// was not serialized yet and store the entire payload in the distributed cache to make it easier
@ -466,7 +466,7 @@ namespace OpenIddict
public override async Task ApplyAuthorizationResponse([NotNull] ApplyAuthorizationResponseContext context)
{
var options = (OpenIddictOptions) context.Options;
var options = (OpenIddictServerOptions) context.Options;
// Remove the authorization request from the distributed cache.
if (options.EnableRequestCaching && !string.IsNullOrEmpty(context.Request.RequestId))

8
src/OpenIddict.Server/Internal/OpenIddictProvider.Discovery.cs → src/OpenIddict.Server/Internal/OpenIddictServerProvider.Discovery.cs

@ -12,16 +12,16 @@ using JetBrains.Annotations;
using Microsoft.AspNetCore.Authentication;
using Microsoft.Extensions.DependencyInjection;
using Newtonsoft.Json.Linq;
using OpenIddict.Core;
using OpenIddict.Abstractions;
namespace OpenIddict
namespace OpenIddict.Server
{
public partial class OpenIddictProvider<TApplication, TAuthorization, TScope, TToken> : OpenIdConnectServerProvider
public partial class OpenIddictServerProvider<TApplication, TAuthorization, TScope, TToken> : OpenIdConnectServerProvider
where TApplication : class where TAuthorization : class where TScope : class where TToken : class
{
public override async Task HandleConfigurationRequest([NotNull] HandleConfigurationRequestContext context)
{
var options = (OpenIddictOptions) context.Options;
var options = (OpenIddictServerOptions) context.Options;
// Note: though it's natively supported by the OpenID Connect server middleware,
// OpenIddict disallows the use of the unsecure code_challenge_method=plain method,

11
src/OpenIddict.Server/Internal/OpenIddictProvider.Exchange.cs → src/OpenIddict.Server/Internal/OpenIddictServerProvider.Exchange.cs

@ -5,7 +5,6 @@
*/
using System;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Threading.Tasks;
using AspNet.Security.OpenIdConnect.Extensions;
@ -13,16 +12,16 @@ using AspNet.Security.OpenIdConnect.Primitives;
using AspNet.Security.OpenIdConnect.Server;
using JetBrains.Annotations;
using Microsoft.Extensions.Logging;
using OpenIddict.Core;
using OpenIddict.Abstractions;
namespace OpenIddict
namespace OpenIddict.Server
{
public partial class OpenIddictProvider<TApplication, TAuthorization, TScope, TToken> : OpenIdConnectServerProvider
public partial class OpenIddictServerProvider<TApplication, TAuthorization, TScope, TToken> : OpenIdConnectServerProvider
where TApplication : class where TAuthorization : class where TScope : class where TToken : class
{
public override async Task ValidateTokenRequest([NotNull] ValidateTokenRequestContext context)
{
var options = (OpenIddictOptions) context.Options;
var options = (OpenIddictServerOptions) context.Options;
// Reject token requests that don't specify a supported grant type.
if (!options.GrantTypes.Contains(context.Request.GrantType))
@ -274,7 +273,7 @@ namespace OpenIddict
public override async Task HandleTokenRequest([NotNull] HandleTokenRequestContext context)
{
var options = (OpenIddictOptions) context.Options;
var options = (OpenIddictServerOptions) context.Options;
if (context.Ticket != null)
{

14
src/OpenIddict.Server/Internal/OpenIddictProvider.Helpers.cs → src/OpenIddict.Server/Internal/OpenIddictServerProvider.Helpers.cs

@ -14,19 +14,19 @@ using AspNet.Security.OpenIdConnect.Primitives;
using AspNet.Security.OpenIdConnect.Server;
using JetBrains.Annotations;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Microsoft.IdentityModel.Tokens;
using Newtonsoft.Json.Linq;
using OpenIddict.Abstractions;
using OpenIddict.Core;
namespace OpenIddict
namespace OpenIddict.Server
{
public partial class OpenIddictProvider<TApplication, TAuthorization, TScope, TToken> : OpenIdConnectServerProvider
public partial class OpenIddictServerProvider<TApplication, TAuthorization, TScope, TToken> : OpenIdConnectServerProvider
where TApplication : class where TAuthorization : class where TScope : class where TToken : class
{
private async Task CreateAuthorizationAsync([NotNull] AuthenticationTicket ticket,
[NotNull] OpenIddictOptions options, [NotNull] OpenIdConnectRequest request)
[NotNull] OpenIddictServerOptions options, [NotNull] OpenIdConnectRequest request)
{
var descriptor = new OpenIddictAuthorizationDescriptor
{
@ -81,7 +81,7 @@ namespace OpenIddict
private async Task<string> CreateTokenAsync(
[NotNull] string type, [NotNull] AuthenticationTicket ticket,
[NotNull] OpenIddictOptions options,
[NotNull] OpenIddictServerOptions options,
[NotNull] OpenIdConnectRequest request,
[NotNull] ISecureDataFormat<AuthenticationTicket> format)
{
@ -214,7 +214,7 @@ namespace OpenIddict
private async Task<AuthenticationTicket> ReceiveTokenAsync(
[NotNull] string type, [NotNull] string value,
[NotNull] OpenIddictOptions options,
[NotNull] OpenIddictServerOptions options,
[NotNull] OpenIdConnectRequest request,
[NotNull] ISecureDataFormat<AuthenticationTicket> format)
{
@ -478,7 +478,7 @@ namespace OpenIddict
}
private async Task<bool> TryExtendTokenAsync(
[NotNull] TToken token, [NotNull] AuthenticationTicket ticket, [NotNull] OpenIddictOptions options)
[NotNull] TToken token, [NotNull] AuthenticationTicket ticket, [NotNull] OpenIddictServerOptions options)
{
var identifier = ticket.GetTokenId();
Debug.Assert(!string.IsNullOrEmpty(identifier), "The token identifier shouldn't be null or empty.");

8
src/OpenIddict.Server/Internal/OpenIddictProvider.Introspection.cs → src/OpenIddict.Server/Internal/OpenIddictServerProvider.Introspection.cs

@ -12,11 +12,11 @@ using AspNet.Security.OpenIdConnect.Primitives;
using AspNet.Security.OpenIdConnect.Server;
using JetBrains.Annotations;
using Microsoft.Extensions.Logging;
using OpenIddict.Core;
using OpenIddict.Abstractions;
namespace OpenIddict
namespace OpenIddict.Server
{
public partial class OpenIddictProvider<TApplication, TAuthorization, TScope, TToken> : OpenIdConnectServerProvider
public partial class OpenIddictServerProvider<TApplication, TAuthorization, TScope, TToken> : OpenIdConnectServerProvider
where TApplication : class where TAuthorization : class where TScope : class where TToken : class
{
public override Task ExtractIntrospectionRequest([NotNull] ExtractIntrospectionRequestContext context)
@ -112,7 +112,7 @@ namespace OpenIddict
public override async Task HandleIntrospectionRequest([NotNull] HandleIntrospectionRequestContext context)
{
var options = (OpenIddictOptions) context.Options;
var options = (OpenIddictServerOptions) context.Options;
Debug.Assert(context.Ticket != null, "The authentication ticket shouldn't be null.");
Debug.Assert(!string.IsNullOrEmpty(context.Request.ClientId), "The client_id parameter shouldn't be null.");

10
src/OpenIddict.Server/Internal/OpenIddictProvider.Revocation.cs → src/OpenIddict.Server/Internal/OpenIddictServerProvider.Revocation.cs

@ -12,16 +12,16 @@ using AspNet.Security.OpenIdConnect.Primitives;
using AspNet.Security.OpenIdConnect.Server;
using JetBrains.Annotations;
using Microsoft.Extensions.Logging;
using OpenIddict.Core;
using OpenIddict.Abstractions;
namespace OpenIddict
namespace OpenIddict.Server
{
public partial class OpenIddictProvider<TApplication, TAuthorization, TScope, TToken> : OpenIdConnectServerProvider
public partial class OpenIddictServerProvider<TApplication, TAuthorization, TScope, TToken> : OpenIdConnectServerProvider
where TApplication : class where TAuthorization : class where TScope : class where TToken : class
{
public override async Task ValidateRevocationRequest([NotNull] ValidateRevocationRequestContext context)
{
var options = (OpenIddictOptions) context.Options;
var options = (OpenIddictServerOptions) context.Options;
Debug.Assert(!options.DisableTokenRevocation, "Token revocation support shouldn't be disabled at this stage.");
@ -163,7 +163,7 @@ namespace OpenIddict
public override async Task HandleRevocationRequest([NotNull] HandleRevocationRequestContext context)
{
var options = (OpenIddictOptions) context.Options;
var options = (OpenIddictServerOptions) context.Options;
Debug.Assert(context.Ticket != null, "The authentication ticket shouldn't be null.");

16
src/OpenIddict.Server/Internal/OpenIddictProvider.Serialization.cs → src/OpenIddict.Server/Internal/OpenIddictServerProvider.Serialization.cs

@ -10,14 +10,14 @@ using AspNet.Security.OpenIdConnect.Primitives;
using AspNet.Security.OpenIdConnect.Server;
using JetBrains.Annotations;
namespace OpenIddict
namespace OpenIddict.Server
{
public partial class OpenIddictProvider<TApplication, TAuthorization, TScope, TToken> : OpenIdConnectServerProvider
public partial class OpenIddictServerProvider<TApplication, TAuthorization, TScope, TToken> : OpenIdConnectServerProvider
where TApplication : class where TAuthorization : class where TScope : class where TToken : class
{
public override async Task DeserializeAccessToken([NotNull] DeserializeAccessTokenContext context)
{
var options = (OpenIddictOptions) context.Options;
var options = (OpenIddictServerOptions) context.Options;
if (options.DisableTokenRevocation)
{
return;
@ -38,7 +38,7 @@ namespace OpenIddict
public override async Task DeserializeAuthorizationCode([NotNull] DeserializeAuthorizationCodeContext context)
{
var options = (OpenIddictOptions) context.Options;
var options = (OpenIddictServerOptions) context.Options;
if (options.DisableTokenRevocation)
{
return;
@ -55,7 +55,7 @@ namespace OpenIddict
public override async Task DeserializeRefreshToken([NotNull] DeserializeRefreshTokenContext context)
{
var options = (OpenIddictOptions) context.Options;
var options = (OpenIddictServerOptions) context.Options;
if (options.DisableTokenRevocation)
{
return;
@ -72,7 +72,7 @@ namespace OpenIddict
public override async Task SerializeAccessToken([NotNull] SerializeAccessTokenContext context)
{
var options = (OpenIddictOptions) context.Options;
var options = (OpenIddictServerOptions) context.Options;
if (options.DisableTokenRevocation)
{
return;
@ -96,7 +96,7 @@ namespace OpenIddict
public override async Task SerializeAuthorizationCode([NotNull] SerializeAuthorizationCodeContext context)
{
var options = (OpenIddictOptions) context.Options;
var options = (OpenIddictServerOptions) context.Options;
if (options.DisableTokenRevocation)
{
return;
@ -122,7 +122,7 @@ namespace OpenIddict
public override async Task SerializeRefreshToken([NotNull] SerializeRefreshTokenContext context)
{
var options = (OpenIddictOptions) context.Options;
var options = (OpenIddictServerOptions) context.Options;
if (options.DisableTokenRevocation)
{
return;

12
src/OpenIddict.Server/Internal/OpenIddictProvider.Session.cs → src/OpenIddict.Server/Internal/OpenIddictServerProvider.Session.cs

@ -18,16 +18,16 @@ using Microsoft.IdentityModel.Tokens;
using Newtonsoft.Json;
using Newtonsoft.Json.Bson;
using Newtonsoft.Json.Linq;
using OpenIddict.Core;
using OpenIddict.Abstractions;
namespace OpenIddict
namespace OpenIddict.Server
{
public partial class OpenIddictProvider<TApplication, TAuthorization, TScope, TToken> : OpenIdConnectServerProvider
public partial class OpenIddictServerProvider<TApplication, TAuthorization, TScope, TToken> : OpenIdConnectServerProvider
where TApplication : class where TAuthorization : class where TScope : class where TToken : class
{
public override async Task ExtractLogoutRequest([NotNull] ExtractLogoutRequestContext context)
{
var options = (OpenIddictOptions) context.Options;
var options = (OpenIddictServerOptions) context.Options;
// If a request_id parameter can be found in the logout request,
// restore the complete logout request from the distributed cache.
@ -127,7 +127,7 @@ namespace OpenIddict
public override async Task HandleLogoutRequest([NotNull] HandleLogoutRequestContext context)
{
var options = (OpenIddictOptions) context.Options;
var options = (OpenIddictServerOptions) context.Options;
// If no request_id parameter can be found in the current request, assume the OpenID Connect
// request was not serialized yet and store the entire payload in the distributed cache
@ -177,7 +177,7 @@ namespace OpenIddict
public override async Task ApplyLogoutResponse([NotNull] ApplyLogoutResponseContext context)
{
var options = (OpenIddictOptions) context.Options;
var options = (OpenIddictServerOptions) context.Options;
// Remove the logout request from the distributed cache.
if (options.EnableRequestCaching && !string.IsNullOrEmpty(context.Request.RequestId))

4
src/OpenIddict.Server/Internal/OpenIddictProvider.Userinfo.cs → src/OpenIddict.Server/Internal/OpenIddictServerProvider.Userinfo.cs

@ -8,9 +8,9 @@ using System.Threading.Tasks;
using AspNet.Security.OpenIdConnect.Server;
using JetBrains.Annotations;
namespace OpenIddict
namespace OpenIddict.Server
{
public partial class OpenIddictProvider<TApplication, TAuthorization, TScope, TToken> : OpenIdConnectServerProvider
public partial class OpenIddictServerProvider<TApplication, TAuthorization, TScope, TToken> : OpenIdConnectServerProvider
where TApplication : class where TAuthorization : class where TScope : class where TToken : class
{
public override Task ExtractUserinfoRequest([NotNull] ExtractUserinfoRequestContext context)

13
src/OpenIddict.Server/Internal/OpenIddictProvider.cs → src/OpenIddict.Server/Internal/OpenIddictServerProvider.cs

@ -14,22 +14,23 @@ using AspNet.Security.OpenIdConnect.Server;
using JetBrains.Annotations;
using Microsoft.AspNetCore.Authentication;
using Microsoft.Extensions.Logging;
using OpenIddict.Abstractions;
using OpenIddict.Core;
namespace OpenIddict
namespace OpenIddict.Server
{
/// <summary>
/// Provides the logic necessary to extract, validate and handle OpenID Connect requests.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
public partial class OpenIddictProvider<TApplication, TAuthorization, TScope, TToken> : OpenIdConnectServerProvider
public partial class OpenIddictServerProvider<TApplication, TAuthorization, TScope, TToken> : OpenIdConnectServerProvider
where TApplication : class where TAuthorization : class where TScope : class where TToken : class
{
/// <summary>
/// Creates a new instance of the <see cref="OpenIddictProvider{TApplication, TAuthorization, TScope, TToken}"/> class.
/// Creates a new instance of the <see cref="OpenIddictServerProvider{TApplication, TAuthorization, TScope, TToken}"/> class.
/// </summary>
public OpenIddictProvider(
[NotNull] ILogger<OpenIddictProvider<TApplication, TAuthorization, TScope, TToken>> logger,
public OpenIddictServerProvider(
[NotNull] ILogger<OpenIddictServerProvider<TApplication, TAuthorization, TScope, TToken>> logger,
[NotNull] OpenIddictApplicationManager<TApplication> applications,
[NotNull] OpenIddictAuthorizationManager<TAuthorization> authorizations,
[NotNull] OpenIddictScopeManager<TScope> scopes,
@ -86,7 +87,7 @@ namespace OpenIddict
public override async Task ProcessSigninResponse([NotNull] ProcessSigninResponseContext context)
{
var options = (OpenIddictOptions) context.Options;
var options = (OpenIddictServerOptions) context.Options;
Debug.Assert(context.Request.IsAuthorizationRequest() ||
context.Request.IsTokenRequest(),

1008
src/OpenIddict.Server/OpenIddictExtensions.cs

File diff suppressed because it is too large

653
src/OpenIddict.Server/OpenIddictServerBuilder.cs

@ -0,0 +1,653 @@
/*
* 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.Collections.Generic;
using System.ComponentModel;
using System.IdentityModel.Tokens.Jwt;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Security.Cryptography.X509Certificates;
using System.Threading;
using AspNet.Security.OpenIdConnect.Primitives;
using AspNet.Security.OpenIdConnect.Server;
using JetBrains.Annotations;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Http;
using Microsoft.IdentityModel.Tokens;
using OpenIddict.Core;
using OpenIddict.Server;
namespace Microsoft.Extensions.DependencyInjection
{
/// <summary>
/// Exposes the necessary methods required to configure the OpenIddict server services.
/// </summary>
public class OpenIddictServerBuilder
{
/// <summary>
/// Initializes a new instance of <see cref="OpenIddictServerBuilder"/>.
/// </summary>
/// <param name="services">The services collection.</param>
public OpenIddictServerBuilder([NotNull] IServiceCollection services)
{
if (services == null)
{
throw new ArgumentNullException(nameof(services));
}
Services = services;
}
/// <summary>
/// Gets the services collection.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
public IServiceCollection Services { get; }
/// <summary>
/// Amends the default OpenIddict server configuration.
/// </summary>
/// <param name="configuration">The delegate used to configure the OpenIddict options.</param>
/// <remarks>This extension can be safely called multiple times.</remarks>
/// <returns>The <see cref="OpenIddictServerBuilder"/>.</returns>
public OpenIddictServerBuilder Configure([NotNull] Action<OpenIddictServerOptions> configuration)
{
if (configuration == null)
{
throw new ArgumentNullException(nameof(configuration));
}
Services.Configure(OpenIdConnectServerDefaults.AuthenticationScheme, configuration);
return this;
}
/// <summary>
/// Registers (and generates if necessary) a user-specific development
/// certificate used to sign the JWT tokens issued by OpenIddict.
/// </summary>
/// <returns>The <see cref="OpenIddictServerBuilder"/>.</returns>
public OpenIddictServerBuilder AddDevelopmentSigningCertificate()
=> Configure(options => options.SigningCredentials.AddDevelopmentCertificate());
/// <summary>
/// Registers (and generates if necessary) a user-specific development
/// certificate used to sign the JWT tokens issued by OpenIddict.
/// </summary>
/// <param name="subject">The subject name associated with the certificate.</param>
/// <returns>The <see cref="OpenIddictServerBuilder"/>.</returns>
public OpenIddictServerBuilder AddDevelopmentSigningCertificate([NotNull] X500DistinguishedName subject)
{
if (subject == null)
{
throw new ArgumentNullException(nameof(subject));
}
return Configure(options => options.SigningCredentials.AddDevelopmentCertificate(subject));
}
/// <summary>
/// Registers a new ephemeral key used to sign the JWT tokens issued by OpenIddict: the key
/// is discarded when the application shuts down and tokens signed using this key are
/// automatically invalidated. This method should only be used during development.
/// On production, using a X.509 certificate stored in the machine store is recommended.
/// </summary>
/// <returns>The <see cref="OpenIddictServerBuilder"/>.</returns>
public OpenIddictServerBuilder AddEphemeralSigningKey()
=> Configure(options => options.SigningCredentials.AddEphemeralKey());
/// <summary>
/// Registers a new ephemeral key used to sign the JWT tokens issued by OpenIddict: the key
/// is discarded when the application shuts down and tokens signed using this key are
/// automatically invalidated. This method should only be used during development.
/// On production, using a X.509 certificate stored in the machine store is recommended.
/// </summary>
/// <param name="algorithm">The algorithm associated with the signing key.</param>
/// <returns>The <see cref="OpenIddictServerBuilder"/>.</returns>
public OpenIddictServerBuilder AddEphemeralSigningKey([NotNull] string algorithm)
{
if (string.IsNullOrEmpty(algorithm))
{
throw new ArgumentException("The algorithm cannot be null or empty.", nameof(algorithm));
}
return Configure(options => options.SigningCredentials.AddEphemeralKey(algorithm));
}
/// <summary>
/// Registers a <see cref="SecurityKey"/> used to encrypt the JWT access tokens issued by OpenIddict.
/// </summary>
/// <param name="key">The security key.</param>
/// <returns>The <see cref="OpenIddictServerBuilder"/>.</returns>
public OpenIddictServerBuilder AddEncryptingKey([NotNull] SecurityKey key)
{
if (key == null)
{
throw new ArgumentNullException(nameof(key));
}
return Configure(options => options.EncryptingCredentials.AddKey(key));
}
/// <summary>
/// Registers a <see cref="X509Certificate2"/> that is used to sign the JWT tokens issued by OpenIddict.
/// </summary>
/// <param name="certificate">The certificate used to sign the security tokens issued by the server.</param>
/// <returns>The <see cref="OpenIddictServerBuilder"/>.</returns>
public OpenIddictServerBuilder AddSigningCertificate([NotNull] X509Certificate2 certificate)
{
if (certificate == null)
{
throw new ArgumentNullException(nameof(certificate));
}
if (!certificate.HasPrivateKey)
{
throw new InvalidOperationException("The certificate doesn't contain the required private key.");
}
return Configure(options => options.SigningCredentials.AddCertificate(certificate));
}
/// <summary>
/// Registers a <see cref="X509Certificate2"/> retrieved from an
/// embedded resource and used to sign the JWT tokens issued by OpenIddict.
/// </summary>
/// <param name="assembly">The assembly containing the certificate.</param>
/// <param name="resource">The name of the embedded resource.</param>
/// <param name="password">The password used to open the certificate.</param>
/// <returns>The <see cref="OpenIddictServerBuilder"/>.</returns>
public OpenIddictServerBuilder AddSigningCertificate(
[NotNull] Assembly assembly, [NotNull] string resource, [NotNull] string password)
{
if (assembly == null)
{
throw new ArgumentNullException(nameof(assembly));
}
if (string.IsNullOrEmpty(resource))
{
throw new ArgumentNullException(nameof(resource));
}
if (string.IsNullOrEmpty(password))
{
throw new ArgumentNullException(nameof(password));
}
return Configure(options => options.SigningCredentials.AddCertificate(assembly, resource, password));
}
/// <summary>
/// Registers a <see cref="X509Certificate2"/> extracted from a
/// stream and used to sign the JWT tokens issued by OpenIddict.
/// </summary>
/// <param name="stream">The stream containing the certificate.</param>
/// <param name="password">The password used to open the certificate.</param>
/// <returns>The <see cref="OpenIddictServerBuilder"/>.</returns>
public OpenIddictServerBuilder AddSigningCertificate([NotNull] Stream stream, [NotNull] string password)
{
if (stream == null)
{
throw new ArgumentNullException(nameof(stream));
}
if (string.IsNullOrEmpty(password))
{
throw new ArgumentNullException(nameof(password));
}
return Configure(options => options.SigningCredentials.AddCertificate(stream, password));
}
/// <summary>
/// Registers a <see cref="X509Certificate2"/> extracted from a
/// stream and used to sign the JWT tokens issued by OpenIddict.
/// </summary>
/// <param name="stream">The stream containing the certificate.</param>
/// <param name="password">The password used to open the certificate.</param>
/// <param name="flags">
/// An enumeration of flags indicating how and where
/// to store the private key of the certificate.
/// </param>
/// <returns>The <see cref="OpenIddictServerBuilder"/>.</returns>
public OpenIddictServerBuilder AddSigningCertificate(
[NotNull] Stream stream, [NotNull] string password, X509KeyStorageFlags flags)
{
if (stream == null)
{
throw new ArgumentNullException(nameof(stream));
}
if (string.IsNullOrEmpty(password))
{
throw new ArgumentNullException(nameof(password));
}
return Configure(options => options.SigningCredentials.AddCertificate(stream, password, flags));
}
/// <summary>
/// Registers a <see cref="X509Certificate2"/> retrieved from the X.509
/// machine store and used to sign the JWT tokens issued by OpenIddict.
/// </summary>
/// <param name="thumbprint">The thumbprint of the certificate used to identify it in the X.509 store.</param>
/// <returns>The <see cref="OpenIddictServerBuilder"/>.</returns>
public OpenIddictServerBuilder AddSigningCertificate([NotNull] string thumbprint)
{
if (string.IsNullOrEmpty(thumbprint))
{
throw new ArgumentNullException(nameof(thumbprint));
}
return Configure(options => options.SigningCredentials.AddCertificate(thumbprint));
}
/// <summary>
/// Registers a <see cref="X509Certificate2"/> retrieved from the given
/// X.509 store and used to sign the JWT tokens issued by OpenIddict.
/// </summary>
/// <param name="thumbprint">The thumbprint of the certificate used to identify it in the X.509 store.</param>
/// <param name="name">The name of the X.509 store.</param>
/// <param name="location">The location of the X.509 store.</param>
/// <returns>The <see cref="OpenIddictServerBuilder"/>.</returns>
public OpenIddictServerBuilder AddSigningCertificate(
[NotNull] string thumbprint, StoreName name, StoreLocation location)
{
if (string.IsNullOrEmpty(thumbprint))
{
throw new ArgumentNullException(nameof(thumbprint));
}
return Configure(options => options.SigningCredentials.AddCertificate(thumbprint, name, location));
}
/// <summary>
/// Registers a <see cref="SecurityKey"/> used to sign the JWT tokens issued by OpenIddict.
/// Note: using <see cref="RsaSecurityKey"/> asymmetric keys is recommended on production.
/// </summary>
/// <param name="key">The security key.</param>
/// <returns>The <see cref="OpenIddictServerBuilder"/>.</returns>
public OpenIddictServerBuilder AddSigningKey([NotNull] SecurityKey key)
{
if (key == null)
{
throw new ArgumentNullException(nameof(key));
}
return Configure(options => options.SigningCredentials.AddKey(key));
}
/// <summary>
/// Enables authorization code flow support. For more information
/// about this specific OAuth2/OpenID Connect flow, visit
/// https://tools.ietf.org/html/rfc6749#section-4.1 and
/// http://openid.net/specs/openid-connect-core-1_0.html#CodeFlowAuth.
/// </summary>
/// <returns>The <see cref="OpenIddictServerBuilder"/>.</returns>
public OpenIddictServerBuilder AllowAuthorizationCodeFlow()
=> Configure(options => options.GrantTypes.Add(OpenIdConnectConstants.GrantTypes.AuthorizationCode));
/// <summary>
/// Enables client credentials flow support. For more information about this
/// specific OAuth2 flow, visit https://tools.ietf.org/html/rfc6749#section-4.4.
/// </summary>
/// <returns>The <see cref="OpenIddictServerBuilder"/>.</returns>
public OpenIddictServerBuilder AllowClientCredentialsFlow()
=> Configure(options => options.GrantTypes.Add(OpenIdConnectConstants.GrantTypes.ClientCredentials));
/// <summary>
/// Enables custom grant type support.
/// </summary>
/// <param name="type">The grant type associated with the flow.</param>
/// <returns>The <see cref="OpenIddictServerBuilder"/>.</returns>
public OpenIddictServerBuilder AllowCustomFlow([NotNull] string type)
{
if (string.IsNullOrEmpty(type))
{
throw new ArgumentException("The grant type cannot be null or empty.", nameof(type));
}
return Configure(options => options.GrantTypes.Add(type));
}
/// <summary>
/// Enables implicit flow support. For more information
/// about this specific OAuth2/OpenID Connect flow, visit
/// https://tools.ietf.org/html/rfc6749#section-4.2 and
/// http://openid.net/specs/openid-connect-core-1_0.html#ImplicitFlowAuth.
/// </summary>
/// <returns>The <see cref="OpenIddictServerBuilder"/>.</returns>
public OpenIddictServerBuilder AllowImplicitFlow()
=> Configure(options => options.GrantTypes.Add(OpenIdConnectConstants.GrantTypes.Implicit));
/// <summary>
/// Enables password flow support. For more information about this specific
/// OAuth2 flow, visit https://tools.ietf.org/html/rfc6749#section-4.3.
/// </summary>
/// <returns>The <see cref="OpenIddictServerBuilder"/>.</returns>
public OpenIddictServerBuilder AllowPasswordFlow()
=> Configure(options => options.GrantTypes.Add(OpenIdConnectConstants.GrantTypes.Password));
/// <summary>
/// Enables refresh token flow support. For more information about this
/// specific OAuth2 flow, visit https://tools.ietf.org/html/rfc6749#section-6.
/// </summary>
/// <returns>The <see cref="OpenIddictServerBuilder"/>.</returns>
public OpenIddictServerBuilder AllowRefreshTokenFlow()
=> Configure(options => options.GrantTypes.Add(OpenIdConnectConstants.GrantTypes.RefreshToken));
/// <summary>
/// Disables the configuration endpoint.
/// </summary>
/// <returns>The <see cref="OpenIddictServerBuilder"/>.</returns>
public OpenIddictServerBuilder DisableConfigurationEndpoint()
=> Configure(options => options.ConfigurationEndpointPath = PathString.Empty);
/// <summary>
/// Disables the cryptography endpoint.
/// </summary>
/// <returns>The <see cref="OpenIddictServerBuilder"/>.</returns>
public OpenIddictServerBuilder DisableCryptographyEndpoint()
=> Configure(options => options.CryptographyEndpointPath = PathString.Empty);
/// <summary>
/// Disables the HTTPS requirement during development.
/// </summary>
/// <returns>The <see cref="OpenIddictServerBuilder"/>.</returns>
public OpenIddictServerBuilder DisableHttpsRequirement()
=> Configure(options => options.AllowInsecureHttp = true);
/// <summary>
/// Disables sliding expiration. When using this option, refresh tokens
/// are issued with a fixed expiration date: when it expires, a complete
/// authorization flow must be started to retrieve a new refresh token.
/// </summary>
/// <returns>The <see cref="OpenIddictServerBuilder"/>.</returns>
public OpenIddictServerBuilder DisableSlidingExpiration()
=> Configure(options => options.UseSlidingExpiration = false);
/// <summary>
/// Disables token revocation, so that authorization code and
/// refresh tokens are never stored and cannot be revoked.
/// Using this option is generally not recommended.
/// </summary>
/// <returns>The <see cref="OpenIddictServerBuilder"/>.</returns>
public OpenIddictServerBuilder DisableTokenRevocation()
=> Configure(options => options.DisableTokenRevocation = true);
/// <summary>
/// Enables the authorization endpoint.
/// </summary>
/// <param name="path">The relative path of the authorization endpoint.</param>
/// <returns>The <see cref="OpenIddictServerBuilder"/>.</returns>
public OpenIddictServerBuilder EnableAuthorizationEndpoint(PathString path)
{
if (!path.HasValue)
{
throw new ArgumentException("The path cannot be empty.", nameof(path));
}
return Configure(options => options.AuthorizationEndpointPath = path);
}
/// <summary>
/// Enables the introspection endpoint.
/// </summary>
/// <param name="path">The relative path of the logout endpoint.</param>
/// <returns>The <see cref="OpenIddictServerBuilder"/>.</returns>
public OpenIddictServerBuilder EnableIntrospectionEndpoint(PathString path)
{
if (!path.HasValue)
{
throw new ArgumentException("The path cannot be empty.", nameof(path));
}
return Configure(options => options.IntrospectionEndpointPath = path);
}
/// <summary>
/// Enables the logout endpoint.
/// </summary>
/// <param name="path">The relative path of the logout endpoint.</param>
/// <returns>The <see cref="OpenIddictServerBuilder"/>.</returns>
public OpenIddictServerBuilder EnableLogoutEndpoint(PathString path)
{
if (!path.HasValue)
{
throw new ArgumentException("The path cannot be empty.", nameof(path));
}
return Configure(options => options.LogoutEndpointPath = path);
}
/// <summary>
/// Enables request caching, so that both authorization and logout requests
/// are automatically stored in the distributed cache, which allows flowing
/// large payloads across requests. Enabling this option is recommended
/// when using external authentication providers or when large GET or POST
/// OpenID Connect authorization requests support is required.
/// </summary>
/// <returns>The <see cref="OpenIddictServerBuilder"/>.</returns>
public OpenIddictServerBuilder EnableRequestCaching()
=> Configure(options => options.EnableRequestCaching = true);
/// <summary>
/// Enables the revocation endpoint.
/// </summary>
/// <param name="path">The relative path of the revocation endpoint.</param>
/// <returns>The <see cref="OpenIddictServerBuilder"/>.</returns>
public OpenIddictServerBuilder EnableRevocationEndpoint( PathString path)
{
if (!path.HasValue)
{
throw new ArgumentException("The path cannot be empty.", nameof(path));
}
return Configure(options => options.RevocationEndpointPath = path);
}
/// <summary>
/// Rejects authorization and token requests that specify scopes that have not been
/// registered using <see cref="RegisterScopes(string[])"/> or
/// <see cref="OpenIddictScopeManager{TScope}.CreateAsync(TScope, CancellationToken)"/>.
/// </summary>
/// <returns>The <see cref="OpenIddictServerBuilder"/>.</returns>
public OpenIddictServerBuilder EnableScopeValidation()
=> Configure(options => options.EnableScopeValidation = true);
/// <summary>
/// Enables the token endpoint.
/// </summary>
/// <param name="path">The relative path of the token endpoint.</param>
/// <returns>The <see cref="OpenIddictServerBuilder"/>.</returns>
public OpenIddictServerBuilder EnableTokenEndpoint(PathString path)
{
if (!path.HasValue)
{
throw new ArgumentException("The path cannot be empty.", nameof(path));
}
return Configure(options => options.TokenEndpointPath = path);
}
/// <summary>
/// Enables the userinfo endpoint.
/// </summary>
/// <param name="path">The relative path of the userinfo endpoint.</param>
/// <returns>The <see cref="OpenIddictServerBuilder"/>.</returns>
public OpenIddictServerBuilder EnableUserinfoEndpoint(PathString path)
{
if (!path.HasValue)
{
throw new ArgumentException("The path cannot be empty.", nameof(path));
}
return Configure(options => options.UserinfoEndpointPath = path);
}
/// <summary>
/// Makes client identification mandatory so that token and revocation
/// requests that don't specify a client_id are automatically rejected.
/// Note: enabling this option doesn't prevent public clients from using
/// the token and revocation endpoints, but specifying a client_id is required.
/// </summary>
/// <returns>The <see cref="OpenIddictServerBuilder"/>.</returns>
public OpenIddictServerBuilder RequireClientIdentification()
=> Configure(options => options.RequireClientIdentification = true);
/// <summary>
/// Sets the access token lifetime, after which client applications must retrieve
/// a new access token by making a grant_type=refresh_token token request
/// or a prompt=none authorization request, depending on the selected flow.
/// Using long-lived access tokens or tokens that never expire is not recommended.
/// </summary>
/// <param name="lifetime">The access token lifetime.</param>
/// <returns>The <see cref="OpenIddictServerBuilder"/>.</returns>
public OpenIddictServerBuilder SetAccessTokenLifetime(TimeSpan lifetime)
=> Configure(options => options.AccessTokenLifetime = lifetime);
/// <summary>
/// Sets the authorization code lifetime, after which client applications
/// are unable to send a grant_type=authorization_code token request.
/// Using short-lived authorization codes is strongly recommended.
/// </summary>
/// <param name="lifetime">The authorization code lifetime.</param>
/// <returns>The <see cref="OpenIddictServerBuilder"/>.</returns>
public OpenIddictServerBuilder SetAuthorizationCodeLifetime(TimeSpan lifetime)
=> Configure(options => options.AuthorizationCodeLifetime = lifetime);
/// <summary>
/// Sets the identity token lifetime, after which client
/// applications should refuse processing identity tokens.
/// </summary>
/// <param name="lifetime">The identity token lifetime.</param>
/// <returns>The <see cref="OpenIddictServerBuilder"/>.</returns>
public OpenIddictServerBuilder SetIdentityTokenLifetime(TimeSpan lifetime)
=> Configure(options => options.IdentityTokenLifetime = lifetime);
/// <summary>
/// Sets the refresh token lifetime, after which client applications must get
/// a new authorization from the user. When sliding expiration is enabled,
/// a new refresh token is always issued to the client application,
/// which prolongs the validity period of the refresh token.
/// </summary>
/// <param name="lifetime">The refresh token lifetime.</param>
/// <returns>The <see cref="OpenIddictServerBuilder"/>.</returns>
public OpenIddictServerBuilder SetRefreshTokenLifetime(TimeSpan lifetime)
=> Configure(options => options.RefreshTokenLifetime = lifetime);
/// <summary>
/// Sets the issuer address, which is used as the base address
/// for the endpoint URIs returned from the discovery endpoint.
/// </summary>
/// <param name="address">The issuer address.</param>
/// <returns>The <see cref="OpenIddictServerBuilder"/>.</returns>
public OpenIddictServerBuilder SetIssuer([NotNull] Uri address)
{
if (address == null)
{
throw new ArgumentNullException(nameof(address));
}
return Configure(options => options.Issuer = address);
}
/// <summary>
/// Registers the specified claims as supported claims so
/// they can be returned as part of the discovery document.
/// </summary>
/// <param name="claims">The supported claims.</param>
/// <returns>The <see cref="OpenIddictServerBuilder"/>.</returns>
public OpenIddictServerBuilder RegisterClaims([NotNull] params string[] claims)
{
if (claims == null)
{
throw new ArgumentNullException(nameof(claims));
}
if (claims.Any(claim => string.IsNullOrEmpty(claim)))
{
throw new ArgumentException("Claims cannot be null or empty.", nameof(claims));
}
return Configure(options => options.Claims.UnionWith(claims));
}
/// <summary>
/// Registers the specified scopes as supported scopes so
/// they can be returned as part of the discovery document.
/// </summary>
/// <param name="scopes">The supported scopes.</param>
/// <returns>The <see cref="OpenIddictServerBuilder"/>.</returns>
public OpenIddictServerBuilder RegisterScopes([NotNull] params string[] scopes)
{
if (scopes == null)
{
throw new ArgumentNullException(nameof(scopes));
}
if (scopes.Any(scope => string.IsNullOrEmpty(scope)))
{
throw new ArgumentException("Scopes cannot be null or empty.", nameof(scopes));
}
return Configure(options => options.Scopes.UnionWith(scopes));
}
/// <summary>
/// Configures OpenIddict to use a specific data protection provider
/// instead of relying on the default instance provided by the DI container.
/// </summary>
/// <param name="provider">The data protection provider used to create token protectors.</param>
/// <returns>The <see cref="OpenIddictServerBuilder"/>.</returns>
public OpenIddictServerBuilder UseDataProtectionProvider([NotNull] IDataProtectionProvider provider)
{
if (provider == null)
{
throw new ArgumentNullException(nameof(provider));
}
return Configure(options => options.DataProtectionProvider = provider);
}
/// <summary>
/// Sets JWT as the default token format for access tokens.
/// Note: this option cannot be used when using reference tokens.
/// </summary>
/// <returns>The <see cref="OpenIddictServerBuilder"/>.</returns>
public OpenIddictServerBuilder UseJsonWebTokens()
=> Configure(options => options.AccessTokenHandler = new JwtSecurityTokenHandler
{
InboundClaimTypeMap = new Dictionary<string, string>(),
OutboundClaimTypeMap = new Dictionary<string, string>()
});
/// <summary>
/// Configures OpenIddict to use reference tokens, so that authorization codes,
/// access tokens and refresh tokens are stored as ciphertext in the database
/// (only an identifier is returned to the client application). Enabling this option
/// is useful to keep track of all the issued tokens, when storing a very large
/// number of claims in the authorization codes, access tokens and refresh tokens
/// or when immediate revocation of reference access tokens is desired.
/// Note: this option cannot be used when configuring JWT as the access token format.
/// </summary>
/// <returns>The <see cref="OpenIddictServerBuilder"/>.</returns>
public OpenIddictServerBuilder UseReferenceTokens()
=> Configure(options => options.UseReferenceTokens = true);
/// <summary>
/// Configures OpenIddict to use rolling refresh tokens. When this option is enabled,
/// a new refresh token is always issued for each refresh token request (and the previous
/// one is automatically revoked unless token revocation was explicitly disabled).
/// </summary>
/// <returns>The <see cref="OpenIddictServerBuilder"/>.</returns>
public OpenIddictServerBuilder UseRollingTokens()
=> Configure(options => options.UseRollingTokens = true);
}
}

123
src/OpenIddict.Server/OpenIddictServerExtensions.cs

@ -0,0 +1,123 @@
/*
* 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.Text;
using AspNet.Security.OpenIdConnect.Server;
using JetBrains.Annotations;
using Microsoft.AspNetCore.Authentication;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Options;
using OpenIddict.Server;
namespace Microsoft.Extensions.DependencyInjection
{
public static class OpenIddictServerExtensions
{
/// <summary>
/// Registers the OpenIddict token server services in the DI container.
/// </summary>
/// <param name="builder">The services builder used by OpenIddict to register new services.</param>
/// <remarks>This extension can be safely called multiple times.</remarks>
/// <returns>The <see cref="OpenIddictServerBuilder"/>.</returns>
public static OpenIddictServerBuilder AddServer([NotNull] this OpenIddictBuilder builder)
{
if (builder == null)
{
throw new ArgumentNullException(nameof(builder));
}
builder.Services.AddAuthentication();
// Register the options initializers used by the OpenID Connect server handler and OpenIddict.
// Note: TryAddEnumerable() is used here to ensure the initializers are only registered once.
builder.Services.TryAddEnumerable(new[]
{
ServiceDescriptor.Singleton<IPostConfigureOptions<OpenIddictServerOptions>,
OpenIddictServerInitializer>(),
ServiceDescriptor.Singleton<IPostConfigureOptions<OpenIddictServerOptions>,
OpenIdConnectServerInitializer>()
});
// Register the OpenIddict handler/provider.
builder.Services.TryAddScoped(typeof(OpenIddictServerProvider<,,,>));
builder.Services.TryAddScoped<OpenIddictServerHandler>();
builder.Services.TryAddScoped(provider =>
{
var options = provider.GetRequiredService<IOptionsMonitor<OpenIddictServerOptions>>()
.Get(OpenIdConnectServerDefaults.AuthenticationScheme);
if (options == null)
{
throw new InvalidOperationException("The OpenIddict validation options cannot be resolved.");
}
if (options.ApplicationType == null || options.AuthorizationType == null ||
options.ScopeType == null || options.TokenType == null)
{
throw new InvalidOperationException(new StringBuilder()
.AppendLine("The entity types must be configured for the token server services to work correctly.")
.Append("To configure the entities, use either 'services.AddOpenIddict().AddCore().UseDefaultModels()' ")
.Append("or 'services.AddOpenIddict().AddCore().UseCustomModels()'.")
.ToString());
}
var type = typeof(OpenIddictServerProvider<,,,>).MakeGenericType(
/* TApplication: */ options.ApplicationType,
/* TAuthorization: */ options.AuthorizationType,
/* TScope: */ options.ScopeType,
/* TToken: */ options.TokenType);
return (OpenIdConnectServerProvider) provider.GetRequiredService(type);
});
// Register the OpenID Connect server handler in the authentication options,
// so it can be discovered by the default authentication handler provider.
builder.Services.Configure<AuthenticationOptions>(options =>
{
// Note: this method is guaranteed to be idempotent. To prevent multiple schemes from being
// registered (which would result in an exception being thrown), a manual check is made here.
if (options.SchemeMap.ContainsKey(OpenIdConnectServerDefaults.AuthenticationScheme))
{
return;
}
options.AddScheme(OpenIdConnectServerDefaults.AuthenticationScheme, scheme =>
{
scheme.HandlerType = typeof(OpenIddictServerHandler);
});
});
return new OpenIddictServerBuilder(builder.Services);
}
/// <summary>
/// Registers the OpenIddict token server services in the DI container.
/// </summary>
/// <param name="builder">The services builder used by OpenIddict to register new services.</param>
/// <param name="configuration">The configuration delegate used to configure the server services.</param>
/// <remarks>This extension can be safely called multiple times.</remarks>
/// <returns>The <see cref="OpenIddictServerBuilder"/>.</returns>
public static OpenIddictBuilder AddServer(
[NotNull] this OpenIddictBuilder builder,
[NotNull] Action<OpenIddictServerBuilder> configuration)
{
if (builder == null)
{
throw new ArgumentNullException(nameof(builder));
}
if (configuration == null)
{
throw new ArgumentNullException(nameof(configuration));
}
configuration(builder.AddServer());
return builder;
}
}
}

28
src/OpenIddict.Server/OpenIddictOptions.cs → src/OpenIddict.Server/OpenIddictServerOptions.cs

@ -11,17 +11,17 @@ using AspNet.Security.OpenIdConnect.Primitives;
using AspNet.Security.OpenIdConnect.Server;
using Microsoft.Extensions.Caching.Distributed;
namespace OpenIddict
namespace OpenIddict.Server
{
/// <summary>
/// Provides various settings needed to configure OpenIddict.
/// </summary>
public class OpenIddictOptions : OpenIdConnectServerOptions
public class OpenIddictServerOptions : OpenIdConnectServerOptions
{
/// <summary>
/// Creates a new instance of the <see cref="OpenIddictOptions"/> class.
/// Creates a new instance of the <see cref="OpenIddictServerOptions"/> class.
/// </summary>
public OpenIddictOptions()
public OpenIddictServerOptions()
{
// Note: OpenIdConnectServerProvider is automatically mapped
// to the generic OpenIddictProvider class by the DI container.
@ -29,6 +29,16 @@ namespace OpenIddict
ProviderType = typeof(OpenIdConnectServerProvider);
}
/// <summary>
/// Gets or sets the type corresponding to the Application entity.
/// </summary>
public Type ApplicationType { get; set; }
/// <summary>
/// Gets or sets the type corresponding to the Authorization entity.
/// </summary>
public Type AuthorizationType { get; set; }
/// <summary>
/// Gets or sets the distributed cache used by OpenIddict. If no cache is explicitly
/// provided, the cache registered in the dependency injection container is used.
@ -93,6 +103,16 @@ namespace OpenIddict
OpenIdConnectConstants.Scopes.OpenId
};
/// <summary>
/// Gets or sets the type corresponding to the Scope entity.
/// </summary>
public Type ScopeType { get; set; }
/// <summary>
/// Gets or sets the type corresponding to the Token entity.
/// </summary>
public Type TokenType { get; set; }
/// <summary>
/// Gets or sets a boolean indicating whether reference tokens should be used.
/// When set to <c>true</c>, authorization codes, access tokens and refresh tokens

3
src/OpenIddict.Stores/OpenIddict.Stores.csproj

@ -13,12 +13,13 @@
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\OpenIddict.Core\OpenIddict.Core.csproj" />
<ProjectReference Include="..\OpenIddict.Abstractions\OpenIddict.Abstractions.csproj" />
<ProjectReference Include="..\OpenIddict.Models\OpenIddict.Models.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="JetBrains.Annotations" Version="$(JetBrainsVersion)" PrivateAssets="All" />
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="$(AspNetCoreVersion)" />
</ItemGroup>
</Project>

2
src/OpenIddict.Stores/Stores/OpenIddictApplicationStore.cs

@ -14,7 +14,7 @@ using JetBrains.Annotations;
using Microsoft.Extensions.Caching.Memory;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using OpenIddict.Core;
using OpenIddict.Abstractions;
using OpenIddict.Models;
namespace OpenIddict.Stores

2
src/OpenIddict.Stores/Stores/OpenIddictAuthorizationStore.cs

@ -14,7 +14,7 @@ using JetBrains.Annotations;
using Microsoft.Extensions.Caching.Memory;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using OpenIddict.Core;
using OpenIddict.Abstractions;
using OpenIddict.Models;
namespace OpenIddict.Stores

2
src/OpenIddict.Stores/Stores/OpenIddictScopeStore.cs

@ -14,7 +14,7 @@ using JetBrains.Annotations;
using Microsoft.Extensions.Caching.Memory;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using OpenIddict.Core;
using OpenIddict.Abstractions;
using OpenIddict.Models;
namespace OpenIddict.Stores

2
src/OpenIddict.Stores/Stores/OpenIddictTokenStore.cs

@ -14,7 +14,7 @@ using JetBrains.Annotations;
using Microsoft.Extensions.Caching.Memory;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using OpenIddict.Core;
using OpenIddict.Abstractions;
using OpenIddict.Models;
namespace OpenIddict.Stores

84
src/OpenIddict/OpenIddictExtensions.cs

@ -13,69 +13,45 @@ namespace Microsoft.Extensions.DependencyInjection
public static class OpenIddictExtensions
{
/// <summary>
/// Registers the default OpenIddict services in the DI container,
/// using the default entities and the default entity key type.
/// Configures OpenIddict to use the default entities, with the default entity key type (string).
/// The default entities are <see cref="OpenIddictApplication"/>, <see cref="OpenIddictAuthorization"/>,
/// <see cref="OpenIddictScope"/> and <see cref="OpenIddictToken"/>.
/// </summary>
/// <param name="services">The services collection.</param>
/// <returns>The <see cref="OpenIddictBuilder"/>.</returns>
public static OpenIddictBuilder AddOpenIddict([NotNull] this IServiceCollection services)
/// <param name="builder">The services builder used by OpenIddict to register new services</param>
/// <returns>The <see cref="OpenIddictCoreBuilder"/>.</returns>
public static OpenIddictCoreBuilder UseDefaultModels([NotNull] this OpenIddictCoreBuilder builder)
{
return services.AddOpenIddict<OpenIddictApplication,
OpenIddictAuthorization,
OpenIddictScope,
OpenIddictToken>();
}
/// <summary>
/// Registers the default OpenIddict services in the DI container,
/// using the default entities and the specified entity key type.
/// </summary>
/// <typeparam name="TKey">The type of the entity primary keys.</typeparam>
/// <param name="services">The services collection.</param>
/// <returns>The <see cref="OpenIddictBuilder"/>.</returns>
public static OpenIddictBuilder AddOpenIddict<TKey>([NotNull] this IServiceCollection services)
where TKey : IEquatable<TKey>
{
return services.AddOpenIddict<OpenIddictApplication<TKey>,
OpenIddictAuthorization<TKey>,
OpenIddictScope<TKey>,
OpenIddictToken<TKey>>();
}
if (builder == null)
{
throw new ArgumentNullException(nameof(builder));
}
/// <summary>
/// Registers the default OpenIddict services in the DI container,
/// using the default entities and the default entity key type.
/// </summary>
/// <param name="services">The services collection.</param>
/// <param name="configuration">The configuration delegate used to register new services.</param>
/// <returns>The <see cref="IServiceCollection"/>.</returns>
public static IServiceCollection AddOpenIddict(
[NotNull] this IServiceCollection services,
[NotNull] Action<OpenIddictBuilder> configuration)
{
return services.AddOpenIddict<OpenIddictApplication,
OpenIddictAuthorization,
OpenIddictScope,
OpenIddictToken>(configuration);
return builder.UseCustomModels<OpenIddictApplication,
OpenIddictAuthorization,
OpenIddictScope,
OpenIddictToken>();
}
/// <summary>
/// Registers the default OpenIddict services in the DI container,
/// using the default entities and the specified entity key type.
/// Configures OpenIddict to use the default entities, with the specified entity key type.
/// The default entities are <see cref="OpenIddictApplication{TKey}"/>, <see cref="OpenIddictAuthorization{TKey}"/>,
/// <see cref="OpenIddictScope{TKey}"/> and <see cref="OpenIddictToken{TKey}"/>.
/// </summary>
/// <typeparam name="TKey">The type of the entity primary keys.</typeparam>
/// <param name="services">The services collection.</param>
/// <param name="configuration">The configuration delegate used to register new services.</param>
/// <returns>The <see cref="IServiceCollection"/>.</returns>
public static IServiceCollection AddOpenIddict<TKey>(
[NotNull] this IServiceCollection services,
[NotNull] Action<OpenIddictBuilder> configuration)
/// <param name="builder">The services builder used by OpenIddict to register new services</param>
/// <returns>The <see cref="OpenIddictCoreBuilder"/>.</returns>
public static OpenIddictCoreBuilder UseDefaultModels<TKey>([NotNull] this OpenIddictCoreBuilder builder)
where TKey : IEquatable<TKey>
{
return services.AddOpenIddict<OpenIddictApplication<TKey>,
OpenIddictAuthorization<TKey>,
OpenIddictScope<TKey>,
OpenIddictToken<TKey>>(configuration);
if (builder == null)
{
throw new ArgumentNullException(nameof(builder));
}
return builder.UseCustomModels<OpenIddictApplication<TKey>,
OpenIddictAuthorization<TKey>,
OpenIddictScope<TKey>,
OpenIddictToken<TKey>>();
}
}
}
}

329
test/OpenIddict.Core.Tests/OpenIddictBuilderTests.cs

@ -1,329 +0,0 @@
/*
* 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 Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Moq;
using Xunit;
namespace OpenIddict.Core.Tests
{
public class OpenIddictBuilderTests
{
[Fact]
public void AddApplicationManager_ThrowsAnExceptionForInvalidManager()
{
// Arrange
var services = new ServiceCollection();
services.AddOptions();
var builder = new OpenIddictBuilder(services);
builder.ApplicationType = typeof(object);
// Act and assert
var exception = Assert.Throws<InvalidOperationException>(() => builder.AddApplicationManager(typeof(object)));
Assert.Equal("The specified type is invalid.", exception.Message);
}
[Fact]
public void AddApplicationManager_OverridesDefaultManager()
{
// Arrange
var services = new ServiceCollection();
services.AddOptions();
var builder = new OpenIddictBuilder(services);
builder.ApplicationType = typeof(object);
var type = new Mock<OpenIddictApplicationManager<object>>(
Mock.Of<IOpenIddictApplicationStore<object>>(),
Mock.Of<ILogger<OpenIddictApplicationManager<object>>>()).Object.GetType();
// Act
builder.AddApplicationManager(type);
var provider = services.BuildServiceProvider();
var manager = provider.GetRequiredService<OpenIddictApplicationManager<object>>();
// Assert
Assert.IsType(type, manager);
}
[Fact]
public void AddApplicationStore_ThrowsAnExceptionForInvalidStore()
{
// Arrange
var services = new ServiceCollection();
services.AddOptions();
var builder = new OpenIddictBuilder(services);
builder.ApplicationType = typeof(object);
// Act and assert
var exception = Assert.Throws<InvalidOperationException>(() => builder.AddApplicationStore(typeof(object)));
Assert.Equal("The specified type is invalid.", exception.Message);
}
[Fact]
public void AddApplicationStore_OverridesDefaultManager()
{
// Arrange
var services = new ServiceCollection();
services.AddOptions();
var builder = new OpenIddictBuilder(services);
builder.ApplicationType = typeof(object);
var type = Mock.Of<IOpenIddictApplicationStore<object>>().GetType();
// Act
builder.AddApplicationStore(type);
var provider = services.BuildServiceProvider();
var store = provider.GetRequiredService<IOpenIddictApplicationStore<object>>();
// Assert
Assert.IsType(type, store);
}
[Fact]
public void AddAuthorizationManager_ThrowsAnExceptionForInvalidManager()
{
// Arrange
var services = new ServiceCollection();
services.AddOptions();
var builder = new OpenIddictBuilder(services);
builder.AuthorizationType = typeof(object);
// Act and assert
var exception = Assert.Throws<InvalidOperationException>(() => builder.AddAuthorizationManager(typeof(object)));
Assert.Equal("The specified type is invalid.", exception.Message);
}
[Fact]
public void AddAuthorizationManager_OverridesDefaultManager()
{
// Arrange
var services = new ServiceCollection();
services.AddOptions();
var builder = new OpenIddictBuilder(services);
builder.AuthorizationType = typeof(object);
var type = new Mock<OpenIddictAuthorizationManager<object>>(
Mock.Of<IOpenIddictAuthorizationStore<object>>(),
Mock.Of<ILogger<OpenIddictAuthorizationManager<object>>>()).Object.GetType();
// Act
builder.AddAuthorizationManager(type);
var provider = services.BuildServiceProvider();
var manager = provider.GetRequiredService<OpenIddictAuthorizationManager<object>>();
// Assert
Assert.IsType(type, manager);
}
[Fact]
public void AddAuthorizationStore_ThrowsAnExceptionForInvalidStore()
{
// Arrange
var services = new ServiceCollection();
services.AddOptions();
var builder = new OpenIddictBuilder(services);
builder.AuthorizationType = typeof(object);
// Act and assert
var exception = Assert.Throws<InvalidOperationException>(() => builder.AddAuthorizationStore(typeof(object)));
Assert.Equal("The specified type is invalid.", exception.Message);
}
[Fact]
public void AddAuthorizationStore_OverridesDefaultManager()
{
// Arrange
var services = new ServiceCollection();
services.AddOptions();
var builder = new OpenIddictBuilder(services);
builder.AuthorizationType = typeof(object);
var type = Mock.Of<IOpenIddictAuthorizationStore<object>>().GetType();
// Act
builder.AddAuthorizationStore(type);
var provider = services.BuildServiceProvider();
var store = provider.GetRequiredService<IOpenIddictAuthorizationStore<object>>();
// Assert
Assert.IsType(type, store);
}
[Fact]
public void AddScopeManager_ThrowsAnExceptionForInvalidManager()
{
// Arrange
var services = new ServiceCollection();
services.AddOptions();
var builder = new OpenIddictBuilder(services);
builder.ScopeType = typeof(object);
// Act and assert
var exception = Assert.Throws<InvalidOperationException>(() => builder.AddScopeManager(typeof(object)));
Assert.Equal("The specified type is invalid.", exception.Message);
}
[Fact]
public void AddScopeManager_OverridesDefaultManager()
{
// Arrange
var services = new ServiceCollection();
services.AddOptions();
var builder = new OpenIddictBuilder(services);
builder.ScopeType = typeof(object);
var type = new Mock<OpenIddictScopeManager<object>>(
Mock.Of<IOpenIddictScopeStore<object>>(),
Mock.Of<ILogger<OpenIddictScopeManager<object>>>()).Object.GetType();
// Act
builder.AddScopeManager(type);
var provider = services.BuildServiceProvider();
var manager = provider.GetRequiredService<OpenIddictScopeManager<object>>();
// Assert
Assert.IsType(type, manager);
}
[Fact]
public void AddScopeStore_ThrowsAnExceptionForInvalidStore()
{
// Arrange
var services = new ServiceCollection();
services.AddOptions();
var builder = new OpenIddictBuilder(services);
builder.ScopeType = typeof(object);
// Act and assert
var exception = Assert.Throws<InvalidOperationException>(() => builder.AddScopeStore(typeof(object)));
Assert.Equal("The specified type is invalid.", exception.Message);
}
[Fact]
public void AddScopeStore_OverridesDefaultManager()
{
// Arrange
var services = new ServiceCollection();
services.AddOptions();
var builder = new OpenIddictBuilder(services);
builder.ScopeType = typeof(object);
var type = Mock.Of<IOpenIddictScopeStore<object>>().GetType();
// Act
builder.AddScopeStore(type);
var provider = services.BuildServiceProvider();
var store = provider.GetRequiredService<IOpenIddictScopeStore<object>>();
// Assert
Assert.IsType(type, store);
}
[Fact]
public void AddTokenManager_ThrowsAnExceptionForInvalidManager()
{
// Arrange
var services = new ServiceCollection();
services.AddOptions();
var builder = new OpenIddictBuilder(services);
builder.TokenType = typeof(object);
// Act and assert
var exception = Assert.Throws<InvalidOperationException>(() => builder.AddTokenManager(typeof(object)));
Assert.Equal("The specified type is invalid.", exception.Message);
}
[Fact]
public void AddTokenManager_OverridesDefaultManager()
{
// Arrange
var services = new ServiceCollection();
services.AddOptions();
var builder = new OpenIddictBuilder(services);
builder.TokenType = typeof(object);
var type = new Mock<OpenIddictTokenManager<object>>(
Mock.Of<IOpenIddictTokenStore<object>>(),
Mock.Of<ILogger<OpenIddictTokenManager<object>>>()).Object.GetType();
// Act
builder.AddTokenManager(type);
var provider = services.BuildServiceProvider();
var manager = provider.GetRequiredService<OpenIddictTokenManager<object>>();
// Assert
Assert.IsType(type, manager);
}
[Fact]
public void AddTokenStore_ThrowsAnExceptionForInvalidStore()
{
// Arrange
var services = new ServiceCollection();
services.AddOptions();
var builder = new OpenIddictBuilder(services);
builder.TokenType = typeof(object);
// Act and assert
var exception = Assert.Throws<InvalidOperationException>(() => builder.AddTokenStore(typeof(object)));
Assert.Equal("The specified type is invalid.", exception.Message);
}
[Fact]
public void AddTokenStore_OverridesDefaultManager()
{
// Arrange
var services = new ServiceCollection();
services.AddOptions();
var builder = new OpenIddictBuilder(services);
builder.TokenType = typeof(object);
var type = Mock.Of<IOpenIddictTokenStore<object>>().GetType();
// Act
builder.AddTokenStore(type);
var provider = services.BuildServiceProvider();
var store = provider.GetRequiredService<IOpenIddictTokenStore<object>>();
// Assert
Assert.IsType(type, store);
}
}
}

487
test/OpenIddict.Core.Tests/OpenIddictCoreBuilderTests.cs

@ -0,0 +1,487 @@
/*
* 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 Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Moq;
using OpenIddict.Abstractions;
using Xunit;
namespace OpenIddict.Core.Tests
{
public class OpenIddictCoreBuilderTests
{
[Fact]
public void ReplaceApplicationManager_ThrowsAnExceptionForInvalidManager()
{
// Arrange
var services = CreateServices();
var builder = CreateBuilder(services);
// Act and assert
var exception = Assert.Throws<ArgumentException>(() => builder.ReplaceApplicationManager(typeof(object)));
Assert.Equal("type", exception.ParamName);
Assert.StartsWith("The specified type is invalid.", exception.Message);
}
[Fact]
public void ReplaceApplicationManager_OverridesDefaultOpenGenericManager()
{
// Arrange
var services = CreateServices();
var builder = CreateBuilder(services);
// Act
builder.ReplaceApplicationManager(typeof(OpenGenericApplicationManager<>));
// Assert
Assert.Contains(services, service =>
service.ServiceType == typeof(OpenIddictApplicationManager<>) &&
service.ImplementationType == typeof(OpenGenericApplicationManager<>));
Assert.DoesNotContain(services, service =>
service.ServiceType == typeof(OpenIddictApplicationManager<>) &&
service.ImplementationType == typeof(OpenIddictApplicationManager<>));
}
[Fact]
public void ReplaceApplicationManager_AddsClosedGenericManager()
{
// Arrange
var services = CreateServices();
var builder = CreateBuilder(services);
// Act
builder.ReplaceApplicationManager(typeof(ClosedGenericApplicationManager));
// Assert
Assert.Contains(services, service =>
service.ServiceType == typeof(OpenIddictApplicationManager<CustomApplication>) &&
service.ImplementationType == typeof(ClosedGenericApplicationManager));
Assert.Contains(services, service =>
service.ServiceType == typeof(OpenIddictApplicationManager<>) &&
service.ImplementationType == typeof(OpenIddictApplicationManager<>));
}
[Fact]
public void ReplaceApplicationStoreResolver_ThrowsAnExceptionForInvalidStoreResolver()
{
// Arrange
var services = CreateServices();
var builder = CreateBuilder(services);
// Act and assert
var exception = Assert.Throws<ArgumentException>(() => builder.ReplaceApplicationStoreResolver(typeof(object)));
Assert.Equal("type", exception.ParamName);
Assert.StartsWith("The specified type is invalid.", exception.Message);
}
[Fact]
public void ReplaceApplicationStoreResolver_OverridesDefaultManager()
{
// Arrange
var services = CreateServices();
var builder = CreateBuilder(services);
var type = Mock.Of<IOpenIddictApplicationStoreResolver>().GetType();
// Act
builder.ReplaceApplicationStoreResolver(type);
var provider = services.BuildServiceProvider();
var store = provider.GetRequiredService<IOpenIddictApplicationStoreResolver>();
// Assert
Assert.IsType(type, store);
}
[Fact]
public void ReplaceAuthorizationManager_ThrowsAnExceptionForInvalidManager()
{
// Arrange
var services = CreateServices();
var builder = CreateBuilder(services);
// Act and assert
var exception = Assert.Throws<ArgumentException>(() => builder.ReplaceAuthorizationManager(typeof(object)));
Assert.Equal("type", exception.ParamName);
Assert.StartsWith("The specified type is invalid.", exception.Message);
}
[Fact]
public void ReplaceAuthorizationManager_OverridesDefaultOpenGenericManager()
{
// Arrange
var services = CreateServices();
var builder = CreateBuilder(services);
// Act
builder.ReplaceAuthorizationManager(typeof(OpenGenericAuthorizationManager<>));
// Assert
Assert.Contains(services, service =>
service.ServiceType == typeof(OpenIddictAuthorizationManager<>) &&
service.ImplementationType == typeof(OpenGenericAuthorizationManager<>));
Assert.DoesNotContain(services, service =>
service.ServiceType == typeof(OpenIddictAuthorizationManager<>) &&
service.ImplementationType == typeof(OpenIddictAuthorizationManager<>));
}
[Fact]
public void ReplaceAuthorizationManager_AddsClosedGenericManager()
{
// Arrange
var services = CreateServices();
var builder = CreateBuilder(services);
// Act
builder.ReplaceAuthorizationManager(typeof(ClosedGenericAuthorizationManager));
// Assert
Assert.Contains(services, service =>
service.ServiceType == typeof(OpenIddictAuthorizationManager<CustomAuthorization>) &&
service.ImplementationType == typeof(ClosedGenericAuthorizationManager));
Assert.Contains(services, service =>
service.ServiceType == typeof(OpenIddictAuthorizationManager<>) &&
service.ImplementationType == typeof(OpenIddictAuthorizationManager<>));
}
[Fact]
public void ReplaceAuthorizationStoreResolver_ThrowsAnExceptionForInvalidStoreResolver()
{
// Arrange
var services = CreateServices();
var builder = CreateBuilder(services);
// Act and assert
var exception = Assert.Throws<ArgumentException>(() => builder.ReplaceAuthorizationStoreResolver(typeof(object)));
Assert.Equal("type", exception.ParamName);
Assert.StartsWith("The specified type is invalid.", exception.Message);
}
[Fact]
public void ReplaceAuthorizationStoreResolver_OverridesDefaultManager()
{
// Arrange
var services = CreateServices();
var builder = CreateBuilder(services);
var type = Mock.Of<IOpenIddictAuthorizationStoreResolver>().GetType();
// Act
builder.ReplaceAuthorizationStoreResolver(type);
var provider = services.BuildServiceProvider();
var store = provider.GetRequiredService<IOpenIddictAuthorizationStoreResolver>();
// Assert
Assert.IsType(type, store);
}
[Fact]
public void ReplaceScopeManager_ThrowsAnExceptionForInvalidManager()
{
// Arrange
var services = CreateServices();
var builder = CreateBuilder(services);
// Act and assert
var exception = Assert.Throws<ArgumentException>(() => builder.ReplaceScopeManager(typeof(object)));
Assert.Equal("type", exception.ParamName);
Assert.StartsWith("The specified type is invalid.", exception.Message);
}
[Fact]
public void ReplaceScopeManager_OverridesDefaultOpenGenericManager()
{
// Arrange
var services = CreateServices();
var builder = CreateBuilder(services);
// Act
builder.ReplaceScopeManager(typeof(OpenGenericScopeManager<>));
// Assert
Assert.Contains(services, service =>
service.ServiceType == typeof(OpenIddictScopeManager<>) &&
service.ImplementationType == typeof(OpenGenericScopeManager<>));
Assert.DoesNotContain(services, service =>
service.ServiceType == typeof(OpenIddictScopeManager<>) &&
service.ImplementationType == typeof(OpenIddictScopeManager<>));
}
[Fact]
public void ReplaceScopeManager_AddsClosedGenericManager()
{
// Arrange
var services = CreateServices();
var builder = CreateBuilder(services);
// Act
builder.ReplaceScopeManager(typeof(ClosedGenericScopeManager));
// Assert
Assert.Contains(services, service =>
service.ServiceType == typeof(OpenIddictScopeManager<CustomScope>) &&
service.ImplementationType == typeof(ClosedGenericScopeManager));
Assert.Contains(services, service =>
service.ServiceType == typeof(OpenIddictScopeManager<>) &&
service.ImplementationType == typeof(OpenIddictScopeManager<>));
}
[Fact]
public void ReplaceScopeStoreResolver_ThrowsAnExceptionForInvalidStoreResolver()
{
// Arrange
var services = CreateServices();
var builder = CreateBuilder(services);
// Act and assert
var exception = Assert.Throws<ArgumentException>(() => builder.ReplaceScopeStoreResolver(typeof(object)));
Assert.Equal("type", exception.ParamName);
Assert.StartsWith("The specified type is invalid.", exception.Message);
}
[Fact]
public void ReplaceScopeStoreResolver_OverridesDefaultManager()
{
// Arrange
var services = CreateServices();
var builder = CreateBuilder(services);
var type = Mock.Of<IOpenIddictScopeStoreResolver>().GetType();
// Act
builder.ReplaceScopeStoreResolver(type);
var provider = services.BuildServiceProvider();
var store = provider.GetRequiredService<IOpenIddictScopeStoreResolver>();
// Assert
Assert.IsType(type, store);
}
[Fact]
public void ReplaceTokenManager_ThrowsAnExceptionForInvalidManager()
{
// Arrange
var services = CreateServices();
var builder = CreateBuilder(services);
// Act and assert
var exception = Assert.Throws<ArgumentException>(() => builder.ReplaceTokenManager(typeof(object)));
Assert.Equal("type", exception.ParamName);
Assert.StartsWith("The specified type is invalid.", exception.Message);
}
[Fact]
public void ReplaceTokenManager_OverridesDefaultOpenGenericManager()
{
// Arrange
var services = CreateServices();
var builder = CreateBuilder(services);
// Act
builder.ReplaceTokenManager(typeof(OpenGenericTokenManager<>));
// Assert
Assert.Contains(services, service =>
service.ServiceType == typeof(OpenIddictTokenManager<>) &&
service.ImplementationType == typeof(OpenGenericTokenManager<>));
Assert.DoesNotContain(services, service =>
service.ServiceType == typeof(OpenIddictTokenManager<>) &&
service.ImplementationType == typeof(OpenIddictTokenManager<>));
}
[Fact]
public void ReplaceTokenManager_AddsClosedGenericManager()
{
// Arrange
var services = CreateServices();
var builder = CreateBuilder(services);
// Act
builder.ReplaceTokenManager(typeof(ClosedGenericTokenManager));
// Assert
Assert.Contains(services, service =>
service.ServiceType == typeof(OpenIddictTokenManager<CustomToken>) &&
service.ImplementationType == typeof(ClosedGenericTokenManager));
Assert.Contains(services, service =>
service.ServiceType == typeof(OpenIddictTokenManager<>) &&
service.ImplementationType == typeof(OpenIddictTokenManager<>));
}
[Fact]
public void ReplaceTokenStoreResolver_ThrowsAnExceptionForInvalidStoreResolver()
{
// Arrange
var services = CreateServices();
var builder = CreateBuilder(services);
// Act and assert
var exception = Assert.Throws<ArgumentException>(() => builder.ReplaceTokenStoreResolver(typeof(object)));
Assert.Equal("type", exception.ParamName);
Assert.StartsWith("The specified type is invalid.", exception.Message);
}
[Fact]
public void ReplaceTokenStoreResolver_OverridesDefaultManager()
{
// Arrange
var services = CreateServices();
var builder = CreateBuilder(services);
var type = Mock.Of<IOpenIddictTokenStoreResolver>().GetType();
// Act
builder.ReplaceTokenStoreResolver(type);
var provider = services.BuildServiceProvider();
var store = provider.GetRequiredService<IOpenIddictTokenStoreResolver>();
// Assert
Assert.IsType(type, store);
}
[Fact]
public void UseCustomModels_CustomEntitiesAreCorrectlySet()
{
// Arrange
var services = CreateServices();
var builder = CreateBuilder(services);
// Act
services.AddOpenIddict().AddCore()
.UseCustomModels<CustomApplication, CustomAuthorization, CustomScope, CustomToken>();
// Assert
var provider = services.BuildServiceProvider();
var options = provider.GetRequiredService<IOptionsMonitor<OpenIddictCoreOptions>>().CurrentValue;
Assert.Equal(typeof(CustomApplication), options.DefaultApplicationType);
Assert.Equal(typeof(CustomAuthorization), options.DefaultAuthorizationType);
Assert.Equal(typeof(CustomScope), options.DefaultScopeType);
Assert.Equal(typeof(CustomToken), options.DefaultTokenType);
}
private static OpenIddictCoreBuilder CreateBuilder(IServiceCollection services)
=> services.AddOpenIddict().AddCore();
private static IServiceCollection CreateServices()
{
var services = new ServiceCollection();
services.AddOptions();
return services;
}
public class CustomApplication { }
public class CustomAuthorization { }
public class CustomScope { }
public class CustomToken { }
private class ClosedGenericApplicationManager : OpenIddictApplicationManager<CustomApplication>
{
public ClosedGenericApplicationManager(
IOpenIddictApplicationStoreResolver resolver,
ILogger<OpenIddictApplicationManager<CustomApplication>> logger,
IOptionsMonitor<OpenIddictCoreOptions> options)
: base(resolver, logger, options)
{
}
}
private class OpenGenericApplicationManager<TApplication> : OpenIddictApplicationManager<TApplication>
where TApplication : class
{
public OpenGenericApplicationManager(
IOpenIddictApplicationStoreResolver resolver,
ILogger<OpenIddictApplicationManager<TApplication>> logger,
IOptionsMonitor<OpenIddictCoreOptions> options)
: base(resolver, logger, options)
{
}
}
private class ClosedGenericAuthorizationManager : OpenIddictAuthorizationManager<CustomAuthorization>
{
public ClosedGenericAuthorizationManager(
IOpenIddictAuthorizationStoreResolver resolver,
ILogger<OpenIddictAuthorizationManager<CustomAuthorization>> logger,
IOptionsMonitor<OpenIddictCoreOptions> options)
: base(resolver, logger, options)
{
}
}
private class OpenGenericAuthorizationManager<TAuthorization> : OpenIddictAuthorizationManager<TAuthorization>
where TAuthorization : class
{
public OpenGenericAuthorizationManager(
IOpenIddictAuthorizationStoreResolver resolver,
ILogger<OpenIddictAuthorizationManager<TAuthorization>> logger,
IOptionsMonitor<OpenIddictCoreOptions> options)
: base(resolver, logger, options)
{
}
}
private class ClosedGenericScopeManager : OpenIddictScopeManager<CustomScope>
{
public ClosedGenericScopeManager(
IOpenIddictScopeStoreResolver resolver,
ILogger<OpenIddictScopeManager<CustomScope>> logger,
IOptionsMonitor<OpenIddictCoreOptions> options)
: base(resolver, logger, options)
{
}
}
private class OpenGenericScopeManager<TScope> : OpenIddictScopeManager<TScope>
where TScope : class
{
public OpenGenericScopeManager(
IOpenIddictScopeStoreResolver resolver,
ILogger<OpenIddictScopeManager<TScope>> logger,
IOptionsMonitor<OpenIddictCoreOptions> options)
: base(resolver, logger, options)
{
}
}
private class ClosedGenericTokenManager : OpenIddictTokenManager<CustomToken>
{
public ClosedGenericTokenManager(
IOpenIddictTokenStoreResolver resolver,
ILogger<OpenIddictTokenManager<CustomToken>> logger,
IOptionsMonitor<OpenIddictCoreOptions> options)
: base(resolver, logger, options)
{
}
}
private class OpenGenericTokenManager<TToken> : OpenIddictTokenManager<TToken>
where TToken : class
{
public OpenGenericTokenManager(
IOpenIddictTokenStoreResolver resolver,
ILogger<OpenIddictTokenManager<TToken>> logger,
IOptionsMonitor<OpenIddictCoreOptions> options)
: base(resolver, logger, options)
{
}
}
}
}

48
test/OpenIddict.Core.Tests/OpenIddictExtensionsTests.cs

@ -1,48 +0,0 @@
/*
* 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 Microsoft.Extensions.DependencyInjection;
using Xunit;
namespace OpenIddict.Core.Tests
{
public class OpenIddictExtensionsTests
{
[Fact]
public void AddOpenIddict_CustomEntitiesAreCorrectlySet()
{
// Arrange
var services = new ServiceCollection();
// Act
var builder = services.AddOpenIddict<object, object, object, object>();
// Assert
Assert.Equal(typeof(object), builder.ApplicationType);
Assert.Equal(typeof(object), builder.AuthorizationType);
Assert.Equal(typeof(object), builder.ScopeType);
Assert.Equal(typeof(object), builder.TokenType);
}
[Theory]
[InlineData(typeof(OpenIddictApplicationManager<object>))]
[InlineData(typeof(OpenIddictAuthorizationManager<object>))]
[InlineData(typeof(OpenIddictScopeManager<object>))]
[InlineData(typeof(OpenIddictTokenManager<object>))]
public void AddOpenIddict_ManagersForCustomEntitiesAreCorrectlyRegistered(Type type)
{
// Arrange
var services = new ServiceCollection();
// Act
services.AddOpenIddict<object, object, object, object>();
// Assert
Assert.Contains(services, service => service.ServiceType == type);
}
}
}

162
test/OpenIddict.EntityFramework.Tests/OpenIddictExtensionsTests.cs

@ -8,117 +8,22 @@ 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),
AuthorizationType = typeof(OpenIddictAuthorization),
ScopeType = typeof(OpenIddictScope),
TokenType = typeof(OpenIddictToken)
};
// 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())
{
ApplicationType = typeof(OpenIddictApplication),
AuthorizationType = typeof(object),
ScopeType = typeof(OpenIddictScope),
TokenType = typeof(OpenIddictToken)
};
// 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())
{
ApplicationType = typeof(OpenIddictApplication),
AuthorizationType = typeof(OpenIddictAuthorization),
ScopeType = typeof(object),
TokenType = typeof(OpenIddictToken)
};
// 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())
{
ApplicationType = typeof(OpenIddictApplication),
AuthorizationType = typeof(OpenIddictAuthorization),
ScopeType = typeof(OpenIddictScope),
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)
[InlineData(typeof(OpenIddictApplicationStoreResolver<DbContext>))]
[InlineData(typeof(OpenIddictAuthorizationStoreResolver<DbContext>))]
[InlineData(typeof(OpenIddictScopeStoreResolver<DbContext>))]
[InlineData(typeof(OpenIddictTokenStoreResolver<DbContext>))]
public void AddEntityFrameworkStores_RegistersEntityFrameworkStoreFactories(Type type)
{
// Arrange
var services = new ServiceCollection();
var builder = new OpenIddictBuilder(services)
{
ApplicationType = typeof(OpenIddictApplication),
AuthorizationType = typeof(OpenIddictAuthorization),
ScopeType = typeof(OpenIddictScope),
TokenType = typeof(OpenIddictToken)
};
var builder = services.AddOpenIddict().AddCore();
// Act
builder.AddEntityFrameworkStores<DbContext>();
@ -126,60 +31,5 @@ namespace OpenIddict.EntityFrameworkCore.Tests
// 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> { }
}
}

162
test/OpenIddict.EntityFrameworkCore.Tests/OpenIddictExtensionsTests.cs

@ -7,117 +7,22 @@
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using OpenIddict.Models;
using Xunit;
namespace OpenIddict.EntityFrameworkCore.Tests
{
public class OpenIddictExtensionsTests
{
[Fact]
public void AddEntityFrameworkCoreStores_ThrowsAnExceptionForInvalidApplicationEntity()
{
// Arrange
var builder = new OpenIddictBuilder(new ServiceCollection())
{
ApplicationType = typeof(object),
AuthorizationType = typeof(OpenIddictAuthorization),
ScopeType = typeof(OpenIddictScope),
TokenType = typeof(OpenIddictToken)
};
// Act and assert
var exception = Assert.Throws<InvalidOperationException>(delegate
{
builder.AddEntityFrameworkCoreStores<DbContext>();
});
Assert.Equal("The Entity Framework Core stores can only be used " +
"with the built-in OpenIddictApplication entity.", exception.Message);
}
[Fact]
public void AddEntityFrameworkCoreStores_ThrowsAnExceptionForInvalidAuthorizationEntity()
{
// Arrange
var builder = new OpenIddictBuilder(new ServiceCollection())
{
ApplicationType = typeof(OpenIddictApplication),
AuthorizationType = typeof(object),
ScopeType = typeof(OpenIddictScope),
TokenType = typeof(OpenIddictToken)
};
// Act and assert
var exception = Assert.Throws<InvalidOperationException>(delegate
{
builder.AddEntityFrameworkCoreStores<DbContext>();
});
Assert.Equal("The Entity Framework Core stores can only be used " +
"with the built-in OpenIddictAuthorization entity.", exception.Message);
}
[Fact]
public void AddEntityFrameworkCoreStores_ThrowsAnExceptionForInvalidScopeEntity()
{
// Arrange
var builder = new OpenIddictBuilder(new ServiceCollection())
{
ApplicationType = typeof(OpenIddictApplication),
AuthorizationType = typeof(OpenIddictAuthorization),
ScopeType = typeof(object),
TokenType = typeof(OpenIddictToken)
};
// Act and assert
var exception = Assert.Throws<InvalidOperationException>(delegate
{
builder.AddEntityFrameworkCoreStores<DbContext>();
});
Assert.Equal("The Entity Framework Core stores can only be used " +
"with the built-in OpenIddictScope entity.", exception.Message);
}
[Fact]
public void AddEntityFrameworkCoreStores_ThrowsAnExceptionForInvalidTokenEntity()
{
// Arrange
var builder = new OpenIddictBuilder(new ServiceCollection())
{
ApplicationType = typeof(OpenIddictApplication),
AuthorizationType = typeof(OpenIddictAuthorization),
ScopeType = typeof(OpenIddictScope),
TokenType = typeof(object)
};
// Act and assert
var exception = Assert.Throws<InvalidOperationException>(delegate
{
builder.AddEntityFrameworkCoreStores<DbContext>();
});
Assert.Equal("The Entity Framework Core 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 AddEntityFrameworkCoreStores_RegistersEntityFrameworkStores(Type type)
[InlineData(typeof(OpenIddictApplicationStoreResolver<DbContext>))]
[InlineData(typeof(OpenIddictAuthorizationStoreResolver<DbContext>))]
[InlineData(typeof(OpenIddictScopeStoreResolver<DbContext>))]
[InlineData(typeof(OpenIddictTokenStoreResolver<DbContext>))]
public void AddEntityFrameworkCoreStores_RegistersEntityFrameworkCoreStoreFactories(Type type)
{
// Arrange
var services = new ServiceCollection();
var builder = new OpenIddictBuilder(services)
{
ApplicationType = typeof(OpenIddictApplication),
AuthorizationType = typeof(OpenIddictAuthorization),
ScopeType = typeof(OpenIddictScope),
TokenType = typeof(OpenIddictToken)
};
var builder = services.AddOpenIddict().AddCore();
// Act
builder.AddEntityFrameworkCoreStores<DbContext>();
@ -125,60 +30,5 @@ namespace OpenIddict.EntityFrameworkCore.Tests
// 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 AddEntityFrameworkCoreStores_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.AddEntityFrameworkCoreStores<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 AddEntityFrameworkCoreStores_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.AddEntityFrameworkCoreStores<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> { }
}
}

1
test/OpenIddict.Mvc.Tests/OpenIddict.Mvc.Tests.csproj

@ -8,6 +8,7 @@
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\OpenIddict\OpenIddict.csproj" />
<ProjectReference Include="..\..\src\OpenIddict.Mvc\OpenIddict.Mvc.csproj" />
</ItemGroup>

2
test/OpenIddict.Mvc.Tests/OpenIddictExtensionsTests.cs

@ -20,7 +20,7 @@ namespace OpenIddict.Mvc.Tests
var services = new ServiceCollection();
services.AddOptions();
var builder = new OpenIddictBuilder(services);
var builder = services.AddOpenIddict().AddServer();
// Act
builder.AddMvcBinders();

10
test/OpenIddict.Server.Tests/Internal/OpenIddictInitializerTests.cs → test/OpenIddict.Server.Tests/Internal/OpenIddictServerInitializerTests.cs

@ -18,9 +18,9 @@ using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Xunit;
namespace OpenIddict.Tests
namespace OpenIddict.Server.Tests
{
public class OpenIddictInitializerTests
public class OpenIddictServerInitializerTests
{
[Fact]
public async Task PostConfigure_ThrowsAnExceptionWhenRandomNumberGeneratorIsNull()
@ -259,7 +259,7 @@ namespace OpenIddict.Tests
"'services.AddOpenIddict().AddEphemeralSigningKey()' to use an ephemeral key.", exception.Message);
}
private static TestServer CreateAuthorizationServer(Action<OpenIddictBuilder> configuration = null)
private static TestServer CreateAuthorizationServer(Action<OpenIddictServerBuilder> configuration = null)
{
var builder = new WebHostBuilder();
@ -273,7 +273,9 @@ namespace OpenIddict.Tests
services.AddOptions();
services.AddDistributedMemoryCache();
services.AddOpenIddict(options => configuration?.Invoke(options));
services.AddOpenIddict()
.AddCore(options => options.UseDefaultModels())
.AddServer(options => configuration?.Invoke(options));
});
builder.Configure(app =>

6
test/OpenIddict.Server.Tests/Internal/OpenIddictProviderTests.Authentication.cs → test/OpenIddict.Server.Tests/Internal/OpenIddictServerProviderTests.Authentication.cs

@ -4,7 +4,6 @@
* the license and the contributors participating to this project.
*/
using System.Collections.Immutable;
using System.IO;
using System.Security.Cryptography;
using System.Threading;
@ -16,13 +15,14 @@ using Microsoft.Extensions.DependencyInjection;
using Moq;
using Newtonsoft.Json;
using Newtonsoft.Json.Bson;
using OpenIddict.Abstractions;
using OpenIddict.Core;
using OpenIddict.Models;
using Xunit;
namespace OpenIddict.Tests
namespace OpenIddict.Server.Tests
{
public partial class OpenIddictProviderTests
public partial class OpenIddictServerProviderTests
{
[Fact]
public async Task ExtractAuthorizationRequest_UnsupportedRequestParameterIsRejected()

7
test/OpenIddict.Server.Tests/Internal/OpenIddictProviderTests.Discovery.cs → test/OpenIddict.Server.Tests/Internal/OpenIddictServerProviderTests.Discovery.cs

@ -10,14 +10,13 @@ using AspNet.Security.OpenIdConnect.Primitives;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication.Facebook;
using Microsoft.AspNetCore.Authentication.Google;
using Microsoft.Extensions.DependencyInjection;
using Newtonsoft.Json.Linq;
using OpenIddict.Core;
using OpenIddict.Abstractions;
using Xunit;
namespace OpenIddict.Tests
namespace OpenIddict.Server.Tests
{
public partial class OpenIddictProviderTests
public partial class OpenIddictServerProviderTests
{
[Fact]
public async Task HandleConfigurationRequest_PlainCodeChallengeMethodIsNotReturned()

5
test/OpenIddict.Server.Tests/Internal/OpenIddictProviderTests.Exchange.cs → test/OpenIddict.Server.Tests/Internal/OpenIddictServerProviderTests.Exchange.cs

@ -16,13 +16,14 @@ using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Moq;
using OpenIddict.Abstractions;
using OpenIddict.Core;
using OpenIddict.Models;
using Xunit;
namespace OpenIddict.Tests
namespace OpenIddict.Server.Tests
{
public partial class OpenIddictProviderTests
public partial class OpenIddictServerProviderTests
{
[Theory]
[InlineData(OpenIdConnectConstants.GrantTypes.AuthorizationCode)]

5
test/OpenIddict.Server.Tests/Internal/OpenIddictProviderTests.Introspection.cs → test/OpenIddict.Server.Tests/Internal/OpenIddictServerProviderTests.Introspection.cs

@ -15,13 +15,14 @@ using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Moq;
using OpenIddict.Abstractions;
using OpenIddict.Core;
using OpenIddict.Models;
using Xunit;
namespace OpenIddict.Tests
namespace OpenIddict.Server.Tests
{
public partial class OpenIddictProviderTests
public partial class OpenIddictServerProviderTests
{
[Fact]
public async Task ExtractIntrospectionRequest_GetRequestsAreRejected()

5
test/OpenIddict.Server.Tests/Internal/OpenIddictProviderTests.Revocation.cs → test/OpenIddict.Server.Tests/Internal/OpenIddictServerProviderTests.Revocation.cs

@ -17,13 +17,14 @@ using Microsoft.AspNetCore.Authentication;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.IdentityModel.Tokens;
using Moq;
using OpenIddict.Abstractions;
using OpenIddict.Core;
using OpenIddict.Models;
using Xunit;
namespace OpenIddict.Tests
namespace OpenIddict.Server.Tests
{
public partial class OpenIddictProviderTests
public partial class OpenIddictServerProviderTests
{
[Theory]
[InlineData(OpenIdConnectConstants.TokenTypeHints.AccessToken)]

5
test/OpenIddict.Server.Tests/Internal/OpenIddictProviderTests.Serialization.cs → test/OpenIddict.Server.Tests/Internal/OpenIddictServerProviderTests.Serialization.cs

@ -16,13 +16,14 @@ using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Moq;
using OpenIddict.Abstractions;
using OpenIddict.Core;
using OpenIddict.Models;
using Xunit;
namespace OpenIddict.Tests
namespace OpenIddict.Server.Tests
{
public partial class OpenIddictProviderTests
public partial class OpenIddictServerProviderTests
{
[Fact]
public async Task DeserializeAccessToken_ReturnsNullForMalformedReferenceToken()

5
test/OpenIddict.Server.Tests/Internal/OpenIddictProviderTests.Session.cs → test/OpenIddict.Server.Tests/Internal/OpenIddictServerProviderTests.Session.cs

@ -12,12 +12,13 @@ using AspNet.Security.OpenIdConnect.Primitives;
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.DependencyInjection;
using Moq;
using OpenIddict.Abstractions;
using OpenIddict.Core;
using Xunit;
namespace OpenIddict.Tests
namespace OpenIddict.Server.Tests
{
public partial class OpenIddictProviderTests
public partial class OpenIddictServerProviderTests
{
[Fact]
public async Task ExtractLogoutRequest_RequestIdParameterIsRejectedWhenRequestCachingIsDisabled()

4
test/OpenIddict.Server.Tests/Internal/OpenIddictProviderTests.Userinfo.cs → test/OpenIddict.Server.Tests/Internal/OpenIddictServerProviderTests.Userinfo.cs

@ -9,9 +9,9 @@ using AspNet.Security.OpenIdConnect.Client;
using AspNet.Security.OpenIdConnect.Primitives;
using Xunit;
namespace OpenIddict.Tests
namespace OpenIddict.Server.Tests
{
public partial class OpenIddictProviderTests
public partial class OpenIddictServerProviderTests
{
[Fact]
public async Task ExtractUserinfoRequest_RequestIsHandledByUserCode()

113
test/OpenIddict.Server.Tests/Internal/OpenIddictProviderTests.cs → test/OpenIddict.Server.Tests/Internal/OpenIddictServerProviderTests.cs

@ -25,17 +25,19 @@ using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.TestHost;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.Net.Http.Headers;
using Moq;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using OpenIddict.Abstractions;
using OpenIddict.Core;
using OpenIddict.Models;
using Xunit;
namespace OpenIddict.Tests
namespace OpenIddict.Server.Tests
{
public partial class OpenIddictProviderTests
public partial class OpenIddictServerProviderTests
{
public const string AuthorizationEndpoint = "/connect/authorize";
public const string ConfigurationEndpoint = "/.well-known/openid-configuration";
@ -1331,7 +1333,7 @@ namespace OpenIddict.Tests
Assert.Equal("value", (string) response["custom_string_parameter"]);
}
private static TestServer CreateAuthorizationServer(Action<OpenIddictBuilder> configuration = null)
private static TestServer CreateAuthorizationServer(Action<OpenIddictServerBuilder> configuration = null)
{
var builder = new WebHostBuilder();
@ -1361,47 +1363,52 @@ namespace OpenIddict.Tests
options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
});
// Replace the default OpenIddict managers.
services.AddSingleton(CreateApplicationManager());
services.AddSingleton(CreateAuthorizationManager());
services.AddSingleton(CreateScopeManager());
services.AddSingleton(CreateTokenManager());
services.AddOpenIddict()
.AddCore(options =>
{
options.UseDefaultModels();
services.AddOpenIddict(options =>
{
// Disable the transport security requirement during testing.
options.DisableHttpsRequirement();
// Enable the tested endpoints.
options.EnableAuthorizationEndpoint(AuthorizationEndpoint)
.EnableIntrospectionEndpoint(IntrospectionEndpoint)
.EnableLogoutEndpoint(LogoutEndpoint)
.EnableRevocationEndpoint(RevocationEndpoint)
.EnableTokenEndpoint(TokenEndpoint)
.EnableUserinfoEndpoint(UserinfoEndpoint);
// Enable the tested flows.
options.AllowAuthorizationCodeFlow()
.AllowClientCredentialsFlow()
.AllowImplicitFlow()
.AllowPasswordFlow()
.AllowRefreshTokenFlow();
// Register the X.509 certificate used to sign the identity tokens.
options.AddSigningCertificate(
assembly: typeof(OpenIddictProviderTests).GetTypeInfo().Assembly,
resource: "OpenIddict.Server.Tests.Certificate.pfx",
password: "OpenIddict");
// Note: overriding the default data protection provider is not necessary for the tests to pass,
// but is useful to ensure unnecessary keys are not persisted in testing environments, which also
// helps make the unit tests run faster, as no registry or disk access is required in this case.
options.UseDataProtectionProvider(new EphemeralDataProtectionProvider(new LoggerFactory()));
// Run the configuration delegate
// registered by the unit tests.
configuration?.Invoke(options);
});
options.Services.AddSingleton(CreateApplicationManager());
options.Services.AddSingleton(CreateAuthorizationManager());
options.Services.AddSingleton(CreateScopeManager());
options.Services.AddSingleton(CreateTokenManager());
})
.AddServer(options =>
{
// Disable the transport security requirement during testing.
options.DisableHttpsRequirement();
// Enable the tested endpoints.
options.EnableAuthorizationEndpoint(AuthorizationEndpoint)
.EnableIntrospectionEndpoint(IntrospectionEndpoint)
.EnableLogoutEndpoint(LogoutEndpoint)
.EnableRevocationEndpoint(RevocationEndpoint)
.EnableTokenEndpoint(TokenEndpoint)
.EnableUserinfoEndpoint(UserinfoEndpoint);
// Enable the tested flows.
options.AllowAuthorizationCodeFlow()
.AllowClientCredentialsFlow()
.AllowImplicitFlow()
.AllowPasswordFlow()
.AllowRefreshTokenFlow();
// Register the X.509 certificate used to sign the identity tokens.
options.AddSigningCertificate(
assembly: typeof(OpenIddictServerProviderTests).GetTypeInfo().Assembly,
resource: "OpenIddict.Server.Tests.Certificate.pfx",
password: "OpenIddict");
// Note: overriding the default data protection provider is not necessary for the tests to pass,
// but is useful to ensure unnecessary keys are not persisted in testing environments, which also
// helps make the unit tests run faster, as no registry or disk access is required in this case.
options.UseDataProtectionProvider(new EphemeralDataProtectionProvider());
// Run the configuration delegate
// registered by the unit tests.
configuration?.Invoke(options);
});
});
builder.Configure(app =>
@ -1511,8 +1518,9 @@ namespace OpenIddict.Tests
Action<Mock<OpenIddictApplicationManager<OpenIddictApplication>>> configuration = null)
{
var manager = new Mock<OpenIddictApplicationManager<OpenIddictApplication>>(
Mock.Of<IOpenIddictApplicationStore<OpenIddictApplication>>(),
Mock.Of<ILogger<OpenIddictApplicationManager<OpenIddictApplication>>>());
Mock.Of<IOpenIddictApplicationStoreResolver>(),
Mock.Of<ILogger<OpenIddictApplicationManager<OpenIddictApplication>>>(),
Mock.Of<IOptionsMonitor<OpenIddictCoreOptions>>());
configuration?.Invoke(manager);
@ -1523,8 +1531,9 @@ namespace OpenIddict.Tests
Action<Mock<OpenIddictAuthorizationManager<OpenIddictAuthorization>>> configuration = null)
{
var manager = new Mock<OpenIddictAuthorizationManager<OpenIddictAuthorization>>(
Mock.Of<IOpenIddictAuthorizationStore<OpenIddictAuthorization>>(),
Mock.Of<ILogger<OpenIddictAuthorizationManager<OpenIddictAuthorization>>>());
Mock.Of<IOpenIddictAuthorizationStoreResolver>(),
Mock.Of<ILogger<OpenIddictAuthorizationManager<OpenIddictAuthorization>>>(),
Mock.Of<IOptionsMonitor<OpenIddictCoreOptions>>());
configuration?.Invoke(manager);
@ -1535,8 +1544,9 @@ namespace OpenIddict.Tests
Action<Mock<OpenIddictScopeManager<OpenIddictScope>>> configuration = null)
{
var manager = new Mock<OpenIddictScopeManager<OpenIddictScope>>(
Mock.Of<IOpenIddictScopeStore<OpenIddictScope>>(),
Mock.Of<ILogger<OpenIddictScopeManager<OpenIddictScope>>>());
Mock.Of<IOpenIddictScopeStoreResolver>(),
Mock.Of<ILogger<OpenIddictScopeManager<OpenIddictScope>>>(),
Mock.Of<IOptionsMonitor<OpenIddictCoreOptions>>());
configuration?.Invoke(manager);
@ -1547,8 +1557,9 @@ namespace OpenIddict.Tests
Action<Mock<OpenIddictTokenManager<OpenIddictToken>>> configuration = null)
{
var manager = new Mock<OpenIddictTokenManager<OpenIddictToken>>(
Mock.Of<IOpenIddictTokenStore<OpenIddictToken>>(),
Mock.Of<ILogger<OpenIddictTokenManager<OpenIddictToken>>>());
Mock.Of<IOpenIddictTokenStoreResolver>(),
Mock.Of<ILogger<OpenIddictTokenManager<OpenIddictToken>>>(),
Mock.Of<IOptionsMonitor<OpenIddictCoreOptions>>());
configuration?.Invoke(manager);

44
test/OpenIddict.Server.Tests/OpenIddictExtensionsTests.cs → test/OpenIddict.Server.Tests/OpenIddictServerBuilderTests.cs

@ -9,23 +9,20 @@ using System.IdentityModel.Tokens.Jwt;
using System.Reflection;
using AspNet.Security.OpenIdConnect.Primitives;
using AspNet.Security.OpenIdConnect.Server;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Hosting.Internal;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using Moq;
using OpenIddict.Models;
using Xunit;
namespace OpenIddict.Tests
namespace OpenIddict.Server.Tests
{
public class OpenIddictExtensionsTests
public class OpenIddictServerBuilderTests
{
[Fact]
public void Configure_OptionsAreCorrectlyAmended()
@ -43,21 +40,6 @@ namespace OpenIddict.Tests
Assert.Equal(TimeSpan.FromDays(1), options.AccessTokenLifetime);
}
[Fact]
public void AddDevelopmentSigningCertificate_ThrowsAnExceptionForNullBuilder()
{
// Arrange
var builder = (OpenIddictBuilder) null;
// Act and assert
var exception = Assert.Throws<ArgumentNullException>(delegate
{
builder.AddDevelopmentSigningCertificate();
});
Assert.Equal("builder", exception.ParamName);
}
[Fact]
public void AddDevelopmentSigningCertificate_ThrowsAnExceptionForNullSubject()
{
@ -211,7 +193,7 @@ namespace OpenIddict.Tests
// Act
builder.AddSigningCertificate(
assembly: typeof(OpenIddictExtensionsTests).GetTypeInfo().Assembly,
assembly: typeof(OpenIddictServerBuilderTests).GetTypeInfo().Assembly,
resource: "OpenIddict.Server.Tests.Certificate.pfx",
password: "OpenIddict");
@ -647,7 +629,7 @@ namespace OpenIddict.Tests
var builder = CreateBuilder(services);
// Act
builder.UseDataProtectionProvider(new EphemeralDataProtectionProvider(new LoggerFactory()));
builder.UseDataProtectionProvider(new EphemeralDataProtectionProvider());
var options = GetOptions(services);
@ -687,14 +669,10 @@ namespace OpenIddict.Tests
Assert.True(options.UseReferenceTokens);
}
private static OpenIddictBuilder CreateBuilder(IServiceCollection services)
=> new OpenIddictBuilder(services)
{
ApplicationType = typeof(OpenIddictApplication),
AuthorizationType = typeof(OpenIddictAuthorization),
ScopeType = typeof(OpenIddictScope),
TokenType = typeof(OpenIddictToken)
};
private static OpenIddictServerBuilder CreateBuilder(IServiceCollection services)
=> services.AddOpenIddict()
.AddCore(options => options.UseDefaultModels())
.AddServer();
private static IServiceCollection CreateServices()
{
@ -707,14 +685,14 @@ namespace OpenIddict.Tests
return services;
}
private static OpenIddictOptions GetOptions(IServiceCollection services)
private static OpenIddictServerOptions GetOptions(IServiceCollection services)
{
services.RemoveAll<IPostConfigureOptions<OpenIdConnectServerOptions>>();
services.RemoveAll<IPostConfigureOptions<OpenIddictOptions>>();
services.RemoveAll<IPostConfigureOptions<OpenIddictServerOptions>>();
var provider = services.BuildServiceProvider();
var options = provider.GetRequiredService<IOptionsSnapshot<OpenIddictOptions>>();
var options = provider.GetRequiredService<IOptionsMonitor<OpenIddictServerOptions>>();
return options.Get(OpenIdConnectServerDefaults.AuthenticationScheme);
}
}

36
test/OpenIddict.Tests/OpenIddictExtensionsTests.cs

@ -6,6 +6,7 @@
using System;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using OpenIddict.Core;
using OpenIddict.Models;
using Xunit;
@ -14,38 +15,39 @@ namespace OpenIddict.Tests
{
public class OpenIddictExtensionsTests
{
[Theory]
[InlineData(typeof(OpenIddictApplicationManager<OpenIddictApplication>))]
[InlineData(typeof(OpenIddictAuthorizationManager<OpenIddictAuthorization>))]
[InlineData(typeof(OpenIddictScopeManager<OpenIddictScope>))]
[InlineData(typeof(OpenIddictTokenManager<OpenIddictToken>))]
public void AddOpenIddict_KeyTypeDefaultsToString(Type type)
public void UseDefaultModels_KeyTypeDefaultsToString()
{
// Arrange
var services = new ServiceCollection();
var builder = services.AddOpenIddict().AddCore();
// Act
services.AddOpenIddict();
builder.UseDefaultModels();
// Assert
Assert.Contains(services, service => service.ImplementationType == type);
var provider = services.BuildServiceProvider();
var options = provider.GetRequiredService<IOptionsMonitor<OpenIddictCoreOptions>>().CurrentValue;
Assert.Equal(typeof(OpenIddictApplication), options.DefaultApplicationType);
Assert.Equal(typeof(OpenIddictAuthorization), options.DefaultAuthorizationType);
Assert.Equal(typeof(OpenIddictScope), options.DefaultScopeType);
Assert.Equal(typeof(OpenIddictToken), options.DefaultTokenType);
}
[Theory]
[InlineData(typeof(OpenIddictApplicationManager<OpenIddictApplication<Guid>>))]
[InlineData(typeof(OpenIddictAuthorizationManager<OpenIddictAuthorization<Guid>>))]
[InlineData(typeof(OpenIddictScopeManager<OpenIddictScope<Guid>>))]
[InlineData(typeof(OpenIddictTokenManager<OpenIddictToken<Guid>>))]
public void AddOpenIddict_KeyTypeCanBeOverriden(Type type)
public void UseDefaultModels_KeyTypeCanBeOverriden()
{
// Arrange
var services = new ServiceCollection();
var builder = services.AddOpenIddict().AddCore();
// Act
services.AddOpenIddict<Guid>();
var provider = services.BuildServiceProvider();
var options = provider.GetRequiredService<IOptionsMonitor<OpenIddictCoreOptions>>().CurrentValue;
// Assert
Assert.Contains(services, service => service.ImplementationType == type);
Assert.Equal(typeof(OpenIddictApplication<Guid>), options.DefaultApplicationType);
Assert.Equal(typeof(OpenIddictAuthorization<Guid>), options.DefaultAuthorizationType);
Assert.Equal(typeof(OpenIddictScope<Guid>), options.DefaultScopeType);
Assert.Equal(typeof(OpenIddictToken<Guid>), options.DefaultTokenType);
}
}
}

Loading…
Cancel
Save