Browse Source

Backport the builders/packages to OpenIddict 1.x

pull/670/head
Kévin Chalet 8 years ago
parent
commit
738ded5a7e
  1. 9
      OpenIddict.sln
  2. 3
      samples/Mvc.Server/Controllers/AuthorizationController.cs
  3. 2
      samples/Mvc.Server/Controllers/UserinfoController.cs
  4. 114
      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. 331
      src/OpenIddict.Core/OpenIddictBuilder.cs
  23. 629
      src/OpenIddict.Core/OpenIddictCoreBuilder.cs
  24. 73
      src/OpenIddict.Core/OpenIddictCoreExtensions.cs
  25. 69
      src/OpenIddict.Core/OpenIddictCoreHelpers.cs
  26. 33
      src/OpenIddict.Core/OpenIddictCoreOptions.cs
  27. 92
      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. 17
      src/OpenIddict.Server/Internal/OpenIddictServerProvider.Authentication.cs
  50. 8
      src/OpenIddict.Server/Internal/OpenIddictServerProvider.Discovery.cs
  51. 14
      src/OpenIddict.Server/Internal/OpenIddictServerProvider.Exchange.cs
  52. 29
      src/OpenIddict.Server/Internal/OpenIddictServerProvider.Helpers.cs
  53. 11
      src/OpenIddict.Server/Internal/OpenIddictServerProvider.Introspection.cs
  54. 13
      src/OpenIddict.Server/Internal/OpenIddictServerProvider.Revocation.cs
  55. 16
      src/OpenIddict.Server/Internal/OpenIddictServerProvider.Serialization.cs
  56. 15
      src/OpenIddict.Server/Internal/OpenIddictServerProvider.Session.cs
  57. 4
      src/OpenIddict.Server/Internal/OpenIddictServerProvider.Userinfo.cs
  58. 8
      src/OpenIddict.Server/Internal/OpenIddictServerProvider.cs
  59. 1069
      src/OpenIddict.Server/OpenIddictExtensions.cs
  60. 614
      src/OpenIddict.Server/OpenIddictServerBuilder.cs
  61. 251
      src/OpenIddict.Server/OpenIddictServerExtensions.cs
  62. 29
      src/OpenIddict.Server/OpenIddictServerOptions.cs
  63. 8
      src/OpenIddict.Stores/OpenIddict.Stores.csproj
  64. 2
      src/OpenIddict.Stores/Stores/OpenIddictApplicationStore.cs
  65. 2
      src/OpenIddict.Stores/Stores/OpenIddictAuthorizationStore.cs
  66. 2
      src/OpenIddict.Stores/Stores/OpenIddictScopeStore.cs
  67. 2
      src/OpenIddict.Stores/Stores/OpenIddictTokenStore.cs
  68. 84
      src/OpenIddict/OpenIddictExtensions.cs
  69. 329
      test/OpenIddict.Core.Tests/OpenIddictBuilderTests.cs
  70. 487
      test/OpenIddict.Core.Tests/OpenIddictCoreBuilderTests.cs
  71. 48
      test/OpenIddict.Core.Tests/OpenIddictExtensionsTests.cs
  72. 162
      test/OpenIddict.EntityFramework.Tests/OpenIddictExtensionsTests.cs
  73. 162
      test/OpenIddict.EntityFrameworkCore.Tests/OpenIddictExtensionsTests.cs
  74. 1
      test/OpenIddict.Mvc.Tests/OpenIddict.Mvc.Tests.csproj
  75. 2
      test/OpenIddict.Mvc.Tests/OpenIddictExtensionsTests.cs
  76. 6
      test/OpenIddict.Server.Tests/Internal/OpenIddictServerProviderTests.Authentication.cs
  77. 8
      test/OpenIddict.Server.Tests/Internal/OpenIddictServerProviderTests.Discovery.cs
  78. 5
      test/OpenIddict.Server.Tests/Internal/OpenIddictServerProviderTests.Exchange.cs
  79. 5
      test/OpenIddict.Server.Tests/Internal/OpenIddictServerProviderTests.Introspection.cs
  80. 5
      test/OpenIddict.Server.Tests/Internal/OpenIddictServerProviderTests.Revocation.cs
  81. 5
      test/OpenIddict.Server.Tests/Internal/OpenIddictServerProviderTests.Serialization.cs
  82. 5
      test/OpenIddict.Server.Tests/Internal/OpenIddictServerProviderTests.Session.cs
  83. 4
      test/OpenIddict.Server.Tests/Internal/OpenIddictServerProviderTests.Userinfo.cs
  84. 115
      test/OpenIddict.Server.Tests/Internal/OpenIddictServerProviderTests.cs
  85. 312
      test/OpenIddict.Server.Tests/OpenIddictServerBuilderTests.cs
  86. 226
      test/OpenIddict.Server.Tests/OpenIddictServerExtensionsTests.cs
  87. 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}

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

@ -20,6 +20,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 +68,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
{

114
samples/Mvc.Server/Startup.cs

@ -9,6 +9,7 @@ using Microsoft.Extensions.DependencyInjection;
using Mvc.Server.Extensions;
using Mvc.Server.Models;
using Mvc.Server.Services;
using OpenIddict.Abstractions;
using OpenIddict.Core;
using OpenIddict.Models;
@ -52,57 +53,66 @@ namespace Mvc.Server
options.ClaimsIdentity.RoleClaimType = OpenIdConnectConstants.Claims.Role;
});
// 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>();
@ -171,7 +181,7 @@ namespace Mvc.Server
});
});
app.UseOpenIddict();
app.UseOpenIddictServer();
app.UseMvcWithDefaultRoute();

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

@ -0,0 +1,23 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\build\packages.props" />
<PropertyGroup>
<TargetFramework>netstandard1.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] IOptions<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 IOptions<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] IOptions<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 IOptions<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] IOptions<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 IOptions<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] IOptions<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 IOptions<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" />

331
src/OpenIddict.Core/OpenIddictBuilder.cs

@ -1,331 +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;
#if NETSTANDARD1_3
using System.Reflection;
#endif
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;
}
}
}

629
src/OpenIddict.Core/OpenIddictCoreBuilder.cs

@ -0,0 +1,629 @@
/*
* Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
* See https://github.com/openiddict/openiddict-core for more information concerning
* the license and the contributors participating to this project.
*/
using System;
using System.ComponentModel;
using System.Reflection;
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.GetTypeInfo().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.GetTypeInfo().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.GetTypeInfo().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.GetTypeInfo().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.GetTypeInfo().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.GetTypeInfo().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.GetTypeInfo().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.GetTypeInfo().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;
}
}
}

69
src/OpenIddict.Core/OpenIddictCoreHelpers.cs

@ -0,0 +1,69 @@
using System;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
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.GetTypeInfo().IsGenericTypeDefinition)
{
throw new ArgumentException("The second parameter must be a generic type definition.", nameof(definition));
}
for (var candidate = type.GetTypeInfo(); candidate != null; candidate = candidate.BaseType?.GetTypeInfo())
{
if (!candidate.IsGenericType && !candidate.AsType().IsConstructedGenericType)
{
continue;
}
if (candidate.GetGenericTypeDefinition() == definition)
{
return candidate.AsType();
}
if (definition.GetTypeInfo().IsInterface)
{
foreach (var contract in candidate.AsType().GetInterfaces().Select(contract => contract.GetTypeInfo()))
{
if (!contract.IsGenericType && !contract.AsType().IsConstructedGenericType)
{
continue;
}
if (contract.GetGenericTypeDefinition() == definition)
{
return contract.AsType();
}
}
}
}
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; }
}
}

92
src/OpenIddict.Core/OpenIddictExtensions.cs

@ -1,92 +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();
var builder = new OpenIddictBuilder(services)
{
ApplicationType = typeof(TApplication),
AuthorizationType = typeof(TAuthorization),
ScopeType = typeof(TScope),
TokenType = typeof(TToken)
};
// Register the OpenIddict core services in the DI container.
builder.Services.TryAddSingleton(builder);
builder.Services.TryAddScoped<OpenIddictApplicationManager<TApplication>>();
builder.Services.TryAddScoped<OpenIddictAuthorizationManager<TAuthorization>>();
builder.Services.TryAddScoped<OpenIddictScopeManager<TScope>>();
builder.Services.TryAddScoped<OpenIddictTokenManager<TToken>>();
return builder;
}
/// <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,15 +5,11 @@
*/
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Reflection;
using JetBrains.Annotations;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.Extensions.DependencyInjection.Extensions;
using OpenIddict.Core;
using OpenIddict.EntityFrameworkCore;
using OpenIddict.Models;
@ -26,8 +22,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)
@ -35,85 +32,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>
@ -123,12 +50,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
@ -136,13 +61,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
@ -175,12 +99,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
@ -189,12 +111,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
@ -313,28 +233,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)
{

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

@ -20,18 +20,19 @@ using Microsoft.IdentityModel.Tokens;
using Newtonsoft.Json;
using Newtonsoft.Json.Bson;
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
{
public override async Task ExtractAuthorizationRequest([NotNull] ExtractAuthorizationRequestContext context)
{
var options = (OpenIddictOptions) context.Options;
var options = (OpenIddictServerOptions) context.Options;
var logger = context.HttpContext.RequestServices.GetRequiredService<ILogger<OpenIddictProvider<TApplication, TAuthorization, TScope, TToken>>>();
var logger = context.HttpContext.RequestServices.GetRequiredService<ILogger<OpenIddictServerProvider<TApplication, TAuthorization, TScope, TToken>>>();
// Reject requests using the unsupported request parameter.
if (!string.IsNullOrEmpty(context.Request.Request))
@ -112,10 +113,10 @@ namespace OpenIddict
public override async Task ValidateAuthorizationRequest([NotNull] ValidateAuthorizationRequestContext context)
{
var options = (OpenIddictOptions) context.Options;
var options = (OpenIddictServerOptions) context.Options;
var applications = context.HttpContext.RequestServices.GetRequiredService<OpenIddictApplicationManager<TApplication>>();
var logger = context.HttpContext.RequestServices.GetRequiredService<ILogger<OpenIddictProvider<TApplication, TAuthorization, TScope, TToken>>>();
var logger = context.HttpContext.RequestServices.GetRequiredService<ILogger<OpenIddictServerProvider<TApplication, TAuthorization, TScope, TToken>>>();
var scopes = context.HttpContext.RequestServices.GetRequiredService<OpenIddictScopeManager<TScope>>();
// Note: the OpenID Connect server middleware supports authorization code, implicit, hybrid,
@ -422,7 +423,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
@ -474,7 +475,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

@ -10,16 +10,16 @@ using AspNet.Security.OpenIdConnect.Primitives;
using AspNet.Security.OpenIdConnect.Server;
using JetBrains.Annotations;
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 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,

14
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;
@ -14,19 +13,20 @@ using AspNet.Security.OpenIdConnect.Server;
using JetBrains.Annotations;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
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
{
public override async Task ValidateTokenRequest([NotNull] ValidateTokenRequestContext context)
{
var options = (OpenIddictOptions) context.Options;
var options = (OpenIddictServerOptions) context.Options;
var applications = context.HttpContext.RequestServices.GetRequiredService<OpenIddictApplicationManager<TApplication>>();
var logger = context.HttpContext.RequestServices.GetRequiredService<ILogger<OpenIddictProvider<TApplication, TAuthorization, TScope, TToken>>>();
var logger = context.HttpContext.RequestServices.GetRequiredService<ILogger<OpenIddictServerProvider<TApplication, TAuthorization, TScope, TToken>>>();
var scopes = context.HttpContext.RequestServices.GetRequiredService<OpenIddictScopeManager<TScope>>();
// Reject token requests that don't specify a supported grant type.
@ -279,9 +279,9 @@ namespace OpenIddict
public override async Task HandleTokenRequest([NotNull] HandleTokenRequestContext context)
{
var options = (OpenIddictOptions) context.Options;
var options = (OpenIddictServerOptions) context.Options;
var logger = context.HttpContext.RequestServices.GetRequiredService<ILogger<OpenIddictProvider<TApplication, TAuthorization, TScope, TToken>>>();
var logger = context.HttpContext.RequestServices.GetRequiredService<ILogger<OpenIddictServerProvider<TApplication, TAuthorization, TScope, TToken>>>();
var tokens = context.HttpContext.RequestServices.GetRequiredService<OpenIddictTokenManager<TToken>>();
if (context.Ticket != null)

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

@ -20,20 +20,21 @@ using Microsoft.Extensions.DependencyInjection;
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] AuthenticationTicket ticket, [NotNull] OpenIddictServerOptions options,
[NotNull] HttpContext context, [NotNull] OpenIdConnectRequest request)
{
var applications = context.RequestServices.GetRequiredService<OpenIddictApplicationManager<TApplication>>();
var authorizations = context.RequestServices.GetRequiredService<OpenIddictAuthorizationManager<TAuthorization>>();
var logger = context.RequestServices.GetRequiredService<ILogger<OpenIddictProvider<TApplication, TAuthorization, TScope, TToken>>>();
var logger = context.RequestServices.GetRequiredService<ILogger<OpenIddictServerProvider<TApplication, TAuthorization, TScope, TToken>>>();
var descriptor = new OpenIddictAuthorizationDescriptor
{
@ -88,7 +89,7 @@ namespace OpenIddict
private async Task<string> CreateTokenAsync(
[NotNull] string type, [NotNull] AuthenticationTicket ticket,
[NotNull] OpenIddictOptions options, [NotNull] HttpContext context,
[NotNull] OpenIddictServerOptions options, [NotNull] HttpContext context,
[NotNull] OpenIdConnectRequest request,
[NotNull] ISecureDataFormat<AuthenticationTicket> format)
{
@ -101,7 +102,7 @@ namespace OpenIddict
"Only authorization codes, access and refresh tokens should be created using this method.");
var applications = context.RequestServices.GetRequiredService<OpenIddictApplicationManager<TApplication>>();
var logger = context.RequestServices.GetRequiredService<ILogger<OpenIddictProvider<TApplication, TAuthorization, TScope, TToken>>>();
var logger = context.RequestServices.GetRequiredService<ILogger<OpenIddictServerProvider<TApplication, TAuthorization, TScope, TToken>>>();
var tokens = context.RequestServices.GetRequiredService<OpenIddictTokenManager<TToken>>();
// When sliding expiration is disabled, the expiration date of generated refresh tokens is fixed
@ -226,11 +227,11 @@ namespace OpenIddict
private async Task<AuthenticationTicket> ReceiveTokenAsync(
[NotNull] string type, [NotNull] string value,
[NotNull] OpenIddictOptions options, [NotNull] HttpContext context,
[NotNull] OpenIddictServerOptions options, [NotNull] HttpContext context,
[NotNull] OpenIdConnectRequest request,
[NotNull] ISecureDataFormat<AuthenticationTicket> format)
{
var logger = context.RequestServices.GetRequiredService<ILogger<OpenIddictProvider<TApplication, TAuthorization, TScope, TToken>>>();
var logger = context.RequestServices.GetRequiredService<ILogger<OpenIddictServerProvider<TApplication, TAuthorization, TScope, TToken>>>();
var tokens = context.RequestServices.GetRequiredService<OpenIddictTokenManager<TToken>>();
Debug.Assert(type == OpenIdConnectConstants.TokenUsages.AccessToken ||
@ -380,7 +381,7 @@ namespace OpenIddict
private async Task<bool> TryRevokeAuthorizationAsync([NotNull] AuthenticationTicket ticket, [NotNull] HttpContext context)
{
var authorizations = context.RequestServices.GetRequiredService<OpenIddictAuthorizationManager<TAuthorization>>();
var logger = context.RequestServices.GetRequiredService<ILogger<OpenIddictProvider<TApplication, TAuthorization, TScope, TToken>>>();
var logger = context.RequestServices.GetRequiredService<ILogger<OpenIddictServerProvider<TApplication, TAuthorization, TScope, TToken>>>();
// Note: if the authorization identifier or the authorization itself
// cannot be found, return true as the authorization doesn't need
@ -419,7 +420,7 @@ namespace OpenIddict
private async Task<bool> TryRevokeTokenAsync([NotNull] TToken token, [NotNull] HttpContext context)
{
var logger = context.RequestServices.GetRequiredService<ILogger<OpenIddictProvider<TApplication, TAuthorization, TScope, TToken>>>();
var logger = context.RequestServices.GetRequiredService<ILogger<OpenIddictServerProvider<TApplication, TAuthorization, TScope, TToken>>>();
var tokens = context.RequestServices.GetRequiredService<OpenIddictTokenManager<TToken>>();
var identifier = await tokens.GetIdAsync(token);
@ -474,7 +475,7 @@ namespace OpenIddict
private async Task<bool> TryRedeemTokenAsync([NotNull] TToken token, [NotNull] HttpContext context)
{
var logger = context.RequestServices.GetRequiredService<ILogger<OpenIddictProvider<TApplication, TAuthorization, TScope, TToken>>>();
var logger = context.RequestServices.GetRequiredService<ILogger<OpenIddictServerProvider<TApplication, TAuthorization, TScope, TToken>>>();
var tokens = context.RequestServices.GetRequiredService<OpenIddictTokenManager<TToken>>();
var identifier = await tokens.GetIdAsync(token);
@ -503,9 +504,9 @@ namespace OpenIddict
private async Task<bool> TryExtendTokenAsync(
[NotNull] TToken token, [NotNull] AuthenticationTicket ticket,
[NotNull] HttpContext context, [NotNull] OpenIddictOptions options)
[NotNull] HttpContext context, [NotNull] OpenIddictServerOptions options)
{
var logger = context.RequestServices.GetRequiredService<ILogger<OpenIddictProvider<TApplication, TAuthorization, TScope, TToken>>>();
var logger = context.RequestServices.GetRequiredService<ILogger<OpenIddictServerProvider<TApplication, TAuthorization, TScope, TToken>>>();
var tokens = context.RequestServices.GetRequiredService<OpenIddictTokenManager<TToken>>();
var identifier = ticket.GetTokenId();
@ -540,7 +541,7 @@ namespace OpenIddict
[NotNull] HttpContext context, [NotNull] OpenIdConnectRequest request,
[NotNull] AuthenticationProperties properties)
{
var logger = context.RequestServices.GetRequiredService<ILogger<OpenIddictProvider<TApplication, TAuthorization, TScope, TToken>>>();
var logger = context.RequestServices.GetRequiredService<ILogger<OpenIddictServerProvider<TApplication, TAuthorization, TScope, TToken>>>();
Debug.Assert(properties != null, "The authentication properties shouldn't be null.");

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

@ -13,11 +13,12 @@ using AspNet.Security.OpenIdConnect.Server;
using JetBrains.Annotations;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
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
{
public override Task ExtractIntrospectionRequest([NotNull] ExtractIntrospectionRequestContext context)
@ -39,7 +40,7 @@ namespace OpenIddict
public override async Task ValidateIntrospectionRequest([NotNull] ValidateIntrospectionRequestContext context)
{
var applications = context.HttpContext.RequestServices.GetRequiredService<OpenIddictApplicationManager<TApplication>>();
var logger = context.HttpContext.RequestServices.GetRequiredService<ILogger<OpenIddictProvider<TApplication, TAuthorization, TScope, TToken>>>();
var logger = context.HttpContext.RequestServices.GetRequiredService<ILogger<OpenIddictServerProvider<TApplication, TAuthorization, TScope, TToken>>>();
// Note: the OpenID Connect server middleware supports unauthenticated introspection requests
// but OpenIddict uses a stricter policy preventing unauthenticated/public applications
@ -116,9 +117,9 @@ namespace OpenIddict
public override async Task HandleIntrospectionRequest([NotNull] HandleIntrospectionRequestContext context)
{
var options = (OpenIddictOptions) context.Options;
var options = (OpenIddictServerOptions) context.Options;
var logger = context.HttpContext.RequestServices.GetRequiredService<ILogger<OpenIddictProvider<TApplication, TAuthorization, TScope, TToken>>>();
var logger = context.HttpContext.RequestServices.GetRequiredService<ILogger<OpenIddictServerProvider<TApplication, TAuthorization, TScope, TToken>>>();
var tokens = context.HttpContext.RequestServices.GetRequiredService<OpenIddictTokenManager<TToken>>();
Debug.Assert(context.Ticket != null, "The authentication ticket shouldn't be null.");

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

@ -13,19 +13,20 @@ using AspNet.Security.OpenIdConnect.Server;
using JetBrains.Annotations;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
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
{
public override async Task ValidateRevocationRequest([NotNull] ValidateRevocationRequestContext context)
{
var options = (OpenIddictOptions) context.Options;
var options = (OpenIddictServerOptions) context.Options;
var applications = context.HttpContext.RequestServices.GetRequiredService<OpenIddictApplicationManager<TApplication>>();
var logger = context.HttpContext.RequestServices.GetRequiredService<ILogger<OpenIddictProvider<TApplication, TAuthorization, TScope, TToken>>>();
var logger = context.HttpContext.RequestServices.GetRequiredService<ILogger<OpenIddictServerProvider<TApplication, TAuthorization, TScope, TToken>>>();
Debug.Assert(!options.DisableTokenRevocation, "Token revocation support shouldn't be disabled at this stage.");
@ -167,9 +168,9 @@ namespace OpenIddict
public override async Task HandleRevocationRequest([NotNull] HandleRevocationRequestContext context)
{
var options = (OpenIddictOptions) context.Options;
var options = (OpenIddictServerOptions) context.Options;
var logger = context.HttpContext.RequestServices.GetRequiredService<ILogger<OpenIddictProvider<TApplication, TAuthorization, TScope, TToken>>>();
var logger = context.HttpContext.RequestServices.GetRequiredService<ILogger<OpenIddictServerProvider<TApplication, TAuthorization, TScope, TToken>>>();
var tokens = context.HttpContext.RequestServices.GetRequiredService<OpenIddictTokenManager<TToken>>();
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;
@ -97,7 +97,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;
@ -124,7 +124,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;

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

@ -19,18 +19,19 @@ using Microsoft.IdentityModel.Tokens;
using Newtonsoft.Json;
using Newtonsoft.Json.Bson;
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
{
public override async Task ExtractLogoutRequest([NotNull] ExtractLogoutRequestContext context)
{
var options = (OpenIddictOptions) context.Options;
var options = (OpenIddictServerOptions) context.Options;
var logger = context.HttpContext.RequestServices.GetRequiredService<ILogger<OpenIddictProvider<TApplication, TAuthorization, TScope, TToken>>>();
var logger = context.HttpContext.RequestServices.GetRequiredService<ILogger<OpenIddictServerProvider<TApplication, TAuthorization, TScope, TToken>>>();
// If a request_id parameter can be found in the logout request,
// restore the complete logout request from the distributed cache.
@ -86,7 +87,7 @@ namespace OpenIddict
public override async Task ValidateLogoutRequest([NotNull] ValidateLogoutRequestContext context)
{
var applications = context.HttpContext.RequestServices.GetRequiredService<OpenIddictApplicationManager<TApplication>>();
var logger = context.HttpContext.RequestServices.GetRequiredService<ILogger<OpenIddictProvider<TApplication, TAuthorization, TScope, TToken>>>();
var logger = context.HttpContext.RequestServices.GetRequiredService<ILogger<OpenIddictServerProvider<TApplication, TAuthorization, TScope, TToken>>>();
// If an optional post_logout_redirect_uri was provided, validate it.
if (!string.IsNullOrEmpty(context.PostLogoutRedirectUri))
@ -133,7 +134,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
@ -183,7 +184,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)

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

@ -13,12 +13,12 @@ using AspNet.Security.OpenIdConnect.Primitives;
using AspNet.Security.OpenIdConnect.Server;
using JetBrains.Annotations;
using Microsoft.AspNetCore.Authentication;
using OpenIddict.Core;
using OpenIddict.Abstractions;
namespace OpenIddict
namespace OpenIddict.Server
{
[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
{
public override Task ProcessChallengeResponse([NotNull] ProcessChallengeResponseContext context)
@ -40,7 +40,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(),

1069
src/OpenIddict.Server/OpenIddictExtensions.cs

File diff suppressed because it is too large

614
src/OpenIddict.Server/OpenIddictServerBuilder.cs

@ -0,0 +1,614 @@
/*
* 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 JetBrains.Annotations;
using Microsoft.AspNetCore.Builder;
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(configuration);
return this;
}
/// <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="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);
}
}

251
src/OpenIddict.Server/OpenIddictServerExtensions.cs

@ -0,0 +1,251 @@
/*
* 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.Linq;
using System.Text;
using AspNet.Security.OpenIdConnect.Primitives;
using AspNet.Security.OpenIdConnect.Server;
using JetBrains.Annotations;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using OpenIddict.Core;
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();
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;
}
/// <summary>
/// Registers the OpenIddict server middleware in the ASP.NET Core pipeline.
/// </summary>
/// <param name="app">The application builder used to register middleware instances.</param>
/// <returns>The <see cref="IApplicationBuilder"/>.</returns>
public static IApplicationBuilder UseOpenIddictServer([NotNull] this IApplicationBuilder app)
{
if (app == null)
{
throw new ArgumentNullException(nameof(app));
}
var configuration = app.ApplicationServices.GetRequiredService<IOptions<OpenIddictCoreOptions>>().Value;
// Resolve the OpenIddict options from the DI container.
var options = app.ApplicationServices.GetRequiredService<IOptions<OpenIddictServerOptions>>().Value;
if (options.ApplicationType == null)
{
options.ApplicationType = configuration.DefaultApplicationType;
}
if (options.AuthorizationType == null)
{
options.AuthorizationType = configuration.DefaultAuthorizationType;
}
if (options.ScopeType == null)
{
options.ScopeType = configuration.DefaultScopeType;
}
if (options.TokenType == null)
{
options.TokenType = configuration.DefaultTokenType;
}
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());
}
// When no authorization provider has been registered in the options,
// create a new OpenIddictProvider instance using the specified entities.
if (options.Provider == null)
{
options.Provider = (OpenIdConnectServerProvider) Activator.CreateInstance(
typeof(OpenIddictServerProvider<,,,>).MakeGenericType(
/* TApplication: */ options.ApplicationType,
/* TAuthorization: */ options.AuthorizationType,
/* TScope: */ options.ScopeType,
/* TToken: */ options.TokenType));
}
// When no distributed cache has been registered in the options, use the
// global instance registered in the dependency injection container.
if (options.Cache == null)
{
options.Cache = app.ApplicationServices.GetRequiredService<IDistributedCache>();
}
// If OpenIddict was configured to use reference tokens, replace the default access tokens/
// authorization codes/refresh tokens formats using a specific data protector to ensure
// that encrypted tokens stored in the database cannot be treated as valid tokens if the
// reference tokens option is later turned off by the developer.
if (options.UseReferenceTokens)
{
// Note: a default data protection provider is always registered by
// the OpenID Connect server handler when none is explicitly set but
// this initializer is registered to be invoked before ASOS' initializer.
// To ensure the provider property is never null, it's manually set here.
if (options.DataProtectionProvider == null)
{
options.DataProtectionProvider = app.ApplicationServices.GetDataProtectionProvider();
}
if (options.AccessTokenFormat == null)
{
var protector = options.DataProtectionProvider.CreateProtector(
nameof(OpenIdConnectServerHandler),
nameof(options.AccessTokenFormat),
nameof(options.UseReferenceTokens),
options.AuthenticationScheme);
options.AccessTokenFormat = new TicketDataFormat(protector);
}
if (options.AuthorizationCodeFormat == null)
{
var protector = options.DataProtectionProvider.CreateProtector(
nameof(OpenIdConnectServerHandler),
nameof(options.AuthorizationCodeFormat),
nameof(options.UseReferenceTokens),
options.AuthenticationScheme);
options.AuthorizationCodeFormat = new TicketDataFormat(protector);
}
if (options.RefreshTokenFormat == null)
{
var protector = options.DataProtectionProvider.CreateProtector(
nameof(OpenIdConnectServerHandler),
nameof(options.RefreshTokenFormat),
nameof(options.UseReferenceTokens),
options.AuthenticationScheme);
options.RefreshTokenFormat = new TicketDataFormat(protector);
}
}
// Ensure at least one flow has been enabled.
if (options.GrantTypes.Count == 0)
{
throw new InvalidOperationException("At least one OAuth2/OpenID Connect flow must be enabled.");
}
// Ensure the authorization endpoint has been enabled when
// the authorization code or implicit grants are supported.
if (!options.AuthorizationEndpointPath.HasValue && (options.GrantTypes.Contains(OpenIdConnectConstants.GrantTypes.AuthorizationCode) ||
options.GrantTypes.Contains(OpenIdConnectConstants.GrantTypes.Implicit)))
{
throw new InvalidOperationException("The authorization endpoint must be enabled to use " +
"the authorization code and implicit flows.");
}
// Ensure the token endpoint has been enabled when the authorization code,
// client credentials, password or refresh token grants are supported.
if (!options.TokenEndpointPath.HasValue && (options.GrantTypes.Contains(OpenIdConnectConstants.GrantTypes.AuthorizationCode) ||
options.GrantTypes.Contains(OpenIdConnectConstants.GrantTypes.ClientCredentials) ||
options.GrantTypes.Contains(OpenIdConnectConstants.GrantTypes.Password) ||
options.GrantTypes.Contains(OpenIdConnectConstants.GrantTypes.RefreshToken)))
{
throw new InvalidOperationException("The token endpoint must be enabled to use the authorization code, " +
"client credentials, password and refresh token flows.");
}
if (options.RevocationEndpointPath.HasValue && options.DisableTokenRevocation)
{
throw new InvalidOperationException("The revocation endpoint cannot be enabled when token revocation is disabled.");
}
if (options.UseReferenceTokens && options.DisableTokenRevocation)
{
throw new InvalidOperationException(
"Reference tokens cannot be used when disabling token revocation.");
}
if (options.UseReferenceTokens && options.AccessTokenHandler != null)
{
throw new InvalidOperationException(
"Reference tokens cannot be used when configuring JWT as the access token format.");
}
if (options.UseSlidingExpiration && options.DisableTokenRevocation && !options.UseRollingTokens)
{
throw new InvalidOperationException("Sliding expiration must be disabled when turning off " +
"token revocation if rolling tokens are not used.");
}
// Ensure at least one asymmetric signing certificate/key was registered if the implicit flow was enabled.
if (!options.SigningCredentials.Any(credentials => credentials.Key is AsymmetricSecurityKey) &&
options.GrantTypes.Contains(OpenIdConnectConstants.GrantTypes.Implicit))
{
throw new InvalidOperationException("At least one asymmetric signing key must be registered when enabling the implicit flow. " +
"Consider registering a X.509 certificate using 'services.AddOpenIddict().AddSigningCertificate()' " +
"or call 'services.AddOpenIddict().AddEphemeralSigningKey()' to use an ephemeral key.");
}
// Automatically add the offline_access scope if the refresh token grant has been enabled.
if (options.GrantTypes.Contains(OpenIdConnectConstants.GrantTypes.RefreshToken))
{
options.Scopes.Add(OpenIdConnectConstants.Scopes.OfflineAccess);
}
return app.UseOpenIdConnectServer(options);
}
}
}

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

@ -11,18 +11,31 @@ 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
{
public OpenIddictOptions()
/// <summary>
/// Creates a new instance of the <see cref="OpenIddictServerOptions"/> class.
/// </summary>
public OpenIddictServerOptions()
{
Provider = null;
}
/// <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.
@ -87,6 +100,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

8
src/OpenIddict.Stores/OpenIddict.Stores.csproj

@ -13,12 +13,18 @@
</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>
<ItemGroup Condition=" '$(TargetFramework)' == 'netstandard1.3' ">
<PackageReference Include="System.ComponentModel.TypeConverter" Version="$(TypeConverterVersion)" />
<PackageReference Include="System.Linq.Queryable" Version="$(QueryableVersion)" />
</ItemGroup>
</Project>

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

@ -15,7 +15,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

@ -15,7 +15,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

@ -15,7 +15,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

@ -15,7 +15,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<IOptions<OpenIddictCoreOptions>>().Value;
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,
IOptions<OpenIddictCoreOptions> options)
: base(resolver, logger, options)
{
}
}
private class OpenGenericApplicationManager<TApplication> : OpenIddictApplicationManager<TApplication>
where TApplication : class
{
public OpenGenericApplicationManager(
IOpenIddictApplicationStoreResolver resolver,
ILogger<OpenIddictApplicationManager<TApplication>> logger,
IOptions<OpenIddictCoreOptions> options)
: base(resolver, logger, options)
{
}
}
private class ClosedGenericAuthorizationManager : OpenIddictAuthorizationManager<CustomAuthorization>
{
public ClosedGenericAuthorizationManager(
IOpenIddictAuthorizationStoreResolver resolver,
ILogger<OpenIddictAuthorizationManager<CustomAuthorization>> logger,
IOptions<OpenIddictCoreOptions> options)
: base(resolver, logger, options)
{
}
}
private class OpenGenericAuthorizationManager<TAuthorization> : OpenIddictAuthorizationManager<TAuthorization>
where TAuthorization : class
{
public OpenGenericAuthorizationManager(
IOpenIddictAuthorizationStoreResolver resolver,
ILogger<OpenIddictAuthorizationManager<TAuthorization>> logger,
IOptions<OpenIddictCoreOptions> options)
: base(resolver, logger, options)
{
}
}
private class ClosedGenericScopeManager : OpenIddictScopeManager<CustomScope>
{
public ClosedGenericScopeManager(
IOpenIddictScopeStoreResolver resolver,
ILogger<OpenIddictScopeManager<CustomScope>> logger,
IOptions<OpenIddictCoreOptions> options)
: base(resolver, logger, options)
{
}
}
private class OpenGenericScopeManager<TScope> : OpenIddictScopeManager<TScope>
where TScope : class
{
public OpenGenericScopeManager(
IOpenIddictScopeStoreResolver resolver,
ILogger<OpenIddictScopeManager<TScope>> logger,
IOptions<OpenIddictCoreOptions> options)
: base(resolver, logger, options)
{
}
}
private class ClosedGenericTokenManager : OpenIddictTokenManager<CustomToken>
{
public ClosedGenericTokenManager(
IOpenIddictTokenStoreResolver resolver,
ILogger<OpenIddictTokenManager<CustomToken>> logger,
IOptions<OpenIddictCoreOptions> options)
: base(resolver, logger, options)
{
}
}
private class OpenGenericTokenManager<TToken> : OpenIddictTokenManager<TToken>
where TToken : class
{
public OpenGenericTokenManager(
IOpenIddictTokenStoreResolver resolver,
ILogger<OpenIddictTokenManager<TToken>> logger,
IOptions<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();

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;
@ -17,13 +16,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()

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

@ -10,15 +10,13 @@ using AspNet.Security.OpenIdConnect.Primitives;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication.Facebook;
using Microsoft.AspNetCore.Authentication.Google;
using Microsoft.AspNetCore.Builder;
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

@ -18,13 +18,14 @@ using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Authentication;
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

@ -17,13 +17,14 @@ using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Authentication;
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

@ -19,13 +19,14 @@ using Microsoft.AspNetCore.Http.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

@ -18,13 +18,14 @@ using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Authentication;
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

@ -13,12 +13,13 @@ using Microsoft.AspNetCore.Builder;
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()

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

@ -26,17 +26,19 @@ using Microsoft.AspNetCore.Http.Authentication;
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";
@ -1332,7 +1334,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();
@ -1345,47 +1347,52 @@ namespace OpenIddict.Tests
services.AddAuthentication();
services.AddOptions();
// 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());
// 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 =>
@ -1430,7 +1437,7 @@ namespace OpenIddict.Tests
SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme
});
app.UseOpenIddict();
app.UseOpenIddictServer();
app.Run(context =>
{
@ -1513,8 +1520,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<IOptions<OpenIddictCoreOptions>>());
configuration?.Invoke(manager);
@ -1525,8 +1533,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<IOptions<OpenIddictCoreOptions>>());
configuration?.Invoke(manager);
@ -1537,8 +1546,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<IOptions<OpenIddictCoreOptions>>());
configuration?.Invoke(manager);
@ -1549,8 +1559,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<IOptions<OpenIddictCoreOptions>>());
configuration?.Invoke(manager);

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

@ -8,200 +8,20 @@ using System;
using System.IdentityModel.Tokens.Jwt;
using System.Reflection;
using AspNet.Security.OpenIdConnect.Primitives;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Builder.Internal;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Hosting.Internal;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
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 UseOpenIddict_ThrowsAnExceptionWhenServicesAreNotRegistered()
{
// Arrange
var services = new ServiceCollection();
var builder = new ApplicationBuilder(services.BuildServiceProvider());
// Act and assert
var exception = Assert.Throws<InvalidOperationException>(() => builder.UseOpenIddict());
Assert.Equal("The OpenIddict services cannot be resolved from the dependency injection container. " +
"Make sure 'services.AddOpenIddict()' is correctly called from 'ConfigureServices()'.", exception.Message);
}
[Fact]
public void UseOpenIddict_ThrowsAnExceptionWhenNoFlowIsEnabled()
{
// Arrange
var services = new ServiceCollection();
services.AddOpenIddict();
var builder = new ApplicationBuilder(services.BuildServiceProvider());
// Act and assert
var exception = Assert.Throws<InvalidOperationException>(() => builder.UseOpenIddict());
Assert.Equal("At least one OAuth2/OpenID Connect flow must be enabled.", exception.Message);
}
[Theory]
[InlineData(OpenIdConnectConstants.GrantTypes.AuthorizationCode)]
[InlineData(OpenIdConnectConstants.GrantTypes.Implicit)]
public void UseOpenIddict_ThrowsAnExceptionWhenAuthorizationEndpointIsDisabled(string flow)
{
// Arrange
var services = new ServiceCollection();
services.AddOpenIddict()
.Configure(options => options.GrantTypes.Add(flow))
.Configure(options => options.AuthorizationEndpointPath = PathString.Empty);
var builder = new ApplicationBuilder(services.BuildServiceProvider());
// Act and assert
var exception = Assert.Throws<InvalidOperationException>(() => builder.UseOpenIddict());
Assert.Equal("The authorization endpoint must be enabled to use " +
"the authorization code and implicit flows.", exception.Message);
}
[Theory]
[InlineData(OpenIdConnectConstants.GrantTypes.AuthorizationCode)]
[InlineData(OpenIdConnectConstants.GrantTypes.ClientCredentials)]
[InlineData(OpenIdConnectConstants.GrantTypes.Password)]
[InlineData(OpenIdConnectConstants.GrantTypes.RefreshToken)]
public void UseOpenIddict_ThrowsAnExceptionWhenTokenEndpointIsDisabled(string flow)
{
// Arrange
var services = new ServiceCollection();
services.AddOpenIddict()
.EnableAuthorizationEndpoint("/connect/authorize")
.Configure(options => options.GrantTypes.Add(flow))
.Configure(options => options.TokenEndpointPath = PathString.Empty);
var builder = new ApplicationBuilder(services.BuildServiceProvider());
// Act and assert
var exception = Assert.Throws<InvalidOperationException>(() => builder.UseOpenIddict());
Assert.Equal("The token endpoint must be enabled to use the authorization code, " +
"client credentials, password and refresh token flows.", exception.Message);
}
[Fact]
public void UseOpenIddict_ThrowsAnExceptionWhenTokenRevocationIsDisabled()
{
// Arrange
var services = new ServiceCollection();
services.AddOpenIddict()
.EnableAuthorizationEndpoint("/connect/authorize")
.EnableRevocationEndpoint("/connect/revocation")
.AllowImplicitFlow()
.DisableTokenRevocation();
var builder = new ApplicationBuilder(services.BuildServiceProvider());
// Act and assert
var exception = Assert.Throws<InvalidOperationException>(() => builder.UseOpenIddict());
Assert.Equal("The revocation endpoint cannot be enabled when token revocation is disabled.", exception.Message);
}
[Fact]
public void UseOpenIddict_ThrowsAnExceptionWhenUsingReferenceTokensWithTokenRevocationDisabled()
{
// Arrange
var services = new ServiceCollection();
services.AddDataProtection();
services.AddOpenIddict()
.EnableAuthorizationEndpoint("/connect/authorize")
.AllowImplicitFlow()
.DisableTokenRevocation()
.UseReferenceTokens();
var builder = new ApplicationBuilder(services.BuildServiceProvider());
// Act and assert
var exception = Assert.Throws<InvalidOperationException>(() => builder.UseOpenIddict());
Assert.Equal("Reference tokens cannot be used when disabling token revocation.", exception.Message);
}
[Fact]
public void UseOpenIddict_ThrowsAnExceptionWhenUsingReferenceTokensIfAnAccessTokenHandlerIsSet()
{
// Arrange
var services = new ServiceCollection();
services.AddDataProtection();
services.AddOpenIddict()
.EnableAuthorizationEndpoint("/connect/authorize")
.AllowImplicitFlow()
.UseReferenceTokens()
.UseJsonWebTokens();
var builder = new ApplicationBuilder(services.BuildServiceProvider());
// Act and assert
var exception = Assert.Throws<InvalidOperationException>(() => builder.UseOpenIddict());
Assert.Equal("Reference tokens cannot be used when configuring JWT as the access token format.", exception.Message);
}
[Fact]
public void UseOpenIddict_ThrowsAnExceptionWhenUsingSlidingExpirationWithoutRollingTokensAndWithTokenRevocationDisabled()
{
// Arrange
var services = new ServiceCollection();
services.AddDataProtection();
services.AddOpenIddict()
.EnableAuthorizationEndpoint("/connect/authorize")
.AllowImplicitFlow()
.DisableTokenRevocation();
var builder = new ApplicationBuilder(services.BuildServiceProvider());
// Act and assert
var exception = Assert.Throws<InvalidOperationException>(() => builder.UseOpenIddict());
Assert.Equal("Sliding expiration must be disabled when turning off " +
"token revocation if rolling tokens are not used.", exception.Message);
}
[Fact]
public void UseOpenIddict_ThrowsAnExceptionWhenNoSigningKeyIsRegisteredIfTheImplicitFlowIsEnabled()
{
// Arrange
var services = new ServiceCollection();
services.AddOpenIddict()
.EnableAuthorizationEndpoint("/connect/authorize")
.AllowImplicitFlow();
var builder = new ApplicationBuilder(services.BuildServiceProvider());
// Act and assert
var exception = Assert.Throws<InvalidOperationException>(() => builder.UseOpenIddict());
Assert.Equal("At least one asymmetric signing key must be registered when enabling the implicit flow. " +
"Consider registering a X.509 certificate using 'services.AddOpenIddict().AddSigningCertificate()' " +
"or call 'services.AddOpenIddict().AddEphemeralSigningKey()' to use an ephemeral key.", exception.Message);
}
[Fact]
public void Configure_OptionsAreCorrectlyAmended()
{
@ -215,37 +35,12 @@ namespace OpenIddict.Tests
builder.Configure(configuration => configuration.Description.DisplayName = "OpenIddict");
var provider = services.BuildServiceProvider();
var options = provider.GetRequiredService<IOptions<OpenIddictOptions>>();
var options = provider.GetRequiredService<IOptions<OpenIddictServerOptions>>();
// Assert
Assert.Equal("OpenIddict", options.Value.Description.DisplayName);
}
[Fact]
public void UseOpenIddict_OpenIdConnectServerMiddlewareIsRegistered()
{
// Arrange
var services = new ServiceCollection();
services.AddOpenIddict()
.AddSigningCertificate(
assembly: typeof(OpenIddictProviderTests).GetTypeInfo().Assembly,
resource: "OpenIddict.Server.Tests.Certificate.pfx",
password: "OpenIddict")
.AllowImplicitFlow()
.EnableAuthorizationEndpoint("/connect/authorize");
var builder = new Mock<IApplicationBuilder>();
builder.SetupGet(mock => mock.ApplicationServices)
.Returns(services.BuildServiceProvider());
// Act
builder.Object.UseOpenIddict();
// Assert
builder.Verify(mock => mock.Use(It.IsAny<Func<RequestDelegate, RequestDelegate>>()), Times.Once());
}
[Fact]
public void AddEphemeralSigningKey_SigningKeyIsCorrectlyAdded()
{
@ -259,7 +54,7 @@ namespace OpenIddict.Tests
builder.AddEphemeralSigningKey();
var provider = services.BuildServiceProvider();
var options = provider.GetRequiredService<IOptions<OpenIddictOptions>>();
var options = provider.GetRequiredService<IOptions<OpenIddictServerOptions>>();
// Assert
Assert.Equal(1, options.Value.SigningCredentials.Count);
@ -286,7 +81,7 @@ namespace OpenIddict.Tests
builder.AddEphemeralSigningKey(algorithm);
var provider = services.BuildServiceProvider();
var options = provider.GetRequiredService<IOptions<OpenIddictOptions>>();
var options = provider.GetRequiredService<IOptions<OpenIddictServerOptions>>();
var credentials = options.Value.SigningCredentials[0];
// Assert
@ -318,7 +113,7 @@ namespace OpenIddict.Tests
builder.AddSigningKey(key);
var provider = services.BuildServiceProvider();
var options = provider.GetRequiredService<IOptions<OpenIddictOptions>>();
var options = provider.GetRequiredService<IOptions<OpenIddictServerOptions>>();
// Assert
Assert.Same(key, options.Value.SigningCredentials[0].Key);
@ -335,12 +130,12 @@ namespace OpenIddict.Tests
// Act
builder.AddSigningCertificate(
assembly: typeof(OpenIddictExtensionsTests).GetTypeInfo().Assembly,
assembly: typeof(OpenIddictServerBuilderTests).GetTypeInfo().Assembly,
resource: "OpenIddict.Server.Tests.Certificate.pfx",
password: "OpenIddict");
var provider = services.BuildServiceProvider();
var options = provider.GetRequiredService<IOptions<OpenIddictOptions>>();
var options = provider.GetRequiredService<IOptions<OpenIddictServerOptions>>();
// Assert
Assert.IsType(typeof(X509SecurityKey), options.Value.SigningCredentials[0].Key);
@ -359,7 +154,7 @@ namespace OpenIddict.Tests
builder.AllowAuthorizationCodeFlow();
var provider = services.BuildServiceProvider();
var options = provider.GetRequiredService<IOptions<OpenIddictOptions>>();
var options = provider.GetRequiredService<IOptions<OpenIddictServerOptions>>();
// Assert
Assert.Contains(OpenIdConnectConstants.GrantTypes.AuthorizationCode, options.Value.GrantTypes);
@ -378,7 +173,7 @@ namespace OpenIddict.Tests
builder.AllowClientCredentialsFlow();
var provider = services.BuildServiceProvider();
var options = provider.GetRequiredService<IOptions<OpenIddictOptions>>();
var options = provider.GetRequiredService<IOptions<OpenIddictServerOptions>>();
// Assert
Assert.Contains(OpenIdConnectConstants.GrantTypes.ClientCredentials, options.Value.GrantTypes);
@ -397,7 +192,7 @@ namespace OpenIddict.Tests
builder.AllowCustomFlow("urn:ietf:params:oauth:grant-type:custom_grant");
var provider = services.BuildServiceProvider();
var options = provider.GetRequiredService<IOptions<OpenIddictOptions>>();
var options = provider.GetRequiredService<IOptions<OpenIddictServerOptions>>();
// Assert
Assert.Contains("urn:ietf:params:oauth:grant-type:custom_grant", options.Value.GrantTypes);
@ -416,7 +211,7 @@ namespace OpenIddict.Tests
builder.AllowImplicitFlow();
var provider = services.BuildServiceProvider();
var options = provider.GetRequiredService<IOptions<OpenIddictOptions>>();
var options = provider.GetRequiredService<IOptions<OpenIddictServerOptions>>();
// Assert
Assert.Contains(OpenIdConnectConstants.GrantTypes.Implicit, options.Value.GrantTypes);
@ -435,7 +230,7 @@ namespace OpenIddict.Tests
builder.AllowPasswordFlow();
var provider = services.BuildServiceProvider();
var options = provider.GetRequiredService<IOptions<OpenIddictOptions>>();
var options = provider.GetRequiredService<IOptions<OpenIddictServerOptions>>();
// Assert
Assert.Contains(OpenIdConnectConstants.GrantTypes.Password, options.Value.GrantTypes);
@ -454,7 +249,7 @@ namespace OpenIddict.Tests
builder.AllowRefreshTokenFlow();
var provider = services.BuildServiceProvider();
var options = provider.GetRequiredService<IOptions<OpenIddictOptions>>();
var options = provider.GetRequiredService<IOptions<OpenIddictServerOptions>>();
// Assert
Assert.Contains(OpenIdConnectConstants.GrantTypes.RefreshToken, options.Value.GrantTypes);
@ -473,7 +268,7 @@ namespace OpenIddict.Tests
builder.DisableConfigurationEndpoint();
var provider = services.BuildServiceProvider();
var options = provider.GetRequiredService<IOptions<OpenIddictOptions>>();
var options = provider.GetRequiredService<IOptions<OpenIddictServerOptions>>();
// Assert
Assert.Equal(PathString.Empty, options.Value.ConfigurationEndpointPath);
@ -492,7 +287,7 @@ namespace OpenIddict.Tests
builder.DisableCryptographyEndpoint();
var provider = services.BuildServiceProvider();
var options = provider.GetRequiredService<IOptions<OpenIddictOptions>>();
var options = provider.GetRequiredService<IOptions<OpenIddictServerOptions>>();
// Assert
Assert.Equal(PathString.Empty, options.Value.CryptographyEndpointPath);
@ -511,7 +306,7 @@ namespace OpenIddict.Tests
builder.DisableSlidingExpiration();
var provider = services.BuildServiceProvider();
var options = provider.GetRequiredService<IOptions<OpenIddictOptions>>();
var options = provider.GetRequiredService<IOptions<OpenIddictServerOptions>>();
// Assert
Assert.False(options.Value.UseSlidingExpiration);
@ -530,7 +325,7 @@ namespace OpenIddict.Tests
builder.DisableTokenRevocation();
var provider = services.BuildServiceProvider();
var options = provider.GetRequiredService<IOptions<OpenIddictOptions>>();
var options = provider.GetRequiredService<IOptions<OpenIddictServerOptions>>();
// Assert
Assert.True(options.Value.DisableTokenRevocation);
@ -549,7 +344,7 @@ namespace OpenIddict.Tests
builder.EnableAuthorizationEndpoint("/endpoint-path");
var provider = services.BuildServiceProvider();
var options = provider.GetRequiredService<IOptions<OpenIddictOptions>>();
var options = provider.GetRequiredService<IOptions<OpenIddictServerOptions>>();
// Assert
Assert.Equal("/endpoint-path", options.Value.AuthorizationEndpointPath);
@ -568,7 +363,7 @@ namespace OpenIddict.Tests
builder.EnableIntrospectionEndpoint("/endpoint-path");
var provider = services.BuildServiceProvider();
var options = provider.GetRequiredService<IOptions<OpenIddictOptions>>();
var options = provider.GetRequiredService<IOptions<OpenIddictServerOptions>>();
// Assert
Assert.Equal("/endpoint-path", options.Value.IntrospectionEndpointPath);
@ -587,7 +382,7 @@ namespace OpenIddict.Tests
builder.EnableLogoutEndpoint("/endpoint-path");
var provider = services.BuildServiceProvider();
var options = provider.GetRequiredService<IOptions<OpenIddictOptions>>();
var options = provider.GetRequiredService<IOptions<OpenIddictServerOptions>>();
// Assert
Assert.Equal("/endpoint-path", options.Value.LogoutEndpointPath);
@ -606,7 +401,7 @@ namespace OpenIddict.Tests
builder.EnableRequestCaching();
var provider = services.BuildServiceProvider();
var options = provider.GetRequiredService<IOptions<OpenIddictOptions>>();
var options = provider.GetRequiredService<IOptions<OpenIddictServerOptions>>();
// Assert
Assert.True(options.Value.EnableRequestCaching);
@ -625,7 +420,7 @@ namespace OpenIddict.Tests
builder.EnableRevocationEndpoint("/endpoint-path");
var provider = services.BuildServiceProvider();
var options = provider.GetRequiredService<IOptions<OpenIddictOptions>>();
var options = provider.GetRequiredService<IOptions<OpenIddictServerOptions>>();
// Assert
Assert.Equal("/endpoint-path", options.Value.RevocationEndpointPath);
@ -644,7 +439,7 @@ namespace OpenIddict.Tests
builder.EnableScopeValidation();
var provider = services.BuildServiceProvider();
var options = provider.GetRequiredService<IOptions<OpenIddictOptions>>();
var options = provider.GetRequiredService<IOptions<OpenIddictServerOptions>>();
// Assert
Assert.True(options.Value.EnableScopeValidation);
@ -663,7 +458,7 @@ namespace OpenIddict.Tests
builder.EnableTokenEndpoint("/endpoint-path");
var provider = services.BuildServiceProvider();
var options = provider.GetRequiredService<IOptions<OpenIddictOptions>>();
var options = provider.GetRequiredService<IOptions<OpenIddictServerOptions>>();
// Assert
Assert.Equal("/endpoint-path", options.Value.TokenEndpointPath);
@ -682,7 +477,7 @@ namespace OpenIddict.Tests
builder.EnableUserinfoEndpoint("/endpoint-path");
var provider = services.BuildServiceProvider();
var options = provider.GetRequiredService<IOptions<OpenIddictOptions>>();
var options = provider.GetRequiredService<IOptions<OpenIddictServerOptions>>();
// Assert
Assert.Equal("/endpoint-path", options.Value.UserinfoEndpointPath);
@ -701,7 +496,7 @@ namespace OpenIddict.Tests
builder.RequireClientIdentification();
var provider = services.BuildServiceProvider();
var options = provider.GetRequiredService<IOptions<OpenIddictOptions>>();
var options = provider.GetRequiredService<IOptions<OpenIddictServerOptions>>();
// Assert
Assert.True(options.Value.RequireClientIdentification);
@ -720,7 +515,7 @@ namespace OpenIddict.Tests
builder.SetAccessTokenLifetime(TimeSpan.FromMinutes(42));
var provider = services.BuildServiceProvider();
var options = provider.GetRequiredService<IOptions<OpenIddictOptions>>();
var options = provider.GetRequiredService<IOptions<OpenIddictServerOptions>>();
// Assert
Assert.Equal(TimeSpan.FromMinutes(42), options.Value.AccessTokenLifetime);
@ -739,7 +534,7 @@ namespace OpenIddict.Tests
builder.SetAuthorizationCodeLifetime(TimeSpan.FromMinutes(42));
var provider = services.BuildServiceProvider();
var options = provider.GetRequiredService<IOptions<OpenIddictOptions>>();
var options = provider.GetRequiredService<IOptions<OpenIddictServerOptions>>();
// Assert
Assert.Equal(TimeSpan.FromMinutes(42), options.Value.AuthorizationCodeLifetime);
@ -758,7 +553,7 @@ namespace OpenIddict.Tests
builder.SetIdentityTokenLifetime(TimeSpan.FromMinutes(42));
var provider = services.BuildServiceProvider();
var options = provider.GetRequiredService<IOptions<OpenIddictOptions>>();
var options = provider.GetRequiredService<IOptions<OpenIddictServerOptions>>();
// Assert
Assert.Equal(TimeSpan.FromMinutes(42), options.Value.IdentityTokenLifetime);
@ -777,7 +572,7 @@ namespace OpenIddict.Tests
builder.SetRefreshTokenLifetime(TimeSpan.FromMinutes(42));
var provider = services.BuildServiceProvider();
var options = provider.GetRequiredService<IOptions<OpenIddictOptions>>();
var options = provider.GetRequiredService<IOptions<OpenIddictServerOptions>>();
// Assert
Assert.Equal(TimeSpan.FromMinutes(42), options.Value.RefreshTokenLifetime);
@ -796,7 +591,7 @@ namespace OpenIddict.Tests
builder.SetIssuer(new Uri("http://www.fabrikam.com/"));
var provider = services.BuildServiceProvider();
var options = provider.GetRequiredService<IOptions<OpenIddictOptions>>();
var options = provider.GetRequiredService<IOptions<OpenIddictServerOptions>>();
// Assert
Assert.Equal(new Uri("http://www.fabrikam.com/"), options.Value.Issuer);
@ -815,7 +610,7 @@ namespace OpenIddict.Tests
builder.RegisterClaims("custom_claim_1", "custom_claim_2");
var provider = services.BuildServiceProvider();
var options = provider.GetRequiredService<IOptions<OpenIddictOptions>>();
var options = provider.GetRequiredService<IOptions<OpenIddictServerOptions>>();
// Assert
Assert.Contains("custom_claim_1", options.Value.Claims);
@ -835,7 +630,7 @@ namespace OpenIddict.Tests
builder.RegisterScopes("custom_scope_1", "custom_scope_2");
var provider = services.BuildServiceProvider();
var options = provider.GetRequiredService<IOptions<OpenIddictOptions>>();
var options = provider.GetRequiredService<IOptions<OpenIddictServerOptions>>();
// Assert
Assert.Contains("custom_scope_1", options.Value.Scopes);
@ -855,7 +650,7 @@ namespace OpenIddict.Tests
builder.UseDataProtectionProvider(new EphemeralDataProtectionProvider());
var provider = services.BuildServiceProvider();
var options = provider.GetRequiredService<IOptions<OpenIddictOptions>>();
var options = provider.GetRequiredService<IOptions<OpenIddictServerOptions>>();
// Assert
Assert.IsType(typeof(EphemeralDataProtectionProvider), options.Value.DataProtectionProvider);
@ -874,7 +669,7 @@ namespace OpenIddict.Tests
builder.UseJsonWebTokens();
var provider = services.BuildServiceProvider();
var options = provider.GetRequiredService<IOptions<OpenIddictOptions>>();
var options = provider.GetRequiredService<IOptions<OpenIddictServerOptions>>();
// Assert
Assert.IsType<JwtSecurityTokenHandler>(options.Value.AccessTokenHandler);
@ -893,19 +688,34 @@ namespace OpenIddict.Tests
builder.UseReferenceTokens();
var provider = services.BuildServiceProvider();
var options = provider.GetRequiredService<IOptions<OpenIddictOptions>>();
var options = provider.GetRequiredService<IOptions<OpenIddictServerOptions>>();
// Assert
Assert.True(options.Value.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()
{
var services = new ServiceCollection();
services.AddAuthentication();
services.AddDistributedMemoryCache();
services.AddLogging();
services.AddSingleton<IHostingEnvironment, HostingEnvironment>();
return services;
}
private static OpenIddictServerOptions GetOptions(IServiceCollection services)
{
var provider = services.BuildServiceProvider();
var options = provider.GetRequiredService<IOptions<OpenIddictServerOptions>>();
return options.Value;
}
}
}

226
test/OpenIddict.Server.Tests/OpenIddictServerExtensionsTests.cs

@ -0,0 +1,226 @@
/*
* 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.Reflection;
using AspNet.Security.OpenIdConnect.Primitives;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Builder.Internal;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Moq;
using Xunit;
namespace OpenIddict.Server.Tests
{
public class OpenIddictServerExtensionsTests
{
[Fact]
public void UseOpenIddictServer_ThrowsAnExceptionWhenNoFlowIsEnabled()
{
// Arrange
var services = new ServiceCollection();
services.AddOpenIddict()
.AddCore(options => options.UseDefaultModels());
var builder = new ApplicationBuilder(services.BuildServiceProvider());
// Act and assert
var exception = Assert.Throws<InvalidOperationException>(() => builder.UseOpenIddictServer());
Assert.Equal("At least one OAuth2/OpenID Connect flow must be enabled.", exception.Message);
}
[Theory]
[InlineData(OpenIdConnectConstants.GrantTypes.AuthorizationCode)]
[InlineData(OpenIdConnectConstants.GrantTypes.Implicit)]
public void UseOpenIddictServer_ThrowsAnExceptionWhenAuthorizationEndpointIsDisabled(string flow)
{
// Arrange
var services = new ServiceCollection();
services.AddOpenIddict()
.AddCore(options => options.UseDefaultModels())
.AddServer()
.Configure(options => options.GrantTypes.Add(flow))
.Configure(options => options.AuthorizationEndpointPath = PathString.Empty);
var builder = new ApplicationBuilder(services.BuildServiceProvider());
// Act and assert
var exception = Assert.Throws<InvalidOperationException>(() => builder.UseOpenIddictServer());
Assert.Equal("The authorization endpoint must be enabled to use " +
"the authorization code and implicit flows.", exception.Message);
}
[Theory]
[InlineData(OpenIdConnectConstants.GrantTypes.AuthorizationCode)]
[InlineData(OpenIdConnectConstants.GrantTypes.ClientCredentials)]
[InlineData(OpenIdConnectConstants.GrantTypes.Password)]
[InlineData(OpenIdConnectConstants.GrantTypes.RefreshToken)]
public void UseOpenIddictServer_ThrowsAnExceptionWhenTokenEndpointIsDisabled(string flow)
{
// Arrange
var services = new ServiceCollection();
services.AddOpenIddict()
.AddCore(options => options.UseDefaultModels())
.AddServer()
.EnableAuthorizationEndpoint("/connect/authorize")
.Configure(options => options.GrantTypes.Add(flow))
.Configure(options => options.TokenEndpointPath = PathString.Empty);
var builder = new ApplicationBuilder(services.BuildServiceProvider());
// Act and assert
var exception = Assert.Throws<InvalidOperationException>(() => builder.UseOpenIddictServer());
Assert.Equal("The token endpoint must be enabled to use the authorization code, " +
"client credentials, password and refresh token flows.", exception.Message);
}
[Fact]
public void UseOpenIddictServer_ThrowsAnExceptionWhenTokenRevocationIsDisabled()
{
// Arrange
var services = new ServiceCollection();
services.AddOpenIddict()
.AddCore(options => options.UseDefaultModels())
.AddServer()
.EnableAuthorizationEndpoint("/connect/authorize")
.EnableRevocationEndpoint("/connect/revocation")
.AllowImplicitFlow()
.DisableTokenRevocation();
var builder = new ApplicationBuilder(services.BuildServiceProvider());
// Act and assert
var exception = Assert.Throws<InvalidOperationException>(() => builder.UseOpenIddictServer());
Assert.Equal("The revocation endpoint cannot be enabled when token revocation is disabled.", exception.Message);
}
[Fact]
public void UseOpenIddictServer_ThrowsAnExceptionWhenUsingReferenceTokensWithTokenRevocationDisabled()
{
// Arrange
var services = new ServiceCollection();
services.AddDataProtection();
services.AddOpenIddict()
.AddCore(options => options.UseDefaultModels())
.AddServer()
.EnableAuthorizationEndpoint("/connect/authorize")
.AllowImplicitFlow()
.DisableTokenRevocation()
.UseReferenceTokens();
var builder = new ApplicationBuilder(services.BuildServiceProvider());
// Act and assert
var exception = Assert.Throws<InvalidOperationException>(() => builder.UseOpenIddictServer());
Assert.Equal("Reference tokens cannot be used when disabling token revocation.", exception.Message);
}
[Fact]
public void UseOpenIddictServer_ThrowsAnExceptionWhenUsingReferenceTokensIfAnAccessTokenHandlerIsSet()
{
// Arrange
var services = new ServiceCollection();
services.AddDataProtection();
services.AddOpenIddict()
.AddCore(options => options.UseDefaultModels())
.AddServer()
.EnableAuthorizationEndpoint("/connect/authorize")
.AllowImplicitFlow()
.UseReferenceTokens()
.UseJsonWebTokens();
var builder = new ApplicationBuilder(services.BuildServiceProvider());
// Act and assert
var exception = Assert.Throws<InvalidOperationException>(() => builder.UseOpenIddictServer());
Assert.Equal("Reference tokens cannot be used when configuring JWT as the access token format.", exception.Message);
}
[Fact]
public void UseOpenIddictServer_ThrowsAnExceptionWhenUsingSlidingExpirationWithoutRollingTokensAndWithTokenRevocationDisabled()
{
// Arrange
var services = new ServiceCollection();
services.AddDataProtection();
services.AddOpenIddict()
.AddCore(options => options.UseDefaultModels())
.AddServer()
.EnableAuthorizationEndpoint("/connect/authorize")
.AllowImplicitFlow()
.DisableTokenRevocation();
var builder = new ApplicationBuilder(services.BuildServiceProvider());
// Act and assert
var exception = Assert.Throws<InvalidOperationException>(() => builder.UseOpenIddictServer());
Assert.Equal("Sliding expiration must be disabled when turning off " +
"token revocation if rolling tokens are not used.", exception.Message);
}
[Fact]
public void UseOpenIddictServer_ThrowsAnExceptionWhenNoSigningKeyIsRegisteredIfTheImplicitFlowIsEnabled()
{
// Arrange
var services = new ServiceCollection();
services.AddOpenIddict()
.AddCore(options => options.UseDefaultModels())
.AddServer()
.EnableAuthorizationEndpoint("/connect/authorize")
.AllowImplicitFlow();
var builder = new ApplicationBuilder(services.BuildServiceProvider());
// Act and assert
var exception = Assert.Throws<InvalidOperationException>(() => builder.UseOpenIddictServer());
Assert.Equal("At least one asymmetric signing key must be registered when enabling the implicit flow. " +
"Consider registering a X.509 certificate using 'services.AddOpenIddict().AddSigningCertificate()' " +
"or call 'services.AddOpenIddict().AddEphemeralSigningKey()' to use an ephemeral key.", exception.Message);
}
[Fact]
public void UseOpenIddictServer_OpenIdConnectServerMiddlewareIsRegistered()
{
// Arrange
var services = new ServiceCollection();
services.AddOpenIddict()
.AddCore(options => options.UseDefaultModels())
.AddServer()
.AddSigningCertificate(
assembly: typeof(OpenIddictServerProviderTests).GetTypeInfo().Assembly,
resource: "OpenIddict.Server.Tests.Certificate.pfx",
password: "OpenIddict")
.AllowImplicitFlow()
.EnableAuthorizationEndpoint("/connect/authorize");
var builder = new Mock<IApplicationBuilder>();
builder.SetupGet(mock => mock.ApplicationServices)
.Returns(services.BuildServiceProvider());
// Act
builder.Object.UseOpenIddictServer();
// Assert
builder.Verify(mock => mock.Use(It.IsAny<Func<RequestDelegate, RequestDelegate>>()), Times.Once());
}
}
}

36
test/OpenIddict.Tests/OpenIddictExtensionsTests.cs

@ -7,6 +7,7 @@
using System;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using OpenIddict.Core;
using OpenIddict.Models;
using Xunit;
@ -15,38 +16,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