@foreach (var provider in Model.OtherLogins)
{
-
+
}
diff --git a/src/OpenIddict.Core/OpenIddict.Core.csproj b/src/OpenIddict.Core/OpenIddict.Core.csproj
index 41e36a8b..2446f756 100644
--- a/src/OpenIddict.Core/OpenIddict.Core.csproj
+++ b/src/OpenIddict.Core/OpenIddict.Core.csproj
@@ -3,7 +3,7 @@
- net451;netstandard1.3
+ netstandard2.0
@@ -25,9 +25,4 @@
-
-
-
-
-
diff --git a/src/OpenIddict.Core/OpenIddictExtensions.cs b/src/OpenIddict.Core/OpenIddictExtensions.cs
index 3ed52d03..d0e2a93c 100644
--- a/src/OpenIddict.Core/OpenIddictExtensions.cs
+++ b/src/OpenIddict.Core/OpenIddictExtensions.cs
@@ -66,22 +66,19 @@ namespace Microsoft.Extensions.DependencyInjection
services.AddOptions();
- var builder = new OpenIddictBuilder(services)
+ // Register the OpenIddict core services in the DI container.
+ services.TryAddScoped>();
+ services.TryAddScoped>();
+ services.TryAddScoped>();
+ services.TryAddScoped>();
+
+ return 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>();
- builder.Services.TryAddScoped>();
- builder.Services.TryAddScoped>();
- builder.Services.TryAddScoped>();
-
- return builder;
}
///
diff --git a/src/OpenIddict.EntityFrameworkCore/OpenIddict.EntityFrameworkCore.csproj b/src/OpenIddict.EntityFrameworkCore/OpenIddict.EntityFrameworkCore.csproj
index 15217e43..3a7c4e6e 100644
--- a/src/OpenIddict.EntityFrameworkCore/OpenIddict.EntityFrameworkCore.csproj
+++ b/src/OpenIddict.EntityFrameworkCore/OpenIddict.EntityFrameworkCore.csproj
@@ -3,7 +3,7 @@
- net451;netstandard1.3
+ netstandard2.0
@@ -21,8 +21,4 @@
-
-
-
-
diff --git a/src/OpenIddict.EntityFrameworkCore/OpenIddictCustomizer.cs b/src/OpenIddict.EntityFrameworkCore/OpenIddictCustomizer.cs
index 861c845e..87c418d2 100644
--- a/src/OpenIddict.EntityFrameworkCore/OpenIddictCustomizer.cs
+++ b/src/OpenIddict.EntityFrameworkCore/OpenIddictCustomizer.cs
@@ -24,6 +24,11 @@ namespace OpenIddict.EntityFrameworkCore
where TToken : OpenIddictToken, new()
where TKey : IEquatable
{
+ public OpenIddictCustomizer([NotNull] ModelCustomizerDependencies dependencies)
+ : base(dependencies)
+ {
+ }
+
public override void Customize([NotNull] ModelBuilder builder, [NotNull] DbContext context)
{
if (builder == null)
diff --git a/src/OpenIddict.EntityFrameworkCore/OpenIddictExtension.cs b/src/OpenIddict.EntityFrameworkCore/OpenIddictExtension.cs
index ad20237b..93aa71d7 100644
--- a/src/OpenIddict.EntityFrameworkCore/OpenIddictExtension.cs
+++ b/src/OpenIddict.EntityFrameworkCore/OpenIddictExtension.cs
@@ -19,7 +19,9 @@ namespace OpenIddict.EntityFrameworkCore
where TToken : OpenIddictToken, new()
where TKey : IEquatable
{
- public void ApplyServices([NotNull] IServiceCollection services)
+ public string LogFragment => null;
+
+ public bool ApplyServices([NotNull] IServiceCollection services)
{
if (services == null)
{
@@ -27,6 +29,14 @@ namespace OpenIddict.EntityFrameworkCore
}
services.AddSingleton>();
+
+ // Return false to indicate that no database
+ // provider was registered by this extension.
+ return false;
}
+
+ public long GetServiceProviderHashCode() => 0;
+
+ public void Validate([NotNull] IDbContextOptions options) { }
}
}
diff --git a/src/OpenIddict.Mvc/OpenIddict.Mvc.csproj b/src/OpenIddict.Mvc/OpenIddict.Mvc.csproj
index 7a350f53..883679fb 100644
--- a/src/OpenIddict.Mvc/OpenIddict.Mvc.csproj
+++ b/src/OpenIddict.Mvc/OpenIddict.Mvc.csproj
@@ -3,7 +3,7 @@
- net451;netstandard1.6
+ netstandard2.0
diff --git a/src/OpenIddict/OpenIddict.csproj b/src/OpenIddict/OpenIddict.csproj
index 49e0c916..e1f26ed7 100644
--- a/src/OpenIddict/OpenIddict.csproj
+++ b/src/OpenIddict/OpenIddict.csproj
@@ -3,7 +3,7 @@
- net451;netstandard1.4
+ netstandard2.0
@@ -21,6 +21,7 @@
+
diff --git a/src/OpenIddict/OpenIddictExtensions.cs b/src/OpenIddict/OpenIddictExtensions.cs
index 6ce4490f..a4970cd0 100644
--- a/src/OpenIddict/OpenIddictExtensions.cs
+++ b/src/OpenIddict/OpenIddictExtensions.cs
@@ -8,16 +8,16 @@ using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.IO;
-using System.Linq;
using System.Reflection;
using System.Security.Cryptography.X509Certificates;
using AspNet.Security.OpenIdConnect.Primitives;
using AspNet.Security.OpenIdConnect.Server;
using JetBrains.Annotations;
+using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Http;
-using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using OpenIddict;
@@ -26,98 +26,6 @@ namespace Microsoft.AspNetCore.Builder
{
public static class OpenIddictExtensions
{
- ///
- /// Registers OpenIddict in the ASP.NET Core pipeline.
- ///
- /// The application builder used to register middleware instances.
- /// The .
- public static IApplicationBuilder UseOpenIddict([NotNull] this IApplicationBuilder app)
- {
- if (app == null)
- {
- throw new ArgumentNullException(nameof(app));
- }
-
- // Resolve the OpenIddict builder from the DI container.
- // If it cannot be found, throw an invalid operation exception.
- var builder = app.ApplicationServices.GetService();
- if (builder == null)
- {
- throw new InvalidOperationException("The OpenIddict services cannot be resolved from the dependency injection container. " +
- "Make sure 'services.AddOpenIddict()' is correctly called from 'ConfigureServices()'.");
- }
-
- // Resolve the OpenIddict options from the DI container.
- var options = app.ApplicationServices.GetRequiredService>().Value;
-
- // 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(OpenIddictProvider<,,,>).MakeGenericType(
- /* TApplication: */ builder.ApplicationType,
- /* TAuthorization: */ builder.AuthorizationType,
- /* TScope: */ builder.ScopeType,
- /* TToken: */ builder.TokenType));
- }
-
- // When no distributed cache has been registered in the options,
- // try to resolve it from the dependency injection container.
- if (options.Cache == null)
- {
- options.Cache = app.ApplicationServices.GetService();
-
- if (options.EnableRequestCaching && options.Cache == null)
- {
- throw new InvalidOperationException("A distributed cache implementation must be registered in the OpenIddict options " +
- "or in the dependency injection container when enabling request caching support.");
- }
- }
-
- // 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.");
- }
-
- // 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.");
- }
-
- return app.UseOpenIdConnectServer(options);
- }
-
///
/// Amends the default OpenIddict configuration.
///
@@ -139,7 +47,44 @@ namespace Microsoft.AspNetCore.Builder
throw new ArgumentNullException(nameof(configuration));
}
- builder.Services.Configure(configuration);
+ // Register the OpenIddict handler/provider.
+ builder.Services.TryAddScoped();
+ builder.Services.TryAddScoped(
+ typeof(OpenIdConnectServerProvider),
+ typeof(OpenIddictProvider<,,,>).MakeGenericType(
+ /* TApplication: */ builder.ApplicationType,
+ /* TAuthorization: */ builder.AuthorizationType,
+ /* TScope: */ builder.ScopeType,
+ /* TToken: */ builder.TokenType));
+
+ // Register the options initializers used by the OpenID Connect server handler and OpenIddict.
+ // Note: TryAddEnumerable() is used here to ensure the initializers are only registered once.
+ builder.Services.TryAddEnumerable(
+ ServiceDescriptor.Singleton,
+ OpenIdConnectServerInitializer>());
+
+ builder.Services.TryAddEnumerable(
+ ServiceDescriptor.Singleton,
+ OpenIddictInitializer>());
+
+ // Register the OpenID Connect server handler in the authentication options,
+ // so it can be discovered by the default authentication handler provider.
+ builder.Services.Configure(options =>
+ {
+ // Note: similarly to Identity, OpenIddict should be registered only once.
+ // To prevent multiple schemes from being registered, a check is made here.
+ if (options.SchemeMap.ContainsKey(OpenIdConnectServerDefaults.AuthenticationScheme))
+ {
+ return;
+ }
+
+ options.AddScheme(OpenIdConnectServerDefaults.AuthenticationScheme, scheme =>
+ {
+ scheme.HandlerType = typeof(OpenIddictHandler);
+ });
+ });
+
+ builder.Services.Configure(OpenIdConnectServerDefaults.AuthenticationScheme, configuration);
return builder;
}
diff --git a/src/OpenIddict/OpenIddictHandler.cs b/src/OpenIddict/OpenIddictHandler.cs
new file mode 100644
index 00000000..69157b74
--- /dev/null
+++ b/src/OpenIddict/OpenIddictHandler.cs
@@ -0,0 +1,23 @@
+using System.ComponentModel;
+using System.Text.Encodings.Web;
+using AspNet.Security.OpenIdConnect.Server;
+using JetBrains.Annotations;
+using Microsoft.AspNetCore.Authentication;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Options;
+
+namespace OpenIddict
+{
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public class OpenIddictHandler : OpenIdConnectServerHandler
+ {
+ public OpenIddictHandler(
+ [NotNull] IOptionsMonitor options,
+ [NotNull] ILoggerFactory logger,
+ [NotNull] UrlEncoder encoder,
+ [NotNull] ISystemClock clock)
+ : base(options, logger, encoder, clock)
+ {
+ }
+ }
+}
diff --git a/src/OpenIddict/OpenIddictInitializer.cs b/src/OpenIddict/OpenIddictInitializer.cs
new file mode 100644
index 00000000..3a713893
--- /dev/null
+++ b/src/OpenIddict/OpenIddictInitializer.cs
@@ -0,0 +1,101 @@
+/*
+ * 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.Linq;
+using AspNet.Security.OpenIdConnect.Primitives;
+using JetBrains.Annotations;
+using Microsoft.Extensions.Caching.Distributed;
+using Microsoft.Extensions.Options;
+using Microsoft.IdentityModel.Tokens;
+
+namespace OpenIddict
+{
+ ///
+ /// Contains the methods required to ensure that the configuration
+ /// used by OpenIddict is in a consistent and valid state.
+ ///
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public class OpenIddictInitializer : IPostConfigureOptions
+ {
+ private readonly IDistributedCache _cache;
+
+ ///
+ /// Creates a new instance of the class.
+ ///
+ public OpenIddictInitializer([NotNull] IDistributedCache cache)
+ {
+ _cache = cache;
+ }
+
+ ///
+ /// Populates the default OpenID Connect server options and ensure
+ /// that the configuration is in a consistent and valid state.
+ ///
+ /// The authentication scheme associated with the handler instance.
+ /// The options instance to initialize.
+ public void PostConfigure([NotNull] string name, [NotNull] OpenIddictOptions options)
+ {
+ if (options == null)
+ {
+ throw new ArgumentNullException(nameof(options));
+ }
+
+ if (string.IsNullOrEmpty(name))
+ {
+ throw new ArgumentException("The options instance name cannot be null or empty.", nameof(name));
+ }
+
+ // When no distributed cache has been registered in the options,
+ // try to resolve it from the dependency injection container.
+ if (options.Cache == null)
+ {
+ options.Cache = _cache;
+ }
+
+ // 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.");
+ }
+
+ // 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.");
+ }
+ }
+ }
+}
diff --git a/src/OpenIddict/OpenIddictOptions.cs b/src/OpenIddict/OpenIddictOptions.cs
index 0960ae63..61aa03e2 100644
--- a/src/OpenIddict/OpenIddictOptions.cs
+++ b/src/OpenIddict/OpenIddictOptions.cs
@@ -16,9 +16,15 @@ namespace OpenIddict
///
public class OpenIddictOptions : OpenIdConnectServerOptions
{
+ ///
+ /// Creates a new instance of the class.
+ ///
public OpenIddictOptions()
{
+ // Note: OpenIdConnectServerProvider is automatically mapped
+ // to the generic OpenIddictProvider class by the DI container.
Provider = null;
+ ProviderType = typeof(OpenIdConnectServerProvider);
}
///
diff --git a/src/OpenIddict/OpenIddictProvider.Authentication.cs b/src/OpenIddict/OpenIddictProvider.Authentication.cs
index 66623dc1..f2dfc781 100644
--- a/src/OpenIddict/OpenIddictProvider.Authentication.cs
+++ b/src/OpenIddict/OpenIddictProvider.Authentication.cs
@@ -14,9 +14,7 @@ using JetBrains.Annotations;
using Microsoft.AspNetCore.Diagnostics;
using Microsoft.AspNetCore.WebUtilities;
using Microsoft.Extensions.Caching.Distributed;
-using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
-using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using Newtonsoft.Json.Bson;
using Newtonsoft.Json.Linq;
@@ -29,13 +27,12 @@ namespace OpenIddict
{
public override async Task ExtractAuthorizationRequest([NotNull] ExtractAuthorizationRequestContext context)
{
- var logger = context.HttpContext.RequestServices.GetRequiredService>>();
- var options = context.HttpContext.RequestServices.GetRequiredService>();
+ var options = (OpenIddictOptions) context.Options;
// Reject requests using the unsupported request parameter.
if (!string.IsNullOrEmpty(context.Request.Request))
{
- logger.LogError("The authorization request was rejected because it contained " +
+ Logger.LogError("The authorization request was rejected because it contained " +
"an unsupported parameter: {Parameter}.", "request");
context.Reject(
@@ -48,7 +45,7 @@ namespace OpenIddict
// Reject requests using the unsupported request_uri parameter.
if (!string.IsNullOrEmpty(context.Request.RequestUri))
{
- logger.LogError("The authorization request was rejected because it contained " +
+ Logger.LogError("The authorization request was rejected because it contained " +
"an unsupported parameter: {Parameter}.", "request_uri");
context.Reject(
@@ -63,9 +60,9 @@ namespace OpenIddict
if (!string.IsNullOrEmpty(context.Request.RequestId))
{
// Return an error if request caching support was not enabled.
- if (!options.Value.EnableRequestCaching)
+ if (!options.EnableRequestCaching)
{
- logger.LogError("The authorization request was rejected because " +
+ Logger.LogError("The authorization request was rejected because " +
"request caching support was not enabled.");
context.Reject(
@@ -79,10 +76,10 @@ namespace OpenIddict
// to avoid collisions with the other types of cached requests.
var key = OpenIddictConstants.Environment.AuthorizationRequest + context.Request.RequestId;
- var payload = await options.Value.Cache.GetAsync(key);
+ var payload = await options.Cache.GetAsync(key);
if (payload == null)
{
- logger.LogError("The authorization request was rejected because an unknown " +
+ Logger.LogError("The authorization request was rejected because an unknown " +
"or invalid request_id parameter was specified.");
context.Reject(
@@ -93,7 +90,7 @@ namespace OpenIddict
}
// Restore the authorization request parameters from the serialized payload.
- using (var reader = new BsonReader(new MemoryStream(payload)))
+ using (var reader = new BsonDataReader(new MemoryStream(payload)))
{
foreach (var parameter in JObject.Load(reader))
{
@@ -111,16 +108,14 @@ namespace OpenIddict
public override async Task ValidateAuthorizationRequest([NotNull] ValidateAuthorizationRequestContext context)
{
- var applications = context.HttpContext.RequestServices.GetRequiredService>();
- var logger = context.HttpContext.RequestServices.GetRequiredService>>();
- var options = context.HttpContext.RequestServices.GetRequiredService>();
+ var options = (OpenIddictOptions) context.Options;
// Note: the OpenID Connect server middleware supports authorization code, implicit, hybrid,
// none and custom flows but OpenIddict uses a stricter policy rejecting unknown flows.
if (!context.Request.IsAuthorizationCodeFlow() && !context.Request.IsHybridFlow() &&
!context.Request.IsImplicitFlow() && !context.Request.IsNoneFlow())
{
- logger.LogError("The authorization request was rejected because the '{ResponseType}' " +
+ Logger.LogError("The authorization request was rejected because the '{ResponseType}' " +
"response type is not supported.", context.Request.ResponseType);
context.Reject(
@@ -132,9 +127,9 @@ namespace OpenIddict
// Reject code flow authorization requests if the authorization code flow is not enabled.
if (context.Request.IsAuthorizationCodeFlow() &&
- !options.Value.GrantTypes.Contains(OpenIdConnectConstants.GrantTypes.AuthorizationCode))
+ !options.GrantTypes.Contains(OpenIdConnectConstants.GrantTypes.AuthorizationCode))
{
- logger.LogError("The authorization request was rejected because " +
+ Logger.LogError("The authorization request was rejected because " +
"the authorization code flow was not enabled.");
context.Reject(
@@ -145,9 +140,9 @@ namespace OpenIddict
}
// Reject implicit flow authorization requests if the implicit flow is not enabled.
- if (context.Request.IsImplicitFlow() && !options.Value.GrantTypes.Contains(OpenIdConnectConstants.GrantTypes.Implicit))
+ if (context.Request.IsImplicitFlow() && !options.GrantTypes.Contains(OpenIdConnectConstants.GrantTypes.Implicit))
{
- logger.LogError("The authorization request was rejected because the implicit flow was not enabled.");
+ Logger.LogError("The authorization request was rejected because the implicit flow was not enabled.");
context.Reject(
error: OpenIdConnectConstants.Errors.UnsupportedResponseType,
@@ -157,10 +152,10 @@ namespace OpenIddict
}
// Reject hybrid flow authorization requests if the authorization code or the implicit flows are not enabled.
- if (context.Request.IsHybridFlow() && (!options.Value.GrantTypes.Contains(OpenIdConnectConstants.GrantTypes.AuthorizationCode) ||
- !options.Value.GrantTypes.Contains(OpenIdConnectConstants.GrantTypes.Implicit)))
+ if (context.Request.IsHybridFlow() && (!options.GrantTypes.Contains(OpenIdConnectConstants.GrantTypes.AuthorizationCode) ||
+ !options.GrantTypes.Contains(OpenIdConnectConstants.GrantTypes.Implicit)))
{
- logger.LogError("The authorization request was rejected because the " +
+ Logger.LogError("The authorization request was rejected because the " +
"authorization code flow or the implicit flow was not enabled.");
context.Reject(
@@ -172,7 +167,7 @@ namespace OpenIddict
// Reject authorization requests that specify scope=offline_access if the refresh token flow is not enabled.
if (context.Request.HasScope(OpenIdConnectConstants.Scopes.OfflineAccess) &&
- !options.Value.GrantTypes.Contains(OpenIdConnectConstants.GrantTypes.RefreshToken))
+ !options.GrantTypes.Contains(OpenIdConnectConstants.GrantTypes.RefreshToken))
{
context.Reject(
error: OpenIdConnectConstants.Errors.InvalidRequest,
@@ -188,7 +183,7 @@ namespace OpenIddict
!context.Request.IsFragmentResponseMode() &&
!context.Request.IsQueryResponseMode())
{
- logger.LogError("The authorization request was rejected because the '{ResponseMode}' " +
+ Logger.LogError("The authorization request was rejected because the '{ResponseMode}' " +
"response mode is not supported.", context.Request.ResponseMode);
context.Reject(
@@ -219,7 +214,7 @@ namespace OpenIddict
// reject the authorization request if the code_challenge_method is missing.
if (string.IsNullOrEmpty(context.Request.CodeChallengeMethod))
{
- logger.LogError("The authorization request was rejected because the " +
+ Logger.LogError("The authorization request was rejected because the " +
"required 'code_challenge_method' parameter was missing.");
context.Reject(
@@ -233,7 +228,7 @@ namespace OpenIddict
// See https://tools.ietf.org/html/rfc7636#section-7.2 for more information.
if (string.Equals(context.Request.CodeChallengeMethod, OpenIdConnectConstants.CodeChallengeMethods.Plain))
{
- logger.LogError("The authorization request was rejected because the " +
+ Logger.LogError("The authorization request was rejected because the " +
"'code_challenge_method' parameter was set to 'plain'.");
context.Reject(
@@ -246,7 +241,7 @@ namespace OpenIddict
// Reject authorization requests that contain response_type=token when a code_challenge is specified.
if (context.Request.HasResponseType(OpenIdConnectConstants.ResponseTypes.Token))
{
- logger.LogError("The authorization request was rejected because the " +
+ Logger.LogError("The authorization request was rejected because the " +
"specified response type was not compatible with PKCE.");
context.Reject(
@@ -258,10 +253,10 @@ namespace OpenIddict
}
// Retrieve the application details corresponding to the requested client_id.
- var application = await applications.FindByClientIdAsync(context.ClientId, context.HttpContext.RequestAborted);
+ var application = await Applications.FindByClientIdAsync(context.ClientId, context.HttpContext.RequestAborted);
if (application == null)
{
- logger.LogError("The authorization request was rejected because the client " +
+ Logger.LogError("The authorization request was rejected because the client " +
"application was not found: '{ClientId}'.", context.ClientId);
context.Reject(
@@ -272,9 +267,9 @@ namespace OpenIddict
}
// Ensure a redirect_uri was associated with the application.
- if (!await applications.HasRedirectUriAsync(application, context.HttpContext.RequestAborted))
+ if (!await Applications.HasRedirectUriAsync(application, context.HttpContext.RequestAborted))
{
- logger.LogError("The authorization request was rejected because no redirect_uri " +
+ Logger.LogError("The authorization request was rejected because no redirect_uri " +
"was registered with the application '{ClientId}'.", context.ClientId);
context.Reject(
@@ -285,9 +280,9 @@ namespace OpenIddict
}
// Ensure the redirect_uri is valid.
- if (!await applications.ValidateRedirectUriAsync(application, context.RedirectUri, context.HttpContext.RequestAborted))
+ if (!await Applications.ValidateRedirectUriAsync(application, context.RedirectUri, context.HttpContext.RequestAborted))
{
- logger.LogError("The authorization request was rejected because the redirect_uri " +
+ Logger.LogError("The authorization request was rejected because the redirect_uri " +
"was invalid: '{RedirectUri}'.", context.RedirectUri);
context.Reject(
@@ -301,7 +296,7 @@ namespace OpenIddict
// from the authorization endpoint are rejected if the client_id corresponds to a confidential application.
// Note: when using the authorization code grant, ValidateTokenRequest is responsible of rejecting
// the token request if the client_id corresponds to an unauthenticated confidential client.
- if (await applications.IsConfidentialAsync(application, context.HttpContext.RequestAborted) &&
+ if (await Applications.IsConfidentialAsync(application, context.HttpContext.RequestAborted) &&
context.Request.HasResponseType(OpenIdConnectConstants.ResponseTypes.Token))
{
context.Reject(
@@ -317,12 +312,12 @@ namespace OpenIddict
public override async Task HandleAuthorizationRequest([NotNull] HandleAuthorizationRequestContext context)
{
- var options = context.HttpContext.RequestServices.GetRequiredService>();
+ var options = (OpenIddictOptions) 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
// to flow across requests and internal/external authentication/registration workflows.
- if (options.Value.EnableRequestCaching && string.IsNullOrEmpty(context.Request.RequestId))
+ if (options.EnableRequestCaching && string.IsNullOrEmpty(context.Request.RequestId))
{
// Generate a request identifier. Note: using a crypto-secure
// random number generator is not necessary in this case.
@@ -330,7 +325,7 @@ namespace OpenIddict
// Store the serialized authorization request parameters in the distributed cache.
var stream = new MemoryStream();
- using (var writer = new BsonWriter(stream))
+ using (var writer = new BsonDataWriter(stream))
{
writer.CloseOutput = false;
@@ -342,7 +337,7 @@ namespace OpenIddict
// to avoid collisions with the other types of cached requests.
var key = OpenIddictConstants.Environment.AuthorizationRequest + context.Request.RequestId;
- await options.Value.Cache.SetAsync(key, stream.ToArray(), new DistributedCacheEntryOptions
+ await options.Cache.SetAsync(key, stream.ToArray(), new DistributedCacheEntryOptions
{
AbsoluteExpiration = context.Options.SystemClock.UtcNow + TimeSpan.FromMinutes(30),
SlidingExpiration = TimeSpan.FromMinutes(10)
@@ -363,15 +358,15 @@ namespace OpenIddict
return;
}
- context.SkipToNextMiddleware();
+ context.SkipHandler();
}
public override async Task ApplyAuthorizationResponse([NotNull] ApplyAuthorizationResponseContext context)
{
- var options = context.HttpContext.RequestServices.GetRequiredService>();
+ var options = (OpenIddictOptions) context.Options;
// Remove the authorization request from the distributed cache.
- if (options.Value.EnableRequestCaching && !string.IsNullOrEmpty(context.Request.RequestId))
+ if (options.EnableRequestCaching && !string.IsNullOrEmpty(context.Request.RequestId))
{
// Note: the cache key is always prefixed with a specific marker
// to avoid collisions with the other types of cached requests.
@@ -380,11 +375,11 @@ namespace OpenIddict
// Note: the ApplyAuthorizationResponse event is called for both successful
// and errored authorization responses but discrimination is not necessary here,
// as the authorization request must be removed from the distributed cache in both cases.
- await options.Value.Cache.RemoveAsync(key);
+ await options.Cache.RemoveAsync(key);
}
- if (!options.Value.ApplicationCanDisplayErrors && !string.IsNullOrEmpty(context.Error) &&
- string.IsNullOrEmpty(context.RedirectUri))
+ if (!options.ApplicationCanDisplayErrors && !string.IsNullOrEmpty(context.Error) &&
+ string.IsNullOrEmpty(context.RedirectUri))
{
// Determine if the status code pages middleware has been enabled for this request.
// If it was not registered or enabled, let the OpenID Connect server middleware render
diff --git a/src/OpenIddict/OpenIddictProvider.Discovery.cs b/src/OpenIddict/OpenIddictProvider.Discovery.cs
index 7e04869c..af037899 100644
--- a/src/OpenIddict/OpenIddictProvider.Discovery.cs
+++ b/src/OpenIddict/OpenIddictProvider.Discovery.cs
@@ -9,8 +9,8 @@ using System.Threading.Tasks;
using AspNet.Security.OpenIdConnect.Primitives;
using AspNet.Security.OpenIdConnect.Server;
using JetBrains.Annotations;
+using Microsoft.AspNetCore.Authentication;
using Microsoft.Extensions.DependencyInjection;
-using Microsoft.Extensions.Options;
using Newtonsoft.Json.Linq;
using OpenIddict.Core;
@@ -19,9 +19,9 @@ namespace OpenIddict
public partial class OpenIddictProvider : OpenIdConnectServerProvider
where TApplication : class where TAuthorization : class where TScope : class where TToken : class
{
- public override Task HandleConfigurationRequest([NotNull] HandleConfigurationRequestContext context)
+ public override async Task HandleConfigurationRequest([NotNull] HandleConfigurationRequestContext context)
{
- var options = context.HttpContext.RequestServices.GetRequiredService>();
+ var options = (OpenIddictOptions) 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,
@@ -32,7 +32,7 @@ namespace OpenIddict
// Note: the OpenID Connect server middleware automatically populates grant_types_supported
// by determining whether the authorization and token endpoints are enabled or not but
// OpenIddict uses a different approach and relies on a configurable "grants list".
- context.GrantTypes.IntersectWith(options.Value.GrantTypes);
+ context.GrantTypes.IntersectWith(options.GrantTypes);
// Note: the "openid" scope is automatically
// added by the OpenID Connect server middleware.
@@ -47,12 +47,12 @@ namespace OpenIddict
context.Scopes.Add(OpenIdConnectConstants.Scopes.OfflineAccess);
}
+ var schemes = context.HttpContext.RequestServices.GetRequiredService();
+
context.Metadata[OpenIddictConstants.Metadata.ExternalProvidersSupported] = new JArray(
- from provider in context.HttpContext.Authentication.GetAuthenticationSchemes()
+ from provider in await schemes.GetAllSchemesAsync()
where !string.IsNullOrEmpty(provider.DisplayName)
- select provider.AuthenticationScheme);
-
- return Task.FromResult(0);
+ select provider.Name);
}
}
}
\ No newline at end of file
diff --git a/src/OpenIddict/OpenIddictProvider.Exchange.cs b/src/OpenIddict/OpenIddictProvider.Exchange.cs
index ee95f42a..a26d1816 100644
--- a/src/OpenIddict/OpenIddictProvider.Exchange.cs
+++ b/src/OpenIddict/OpenIddictProvider.Exchange.cs
@@ -10,10 +10,7 @@ using AspNet.Security.OpenIdConnect.Extensions;
using AspNet.Security.OpenIdConnect.Primitives;
using AspNet.Security.OpenIdConnect.Server;
using JetBrains.Annotations;
-using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
-using Microsoft.Extensions.Options;
-using OpenIddict.Core;
namespace OpenIddict
{
@@ -22,14 +19,12 @@ namespace OpenIddict
{
public override async Task ValidateTokenRequest([NotNull] ValidateTokenRequestContext context)
{
- var applications = context.HttpContext.RequestServices.GetRequiredService>();
- var logger = context.HttpContext.RequestServices.GetRequiredService>>();
- var options = context.HttpContext.RequestServices.GetRequiredService>();
+ var options = (OpenIddictOptions) context.Options;
// Reject token requests that don't specify a supported grant type.
- if (!options.Value.GrantTypes.Contains(context.Request.GrantType))
+ if (!options.GrantTypes.Contains(context.Request.GrantType))
{
- logger.LogError("The token request was rejected because the '{Grant}' " +
+ Logger.LogError("The token request was rejected because the '{Grant}' " +
"grant is not supported.", context.Request.GrantType);
context.Reject(
@@ -41,7 +36,7 @@ namespace OpenIddict
// Reject token requests that specify scope=offline_access if the refresh token flow is not enabled.
if (context.Request.HasScope(OpenIdConnectConstants.Scopes.OfflineAccess) &&
- !options.Value.GrantTypes.Contains(OpenIdConnectConstants.GrantTypes.RefreshToken))
+ !options.GrantTypes.Contains(OpenIdConnectConstants.GrantTypes.RefreshToken))
{
context.Reject(
error: OpenIdConnectConstants.Errors.InvalidRequest,
@@ -100,7 +95,7 @@ namespace OpenIddict
if (string.IsNullOrEmpty(context.ClientId))
{
// Reject the request if client identification is mandatory.
- if (options.Value.RequireClientIdentification)
+ if (options.RequireClientIdentification)
{
context.Reject(
error: OpenIdConnectConstants.Errors.InvalidRequest,
@@ -109,7 +104,7 @@ namespace OpenIddict
return;
}
- logger.LogDebug("The token request validation process was partially skipped " +
+ Logger.LogDebug("The token request validation process was partially skipped " +
"because the 'client_id' parameter was missing or empty.");
context.Skip();
@@ -118,10 +113,10 @@ namespace OpenIddict
}
// Retrieve the application details corresponding to the requested client_id.
- var application = await applications.FindByClientIdAsync(context.ClientId, context.HttpContext.RequestAborted);
+ var application = await Applications.FindByClientIdAsync(context.ClientId, context.HttpContext.RequestAborted);
if (application == null)
{
- logger.LogError("The token request was rejected because the client " +
+ Logger.LogError("The token request was rejected because the client " +
"application was not found: '{ClientId}'.", context.ClientId);
context.Reject(
@@ -131,12 +126,12 @@ namespace OpenIddict
return;
}
- if (await applications.IsPublicAsync(application, context.HttpContext.RequestAborted))
+ if (await Applications.IsPublicAsync(application, context.HttpContext.RequestAborted))
{
// Note: public applications are not allowed to use the client credentials grant.
if (context.Request.IsClientCredentialsGrantType())
{
- logger.LogError("The token request was rejected because the public client application '{ClientId}' " +
+ Logger.LogError("The token request was rejected because the public client application '{ClientId}' " +
"was not allowed to use the client credentials grant.", context.Request.ClientId);
context.Reject(
@@ -149,7 +144,7 @@ namespace OpenIddict
// Reject tokens requests containing a client_secret when the client is a public application.
if (!string.IsNullOrEmpty(context.ClientSecret))
{
- logger.LogError("The token request was rejected because the public application '{ClientId}' " +
+ Logger.LogError("The token request was rejected because the public application '{ClientId}' " +
"was not allowed to send a client secret.", context.ClientId);
context.Reject(
@@ -159,7 +154,7 @@ namespace OpenIddict
return;
}
- logger.LogInformation("The token request validation process was not fully validated because " +
+ Logger.LogInformation("The token request validation process was not fully validated because " +
"the client '{ClientId}' was a public application.", context.ClientId);
// If client authentication cannot be enforced, call context.Skip() to inform
@@ -173,7 +168,7 @@ namespace OpenIddict
// to protect them from impersonation attacks.
if (string.IsNullOrEmpty(context.ClientSecret))
{
- logger.LogError("The token request was rejected because the confidential application " +
+ Logger.LogError("The token request was rejected because the confidential application " +
"'{ClientId}' didn't specify a client secret.", context.ClientId);
context.Reject(
@@ -183,9 +178,9 @@ namespace OpenIddict
return;
}
- if (!await applications.ValidateClientSecretAsync(application, context.ClientSecret, context.HttpContext.RequestAborted))
+ if (!await Applications.ValidateClientSecretAsync(application, context.ClientSecret, context.HttpContext.RequestAborted))
{
- logger.LogError("The token request was rejected because the confidential application " +
+ Logger.LogError("The token request was rejected because the confidential application " +
"'{ClientId}' didn't specify valid client credentials.", context.ClientId);
context.Reject(
@@ -200,12 +195,10 @@ namespace OpenIddict
public override async Task HandleTokenRequest([NotNull] HandleTokenRequestContext context)
{
- var options = context.HttpContext.RequestServices.GetRequiredService>();
- var logger = context.HttpContext.RequestServices.GetRequiredService>>();
- var tokens = context.HttpContext.RequestServices.GetRequiredService>();
+ var options = (OpenIddictOptions) context.Options;
- if (!options.Value.DisableTokenRevocation && (context.Request.IsAuthorizationCodeGrantType() ||
- context.Request.IsRefreshTokenGrantType()))
+ if (!options.DisableTokenRevocation && (context.Request.IsAuthorizationCodeGrantType() ||
+ context.Request.IsRefreshTokenGrantType()))
{
Debug.Assert(context.Ticket != null, "The authentication ticket shouldn't be null.");
@@ -216,10 +209,10 @@ namespace OpenIddict
if (context.Request.IsAuthorizationCodeGrantType())
{
// Retrieve the token from the database and ensure it is still valid.
- var token = await tokens.FindByIdAsync(identifier, context.HttpContext.RequestAborted);
+ var token = await Tokens.FindByIdAsync(identifier, context.HttpContext.RequestAborted);
if (token == null)
{
- logger.LogError("The token request was rejected because the authorization code was revoked.");
+ Logger.LogError("The token request was rejected because the authorization code was revoked.");
context.Reject(
error: OpenIdConnectConstants.Errors.InvalidGrant,
@@ -229,16 +222,16 @@ namespace OpenIddict
}
// Revoke the authorization code to prevent token reuse.
- await tokens.RevokeAsync(token, context.HttpContext.RequestAborted);
+ await Tokens.RevokeAsync(token, context.HttpContext.RequestAborted);
}
else if (context.Request.IsRefreshTokenGrantType())
{
// Retrieve the token from the database and ensure it is still valid.
- var token = await tokens.FindByIdAsync(identifier, context.HttpContext.RequestAborted);
+ var token = await Tokens.FindByIdAsync(identifier, context.HttpContext.RequestAborted);
if (token == null)
{
- logger.LogError("The token request was rejected because the refresh token was revoked.");
+ Logger.LogError("The token request was rejected because the refresh token was revoked.");
context.Reject(
error: OpenIdConnectConstants.Errors.InvalidGrant,
@@ -252,14 +245,14 @@ namespace OpenIddict
// See https://tools.ietf.org/html/rfc6749#section-6.
if (context.Options.UseSlidingExpiration)
{
- await tokens.RevokeAsync(token, context.HttpContext.RequestAborted);
+ await Tokens.RevokeAsync(token, context.HttpContext.RequestAborted);
}
}
}
// Invoke the rest of the pipeline to allow
// the user code to handle the token request.
- context.SkipToNextMiddleware();
+ context.SkipHandler();
}
}
}
\ No newline at end of file
diff --git a/src/OpenIddict/OpenIddictProvider.Introspection.cs b/src/OpenIddict/OpenIddictProvider.Introspection.cs
index 46472dca..1350f2c4 100644
--- a/src/OpenIddict/OpenIddictProvider.Introspection.cs
+++ b/src/OpenIddict/OpenIddictProvider.Introspection.cs
@@ -11,10 +11,7 @@ using AspNet.Security.OpenIdConnect.Extensions;
using AspNet.Security.OpenIdConnect.Primitives;
using AspNet.Security.OpenIdConnect.Server;
using JetBrains.Annotations;
-using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
-using Microsoft.Extensions.Options;
-using OpenIddict.Core;
namespace OpenIddict
{
@@ -39,9 +36,6 @@ namespace OpenIddict
public override async Task ValidateIntrospectionRequest([NotNull] ValidateIntrospectionRequestContext context)
{
- var applications = context.HttpContext.RequestServices.GetRequiredService>();
- var logger = context.HttpContext.RequestServices.GetRequiredService>>();
-
// Note: the OpenID Connect server middleware supports unauthenticated introspection requests
// but OpenIddict uses a stricter policy preventing unauthenticated/public applications
// from using the introspection endpoint, as required by the specifications.
@@ -56,10 +50,10 @@ namespace OpenIddict
}
// Retrieve the application details corresponding to the requested client_id.
- var application = await applications.FindByClientIdAsync(context.ClientId, context.HttpContext.RequestAborted);
+ var application = await Applications.FindByClientIdAsync(context.ClientId, context.HttpContext.RequestAborted);
if (application == null)
{
- logger.LogError("The introspection request was rejected because the client " +
+ Logger.LogError("The introspection request was rejected because the client " +
"application was not found: '{ClientId}'.", context.ClientId);
context.Reject(
@@ -70,9 +64,9 @@ namespace OpenIddict
}
// Reject non-confidential applications.
- if (!await applications.IsConfidentialAsync(application, context.HttpContext.RequestAborted))
+ if (!await Applications.IsConfidentialAsync(application, context.HttpContext.RequestAborted))
{
- logger.LogError("The introspection request was rejected because the public application " +
+ Logger.LogError("The introspection request was rejected because the public application " +
"'{ClientId}' was not allowed to use this endpoint.", context.ClientId);
context.Reject(
@@ -83,9 +77,9 @@ namespace OpenIddict
}
// Validate the client credentials.
- if (!await applications.ValidateClientSecretAsync(application, context.ClientSecret, context.HttpContext.RequestAborted))
+ if (!await Applications.ValidateClientSecretAsync(application, context.ClientSecret, context.HttpContext.RequestAborted))
{
- logger.LogError("The introspection request was rejected because the confidential application " +
+ Logger.LogError("The introspection request was rejected because the confidential application " +
"'{ClientId}' didn't specify valid client credentials.", context.ClientId);
context.Reject(
@@ -100,9 +94,7 @@ namespace OpenIddict
public override async Task HandleIntrospectionRequest([NotNull] HandleIntrospectionRequestContext context)
{
- var options = context.HttpContext.RequestServices.GetRequiredService>();
- var logger = context.HttpContext.RequestServices.GetRequiredService>>();
- var tokens = context.HttpContext.RequestServices.GetRequiredService>();
+ var options = (OpenIddictOptions) context.Options;
Debug.Assert(context.Ticket != null, "The authentication ticket shouldn't be null.");
Debug.Assert(!string.IsNullOrEmpty(context.Request.ClientId), "The client_id parameter shouldn't be null.");
@@ -115,7 +107,7 @@ namespace OpenIddict
// doesn't have any audience: in this case, the caller is allowed to introspect the token even if it's not listed as a valid audience.
if (context.Ticket.IsAccessToken() && context.Ticket.HasAudience() && !context.Ticket.HasAudience(context.Request.ClientId))
{
- logger.LogWarning("The client application '{ClientId}' is not allowed to introspect the access " +
+ Logger.LogWarning("The client application '{ClientId}' is not allowed to introspect the access " +
"token '{Identifier}' because it's not listed as a valid audience.",
context.Request.ClientId, identifier);
@@ -125,14 +117,14 @@ namespace OpenIddict
}
// When the received ticket is revocable, ensure it is still valid.
- if (!options.Value.DisableTokenRevocation && (context.Ticket.IsAuthorizationCode() || context.Ticket.IsRefreshToken()))
+ if (!options.DisableTokenRevocation && (context.Ticket.IsAuthorizationCode() || context.Ticket.IsRefreshToken()))
{
// Retrieve the token from the database using the unique identifier stored in the authentication ticket:
// if the corresponding entry cannot be found, return Active = false to indicate that is is no longer valid.
- var token = await tokens.FindByIdAsync(identifier, context.HttpContext.RequestAborted);
+ var token = await Tokens.FindByIdAsync(identifier, context.HttpContext.RequestAborted);
if (token == null)
{
- logger.LogInformation("The token {Identifier} was declared as inactive because " +
+ Logger.LogInformation("The token {Identifier} was declared as inactive because " +
"it was revoked.", identifier);
context.Active = false;
diff --git a/src/OpenIddict/OpenIddictProvider.Revocation.cs b/src/OpenIddict/OpenIddictProvider.Revocation.cs
index afb4e3ae..49d0c392 100644
--- a/src/OpenIddict/OpenIddictProvider.Revocation.cs
+++ b/src/OpenIddict/OpenIddictProvider.Revocation.cs
@@ -10,10 +10,7 @@ using AspNet.Security.OpenIdConnect.Extensions;
using AspNet.Security.OpenIdConnect.Primitives;
using AspNet.Security.OpenIdConnect.Server;
using JetBrains.Annotations;
-using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
-using Microsoft.Extensions.Options;
-using OpenIddict.Core;
namespace OpenIddict
{
@@ -22,11 +19,9 @@ namespace OpenIddict
{
public override async Task ValidateRevocationRequest([NotNull] ValidateRevocationRequestContext context)
{
- var applications = context.HttpContext.RequestServices.GetRequiredService>();
- var logger = context.HttpContext.RequestServices.GetRequiredService>>();
- var options = context.HttpContext.RequestServices.GetRequiredService>();
+ var options = (OpenIddictOptions) context.Options;
- Debug.Assert(!options.Value.DisableTokenRevocation, "Token revocation support shouldn't be disabled at this stage.");
+ Debug.Assert(!options.DisableTokenRevocation, "Token revocation support shouldn't be disabled at this stage.");
// When token_type_hint is specified, reject the request if it doesn't correspond to a revocable token.
if (!string.IsNullOrEmpty(context.Request.TokenTypeHint) &&
@@ -49,9 +44,9 @@ namespace OpenIddict
if (string.IsNullOrEmpty(context.ClientId))
{
// Reject the request if client identification is mandatory.
- if (options.Value.RequireClientIdentification)
+ if (options.RequireClientIdentification)
{
- logger.LogError("The revocation request was rejected becaused the " +
+ Logger.LogError("The revocation request was rejected becaused the " +
"mandatory client_id parameter was missing or empty.");
context.Reject(
@@ -61,7 +56,7 @@ namespace OpenIddict
return;
}
- logger.LogInformation("The revocation request validation process was skipped " +
+ Logger.LogInformation("The revocation request validation process was skipped " +
"because the client_id parameter was missing or empty.");
context.Skip();
@@ -70,7 +65,7 @@ namespace OpenIddict
}
// Retrieve the application details corresponding to the requested client_id.
- var application = await applications.FindByClientIdAsync(context.ClientId, context.HttpContext.RequestAborted);
+ var application = await Applications.FindByClientIdAsync(context.ClientId, context.HttpContext.RequestAborted);
if (application == null)
{
context.Reject(
@@ -81,7 +76,7 @@ namespace OpenIddict
}
// Reject revocation requests containing a client_secret if the client application is not confidential.
- if (await applications.IsPublicAsync(application, context.HttpContext.RequestAborted))
+ if (await Applications.IsPublicAsync(application, context.HttpContext.RequestAborted))
{
// Reject tokens requests containing a client_secret when the client is a public application.
if (!string.IsNullOrEmpty(context.ClientSecret))
@@ -93,7 +88,7 @@ namespace OpenIddict
return;
}
- logger.LogInformation("The revocation request validation process was not fully validated because " +
+ Logger.LogInformation("The revocation request validation process was not fully validated because " +
"the client '{ClientId}' was a public application.", context.ClientId);
// If client authentication cannot be enforced, call context.Skip() to inform
@@ -114,7 +109,7 @@ namespace OpenIddict
return;
}
- if (!await applications.ValidateClientSecretAsync(application, context.ClientSecret, context.HttpContext.RequestAborted))
+ if (!await Applications.ValidateClientSecretAsync(application, context.ClientSecret, context.HttpContext.RequestAborted))
{
context.Reject(
error: OpenIdConnectConstants.Errors.InvalidClient,
@@ -128,16 +123,13 @@ namespace OpenIddict
public override async Task HandleRevocationRequest([NotNull] HandleRevocationRequestContext context)
{
- var logger = context.HttpContext.RequestServices.GetRequiredService>>();
- var tokens = context.HttpContext.RequestServices.GetRequiredService>();
-
Debug.Assert(context.Ticket != null, "The authentication ticket shouldn't be null.");
// If the received token is not an authorization code or a refresh token,
// return an error to indicate that the token cannot be revoked.
if (!context.Ticket.IsAuthorizationCode() && !context.Ticket.IsRefreshToken())
{
- logger.LogError("The revocation request was rejected because the token was not revocable.");
+ Logger.LogError("The revocation request was rejected because the token was not revocable.");
context.Reject(
error: OpenIdConnectConstants.Errors.UnsupportedTokenType,
@@ -152,10 +144,10 @@ namespace OpenIddict
// Retrieve the token from the database. If the token cannot be found,
// assume it is invalid and consider the revocation as successful.
- var token = await tokens.FindByIdAsync(identifier, context.HttpContext.RequestAborted);
+ var token = await Tokens.FindByIdAsync(identifier, context.HttpContext.RequestAborted);
if (token == null)
{
- logger.LogInformation("The token '{Identifier}' was already revoked.", identifier);
+ Logger.LogInformation("The token '{Identifier}' was already revoked.", identifier);
context.Revoked = true;
@@ -163,9 +155,9 @@ namespace OpenIddict
}
// Revoke the token.
- await tokens.RevokeAsync(token, context.HttpContext.RequestAborted);
+ await Tokens.RevokeAsync(token, context.HttpContext.RequestAborted);
- logger.LogInformation("The token '{Identifier}' was successfully revoked.", identifier);
+ Logger.LogInformation("The token '{Identifier}' was successfully revoked.", identifier);
context.Revoked = true;
}
diff --git a/src/OpenIddict/OpenIddictProvider.Serialization.cs b/src/OpenIddict/OpenIddictProvider.Serialization.cs
index da3bcd00..454f68d7 100644
--- a/src/OpenIddict/OpenIddictProvider.Serialization.cs
+++ b/src/OpenIddict/OpenIddictProvider.Serialization.cs
@@ -11,8 +11,6 @@ using AspNet.Security.OpenIdConnect.Extensions;
using AspNet.Security.OpenIdConnect.Primitives;
using AspNet.Security.OpenIdConnect.Server;
using JetBrains.Annotations;
-using Microsoft.Extensions.DependencyInjection;
-using Microsoft.Extensions.Options;
using OpenIddict.Core;
namespace OpenIddict
@@ -22,13 +20,11 @@ namespace OpenIddict
{
public override async Task SerializeAuthorizationCode([NotNull] SerializeAuthorizationCodeContext context)
{
- var applications = context.HttpContext.RequestServices.GetRequiredService>();
- var options = context.HttpContext.RequestServices.GetRequiredService>();
- var tokens = context.HttpContext.RequestServices.GetRequiredService>();
+ var options = (OpenIddictOptions) context.Options;
Debug.Assert(!string.IsNullOrEmpty(context.Request.ClientId), "The client identifier shouldn't be null or empty.");
- if (!options.Value.DisableTokenRevocation)
+ if (!options.DisableTokenRevocation)
{
// Resolve the subject from the authentication ticket. If it cannot be found, throw an exception.
var subject = context.Ticket.Principal.GetClaim(OpenIdConnectConstants.Claims.Subject);
@@ -38,14 +34,14 @@ namespace OpenIddict
}
// If a null value was returned by CreateAsync, return immediately.
- var token = await tokens.CreateAsync(OpenIdConnectConstants.TokenTypeHints.AuthorizationCode, subject, context.HttpContext.RequestAborted);
+ var token = await Tokens.CreateAsync(OpenIdConnectConstants.TokenTypeHints.AuthorizationCode, subject, context.HttpContext.RequestAborted);
if (token == null)
{
return;
}
// Throw an exception if the token identifier can't be resolved.
- var identifier = await tokens.GetIdAsync(token, context.HttpContext.RequestAborted);
+ var identifier = await Tokens.GetIdAsync(token, context.HttpContext.RequestAborted);
if (string.IsNullOrEmpty(identifier))
{
throw new InvalidOperationException("The unique key associated with an authorization code cannot be null or empty.");
@@ -56,30 +52,28 @@ namespace OpenIddict
// generated by the OpenID Connect server middleware.
context.Ticket.SetProperty(OpenIdConnectConstants.Properties.TokenId, identifier);
- var application = await applications.FindByClientIdAsync(context.Request.ClientId, context.HttpContext.RequestAborted);
+ var application = await Applications.FindByClientIdAsync(context.Request.ClientId, context.HttpContext.RequestAborted);
if (application == null)
{
throw new InvalidOperationException("The client application cannot be retrieved from the database.");
}
- await tokens.SetClientAsync(token, await applications.GetIdAsync(application, context.HttpContext.RequestAborted), context.HttpContext.RequestAborted);
+ await Tokens.SetClientAsync(token, await Applications.GetIdAsync(application, context.HttpContext.RequestAborted), context.HttpContext.RequestAborted);
// If an authorization identifier was specified, bind it to the token.
var authorization = context.Ticket.GetProperty(OpenIddictConstants.Properties.AuthorizationId);
if (!string.IsNullOrEmpty(authorization))
{
- await tokens.SetAuthorizationAsync(token, authorization, context.HttpContext.RequestAborted);
+ await Tokens.SetAuthorizationAsync(token, authorization, context.HttpContext.RequestAborted);
}
}
}
public override async Task SerializeRefreshToken([NotNull] SerializeRefreshTokenContext context)
{
- var applications = context.HttpContext.RequestServices.GetRequiredService>();
- var options = context.HttpContext.RequestServices.GetRequiredService>();
- var tokens = context.HttpContext.RequestServices.GetRequiredService>();
+ var options = (OpenIddictOptions) context.Options;
- if (!options.Value.DisableTokenRevocation)
+ if (!options.DisableTokenRevocation)
{
// Resolve the subject from the authentication ticket. If it cannot be found, throw an exception.
var subject = context.Ticket.Principal.GetClaim(OpenIdConnectConstants.Claims.Subject);
@@ -89,14 +83,14 @@ namespace OpenIddict
}
// If a null value was returned by CreateAsync, return immediately.
- var token = await tokens.CreateAsync(OpenIdConnectConstants.TokenTypeHints.RefreshToken, subject, context.HttpContext.RequestAborted);
+ var token = await Tokens.CreateAsync(OpenIdConnectConstants.TokenTypeHints.RefreshToken, subject, context.HttpContext.RequestAborted);
if (token == null)
{
return;
}
// Throw an exception if the token identifier can't be resolved.
- var identifier = await tokens.GetIdAsync(token, context.HttpContext.RequestAborted);
+ var identifier = await Tokens.GetIdAsync(token, context.HttpContext.RequestAborted);
if (string.IsNullOrEmpty(identifier))
{
throw new InvalidOperationException("The unique key associated with a refresh token cannot be null or empty.");
@@ -110,20 +104,20 @@ namespace OpenIddict
// If the client application is known, associate it with the token.
if (!string.IsNullOrEmpty(context.Request.ClientId))
{
- var application = await applications.FindByClientIdAsync(context.Request.ClientId, context.HttpContext.RequestAborted);
+ var application = await Applications.FindByClientIdAsync(context.Request.ClientId, context.HttpContext.RequestAborted);
if (application == null)
{
throw new InvalidOperationException("The client application cannot be retrieved from the database.");
}
- await tokens.SetClientAsync(token, await applications.GetIdAsync(application, context.HttpContext.RequestAborted), context.HttpContext.RequestAborted);
+ await Tokens.SetClientAsync(token, await Applications.GetIdAsync(application, context.HttpContext.RequestAborted), context.HttpContext.RequestAborted);
}
// If an authorization identifier was specified, bind it to the token.
var authorization = context.Ticket.GetProperty(OpenIddictConstants.Properties.AuthorizationId);
if (!string.IsNullOrEmpty(authorization))
{
- await tokens.SetAuthorizationAsync(token, authorization, context.HttpContext.RequestAborted);
+ await Tokens.SetAuthorizationAsync(token, authorization, context.HttpContext.RequestAborted);
}
}
}
diff --git a/src/OpenIddict/OpenIddictProvider.Session.cs b/src/OpenIddict/OpenIddictProvider.Session.cs
index 0dfc66c1..e8e6c5f6 100644
--- a/src/OpenIddict/OpenIddictProvider.Session.cs
+++ b/src/OpenIddict/OpenIddictProvider.Session.cs
@@ -13,9 +13,7 @@ using JetBrains.Annotations;
using Microsoft.AspNetCore.Diagnostics;
using Microsoft.AspNetCore.WebUtilities;
using Microsoft.Extensions.Caching.Distributed;
-using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
-using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using Newtonsoft.Json.Bson;
using Newtonsoft.Json.Linq;
@@ -28,17 +26,16 @@ namespace OpenIddict
{
public override async Task ExtractLogoutRequest([NotNull] ExtractLogoutRequestContext context)
{
- var logger = context.HttpContext.RequestServices.GetRequiredService>>();
- var options = context.HttpContext.RequestServices.GetRequiredService>();
+ var options = (OpenIddictOptions) context.Options;
// If a request_id parameter can be found in the logout request,
// restore the complete logout request from the distributed cache.
if (!string.IsNullOrEmpty(context.Request.RequestId))
{
// Return an error if request caching support was not enabled.
- if (!options.Value.EnableRequestCaching)
+ if (!options.EnableRequestCaching)
{
- logger.LogError("The logout request was rejected because " +
+ Logger.LogError("The logout request was rejected because " +
"request caching support was not enabled.");
context.Reject(
@@ -52,10 +49,10 @@ namespace OpenIddict
// to avoid collisions with the other types of cached requests.
var key = OpenIddictConstants.Environment.LogoutRequest + context.Request.RequestId;
- var payload = await options.Value.Cache.GetAsync(key);
+ var payload = await options.Cache.GetAsync(key);
if (payload == null)
{
- logger.LogError("The logout request was rejected because an unknown " +
+ Logger.LogError("The logout request was rejected because an unknown " +
"or invalid request_id parameter was specified.");
context.Reject(
@@ -66,7 +63,7 @@ namespace OpenIddict
}
// Restore the logout request parameters from the serialized payload.
- using (var reader = new BsonReader(new MemoryStream(payload)))
+ using (var reader = new BsonDataReader(new MemoryStream(payload)))
{
foreach (var parameter in JObject.Load(reader))
{
@@ -84,16 +81,13 @@ namespace OpenIddict
public override async Task ValidateLogoutRequest([NotNull] ValidateLogoutRequestContext context)
{
- var applications = context.HttpContext.RequestServices.GetRequiredService>();
- var logger = context.HttpContext.RequestServices.GetRequiredService>>();
-
// If an optional post_logout_redirect_uri was provided, validate it.
if (!string.IsNullOrEmpty(context.PostLogoutRedirectUri))
{
- var application = await applications.FindByLogoutRedirectUri(context.PostLogoutRedirectUri, context.HttpContext.RequestAborted);
+ var application = await Applications.FindByLogoutRedirectUri(context.PostLogoutRedirectUri, context.HttpContext.RequestAborted);
if (application == null)
{
- logger.LogError("The logout request was rejected because the client application corresponding " +
+ Logger.LogError("The logout request was rejected because the client application corresponding " +
"to the specified post_logout_redirect_uri was not found in the database: " +
"'{PostLogoutRedirectUri}'.", context.PostLogoutRedirectUri);
@@ -110,12 +104,12 @@ namespace OpenIddict
public override async Task HandleLogoutRequest([NotNull] HandleLogoutRequestContext context)
{
- var options = context.HttpContext.RequestServices.GetRequiredService>();
+ var options = (OpenIddictOptions) 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 to flow across requests and internal/external logout workflows.
- if (options.Value.EnableRequestCaching && string.IsNullOrEmpty(context.Request.RequestId))
+ if (options.EnableRequestCaching && string.IsNullOrEmpty(context.Request.RequestId))
{
// Generate a request identifier. Note: using a crypto-secure
// random number generator is not necessary in this case.
@@ -123,7 +117,7 @@ namespace OpenIddict
// Store the serialized logout request parameters in the distributed cache.
var stream = new MemoryStream();
- using (var writer = new BsonWriter(stream))
+ using (var writer = new BsonDataWriter(stream))
{
writer.CloseOutput = false;
@@ -135,7 +129,7 @@ namespace OpenIddict
// to avoid collisions with the other types of cached requests.
var key = OpenIddictConstants.Environment.LogoutRequest + context.Request.RequestId;
- await options.Value.Cache.SetAsync(key, stream.ToArray(), new DistributedCacheEntryOptions
+ await options.Cache.SetAsync(key, stream.ToArray(), new DistributedCacheEntryOptions
{
AbsoluteExpiration = context.Options.SystemClock.UtcNow + TimeSpan.FromMinutes(30),
SlidingExpiration = TimeSpan.FromMinutes(10)
@@ -159,10 +153,10 @@ namespace OpenIddict
public override async Task ApplyLogoutResponse([NotNull] ApplyLogoutResponseContext context)
{
- var options = context.HttpContext.RequestServices.GetRequiredService>();
+ var options = (OpenIddictOptions) context.Options;
// Remove the logout request from the distributed cache.
- if (options.Value.EnableRequestCaching && !string.IsNullOrEmpty(context.Request.RequestId))
+ if (options.EnableRequestCaching && !string.IsNullOrEmpty(context.Request.RequestId))
{
// Note: the cache key is always prefixed with a specific marker
// to avoid collisions with the other types of cached requests.
@@ -171,11 +165,11 @@ namespace OpenIddict
// Note: the ApplyLogoutResponse event is called for both successful
// and errored logout responses but discrimination is not necessary here,
// as the logout request must be removed from the distributed cache in both cases.
- await options.Value.Cache.RemoveAsync(key);
+ await options.Cache.RemoveAsync(key);
}
- if (!options.Value.ApplicationCanDisplayErrors && !string.IsNullOrEmpty(context.Error) &&
- string.IsNullOrEmpty(context.PostLogoutRedirectUri))
+ if (!options.ApplicationCanDisplayErrors && !string.IsNullOrEmpty(context.Error) &&
+ string.IsNullOrEmpty(context.PostLogoutRedirectUri))
{
// Determine if the status code pages middleware has been enabled for this request.
// If it was not registered or enabled, let the OpenID Connect server middleware render
diff --git a/src/OpenIddict/OpenIddictProvider.Userinfo.cs b/src/OpenIddict/OpenIddictProvider.Userinfo.cs
index 214cf1b7..f6a8a72b 100644
--- a/src/OpenIddict/OpenIddictProvider.Userinfo.cs
+++ b/src/OpenIddict/OpenIddictProvider.Userinfo.cs
@@ -23,7 +23,7 @@ namespace OpenIddict
// Invoke the rest of the pipeline to allow
// the user code to handle the userinfo request.
- context.SkipToNextMiddleware();
+ context.SkipHandler();
return Task.FromResult(0);
}
diff --git a/src/OpenIddict/OpenIddictProvider.cs b/src/OpenIddict/OpenIddictProvider.cs
index c6b3a336..7e942429 100644
--- a/src/OpenIddict/OpenIddictProvider.cs
+++ b/src/OpenIddict/OpenIddictProvider.cs
@@ -6,13 +6,52 @@
using System.ComponentModel;
using AspNet.Security.OpenIdConnect.Server;
+using JetBrains.Annotations;
+using Microsoft.Extensions.Logging;
+using OpenIddict.Core;
namespace OpenIddict
{
+ ///
+ /// Provides the logic necessary to extract, validate and handle OpenID Connect requests.
+ ///
[EditorBrowsable(EditorBrowsableState.Never)]
public partial class OpenIddictProvider : OpenIdConnectServerProvider
where TApplication : class where TAuthorization : class where TScope : class where TToken : class
{
- // Note: this class is split into specialized partial classes.
+ ///
+ /// Creates a new instance of the class.
+ ///
+ public OpenIddictProvider(
+ [NotNull] ILogger> logger,
+ [NotNull] OpenIddictApplicationManager applications,
+ [NotNull] OpenIddictAuthorizationManager authorizations,
+ [NotNull] OpenIddictTokenManager tokens)
+ {
+ Applications = applications;
+ Authorizations = authorizations;
+ Logger = logger;
+ Tokens = tokens;
+ }
+
+ ///
+ /// Gets the applications manager.
+ ///
+ public OpenIddictApplicationManager Applications { get; }
+
+ ///
+ /// Gets the authorizations manager.
+ ///
+ public OpenIddictAuthorizationManager Authorizations { get; }
+
+ ///
+ /// Gets the logger associated with the current class.
+ ///
+ public ILogger Logger { get; }
+
+ ///
+ /// Gets the tokens manager.
+ ///
+ public OpenIddictTokenManager Tokens { get; }
}
}
\ No newline at end of file
diff --git a/test/OpenIddict.Core.Tests/OpenIddict.Core.Tests.csproj b/test/OpenIddict.Core.Tests/OpenIddict.Core.Tests.csproj
index b1190b84..4034e462 100644
--- a/test/OpenIddict.Core.Tests/OpenIddict.Core.Tests.csproj
+++ b/test/OpenIddict.Core.Tests/OpenIddict.Core.Tests.csproj
@@ -3,8 +3,8 @@
- netcoreapp1.0;net452
- netcoreapp1.0
+ netcoreapp2.0;net461
+ netcoreapp2.0
diff --git a/test/OpenIddict.EntityFrameworkCore.Tests/OpenIddict.EntityFrameworkCore.Tests.csproj b/test/OpenIddict.EntityFrameworkCore.Tests/OpenIddict.EntityFrameworkCore.Tests.csproj
index d7e11a3b..a86dfab0 100644
--- a/test/OpenIddict.EntityFrameworkCore.Tests/OpenIddict.EntityFrameworkCore.Tests.csproj
+++ b/test/OpenIddict.EntityFrameworkCore.Tests/OpenIddict.EntityFrameworkCore.Tests.csproj
@@ -3,8 +3,8 @@
- netcoreapp1.0;net452
- netcoreapp1.0
+ netcoreapp2.0;net461
+ netcoreapp2.0
diff --git a/test/OpenIddict.Mvc.Tests/OpenIddict.Mvc.Tests.csproj b/test/OpenIddict.Mvc.Tests/OpenIddict.Mvc.Tests.csproj
index 616e6347..20d98d8c 100644
--- a/test/OpenIddict.Mvc.Tests/OpenIddict.Mvc.Tests.csproj
+++ b/test/OpenIddict.Mvc.Tests/OpenIddict.Mvc.Tests.csproj
@@ -3,8 +3,8 @@
- netcoreapp1.0;net452
- netcoreapp1.0
+ netcoreapp2.0;net461
+ netcoreapp2.0
diff --git a/test/OpenIddict.Tests/OpenIddict.Tests.csproj b/test/OpenIddict.Tests/OpenIddict.Tests.csproj
index df06533e..4f54702f 100644
--- a/test/OpenIddict.Tests/OpenIddict.Tests.csproj
+++ b/test/OpenIddict.Tests/OpenIddict.Tests.csproj
@@ -3,8 +3,8 @@
- netcoreapp1.0;net452
- netcoreapp1.0
+ netcoreapp2.0;net461
+ netcoreapp2.0
@@ -34,7 +34,7 @@
-
+ $(DefineConstants);SUPPORTS_ECDSA
diff --git a/test/OpenIddict.Tests/OpenIddictExtensionsTests.cs b/test/OpenIddict.Tests/OpenIddictExtensionsTests.cs
index f949f52f..109b12df 100644
--- a/test/OpenIddict.Tests/OpenIddictExtensionsTests.cs
+++ b/test/OpenIddict.Tests/OpenIddictExtensionsTests.cs
@@ -2,11 +2,15 @@
using System.IdentityModel.Tokens.Jwt;
using System.Reflection;
using AspNet.Security.OpenIdConnect.Primitives;
+using AspNet.Security.OpenIdConnect.Server;
using Microsoft.AspNetCore.Builder;
-using Microsoft.AspNetCore.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.DependencyInjection.Extensions;
+using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using Moq;
@@ -16,199 +20,36 @@ namespace OpenIddict.Tests
{
public class OpenIddictExtensionsTests
{
- [Fact]
- public void UseOpenIddict_ThrowsAnExceptionWhenServicesAreNotRegistered()
- {
- // Arrange
- var services = new ServiceCollection();
- var builder = new ApplicationBuilder(services.BuildServiceProvider());
-
- // Act and assert
- var exception = Assert.Throws(() => 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_ThrowsAnExceptionWhenNoDistributedCacheIsRegisteredIfRequestCachingIsEnabled()
- {
- // Arrange
- var services = new ServiceCollection();
-
- services.AddOpenIddict()
- .EnableRequestCaching();
-
- var builder = new ApplicationBuilder(services.BuildServiceProvider());
-
- // Act and assert
- var exception = Assert.Throws(() => builder.UseOpenIddict());
-
- Assert.Equal("A distributed cache implementation must be registered in the OpenIddict options " +
- "or in the dependency injection container when enabling request caching support.", 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(() => 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(() => 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(() => 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(() => builder.UseOpenIddict());
-
- Assert.Equal("The revocation endpoint cannot be enabled when token revocation is disabled.", 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(() => 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()
{
// Arrange
- var services = new ServiceCollection();
- services.AddOptions();
-
+ var services = CreateServices();
var builder = new OpenIddictBuilder(services);
// Act
- builder.Configure(configuration => configuration.Description.DisplayName = "OpenIddict");
-
- var provider = services.BuildServiceProvider();
- var options = provider.GetRequiredService>();
-
- // Assert
- Assert.Equal("OpenIddict", options.Value.Description.DisplayName);
- }
-
- [Fact]
- public void UseOpenIddict_OpenIdConnectServerMiddlewareIsRegistered()
- {
- // Arrange
- var services = new ServiceCollection();
+ builder.Configure(configuration => configuration.AccessTokenLifetime = TimeSpan.FromDays(1));
- services.AddOpenIddict()
- .AddSigningCertificate(
- assembly: typeof(OpenIddictProviderTests).GetTypeInfo().Assembly,
- resource: "OpenIddict.Tests.Certificate.pfx",
- password: "OpenIddict")
- .AllowImplicitFlow()
- .EnableAuthorizationEndpoint("/connect/authorize");
-
- var builder = new Mock();
- builder.SetupGet(mock => mock.ApplicationServices)
- .Returns(services.BuildServiceProvider());
-
- // Act
- builder.Object.UseOpenIddict();
+ var options = GetOptions(services);
// Assert
- builder.Verify(mock => mock.Use(It.IsAny>()), Times.Once());
+ Assert.Equal(TimeSpan.FromDays(1), options.AccessTokenLifetime);
}
[Fact]
public void AddEphemeralSigningKey_SigningKeyIsCorrectlyAdded()
{
// Arrange
- var services = new ServiceCollection();
- services.AddOptions();
-
+ var services = CreateServices();
var builder = new OpenIddictBuilder(services);
// Act
builder.AddEphemeralSigningKey();
- var provider = services.BuildServiceProvider();
- var options = provider.GetRequiredService>();
+ var options = GetOptions(services);
// Assert
- Assert.Equal(1, options.Value.SigningCredentials.Count);
+ Assert.Equal(1, options.SigningCredentials.Count);
}
[Theory]
@@ -223,17 +64,14 @@ namespace OpenIddict.Tests
public void AddEphemeralSigningKey_SigningCredentialsUseSpecifiedAlgorithm(string algorithm)
{
// Arrange
- var services = new ServiceCollection();
- services.AddOptions();
-
+ var services = CreateServices();
var builder = new OpenIddictBuilder(services);
// Act
builder.AddEphemeralSigningKey(algorithm);
- var provider = services.BuildServiceProvider();
- var options = provider.GetRequiredService>();
- var credentials = options.Value.SigningCredentials[0];
+ var options = GetOptions(services);
+ var credentials = options.SigningCredentials[0];
// Assert
Assert.Equal(algorithm, credentials.Algorithm);
@@ -250,9 +88,7 @@ namespace OpenIddict.Tests
public void AddSigningKey_SigningKeyIsCorrectlyAdded(string algorithm)
{
// Arrange
- var services = new ServiceCollection();
- services.AddOptions();
-
+ var services = CreateServices();
var builder = new OpenIddictBuilder(services);
var factory = Mock.Of(mock =>
@@ -263,20 +99,17 @@ namespace OpenIddict.Tests
// Act
builder.AddSigningKey(key);
- var provider = services.BuildServiceProvider();
- var options = provider.GetRequiredService>();
+ var options = GetOptions(services);
// Assert
- Assert.Same(key, options.Value.SigningCredentials[0].Key);
+ Assert.Same(key, options.SigningCredentials[0].Key);
}
[Fact]
public void AddSigningCertificate_SigningKeyIsCorrectlyAdded()
{
// Arrange
- var services = new ServiceCollection();
- services.AddOptions();
-
+ var services = CreateServices();
var builder = new OpenIddictBuilder(services);
// Act
@@ -285,486 +118,432 @@ namespace OpenIddict.Tests
resource: "OpenIddict.Tests.Certificate.pfx",
password: "OpenIddict");
- var provider = services.BuildServiceProvider();
- var options = provider.GetRequiredService>();
+ var options = GetOptions(services);
// Assert
- Assert.IsType(typeof(X509SecurityKey), options.Value.SigningCredentials[0].Key);
+ Assert.IsType(options.SigningCredentials[0].Key);
}
[Fact]
public void AllowAuthorizationCodeFlow_CodeFlowIsAddedToGrantTypes()
{
// Arrange
- var services = new ServiceCollection();
- services.AddOptions();
-
+ var services = CreateServices();
var builder = new OpenIddictBuilder(services);
// Act
builder.AllowAuthorizationCodeFlow();
- var provider = services.BuildServiceProvider();
- var options = provider.GetRequiredService>();
+ var options = GetOptions(services);
// Assert
- Assert.Contains(OpenIdConnectConstants.GrantTypes.AuthorizationCode, options.Value.GrantTypes);
+ Assert.Contains(OpenIdConnectConstants.GrantTypes.AuthorizationCode, options.GrantTypes);
}
[Fact]
public void AllowClientCredentialsFlow_ClientCredentialsFlowIsAddedToGrantTypes()
{
// Arrange
- var services = new ServiceCollection();
- services.AddOptions();
-
+ var services = CreateServices();
var builder = new OpenIddictBuilder(services);
// Act
builder.AllowClientCredentialsFlow();
- var provider = services.BuildServiceProvider();
- var options = provider.GetRequiredService>();
+ var options = GetOptions(services);
// Assert
- Assert.Contains(OpenIdConnectConstants.GrantTypes.ClientCredentials, options.Value.GrantTypes);
+ Assert.Contains(OpenIdConnectConstants.GrantTypes.ClientCredentials, options.GrantTypes);
}
[Fact]
public void AllowCustomFlow_CustomFlowIsAddedToGrantTypes()
{
// Arrange
- var services = new ServiceCollection();
- services.AddOptions();
-
+ var services = CreateServices();
var builder = new OpenIddictBuilder(services);
// Act
builder.AllowCustomFlow("urn:ietf:params:oauth:grant-type:custom_grant");
- var provider = services.BuildServiceProvider();
- var options = provider.GetRequiredService>();
+ var options = GetOptions(services);
// Assert
- Assert.Contains("urn:ietf:params:oauth:grant-type:custom_grant", options.Value.GrantTypes);
+ Assert.Contains("urn:ietf:params:oauth:grant-type:custom_grant", options.GrantTypes);
}
[Fact]
public void AllowImplicitFlow_ImplicitFlowIsAddedToGrantTypes()
{
// Arrange
- var services = new ServiceCollection();
- services.AddOptions();
-
+ var services = CreateServices();
var builder = new OpenIddictBuilder(services);
// Act
builder.AllowImplicitFlow();
- var provider = services.BuildServiceProvider();
- var options = provider.GetRequiredService>();
+ var options = GetOptions(services);
// Assert
- Assert.Contains(OpenIdConnectConstants.GrantTypes.Implicit, options.Value.GrantTypes);
+ Assert.Contains(OpenIdConnectConstants.GrantTypes.Implicit, options.GrantTypes);
}
[Fact]
public void AllowPasswordFlow_PasswordFlowIsAddedToGrantTypes()
{
// Arrange
- var services = new ServiceCollection();
- services.AddOptions();
-
+ var services = CreateServices();
var builder = new OpenIddictBuilder(services);
// Act
builder.AllowPasswordFlow();
- var provider = services.BuildServiceProvider();
- var options = provider.GetRequiredService>();
+ var options = GetOptions(services);
// Assert
- Assert.Contains(OpenIdConnectConstants.GrantTypes.Password, options.Value.GrantTypes);
+ Assert.Contains(OpenIdConnectConstants.GrantTypes.Password, options.GrantTypes);
}
[Fact]
public void AllowRefreshTokenFlow_RefreshTokenFlowIsAddedToGrantTypes()
{
// Arrange
- var services = new ServiceCollection();
- services.AddOptions();
-
+ var services = CreateServices();
var builder = new OpenIddictBuilder(services);
// Act
builder.AllowRefreshTokenFlow();
- var provider = services.BuildServiceProvider();
- var options = provider.GetRequiredService>();
+ var options = GetOptions(services);
// Assert
- Assert.Contains(OpenIdConnectConstants.GrantTypes.RefreshToken, options.Value.GrantTypes);
+ Assert.Contains(OpenIdConnectConstants.GrantTypes.RefreshToken, options.GrantTypes);
}
[Fact]
public void DisableConfigurationEndpoint_ConfigurationEndpointIsDisabled()
{
// Arrange
- var services = new ServiceCollection();
- services.AddOptions();
-
+ var services = CreateServices();
var builder = new OpenIddictBuilder(services);
// Act
builder.DisableConfigurationEndpoint();
- var provider = services.BuildServiceProvider();
- var options = provider.GetRequiredService>();
+ var options = GetOptions(services);
// Assert
- Assert.Equal(PathString.Empty, options.Value.ConfigurationEndpointPath);
+ Assert.Equal(PathString.Empty, options.ConfigurationEndpointPath);
}
[Fact]
public void DisableCryptographyEndpoint_CryptographyEndpointIsDisabled()
{
// Arrange
- var services = new ServiceCollection();
- services.AddOptions();
-
+ var services = CreateServices();
var builder = new OpenIddictBuilder(services);
// Act
builder.DisableCryptographyEndpoint();
- var provider = services.BuildServiceProvider();
- var options = provider.GetRequiredService>();
+ var options = GetOptions(services);
// Assert
- Assert.Equal(PathString.Empty, options.Value.CryptographyEndpointPath);
+ Assert.Equal(PathString.Empty, options.CryptographyEndpointPath);
}
[Fact]
public void DisableSlidingExpiration_SlidingExpirationIsDisabled()
{
// Arrange
- var services = new ServiceCollection();
- services.AddOptions();
-
+ var services = CreateServices();
var builder = new OpenIddictBuilder(services);
// Act
builder.DisableSlidingExpiration();
- var provider = services.BuildServiceProvider();
- var options = provider.GetRequiredService>();
+ var options = GetOptions(services);
// Assert
- Assert.False(options.Value.UseSlidingExpiration);
+ Assert.False(options.UseSlidingExpiration);
}
[Fact]
public void DisableTokenRevocation_TokenRevocationIsDisabled()
{
// Arrange
- var services = new ServiceCollection();
- services.AddOptions();
-
+ var services = CreateServices();
var builder = new OpenIddictBuilder(services);
// Act
builder.DisableTokenRevocation();
- var provider = services.BuildServiceProvider();
- var options = provider.GetRequiredService>();
+ var options = GetOptions(services);
// Assert
- Assert.True(options.Value.DisableTokenRevocation);
+ Assert.True(options.DisableTokenRevocation);
}
[Fact]
public void EnableAuthorizationEndpoint_AuthorizationEndpointIsEnabled()
{
// Arrange
- var services = new ServiceCollection();
- services.AddOptions();
-
+ var services = CreateServices();
var builder = new OpenIddictBuilder(services);
// Act
builder.EnableAuthorizationEndpoint("/endpoint-path");
- var provider = services.BuildServiceProvider();
- var options = provider.GetRequiredService>();
+ var options = GetOptions(services);
// Assert
- Assert.Equal("/endpoint-path", options.Value.AuthorizationEndpointPath);
+ Assert.Equal("/endpoint-path", options.AuthorizationEndpointPath);
}
[Fact]
public void EnableIntrospectionEndpoint_IntrospectionEndpointIsEnabled()
{
// Arrange
- var services = new ServiceCollection();
- services.AddOptions();
-
+ var services = CreateServices();
var builder = new OpenIddictBuilder(services);
// Act
builder.EnableIntrospectionEndpoint("/endpoint-path");
- var provider = services.BuildServiceProvider();
- var options = provider.GetRequiredService>();
+ var options = GetOptions(services);
// Assert
- Assert.Equal("/endpoint-path", options.Value.IntrospectionEndpointPath);
+ Assert.Equal("/endpoint-path", options.IntrospectionEndpointPath);
}
[Fact]
public void EnableLogoutEndpoint_LogoutEndpointIsEnabled()
{
// Arrange
- var services = new ServiceCollection();
- services.AddOptions();
-
+ var services = CreateServices();
var builder = new OpenIddictBuilder(services);
// Act
builder.EnableLogoutEndpoint("/endpoint-path");
- var provider = services.BuildServiceProvider();
- var options = provider.GetRequiredService>();
+ var options = GetOptions(services);
// Assert
- Assert.Equal("/endpoint-path", options.Value.LogoutEndpointPath);
+ Assert.Equal("/endpoint-path", options.LogoutEndpointPath);
}
[Fact]
public void EnableRequestCaching_RequestCachingIsEnabled()
{
// Arrange
- var services = new ServiceCollection();
- services.AddOptions();
-
+ var services = CreateServices();
var builder = new OpenIddictBuilder(services);
// Act
builder.EnableRequestCaching();
- var provider = services.BuildServiceProvider();
- var options = provider.GetRequiredService>();
+ var options = GetOptions(services);
// Assert
- Assert.True(options.Value.EnableRequestCaching);
+ Assert.True(options.EnableRequestCaching);
}
[Fact]
public void EnableRevocationEndpoint_RevocationEndpointIsEnabled()
{
// Arrange
- var services = new ServiceCollection();
- services.AddOptions();
-
+ var services = CreateServices();
var builder = new OpenIddictBuilder(services);
// Act
builder.EnableRevocationEndpoint("/endpoint-path");
- var provider = services.BuildServiceProvider();
- var options = provider.GetRequiredService>();
+ var options = GetOptions(services);
// Assert
- Assert.Equal("/endpoint-path", options.Value.RevocationEndpointPath);
+ Assert.Equal("/endpoint-path", options.RevocationEndpointPath);
}
[Fact]
public void EnableTokenEndpoint_TokenEndpointIsEnabled()
{
// Arrange
- var services = new ServiceCollection();
- services.AddOptions();
-
+ var services = CreateServices();
var builder = new OpenIddictBuilder(services);
// Act
builder.EnableTokenEndpoint("/endpoint-path");
- var provider = services.BuildServiceProvider();
- var options = provider.GetRequiredService>();
+ var options = GetOptions(services);
// Assert
- Assert.Equal("/endpoint-path", options.Value.TokenEndpointPath);
+ Assert.Equal("/endpoint-path", options.TokenEndpointPath);
}
[Fact]
public void EnableUserinfoEndpoint_UserinfoEndpointIsEnabled()
{
// Arrange
- var services = new ServiceCollection();
- services.AddOptions();
-
+ var services = CreateServices();
var builder = new OpenIddictBuilder(services);
// Act
builder.EnableUserinfoEndpoint("/endpoint-path");
- var provider = services.BuildServiceProvider();
- var options = provider.GetRequiredService>();
+ var options = GetOptions(services);
// Assert
- Assert.Equal("/endpoint-path", options.Value.UserinfoEndpointPath);
+ Assert.Equal("/endpoint-path", options.UserinfoEndpointPath);
}
[Fact]
public void RequireClientIdentification_ClientIdentificationIsEnforced()
{
// Arrange
- var services = new ServiceCollection();
- services.AddOptions();
-
+ var services = CreateServices();
var builder = new OpenIddictBuilder(services);
// Act
builder.RequireClientIdentification();
- var provider = services.BuildServiceProvider();
- var options = provider.GetRequiredService>();
+ var options = GetOptions(services);
// Assert
- Assert.True(options.Value.RequireClientIdentification);
+ Assert.True(options.RequireClientIdentification);
}
[Fact]
public void SetAccessTokenLifetime_DefaultAccessTokenLifetimeIsReplaced()
{
// Arrange
- var services = new ServiceCollection();
- services.AddOptions();
-
+ var services = CreateServices();
var builder = new OpenIddictBuilder(services);
// Act
builder.SetAccessTokenLifetime(TimeSpan.FromMinutes(42));
- var provider = services.BuildServiceProvider();
- var options = provider.GetRequiredService>();
+ var options = GetOptions(services);
// Assert
- Assert.Equal(TimeSpan.FromMinutes(42), options.Value.AccessTokenLifetime);
+ Assert.Equal(TimeSpan.FromMinutes(42), options.AccessTokenLifetime);
}
[Fact]
public void SetAuthorizationCodeLifetime_DefaultAuthorizationCodeLifetimeIsReplaced()
{
// Arrange
- var services = new ServiceCollection();
- services.AddOptions();
-
+ var services = CreateServices();
var builder = new OpenIddictBuilder(services);
// Act
builder.SetAuthorizationCodeLifetime(TimeSpan.FromMinutes(42));
- var provider = services.BuildServiceProvider();
- var options = provider.GetRequiredService>();
+ var options = GetOptions(services);
// Assert
- Assert.Equal(TimeSpan.FromMinutes(42), options.Value.AuthorizationCodeLifetime);
+ Assert.Equal(TimeSpan.FromMinutes(42), options.AuthorizationCodeLifetime);
}
[Fact]
public void SetIdentityTokenLifetime_DefaultIdentityTokenLifetimeIsReplaced()
{
// Arrange
- var services = new ServiceCollection();
- services.AddOptions();
-
+ var services = CreateServices();
var builder = new OpenIddictBuilder(services);
// Act
builder.SetIdentityTokenLifetime(TimeSpan.FromMinutes(42));
- var provider = services.BuildServiceProvider();
- var options = provider.GetRequiredService>();
+ var options = GetOptions(services);
// Assert
- Assert.Equal(TimeSpan.FromMinutes(42), options.Value.IdentityTokenLifetime);
+ Assert.Equal(TimeSpan.FromMinutes(42), options.IdentityTokenLifetime);
}
[Fact]
public void SetRefreshTokenLifetime_DefaultRefreshTokenLifetimeIsReplaced()
{
// Arrange
- var services = new ServiceCollection();
- services.AddOptions();
-
+ var services = CreateServices();
var builder = new OpenIddictBuilder(services);
// Act
builder.SetRefreshTokenLifetime(TimeSpan.FromMinutes(42));
- var provider = services.BuildServiceProvider();
- var options = provider.GetRequiredService>();
+ var options = GetOptions(services);
// Assert
- Assert.Equal(TimeSpan.FromMinutes(42), options.Value.RefreshTokenLifetime);
+ Assert.Equal(TimeSpan.FromMinutes(42), options.RefreshTokenLifetime);
}
[Fact]
public void SetIssuer_AddressIsReplaced()
{
// Arrange
- var services = new ServiceCollection();
- services.AddOptions();
-
+ var services = CreateServices();
var builder = new OpenIddictBuilder(services);
// Act
builder.SetIssuer(new Uri("http://www.fabrikam.com/"));
- var provider = services.BuildServiceProvider();
- var options = provider.GetRequiredService>();
+ var options = GetOptions(services);
// Assert
- Assert.Equal(new Uri("http://www.fabrikam.com/"), options.Value.Issuer);
+ Assert.Equal(new Uri("http://www.fabrikam.com/"), options.Issuer);
}
[Fact]
public void UseDataProtectionProvider_DefaultProviderIsReplaced()
{
// Arrange
- var services = new ServiceCollection();
- services.AddOptions();
-
+ var services = CreateServices();
var builder = new OpenIddictBuilder(services);
// Act
- builder.UseDataProtectionProvider(new EphemeralDataProtectionProvider());
+ builder.UseDataProtectionProvider(new EphemeralDataProtectionProvider(new LoggerFactory()));
- var provider = services.BuildServiceProvider();
- var options = provider.GetRequiredService>();
+ var options = GetOptions(services);
// Assert
- Assert.IsType(typeof(EphemeralDataProtectionProvider), options.Value.DataProtectionProvider);
+ Assert.IsType(options.DataProtectionProvider);
}
[Fact]
public void UseJsonWebTokens_AccessTokenHandlerIsCorrectlySet()
{
// Arrange
- var services = new ServiceCollection();
- services.AddOptions();
-
+ var services = CreateServices();
var builder = new OpenIddictBuilder(services);
// Act
builder.UseJsonWebTokens();
- var provider = services.BuildServiceProvider();
- var options = provider.GetRequiredService>();
+ var options = GetOptions(services);
// Assert
- Assert.IsType(typeof(JwtSecurityTokenHandler), options.Value.AccessTokenHandler);
+ Assert.IsType(options.AccessTokenHandler);
+ }
+
+ private static IServiceCollection CreateServices()
+ {
+ var services = new ServiceCollection();
+ services.AddAuthentication();
+ services.AddDistributedMemoryCache();
+ services.AddLogging();
+ services.AddSingleton();
+
+ return services;
+ }
+
+ private static OpenIddictOptions GetOptions(IServiceCollection services)
+ {
+ services.RemoveAll>();
+ services.RemoveAll>();
+
+ var provider = services.BuildServiceProvider();
+
+ var options = provider.GetRequiredService>();
+ return options.Get(OpenIdConnectServerDefaults.AuthenticationScheme);
}
}
}
diff --git a/test/OpenIddict.Tests/OpenIddictInitializerTests.cs b/test/OpenIddict.Tests/OpenIddictInitializerTests.cs
new file mode 100644
index 00000000..6f527ae2
--- /dev/null
+++ b/test/OpenIddict.Tests/OpenIddictInitializerTests.cs
@@ -0,0 +1,164 @@
+using System;
+using System.Threading.Tasks;
+using AspNet.Security.OpenIdConnect.Client;
+using AspNet.Security.OpenIdConnect.Primitives;
+using AspNet.Security.OpenIdConnect.Server;
+using Microsoft.AspNetCore.Authentication;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.TestHost;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Logging;
+using Xunit;
+
+namespace OpenIddict.Tests
+{
+ public class OpenIddictInitializerTests
+ {
+ [Fact]
+ public async Task PostConfigure_ThrowsAnExceptionWhenNoFlowIsEnabled()
+ {
+ // Arrange
+ var server = CreateAuthorizationServer(builder =>
+ {
+ builder.Configure(options => { });
+ });
+
+ var client = new OpenIdConnectClient(server.CreateClient());
+
+ // Act and assert
+ var exception = await Assert.ThrowsAsync(delegate
+ {
+ return client.GetAsync("/");
+ });
+
+ // Assert
+ Assert.Equal("At least one OAuth2/OpenID Connect flow must be enabled.", exception.Message);
+ }
+
+ [Theory]
+ [InlineData(OpenIdConnectConstants.GrantTypes.AuthorizationCode)]
+ [InlineData(OpenIdConnectConstants.GrantTypes.Implicit)]
+ public async Task PostConfigure_ThrowsAnExceptionWhenAuthorizationEndpointIsDisabled(string flow)
+ {
+ // Arrange
+ var server = CreateAuthorizationServer(builder =>
+ {
+ builder.Configure(options => options.GrantTypes.Add(flow))
+ .Configure(options => options.AuthorizationEndpointPath = PathString.Empty);
+ });
+
+ var client = new OpenIdConnectClient(server.CreateClient());
+
+ // Act and assert
+ var exception = await Assert.ThrowsAsync(delegate
+ {
+ return client.GetAsync("/");
+ });
+
+ 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 async Task PostConfigure_ThrowsAnExceptionWhenTokenEndpointIsDisabled(string flow)
+ {
+ // Arrange
+ var server = CreateAuthorizationServer(builder =>
+ {
+ builder.EnableAuthorizationEndpoint("/connect/authorize")
+ .Configure(options => options.GrantTypes.Add(flow))
+ .Configure(options => options.TokenEndpointPath = PathString.Empty);
+ });
+
+ var client = new OpenIdConnectClient(server.CreateClient());
+
+ // Act and assert
+ var exception = await Assert.ThrowsAsync(delegate
+ {
+ return client.GetAsync("/");
+ });
+
+ Assert.Equal("The token endpoint must be enabled to use the authorization code, " +
+ "client credentials, password and refresh token flows.", exception.Message);
+ }
+
+ [Fact]
+ public async Task PostConfigure_ThrowsAnExceptionWhenTokenRevocationIsDisabled()
+ {
+ // Arrange
+ var server = CreateAuthorizationServer(builder =>
+ {
+ builder.EnableAuthorizationEndpoint("/connect/authorize")
+ .EnableRevocationEndpoint("/connect/revocation")
+ .AllowImplicitFlow()
+ .DisableTokenRevocation();
+ });
+
+ var client = new OpenIdConnectClient(server.CreateClient());
+
+ // Act and assert
+ var exception = await Assert.ThrowsAsync(delegate
+ {
+ return client.GetAsync("/");
+ });
+
+ Assert.Equal("The revocation endpoint cannot be enabled when token revocation is disabled.", exception.Message);
+ }
+
+ [Fact]
+ public async Task PostConfigure_ThrowsAnExceptionWhenNoSigningKeyIsRegisteredIfTheImplicitFlowIsEnabled()
+ {
+ // Arrange
+ var server = CreateAuthorizationServer(builder =>
+ {
+ builder.EnableAuthorizationEndpoint("/connect/authorize")
+ .AllowImplicitFlow();
+ });
+
+ var client = new OpenIdConnectClient(server.CreateClient());
+
+ // Act and assert
+ var exception = await Assert.ThrowsAsync(delegate
+ {
+ return client.GetAsync("/");
+ });
+
+ 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);
+ }
+
+ private static TestServer CreateAuthorizationServer(Action configuration = null)
+ {
+ var builder = new WebHostBuilder();
+
+ builder.UseEnvironment("Testing");
+
+ builder.ConfigureLogging(options => options.AddDebug());
+
+ builder.ConfigureServices(services =>
+ {
+ services.AddAuthentication();
+ services.AddOptions();
+ services.AddDistributedMemoryCache();
+
+ services.AddOpenIddict(options => configuration?.Invoke(options));
+ });
+
+ builder.Configure(app =>
+ {
+ app.UseAuthentication();
+
+ app.Run(context => context.ChallengeAsync(OpenIdConnectServerDefaults.AuthenticationScheme));
+ });
+
+ return new TestServer(builder);
+ }
+ }
+}
diff --git a/test/OpenIddict.Tests/OpenIddictProviderTests.Authentication.cs b/test/OpenIddict.Tests/OpenIddictProviderTests.Authentication.cs
index c6c39607..567767c8 100644
--- a/test/OpenIddict.Tests/OpenIddictProviderTests.Authentication.cs
+++ b/test/OpenIddict.Tests/OpenIddictProviderTests.Authentication.cs
@@ -521,7 +521,8 @@ namespace OpenIddict.Tests
cache.Verify(mock => mock.SetAsync(
OpenIddictConstants.Environment.AuthorizationRequest + identifier,
It.IsAny(),
- It.IsAny()), Times.Once());
+ It.IsAny(),
+ It.IsAny()), Times.Once());
}
[Theory]
@@ -596,7 +597,7 @@ namespace OpenIddict.Tests
};
var stream = new MemoryStream();
- using (var writer = new BsonWriter(stream))
+ using (var writer = new BsonDataWriter(stream))
{
writer.CloseOutput = false;
@@ -606,8 +607,9 @@ namespace OpenIddict.Tests
var cache = new Mock();
- cache.Setup(mock => mock.GetAsync(OpenIddictConstants.Environment.AuthorizationRequest +
- "b2ee7815-5579-4ff7-86b0-ba671b939d96"))
+ cache.Setup(mock => mock.GetAsync(
+ OpenIddictConstants.Environment.AuthorizationRequest + "b2ee7815-5579-4ff7-86b0-ba671b939d96",
+ It.IsAny()))
.ReturnsAsync(stream.ToArray());
var server = CreateAuthorizationServer(builder =>
@@ -646,8 +648,8 @@ namespace OpenIddict.Tests
Assert.NotNull(response.AccessToken);
cache.Verify(mock => mock.RemoveAsync(
- OpenIddictConstants.Environment.AuthorizationRequest +
- "b2ee7815-5579-4ff7-86b0-ba671b939d96"), Times.Once());
+ OpenIddictConstants.Environment.AuthorizationRequest + "b2ee7815-5579-4ff7-86b0-ba671b939d96",
+ It.IsAny()), Times.Once());
}
[Fact]
diff --git a/test/OpenIddict.Tests/OpenIddictProviderTests.Exchange.cs b/test/OpenIddict.Tests/OpenIddictProviderTests.Exchange.cs
index 35cc7264..33fedc91 100644
--- a/test/OpenIddict.Tests/OpenIddictProviderTests.Exchange.cs
+++ b/test/OpenIddict.Tests/OpenIddictProviderTests.Exchange.cs
@@ -8,7 +8,6 @@ using AspNet.Security.OpenIdConnect.Server;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
-using Microsoft.AspNetCore.Http.Authentication;
using Microsoft.Extensions.DependencyInjection;
using Moq;
using OpenIddict.Core;
diff --git a/test/OpenIddict.Tests/OpenIddictProviderTests.Introspection.cs b/test/OpenIddict.Tests/OpenIddictProviderTests.Introspection.cs
index 0d050c08..2577952c 100644
--- a/test/OpenIddict.Tests/OpenIddictProviderTests.Introspection.cs
+++ b/test/OpenIddict.Tests/OpenIddictProviderTests.Introspection.cs
@@ -9,7 +9,6 @@ using AspNet.Security.OpenIdConnect.Server;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
-using Microsoft.AspNetCore.Http.Authentication;
using Microsoft.Extensions.DependencyInjection;
using Moq;
using OpenIddict.Core;
diff --git a/test/OpenIddict.Tests/OpenIddictProviderTests.Revocation.cs b/test/OpenIddict.Tests/OpenIddictProviderTests.Revocation.cs
index 33492f1f..740141ce 100644
--- a/test/OpenIddict.Tests/OpenIddictProviderTests.Revocation.cs
+++ b/test/OpenIddict.Tests/OpenIddictProviderTests.Revocation.cs
@@ -10,7 +10,6 @@ using AspNet.Security.OpenIdConnect.Primitives;
using AspNet.Security.OpenIdConnect.Server;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Builder;
-using Microsoft.AspNetCore.Http.Authentication;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.IdentityModel.Tokens;
using Moq;
diff --git a/test/OpenIddict.Tests/OpenIddictProviderTests.Session.cs b/test/OpenIddict.Tests/OpenIddictProviderTests.Session.cs
index e13b94fb..aa272c0b 100644
--- a/test/OpenIddict.Tests/OpenIddictProviderTests.Session.cs
+++ b/test/OpenIddict.Tests/OpenIddictProviderTests.Session.cs
@@ -126,7 +126,8 @@ namespace OpenIddict.Tests
cache.Verify(mock => mock.SetAsync(
OpenIddictConstants.Environment.LogoutRequest + identifier,
It.IsAny(),
- It.IsAny()), Times.Once());
+ It.IsAny(),
+ It.IsAny()), Times.Once());
}
[Fact]
diff --git a/test/OpenIddict.Tests/OpenIddictProviderTests.cs b/test/OpenIddict.Tests/OpenIddictProviderTests.cs
index eb93fafc..ad04f052 100644
--- a/test/OpenIddict.Tests/OpenIddictProviderTests.cs
+++ b/test/OpenIddict.Tests/OpenIddictProviderTests.cs
@@ -12,7 +12,6 @@ using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Diagnostics;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
-using Microsoft.AspNetCore.Http.Authentication;
using Microsoft.AspNetCore.TestHost;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
@@ -44,46 +43,66 @@ namespace OpenIddict.Tests
builder.ConfigureServices(services =>
{
- services.AddAuthentication();
services.AddOptions();
+ services.AddDistributedMemoryCache();
- var instance = services.AddOpenIddict()
+ // Note: the following client_id/client_secret are fake and are only
+ // used to test the metadata returned by the discovery endpoint.
+ services.AddAuthentication()
+ .AddFacebook(options =>
+ {
+ options.ClientId = "16018790-E88E-4553-8036-BB342579FF19";
+ options.ClientSecret = "3D6499AF-5607-489B-815A-F3ACF1617296";
+ options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
+ })
+
+ .AddGoogle(options =>
+ {
+ options.ClientId = "BAF437A5-87FA-4D06-8EFD-F9BA96CCEDC4";
+ options.ClientSecret = "27DF07D3-6B03-4EE0-95CD-3AC16782216B";
+ options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
+ });
+
+ // Replace the default OpenIddict managers.
+ services.AddSingleton(CreateApplicationManager());
+ services.AddSingleton(CreateAuthorizationManager());
+ services.AddSingleton(CreateTokenManager());
+
+ services.AddOpenIddict(options =>
+ {
// Disable the transport security requirement during testing.
- .DisableHttpsRequirement()
+ options.DisableHttpsRequirement();
// Enable the tested endpoints.
- .EnableAuthorizationEndpoint(AuthorizationEndpoint)
- .EnableIntrospectionEndpoint(IntrospectionEndpoint)
- .EnableLogoutEndpoint(LogoutEndpoint)
- .EnableRevocationEndpoint(RevocationEndpoint)
- .EnableTokenEndpoint(TokenEndpoint)
- .EnableUserinfoEndpoint(UserinfoEndpoint)
+ options.EnableAuthorizationEndpoint(AuthorizationEndpoint)
+ .EnableIntrospectionEndpoint(IntrospectionEndpoint)
+ .EnableLogoutEndpoint(LogoutEndpoint)
+ .EnableRevocationEndpoint(RevocationEndpoint)
+ .EnableTokenEndpoint(TokenEndpoint)
+ .EnableUserinfoEndpoint(UserinfoEndpoint);
// Enable the tested flows.
- .AllowAuthorizationCodeFlow()
- .AllowClientCredentialsFlow()
- .AllowImplicitFlow()
- .AllowPasswordFlow()
- .AllowRefreshTokenFlow()
+ options.AllowAuthorizationCodeFlow()
+ .AllowClientCredentialsFlow()
+ .AllowImplicitFlow()
+ .AllowPasswordFlow()
+ .AllowRefreshTokenFlow();
// Register the X.509 certificate used to sign the identity tokens.
- .AddSigningCertificate(
+ options.AddSigningCertificate(
assembly: typeof(OpenIddictProviderTests).GetTypeInfo().Assembly,
resource: "OpenIddict.Tests.Certificate.pfx",
- password: "OpenIddict")
+ 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.
- .UseDataProtectionProvider(new EphemeralDataProtectionProvider());
+ options.UseDataProtectionProvider(new EphemeralDataProtectionProvider(new LoggerFactory()));
- // Replace the default application/token managers.
- services.AddSingleton(CreateApplicationManager());
- services.AddSingleton(CreateTokenManager());
-
- // Run the configuration delegate
- // registered by the unit tests.
- configuration?.Invoke(instance);
+ // Run the configuration delegate
+ // registered by the unit tests.
+ configuration?.Invoke(options);
+ });
});
builder.Configure(app =>
@@ -110,25 +129,7 @@ namespace OpenIddict.Tests
return next(context);
});
- app.UseCookieAuthentication();
-
- // Note: the following client_id/client_secret are fake and are only
- // used to test the metadata returned by the discovery endpoint.
- app.UseFacebookAuthentication(new FacebookOptions
- {
- ClientId = "16018790-E88E-4553-8036-BB342579FF19",
- ClientSecret = "3D6499AF-5607-489B-815A-F3ACF1617296",
- SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme
- });
-
- app.UseGoogleAuthentication(new GoogleOptions
- {
- ClientId = "BAF437A5-87FA-4D06-8EFD-F9BA96CCEDC4",
- ClientSecret = "27DF07D3-6B03-4EE0-95CD-3AC16782216B",
- SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme
- });
-
- app.UseOpenIddict();
+ app.UseAuthentication();
app.Run(context =>
{
@@ -147,12 +148,12 @@ namespace OpenIddict.Tests
ticket.SetProperty(OpenIddictConstants.Properties.AuthorizationId, "1AF06AB2-A0FC-4E3D-86AF-E04DA8C7BE70");
- return context.Authentication.SignInAsync(ticket.AuthenticationScheme, ticket.Principal, ticket.Properties);
+ return context.SignInAsync(ticket.AuthenticationScheme, ticket.Principal, ticket.Properties);
}
else if (request.IsLogoutRequest())
{
- return context.Authentication.SignOutAsync(OpenIdConnectServerDefaults.AuthenticationScheme);
+ return context.SignOutAsync(OpenIdConnectServerDefaults.AuthenticationScheme);
}
else if (request.IsUserinfoRequest())