public void Configure(string name, OpenIddictValidationOptions options) { // Ignore validation handler instances that don't correspond to the instance managed by the OpenID module. if (!string.Equals(name, OpenIddictValidationDefaults.AuthenticationScheme)) { return; } var settings = GetValidationSettingsAsync().GetAwaiter().GetResult(); if (settings == null) { return; } // If the tokens are issued by an authorization server located in a separate tenant, // resolve the isolated data protection provider associated with the specified tenant. if (!string.IsNullOrEmpty(settings.Tenant) && !string.Equals(settings.Tenant, _shellSettings.Name)) { _shellHost.GetScopeAsync(settings.Tenant).GetAwaiter().GetResult().UsingAsync(async scope => { // If the other tenant is released, ensure the current tenant is also restarted as it // relies on a data protection provider whose lifetime is managed by the other tenant. // To make sure the other tenant is not disposed before all the pending requests are // processed by the current tenant, a tenant dependency is manually added. scope.ShellContext.AddDependentShell(await _shellHost.GetOrCreateShellContextAsync(_shellSettings)); // Note: the data protection provider is always registered as a singleton and thus will // survive the current scope, which is mainly used to prevent the other tenant from being // released before we have a chance to declare the current tenant as a dependent tenant. options.DataProtectionProvider = scope.ServiceProvider.GetDataProtectionProvider(); }).GetAwaiter().GetResult(); } // Don't allow the current tenant to choose the valid audiences, as this would // otherwise allow it to introspect tokens meant to be used with another tenant. options.Audiences.Add(OpenIdConstants.Prefixes.Tenant + _shellSettings.Name); CreateTenantScope(settings.Tenant).UsingAsync(async scope => { var service = scope.ServiceProvider.GetService <IOpenIdServerService>(); if (service == null) { return; } var configuration = await GetServerSettingsAsync(service); if (configuration == null) { return; } options.UseReferenceTokens = configuration.UseReferenceTokens; }).GetAwaiter().GetResult(); }
public void Configure(OpenIddictValidationOptions options) { if (options is null) { throw new ArgumentNullException(nameof(options)); } // Register the built-in event handlers used by the OpenIddict ASP.NET Core validation components. options.Handlers.AddRange(OpenIddictValidationAspNetCoreHandlers.DefaultHandlers); }
public void Configure(string name, OpenIddictValidationOptions options) { // Ignore validation handler instances that don't correspond to the private instance managed by the OpenID module. if (!string.Equals(name, OpenIdConstants.Schemes.Userinfo)) { return; } options.Audiences.Add(OpenIdConstants.Prefixes.Tenant + _shellSettings.Name); }
public void Configure([NotNull] OpenIddictValidationOptions options) { if (options == null) { throw new ArgumentNullException(nameof(options)); } // Register the built-in event handlers used by the OpenIddict ASP.NET Core validation components. foreach (var handler in OpenIddictValidationAspNetCoreHandlers.DefaultHandlers) { options.DefaultHandlers.Add(handler); } }
public void Configure(string name, OpenIddictValidationOptions options) { // Ignore validation handler instances that don't correspond to the private instance managed by the OpenID module. if (!string.Equals(name, OpenIdConstants.Schemes.Userinfo)) { return; } options.Audiences.Add(OpenIdConstants.Prefixes.Tenant + _shellSettings.Name); var serverSettings = GetServerSettingsAsync().GetAwaiter().GetResult(); if (serverSettings == null) { return; } options.UseReferenceTokens = serverSettings.UseReferenceTokens; }
/// <summary> /// Populates the default OpenIddict validation options and ensure /// that the configuration is in a consistent and valid state. /// </summary> /// <param name="name">The authentication scheme associated with the handler instance.</param> /// <param name="options">The options instance to initialize.</param> public void PostConfigure([NotNull] string name, [NotNull] OpenIddictValidationOptions 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)); } if (options.EventsType == null || options.EventsType != typeof(OpenIddictValidationProvider)) { throw new InvalidOperationException(new StringBuilder() .AppendLine("OpenIddict can only be used with its built-in validation provider.") .AppendLine("This error may indicate that 'OpenIddictValidationOptions.EventsType' was manually set.") .Append("To execute custom request handling logic, consider registering an event handler using ") .Append("the generic 'services.AddOpenIddict().AddValidation().AddEventHandler()' method.") .ToString()); } if (options.DataProtectionProvider == null) { options.DataProtectionProvider = _dataProtectionProvider; } if (options.UseReferenceTokens && options.AccessTokenFormat == null) { var protector = options.DataProtectionProvider.CreateProtector( "OpenIdConnectServerHandler", nameof(options.AccessTokenFormat), nameof(options.UseReferenceTokens), "ASOS"); options.AccessTokenFormat = new TicketDataFormat(protector); } }
public void Configure(OpenIddictValidationOptions options) { var settings = GetValidationSettingsAsync().GetAwaiter().GetResult(); if (settings == null) { return; } // If the tokens are issued by an authorization server located in an Orchard tenant, retrieve the // authority and the signing key and register them in the token validation parameters to prevent // the handler from using an HTTP call to retrieve the discovery document from the other tenant. // Otherwise, set the authority to allow the handler to retrieve the endpoint URLs/signing keys // from the remote server's metadata by sending an OpenID Connect/OAuth 2.0 discovery request. if (settings.Authority != null) { options.Issuer = settings.Authority; options.Audiences.Add(settings.Audience); // Note: OpenIddict 3.0 only accepts tokens issued with a non-empty token type (e.g "at+jwt") // or with the generic "JWT" type and a special "token_type" claim containing the actual type // for backward compatibility, which matches the recommended best practices and helps prevent // token substitution attacks by ensuring JWT tokens of any other type are always rejected. // Unfortunately, most of the OAuth 2.0/OpenID Connect servers haven't been updated to emit // access tokens using the "at+jwt" token type header. To ensure the validation handler can still // be used with these servers, an option is provided to disable the token validation logic. // In this case, the received tokens are assumed to be access tokens (which is the only type // currently used in the API validation feature), no matter what their actual "typ" header is. if (settings.DisableTokenTypeValidation) { options.TokenValidationParameters.TypeValidator = (type, token, parameters) => JsonWebTokenTypes.AccessToken; } } // Note: the shell host guarantees that the OpenID server service resolved inside // this using block won't be disposed until the service scope itself is released. CreateTenantScope(settings.Tenant).UsingAsync(async scope => { var service = scope.ServiceProvider.GetService <IOpenIdServerService>(); if (service == null) { return; } var configuration = await GetServerSettingsAsync(service); if (configuration == null) { return; } options.Configuration = new OpenIdConnectConfiguration { Issuer = configuration.Authority?.AbsoluteUri }; // Import the signing keys from the OpenID server configuration. foreach (var key in await service.GetSigningKeysAsync()) { options.Configuration.SigningKeys.Add(key); } // Register the encryption keys used by the OpenID Connect server. foreach (var key in await service.GetEncryptionKeysAsync()) { options.EncryptionCredentials.Add(new EncryptingCredentials(key, SecurityAlgorithms.RsaOAEP, SecurityAlgorithms.Aes256CbcHmacSha512)); } // When the server is another tenant, don't allow the current tenant // to choose the valid audiences, as this would otherwise allow it // to validate/introspect tokens meant to be used with another tenant. options.Audiences.Add(OpenIdConstants.Prefixes.Tenant + _shellSettings.Name); // Note: token entry validation must be enabled to be able to validate reference tokens. options.EnableTokenEntryValidation = configuration.UseReferenceAccessTokens; // If an authority was explicitly set in the OpenID server options, // prefer it to the dynamic tenant comparison as it's more efficient. if (configuration.Authority != null) { options.TokenValidationParameters.ValidIssuer = configuration.Authority.AbsoluteUri; } else { options.TokenValidationParameters.IssuerValidator = (issuer, token, parameters) => { if (!Uri.TryCreate(issuer, UriKind.Absolute, out Uri uri)) { throw new SecurityTokenInvalidIssuerException("The token issuer is not valid."); } var tenant = _runningShellTable.Match(HostString.FromUriComponent(uri), uri.AbsolutePath); if (tenant == null || !string.Equals(tenant.Name, settings.Tenant)) { throw new SecurityTokenInvalidIssuerException("The token issuer is not valid."); } return(issuer); }; } }).GetAwaiter().GetResult(); }
public void Configure(OpenIddictValidationOptions options) => Debug.Fail("This infrastructure method shouldn't be called.");