Versatile OpenID Connect stack for ASP.NET Core and Microsoft.Owin (compatible with ASP.NET 4.6.1)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

146 lines
6.2 KiB

/*
* 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 Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Protocols;
using Microsoft.IdentityModel.Tokens;
using OpenIddict.Extensions;
namespace OpenIddict.Validation;
/// <summary>
/// Contains the methods required to ensure that the OpenIddict validation configuration is valid.
/// </summary>
public sealed class OpenIddictValidationConfiguration : IPostConfigureOptions<OpenIddictValidationOptions>
{
private readonly OpenIddictValidationService _service;
/// <summary>
/// Creates a new instance of the <see cref="OpenIddictValidationConfiguration"/> class.
/// </summary>
/// <param name="service">The validation service.</param>
public OpenIddictValidationConfiguration(OpenIddictValidationService service)
=> _service = service ?? throw new ArgumentNullException(nameof(service));
/// <inheritdoc/>
public void PostConfigure(string? name, OpenIddictValidationOptions options)
{
if (options is null)
{
throw new ArgumentNullException(nameof(options));
}
if (options.JsonWebTokenHandler is null)
{
throw new InvalidOperationException(SR.GetResourceString(SR.ID0075));
}
if (options.Configuration is null && options.ConfigurationManager is null &&
options.Issuer is null && options.ConfigurationEndpoint is null)
{
throw new InvalidOperationException(SR.GetResourceString(SR.ID0128));
}
if (options.Issuer is not null)
{
if (!options.Issuer.IsAbsoluteUri || !options.Issuer.IsWellFormedOriginalString())
{
throw new InvalidOperationException(SR.GetResourceString(SR.ID0136));
}
if (!string.IsNullOrEmpty(options.Issuer.Fragment) || !string.IsNullOrEmpty(options.Issuer.Query))
{
throw new InvalidOperationException(SR.GetResourceString(SR.ID0137));
}
}
if (options.ValidationType is OpenIddictValidationType.Introspection)
{
if (!options.Handlers.Exists(static descriptor => descriptor.ContextType == typeof(ApplyIntrospectionRequestContext)))
{
throw new InvalidOperationException(SR.GetResourceString(SR.ID0129));
}
if (options.Issuer is null && options.ConfigurationEndpoint is null)
{
throw new InvalidOperationException(SR.GetResourceString(SR.ID0130));
}
if (string.IsNullOrEmpty(options.ClientId))
{
throw new InvalidOperationException(SR.GetResourceString(SR.ID0131));
}
if (string.IsNullOrEmpty(options.ClientSecret))
{
throw new InvalidOperationException(SR.GetResourceString(SR.ID0132));
}
if (options.EnableAuthorizationEntryValidation)
{
throw new InvalidOperationException(SR.GetResourceString(SR.ID0133));
}
if (options.EnableTokenEntryValidation)
{
throw new InvalidOperationException(SR.GetResourceString(SR.ID0134));
}
}
// If all the registered encryption credentials are backed by a X.509 certificate, at least one of them must be valid.
if (options.EncryptionCredentials.Count is not 0 &&
options.EncryptionCredentials.TrueForAll(credentials => credentials.Key is X509SecurityKey x509SecurityKey &&
(x509SecurityKey.Certificate.NotBefore > DateTime.Now || x509SecurityKey.Certificate.NotAfter < DateTime.Now)))
{
throw new InvalidOperationException(SR.GetResourceString(SR.ID0087));
}
if (options.ConfigurationManager is null)
{
if (options.Configuration is not null)
{
if (options.Configuration.Issuer is not null &&
options.Configuration.Issuer != options.Issuer)
{
throw new InvalidOperationException(SR.GetResourceString(SR.ID0394));
}
// Note: the issuer may be null. In this case, it will be usually provided by
// a validation handler registered by the host (e.g ASP.NET Core or OWIN/Katana).
options.Configuration.Issuer ??= options.Issuer;
options.ConfigurationManager = new StaticConfigurationManager<OpenIddictConfiguration>(options.Configuration);
}
else
{
if (!options.Handlers.Exists(static descriptor => descriptor.ContextType == typeof(ApplyConfigurationRequestContext)) ||
!options.Handlers.Exists(static descriptor => descriptor.ContextType == typeof(ApplyCryptographyRequestContext)))
{
throw new InvalidOperationException(SR.GetResourceString(SR.ID0135));
}
options.ConfigurationEndpoint = OpenIddictHelpers.CreateAbsoluteUri(
options.Issuer,
options.ConfigurationEndpoint ?? new Uri(".well-known/openid-configuration", UriKind.Relative));
options.ConfigurationManager = new ConfigurationManager<OpenIddictConfiguration>(
options.ConfigurationEndpoint.AbsoluteUri, new OpenIddictValidationRetriever(_service))
{
AutomaticRefreshInterval = ConfigurationManager<OpenIddictConfiguration>.DefaultAutomaticRefreshInterval,
RefreshInterval = ConfigurationManager<OpenIddictConfiguration>.DefaultRefreshInterval
};
}
}
// Sort the handlers collection using the order associated with each handler.
options.Handlers.Sort((left, right) => left.Order.CompareTo(right.Order));
// Attach the encryption credentials to the token validation parameters.
options.TokenValidationParameters.TokenDecryptionKeys =
from credentials in options.EncryptionCredentials
select credentials.Key;
}
}