/// <summary>
        /// Validates allowed CORS origins for valid format.
        /// </summary>
        /// <param name="context">The context.</param>
        /// <returns></returns>
        protected virtual Task ValidateAllowedCorsOriginsAsync(ClientConfigurationValidationContext context)
        {
            if (context.Client.AllowedCorsOrigins?.Any() == true)
            {
                foreach (var origin in context.Client.AllowedCorsOrigins)
                {
                    var fail = true;

                    if (!string.IsNullOrWhiteSpace(origin) && Uri.TryCreate(origin, UriKind.Absolute, out var uri))
                    {
                        if (uri.AbsolutePath == "/" && !origin.EndsWith("/"))
                        {
                            fail = false;
                        }
                    }

                    if (fail)
                    {
                        if (!string.IsNullOrWhiteSpace(origin))
                        {
                            context.SetError($"AllowedCorsOrigins contains invalid origin: {origin}");
                        }
                        else
                        {
                            context.SetError($"AllowedCorsOrigins contains invalid origin. There is an empty value.");
                        }
                        return(Task.CompletedTask);
                    }
                }
            }

            return(Task.CompletedTask);
        }
        /// <summary>
        /// Validates that URI schemes is not in the list of invalid URI scheme prefixes, as controlled by the ValidationOptions.
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        protected virtual Task ValidateUriSchemesAsync(ClientConfigurationValidationContext context)
        {
            // todo: null check for backwards compat; remove in 3.0
            if (_options != null)
            {
                if (context.Client.RedirectUris?.Any() == true)
                {
                    foreach (var uri in context.Client.RedirectUris)
                    {
                        if (_options.Validation.InvalidRedirectUriPrefixes
                            .Any(scheme => uri?.StartsWith(scheme, StringComparison.OrdinalIgnoreCase) == true))
                        {
                            context.SetError($"RedirectUri '{uri}' uses invalid scheme. If this scheme should be allowed, then configure it via ValidationOptions.");
                        }
                    }
                }

                if (context.Client.PostLogoutRedirectUris?.Any() == true)
                {
                    foreach (var uri in context.Client.PostLogoutRedirectUris)
                    {
                        if (_options.Validation.InvalidRedirectUriPrefixes
                            .Any(scheme => uri.StartsWith(scheme, StringComparison.OrdinalIgnoreCase)))
                        {
                            context.SetError($"PostLogoutRedirectUri '{uri}' uses invalid scheme. If this scheme should be allowed, then configure it via ValidationOptions.");
                        }
                    }
                }
            }

            return(Task.CompletedTask);
        }
Esempio n. 3
0
        /// <summary>
        /// Validates lifetime related configuration settings.
        /// </summary>
        /// <param name="context">The context.</param>
        /// <returns></returns>
        protected virtual Task ValidateLifetimesAsync(ClientConfigurationValidationContext context)
        {
            if (context.Client.AccessTokenLifetime <= 0)
            {
                context.SetError("access token lifetime is 0 or negative");
                return(Task.CompletedTask);
            }

            if (context.Client.IdentityTokenLifetime <= 0)
            {
                context.SetError("identity token lifetime is 0 or negative");
                return(Task.CompletedTask);
            }

            // 0 means unlimited lifetime
            if (context.Client.AbsoluteRefreshTokenLifetime < 0)
            {
                context.SetError("absolute refresh token lifetime is negative");
                return(Task.CompletedTask);
            }

            // 0 might mean that sliding is disabled
            if (context.Client.SlidingRefreshTokenLifetime < 0)
            {
                context.SetError("sliding refresh token lifetime is negative");
                return(Task.CompletedTask);
            }

            return(Task.CompletedTask);
        }
        /// <summary>
        /// Validates that URI schemes is not in the list of invalid URI scheme prefixes, as controlled by the ValidationOptions.
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        protected virtual Task ValidateUriSchemesAsync(ClientConfigurationValidationContext context)
        {
            if (context.Client.RedirectUris?.Any() == true)
            {
                foreach (var uri in context.Client.RedirectUris)
                {
                    if ((uri?.IsAbsoluteUri ?? true) && _options.Validation.InvalidRedirectUriPrefixes
                        .Any(scheme => string.Equals(uri?.Scheme, scheme, StringComparison.OrdinalIgnoreCase)))
                    {
                        context.SetError($"RedirectUri '{uri}' uses invalid scheme. If this scheme should be allowed, then configure it via ValidationOptions.");
                    }
                }
            }

            if (context.Client.PostLogoutRedirectUris?.Any() == true)
            {
                foreach (var uri in context.Client.PostLogoutRedirectUris)
                {
                    if (uri.IsAbsoluteUri && _options.Validation.InvalidRedirectUriPrefixes
                        .Any(scheme => string.Equals(uri.Scheme, scheme, StringComparison.OrdinalIgnoreCase)))
                    {
                        context.SetError($"PostLogoutRedirectUri '{uri}' uses invalid scheme. If this scheme should be allowed, then configure it via ValidationOptions.");
                    }
                }
            }

            return(Task.CompletedTask);
        }
        /// <summary>
        /// Validates grant type related configuration settings.
        /// </summary>
        /// <param name="context">The context.</param>
        /// <returns></returns>
        protected virtual Task ValidateGrantTypesAsync(ClientConfigurationValidationContext context)
        {
            if (context.Client.AllowedGrantTypes?.Any() != true)
            {
                context.SetError("no allowed grant type specified");
            }

            return(Task.CompletedTask);
        }
        /// <summary>
        /// Determines whether the configuration of a client is valid.
        /// </summary>
        /// <param name="context">The context.</param>
        /// <returns></returns>
        public async Task ValidateAsync(ClientConfigurationValidationContext context)
        {
            if (context.Client.ProtocolType == IdentityServerConstants.ProtocolTypes.OpenIdConnect)
            {
                await ValidateGrantTypesAsync(context);

                if (context.IsValid == false)
                {
                    return;
                }

                await ValidateLifetimesAsync(context);

                if (context.IsValid == false)
                {
                    return;
                }

                await ValidateRedirectUriAsync(context);

                if (context.IsValid == false)
                {
                    return;
                }

                await ValidateAllowedCorsOriginsAsync(context);

                if (context.IsValid == false)
                {
                    return;
                }

                await ValidateUriSchemesAsync(context);

                if (context.IsValid == false)
                {
                    return;
                }

                await ValidateSecretsAsync(context);

                if (context.IsValid == false)
                {
                    return;
                }

                await ValidatePropertiesAsync(context);

                if (context.IsValid == false)
                {
                    return;
                }
            }
        }
        /// <summary>
        /// Validates redirect URI related configuration.
        /// </summary>
        /// <param name="context">The context.</param>
        /// <returns></returns>
        protected virtual Task ValidateRedirectUriAsync(ClientConfigurationValidationContext context)
        {
            if (context.Client.AllowedGrantTypes.Contains(GrantType.AuthorizationCode) ||
                context.Client.AllowedGrantTypes.Contains(GrantType.Hybrid) ||
                context.Client.AllowedGrantTypes.Contains(GrantType.Implicit))
            {
                if (!context.Client.RedirectUris.Any())
                {
                    context.SetError("No redirect URI configured.");
                }
            }

            return(Task.CompletedTask);
        }
        /// <summary>
        /// Validates secret related configuration.
        /// </summary>
        /// <param name="context">The context.</param>
        /// <returns></returns>
        protected virtual Task ValidateSecretsAsync(ClientConfigurationValidationContext context)
        {
            foreach (var grantType in context.Client.AllowedGrantTypes)
            {
                if (!string.Equals(grantType, GrantType.Implicit))
                {
                    if (context.Client.RequireClientSecret && context.Client.ClientSecrets.Count == 0)
                    {
                        context.SetError($"Client secret is required for {grantType}, but no client secret is configured.");
                        return(Task.CompletedTask);
                    }
                }
            }

            return(Task.CompletedTask);
        }
        /// <summary>
        /// Determines whether the configuration of a client is valid.
        /// </summary>
        /// <param name="context">The context.</param>
        /// <returns></returns>
        public async Task ValidateAsync(ClientConfigurationValidationContext context)
        {
            await ValidateGrantTypesAsync(context);

            if (context.IsValid == false)
            {
                return;
            }

            await ValidateLifetimesAsync(context);

            if (context.IsValid == false)
            {
                return;
            }

            await ValidateRedirectUriAsync(context);

            if (context.IsValid == false)
            {
                return;
            }

            await ValidateUriSchemesAsync(context);

            if (context.IsValid == false)
            {
                return;
            }

            await ValidateSecretsAsync(context);

            if (context.IsValid == false)
            {
                return;
            }

            await ValidatePropertiesAsync(context);

            if (context.IsValid == false)
            {
                return;
            }
        }
        /// <summary>
        /// Validates allowed CORS origins for valid format.
        /// </summary>
        /// <param name="context">The context.</param>
        /// <returns></returns>
        protected virtual Task ValidateAllowedCorsOriginsAsync(ClientConfigurationValidationContext context)
        {
            if (context.Client.AllowedCorsOrigins?.Any() == true)
            {
                foreach (var origin in context.Client.AllowedCorsOrigins)
                {
                    var fail = true;

                    if (!String.IsNullOrWhiteSpace(origin) && Uri.TryCreate(origin, UriKind.Absolute, out var uri))
                    {
                        if (uri.Scheme.Equals("http", StringComparison.OrdinalIgnoreCase) ||
                            uri.Scheme.Equals("https", StringComparison.OrdinalIgnoreCase))
                        {
                            // http + :// + host/authority
                            var originLength = uri.Scheme.Length + 3 + uri.Authority.Length;
                            var path         = origin.Substring(originLength);
                            if (String.IsNullOrWhiteSpace(path))
                            {
                                fail = false;
                            }
                        }
                    }

                    if (fail)
                    {
                        if (!String.IsNullOrWhiteSpace(origin))
                        {
                            context.SetError($"AllowedCorsOrigins contains invalid origin: {origin}");
                        }
                        else
                        {
                            context.SetError($"AllowedCorsOrigins contains invalid origin. There is an empty value.");
                        }
                        return(Task.CompletedTask);
                    }
                }
            }

            return(Task.CompletedTask);
        }
 /// <summary>
 /// Validates properties related configuration settings.
 /// </summary>
 /// <param name="context">The context.</param>
 /// <returns></returns>
 protected virtual Task ValidatePropertiesAsync(ClientConfigurationValidationContext context)
 {
     return(Task.CompletedTask);
 }
Esempio n. 12
0
 /// <summary>
 /// Determines whether the configuration of a client is valid.
 /// </summary>
 /// <param name="context">The context.</param>
 /// <returns></returns>
 public Task ValidateAsync(ClientConfigurationValidationContext context)
 {
     context.IsValid = true;
     return(Task.CompletedTask);
 }