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);
            }
        }
Example #7
0
        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.");