/// <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); }
/// <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); }
/// <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); }