public async Task <TokenRawResult> ProcessRawAsync(IFormCollection formCollection) { _logger.LogTrace("Processing token request."); var rawResult = new TokenRawResult(); // validate HTTP if (formCollection.IsNullOrEmpty()) { _logger.LogWarning($"Invalid {nameof(formCollection)} for token endpoint"); rawResult.TokenErrorResult = Error(OidcConstants.TokenErrors.InvalidRequest); return(rawResult); } var clientId = formCollection[OidcConstants.TokenRequest.ClientId]; var client = await _clients.FindEnabledClientByIdAsync(clientId); if (client == null) { _logger.LogError($"No client with id '{clientId}' found. aborting"); rawResult.TokenErrorResult = Error($"{OidcConstants.TokenRequest.ClientId} bad", $"No client with id '{clientId}' found. aborting"); return(rawResult); } var clientSecretValidationResult = new ClientSecretValidationResult { IsError = false, Client = client, Secret = null }; // validate request var form = formCollection.AsNameValueCollection(); _logger.LogTrace("Calling into token request validator: {type}", _requestValidator.GetType().FullName); var requestResult = await _requestValidator.ValidateRequestAsync(form, clientSecretValidationResult); if (requestResult.IsError) { await _events.RaiseAsync(new TokenIssuedFailureEvent(requestResult)); rawResult.TokenErrorResult = Error(requestResult.Error, requestResult.ErrorDescription, requestResult.CustomResponse); return(rawResult); } // create response _logger.LogTrace("Calling into token request response generator: {type}", _responseGenerator.GetType().FullName); var response = await _responseGenerator.ProcessAsync(requestResult); await _events.RaiseAsync(new TokenIssuedSuccessEvent(response, requestResult)); LogTokens(response, requestResult); // return result _logger.LogDebug("Token request success."); rawResult.TokenResult = new TokenResult(response); return(rawResult); }
public async Task <ClientSecretValidationResult> ValidateAsync(HttpContext context) { var fail = new ClientSecretValidationResult() { IsError = true, Error = OidcConstants.TokenErrors.InvalidClient, }; if (!_plugins.Any()) { await RaiseFailureEventAsync("unknown", "No client id found"); fail.ErrorDescription = "No IClientSecretValidatorPlugin were found!"; _logger.LogError(fail.ErrorDescription); return(fail); } var parsedSecret = await _parser.ParseAsync(context); if (parsedSecret == null) { await RaiseFailureEventAsync("unknown", "No client id found"); fail.ErrorDescription = "No client identifier found"; _logger.LogError(fail.ErrorDescription); return(fail); } // load client var client = await _clients.FindEnabledClientByIdAsync(parsedSecret.Id); if (client == null) { await RaiseFailureEventAsync(parsedSecret.Id, "Unknown client"); fail.ErrorDescription = $"No client with id '{parsedSecret.Id}' found. aborting"; _logger.LogError(fail.ErrorDescription); return(fail); } foreach (var plugin in _plugins) { var result = await plugin.ValidateAsync(context); if (result.IsError) { return(result); } } var success = new ClientSecretValidationResult { IsError = false, Client = client, Secret = parsedSecret }; return(success); }
/// <summary> /// Validates the current request. /// </summary> /// <param name="context">The context.</param> /// <returns></returns> public async Task <ClientSecretValidationResult> ValidateAsync(HttpContext context) { _logger.LogDebug("Start client validation"); var fail = new ClientSecretValidationResult { IsError = true }; var parsedSecret = await _parser.ParseAsync(context); if (parsedSecret == null) { await RaiseFailureEventAsync("unknown", "No client id found"); _logger.LogError("No client identifier found"); return(fail); } // load client var client = await _clients.FindEnabledClientByIdAsync(parsedSecret.Id); if (client == null) { await RaiseFailureEventAsync(parsedSecret.Id, "Unknown client"); _logger.LogError("No client with id '{clientId}' found. aborting", parsedSecret.Id); return(fail); } var form = (await context.Request.ReadFormAsync()).AsNameValueCollection(); var grantType = form.Get(OidcConstants.TokenRequest.GrantType); if (grantType == OidcConstants.GrantTypes.RefreshToken) { // upcast; ClientExtra clientExtra = client as ClientExtra; if (!clientExtra.RequireRefreshClientSecret) { _logger.LogDebug("Public Client - skipping secret validation success"); _logger.LogDebug("Client validation success"); var success = new ClientSecretValidationResult { IsError = false, Client = client, Secret = parsedSecret }; await RaiseSuccessEventAsync(client.ClientId, parsedSecret.Type); return(success); } } return(await StockClientSecretValidator.ValidateAsync(context)); }
public async Task <ClientSecretValidationResult> ValidateAsync(HttpContext context) { var fail = new ClientSecretValidationResult { IsError = true }; var parsedSecret = await ParseAsync(context); if (parsedSecret == null) { await RaiseFailureEventAsync("unknown", "No client id found"); return(fail); } var client = await _clients.FindEnabledClientByIdAsync(parsedSecret.Id); if (client == null) { await RaiseFailureEventAsync(parsedSecret.Id, "Unknown client"); return(fail); } SecretValidationResult secretValidationResult = null; if (client.RequireClientSecret || !client.IsImplicitOnly()) { secretValidationResult = await _validator.ValidateAsync(client.ClientSecrets, parsedSecret); if (secretValidationResult.Success == false) { await RaiseFailureEventAsync(client.ClientId, "Invalid client secret"); return(fail); } } var success = new ClientSecretValidationResult { IsError = false, Client = client, Secret = parsedSecret, Confirmation = secretValidationResult?.Confirmation }; await RaiseSuccessEventAsync(client.ClientId, parsedSecret.Type); return(success); }
/// <summary> /// Validates the current request. /// </summary> /// <param name="context">The context.</param> /// <returns></returns> public async Task <ClientSecretValidationResult> ValidateAsync(IDictionary <string, string> form) { _logger.LogDebug("Start client validation"); var fail = new ClientSecretValidationResult { IsError = true }; var parsedSecret = await _parser.ParseAsync(form); if (parsedSecret == null) { await RaiseFailureEventAsync("unknown", "No client id found"); _logger.LogError("No client identifier found"); return(fail); } // load client var client = await _clients.FindEnabledClientByIdAsync(parsedSecret.Id); if (client == null) { await RaiseFailureEventAsync(parsedSecret.Id, "Unknown client"); _logger.LogError("No client with id '{clientId}' found. aborting", parsedSecret.Id); return(fail); } if (!client.RequireClientSecret || client.IsImplicitOnly()) { _logger.LogDebug("Public Client - skipping secret validation success"); } else { var result = await _validator.ValidateAsync(parsedSecret, client.ClientSecrets); if (result.Success == false) { await RaiseFailureEventAsync(client.ClientId, "Invalid client secret"); _logger.LogError("Client secret validation failed for client: {clientId}.", client.ClientId); return(fail); } } _logger.LogDebug("Client validation success"); var success = new ClientSecretValidationResult { IsError = false, Client = client, Secret = parsedSecret }; await RaiseSuccessEventAsync(client.ClientId, parsedSecret.Type); return(success); }
public async Task <TokenRequestValidationResult> ValidateRequestAsync(NameValueCollection parameters, ClientSecretValidationResult clientValidationResult) { var grantType = parameters.Get(OidcConstants.TokenRequest.GrantType); _validatedRequest = new ValidatedTokenRequest { Raw = parameters ?? throw new ArgumentNullException(nameof(parameters)), Options = _options }; switch (grantType) { case OidcConstants.GrantTypes.AuthorizationCode: return(await RunValidationAsync(ValidateAuthorizationCodeRequestAsync, parameters)); case OidcConstants.GrantTypes.ClientCredentials: return(await RunValidationAsync(ValidateClientCredentialsRequestAsync, parameters)); case OidcConstants.GrantTypes.Password: return(await RunValidationAsync(ValidateResourceOwnerCredentialRequestAsync, parameters)); case OidcConstants.GrantTypes.RefreshToken: return(await RunValidationAsync(ValidateRefreshTokenRequestAsync, parameters)); case OidcConstants.GrantTypes.DeviceCode: return(await RunValidationAsync(ValidateDeviceCodeRequestAsync, parameters)); default: return(await RunValidationAsync(ValidateExtensionGrantRequestAsync, parameters)); } }
/// <summary> /// Validates the request. /// </summary> /// <param name="parameters">The parameters.</param> /// <param name="clientValidationResult">The client validation result.</param> /// <returns></returns> /// <exception cref="System.ArgumentNullException"> /// parameters /// or /// client /// </exception> public async Task <TokenRequestValidationResult> ValidateRequestAsync(NameValueCollection parameters, ClientSecretValidationResult clientValidationResult) { var result = await _inner.ValidateRequestAsync(parameters, clientValidationResult); if (!result.IsError) { if (result.ValidatedRequest.Subject?.IsAnonymous() == true) { result.ValidatedRequest.AccessTokenLifetime = _options.AccessTokenLifetime; } } return(result); }
public virtual async Task <IdentityUtilsResult <TokenResponse> > GetToken(TokenRequest request) { var config = HttpContext.RequestServices.GetService(typeof(IIdentityUtilsAuthenticationConfig)) as IIdentityUtilsAuthenticationConfig; request.ClientId = config?.ClientId ?? request.ClientId; HttpContext.Request.Form = new FormCollection(new Dictionary <string, StringValues> { { "client_id", request.ClientId }, { "grant_type", request.GrantType }, { "username", request.Username }, { "password", request.Password }, { "refresh_token", request.RefreshToken }, }); // validate client var client = await clientStore.FindEnabledClientByIdAsync(request.ClientId); var invalidClient = !client.AllowedGrantTypes.Intersect(GrantTypes.ResourceOwnerPassword).Any() && !(request.GrantType == AuthenticationConstants.GrantTypeRefreshToken); if (client == null || invalidClient) { return(IdentityUtilsResult <TokenResponse> .ErrorResult($"Client id not found or invalid grant type")); } var clientResult = new ClientSecretValidationResult { IsError = false, Client = client }; var form = new NameValueCollection { { "client_id", request.ClientId }, { "grant_type", request.GrantType }, { "refresh_token", request.RefreshToken }, { "username", request.Username }, { "password", request.Password }, }; // validate request var requestResult = await requestValidator.ValidateRequestAsync(form, clientResult); if (requestResult.IsError) { await events.RaiseAsync(new TokenIssuedFailureEvent(requestResult)); return(IdentityUtilsResult <TokenResponse> .ErrorResult($"{requestResult.Error} - {requestResult.ErrorDescription}")); } // create response var response = await responseGenerator.ProcessAsync(requestResult); await events.RaiseAsync(new TokenIssuedSuccessEvent(response, requestResult)); // return result var tokenResponse = new TokenResponse { AccessToken = response.AccessToken, RefreshToken = response.RefreshToken, Lifetime = response.AccessTokenLifetime, Scopes = response.Scope.Split(' ') }; return(IdentityUtilsResult <TokenResponse> .SuccessResult(tokenResponse)); }
public async Task <RevocationRawResult> ProcessRawRevocationAsync(IFormCollection formCollection) { _logger.LogTrace("Processing token request."); var rawResult = new RevocationRawResult() { StatusCodeResult = new StatusCodeResult(HttpStatusCode.BadRequest) }; // validate HTTP if (formCollection.IsNullOrEmpty()) { _logger.LogWarning($"Invalid {nameof(formCollection)} for token endpoint"); rawResult.ErrorResult = ErrorRevocation(OidcConstants.TokenErrors.InvalidRequest); return(rawResult); } var clientId = formCollection[OidcConstants.TokenRequest.ClientId]; var client = await _clients.FindEnabledClientByIdAsync(clientId); if (client == null) { _logger.LogError($"No client with id '{clientId}' found. aborting"); rawResult.ErrorResult = ErrorRevocation($"{OidcConstants.TokenRequest.ClientId} bad"); return(rawResult); } var clientValidationResult = new ClientSecretValidationResult { IsError = false, Client = client, Secret = null }; // validate request var form = formCollection.AsNameValueCollection(); _logger.LogTrace("Calling into token revocation request validator: {type}", _requestValidator.GetType().FullName); var requestValidationResult = await _revocationRequestValidator.ValidateRequestAsync(form, clientValidationResult.Client); if (requestValidationResult.IsError) { rawResult.ErrorResult = new TokenRevocationErrorResult(requestValidationResult.Error); return(rawResult); } _logger.LogTrace("Calling into token revocation response generator: {type}", _responseGenerator.GetType().FullName); var response = await _revocationResponseGenerator.ProcessAsync(requestValidationResult); if (response.Success) { _logger.LogInformation("Token successfully revoked"); await _events.RaiseAsync(new TokenRevokedSuccessEvent(requestValidationResult, requestValidationResult.Client)); } else { _logger.LogInformation("No matching token found"); } if (response.Error.IsPresent()) { rawResult.ErrorResult = new TokenRevocationErrorResult(response.Error); return(rawResult); } rawResult.StatusCodeResult = new StatusCodeResult(HttpStatusCode.OK); return(rawResult); }
/// <summary> /// Validates the current request. /// </summary> /// <param name="context">The context.</param> /// <returns></returns> public async Task <ClientSecretValidationResult> ValidateAsync(HttpContext context) { using var activity = Tracing.ValidationActivitySource.StartActivity("ClientSecretValidator.Validate"); _logger.LogDebug("Start client validation"); var fail = new ClientSecretValidationResult { IsError = true }; var parsedSecret = await _parser.ParseAsync(context); if (parsedSecret == null) { await RaiseFailureEventAsync("unknown", "No client id found"); _logger.LogError("No client identifier found"); return(fail); } // load client var client = await _clients.FindEnabledClientByIdAsync(parsedSecret.Id); if (client == null) { await RaiseFailureEventAsync(parsedSecret.Id, "Unknown client"); _logger.LogError("No client with id '{clientId}' found. aborting", parsedSecret.Id); return(fail); } SecretValidationResult secretValidationResult = null; if (!client.RequireClientSecret || client.IsImplicitOnly()) { _logger.LogDebug("Public Client - skipping secret validation success"); } else { secretValidationResult = await _validator.ValidateAsync(client.ClientSecrets, parsedSecret); if (secretValidationResult.Success == false) { await RaiseFailureEventAsync(client.ClientId, "Invalid client secret"); _logger.LogError("Client secret validation failed for client: {clientId}.", client.ClientId); return(fail); } } _logger.LogDebug("Client validation success"); var success = new ClientSecretValidationResult { IsError = false, Client = client, Secret = parsedSecret, Confirmation = secretValidationResult?.Confirmation }; await RaiseSuccessEventAsync(client.ClientId, parsedSecret.Type); return(success); }
/// <summary> /// Validates the current request. /// </summary> /// <param name="context">The context.</param> /// <returns></returns> public async Task <ClientSecretValidationResult> ValidateAsync(HttpContext context) { _logger.LogDebug("Start client validation"); var fail = new ClientSecretValidationResult { IsError = true }; var parsedSecret = await _parser.ParseAsync(context); if (parsedSecret == null) { await RaiseFailureEventAsync("unknown", "No client id found"); _logger.LogError("No client identifier found"); return(fail); } // load client var client = await _clients.FindEnabledClientByIdAsync(parsedSecret.Id) as ClientExtra; if (client == null) { await RaiseFailureEventAsync(parsedSecret.Id, $"Unknown client for tenant: '{_scopedTenantRequestContext.Context.TenantName}'"); _logger.LogError($"No client with id '{parsedSecret.Id}' for tenant: '{_scopedTenantRequestContext.Context.TenantName}' found. aborting"); return(fail); } SecretValidationResult secretValidationResult = null; if (!client.RequireClientSecret || client.IsImplicitOnly()) { _logger.LogDebug("Public Client - skipping secret validation success"); } else { //////////////////////////////////////// // Check if this is a refresh_token //////////////////////////////////////// bool continueValidation = true; if (!client.RequireRefreshClientSecret) { try { var parameters = (await context.Request.ReadFormAsync()).AsNameValueCollection(); var grantType = parameters.Get(OidcConstants.TokenRequest.GrantType); if (!string.IsNullOrWhiteSpace(grantType) && grantType == OidcConstants.GrantTypes.RefreshToken) { // let it through _logger.LogDebug("RequireRefreshClientSecret == false - skipping secret validation success"); continueValidation = false; } } catch (Exception ex) { // let it through _logger.LogDebug("RequireRefreshClientSecret == false - skipping secret validation success"); continueValidation = false; } } if (continueValidation) { secretValidationResult = await _validator.ValidateAsync(client.ClientSecrets, parsedSecret); if (secretValidationResult.Success == false) { await RaiseFailureEventAsync(client.ClientId, "Invalid client secret"); _logger.LogError("Client secret validation failed for client: {clientId}.", client.ClientId); return(fail); } } } _logger.LogDebug("Client validation success"); var success = new ClientSecretValidationResult { IsError = false, Client = client, Secret = parsedSecret, Confirmation = secretValidationResult?.Confirmation }; await RaiseSuccessEventAsync(client.ClientId, parsedSecret.Type); return(success); }
private DeviceAuthorizationRequestValidationResult ValidateClient(ValidatedDeviceAuthorizationRequest request, ClientSecretValidationResult clientValidationResult) { ////////////////////////////////////////////////////////// // set client & secret ////////////////////////////////////////////////////////// if (clientValidationResult == null) { throw new ArgumentNullException(nameof(clientValidationResult)); } request.SetClient(clientValidationResult.Client, clientValidationResult.Secret); ////////////////////////////////////////////////////////// // check if client protocol type is oidc ////////////////////////////////////////////////////////// if (request.Client.ProtocolType != IdentityServerConstants.ProtocolTypes.OpenIdConnect) { LogError("Invalid protocol type for OIDC authorize endpoint", request.Client.ProtocolType, request); return(Invalid(request, OidcConstants.AuthorizeErrors.UnauthorizedClient, "Invalid protocol")); } ////////////////////////////////////////////////////////// // check if client allows device flow ////////////////////////////////////////////////////////// if (!request.Client.AllowedGrantTypes.Contains(GrantType.DeviceFlow)) { LogError("Client not configured for device flow", GrantType.DeviceFlow, request); return(Invalid(request, OidcConstants.AuthorizeErrors.UnauthorizedClient)); } return(Valid(request)); }
public async Task <DeviceAuthorizationRequestValidationResult> ValidateAsync(NameValueCollection parameters, ClientSecretValidationResult clientValidationResult) { using var activity = Tracing.BasicActivitySource.StartActivity("DeviceAuthorizationRequestValidator.Validate"); _logger.LogDebug("Start device authorization request validation"); var request = new ValidatedDeviceAuthorizationRequest { Raw = parameters ?? throw new ArgumentNullException(nameof(parameters)), Options = _options }; var clientResult = ValidateClient(request, clientValidationResult); if (clientResult.IsError) { return(clientResult); } var scopeResult = await ValidateScopeAsync(request); if (scopeResult.IsError) { return(scopeResult); } _logger.LogDebug("{clientId} device authorization request validation success", request.Client.ClientId); return(Valid(request)); }
public Task <TokenRequestValidationResult> ValidateRequestAsync(NameValueCollection parameters, ClientSecretValidationResult clientValidationResult) { throw new NotImplementedException(); }
/// <summary> /// Validates the request. /// </summary> /// <param name="parameters">The parameters.</param> /// <param name="clientValidationResult">The client validation result.</param> /// <returns></returns> /// <exception cref="System.ArgumentNullException"> /// parameters /// or /// client /// </exception> public async Task <TokenRequestValidationResult> ValidateRequestAsync(NameValueCollection parameters, ClientSecretValidationResult clientValidationResult) { using var activity = Tracing.BasicActivitySource.StartActivity("TokenRequestValidator.ValidateRequest"); _logger.LogDebug("Start token request validation"); _validatedRequest = new ValidatedTokenRequest { IssuerName = await _issuerNameService.GetCurrentAsync(), Raw = parameters ?? throw new ArgumentNullException(nameof(parameters)), Options = _options }; if (clientValidationResult == null) { throw new ArgumentNullException(nameof(clientValidationResult)); } _validatedRequest.SetClient(clientValidationResult.Client, clientValidationResult.Secret, clientValidationResult.Confirmation); ///////////////////////////////////////////// // check client protocol type ///////////////////////////////////////////// if (_validatedRequest.Client.ProtocolType != IdentityServerConstants.ProtocolTypes.OpenIdConnect) { LogError("Invalid protocol type for client", new { clientId = _validatedRequest.Client.ClientId, expectedProtocolType = IdentityServerConstants.ProtocolTypes.OpenIdConnect, actualProtocolType = _validatedRequest.Client.ProtocolType }); return(Invalid(OidcConstants.TokenErrors.InvalidClient)); } ///////////////////////////////////////////// // check grant type ///////////////////////////////////////////// var grantType = parameters.Get(OidcConstants.TokenRequest.GrantType); if (grantType.IsMissing()) { LogError("Grant type is missing"); return(Invalid(OidcConstants.TokenErrors.UnsupportedGrantType)); } if (grantType.Length > _options.InputLengthRestrictions.GrantType) { LogError("Grant type is too long"); return(Invalid(OidcConstants.TokenErrors.UnsupportedGrantType)); } _validatedRequest.GrantType = grantType; ////////////////////////////////////////////////////////// // check for resource indicator and basic formatting ////////////////////////////////////////////////////////// var resourceIndicators = parameters.GetValues(OidcConstants.TokenRequest.Resource) ?? Enumerable.Empty <string>(); if (resourceIndicators?.Any(x => x.Length > _options.InputLengthRestrictions.ResourceIndicatorMaxLength) == true) { return(Invalid(OidcConstants.AuthorizeErrors.InvalidTarget, "Resource indicator maximum length exceeded")); } if (!resourceIndicators.AreValidResourceIndicatorFormat(_logger)) { return(Invalid(OidcConstants.AuthorizeErrors.InvalidTarget, "Invalid resource indicator format")); } if (resourceIndicators.Count() > 1) { return(Invalid(OidcConstants.AuthorizeErrors.InvalidTarget, "Multiple resource indicators not supported on token endpoint.")); } _validatedRequest.RequestedResourceIndicator = resourceIndicators.SingleOrDefault(); ////////////////////////////////////////////////////////// // run specific logic for grants ////////////////////////////////////////////////////////// switch (grantType) { case OidcConstants.GrantTypes.AuthorizationCode: return(await RunValidationAsync(ValidateAuthorizationCodeRequestAsync, parameters)); case OidcConstants.GrantTypes.ClientCredentials: return(await RunValidationAsync(ValidateClientCredentialsRequestAsync, parameters)); case OidcConstants.GrantTypes.Password: return(await RunValidationAsync(ValidateResourceOwnerCredentialRequestAsync, parameters)); case OidcConstants.GrantTypes.RefreshToken: return(await RunValidationAsync(ValidateRefreshTokenRequestAsync, parameters)); case OidcConstants.GrantTypes.DeviceCode: return(await RunValidationAsync(ValidateDeviceCodeRequestAsync, parameters)); case OidcConstants.GrantTypes.Ciba: return(await RunValidationAsync(ValidateCibaRequestRequestAsync, parameters)); default: return(await RunValidationAsync(ValidateExtensionGrantRequestAsync, parameters)); } }
/// <summary> /// 登录校验密钥 /// </summary> /// <param name="context"></param> /// <returns></returns> public async Task <ClientSecretValidationResult> ValidateAsync(HttpContext context) { var _signInManager = (SignInManager <ApplicationUser>)context.RequestServices.GetService(typeof(SignInManager <ApplicationUser>)); _logger.LogDebug("Start client validation"); //错误返回 var fail = new ClientSecretValidationResult { IsError = true }; //根据上下文查找密钥 var parsedSecret = await _parser.ParseAsync(context); if (parsedSecret == null) { await RaiseFailureEventAsync("unknown", "No client id found"); _logger.LogError("No client identifier found"); return(fail); } // 加载客户端配置 var client = await _clients.FindEnabledClientByIdAsync(parsedSecret.Id); if (client == null) { await RaiseFailureEventAsync(parsedSecret.Id, "Unknown client"); _logger.LogError("No client with id '{clientId}' found. aborting", parsedSecret.Id); return(fail); } SecretValidationResult secretValidationResult = null; if (!client.RequireClientSecret || client.IsImplicitOnly()) { _logger.LogDebug("Public Client - skipping secret validation success"); } else { //验证客户端密钥 secretValidationResult = await _validator.ValidateAsync(parsedSecret, client.ClientSecrets); if (secretValidationResult.Success == false) { await RaiseFailureEventAsync(client.ClientId, "Invalid client secret"); _logger.LogError("Client secret validation failed for client: {clientId}.", client.ClientId); return(fail); } } _logger.LogDebug("Client validation success"); //var user = await _signInManager.UserManager.FindByNameAsync(context.User.Identity.Name); //var claimsPrincipal = await _signInManager.ClaimsFactory.CreateAsync(user); var success = new ClientSecretValidationResult { IsError = false, Client = client, Secret = parsedSecret, Confirmation = secretValidationResult?.Confirmation }; await RaiseSuccessEventAsync(client.ClientId, parsedSecret.Type); return(success); }
/// <summary> /// Validates the request. /// </summary> /// <param name="parameters">The parameters.</param> /// <param name="clientValidationResult">The client validation result.</param> /// <returns></returns> /// <exception cref="System.ArgumentNullException"> /// parameters /// or /// client /// </exception> public async Task <TokenRequestValidationResult> ValidateRequestAsync(NameValueCollection parameters, ClientSecretValidationResult clientValidationResult) { _logger.LogDebug("Start token request validation"); _validatedRequest = new ValidatedTokenRequest { Raw = parameters ?? throw new ArgumentNullException(nameof(parameters)), Options = _options }; if (clientValidationResult == null) { throw new ArgumentNullException(nameof(clientValidationResult)); } _validatedRequest.SetClient(clientValidationResult.Client, clientValidationResult.Secret, clientValidationResult.Confirmation); ///////////////////////////////////////////// // check client protocol type ///////////////////////////////////////////// if (_validatedRequest.Client.ProtocolType != IdentityServerConstants.ProtocolTypes.OpenIdConnect) { LogError("Invalid protocol type for client", new { clientId = _validatedRequest.Client.ClientId, expectedProtocolType = IdentityServerConstants.ProtocolTypes.OpenIdConnect, actualProtocolType = _validatedRequest.Client.ProtocolType }); return(Invalid(OidcConstants.TokenErrors.InvalidClient)); } ///////////////////////////////////////////// // check grant type ///////////////////////////////////////////// var grantType = parameters.Get(OidcConstants.TokenRequest.GrantType); if (grantType.IsMissing()) { LogError("Grant type is missing"); return(Invalid(OidcConstants.TokenErrors.UnsupportedGrantType)); } if (grantType.Length > _options.InputLengthRestrictions.GrantType) { LogError("Grant type is too long"); return(Invalid(OidcConstants.TokenErrors.UnsupportedGrantType)); } _validatedRequest.GrantType = grantType; switch (grantType) { //case OidcConstants.GrantTypes.AuthorizationCode: // return await RunValidationAsync(ValidateAuthorizationCodeRequestAsync, parameters); case OidcConstants.GrantTypes.ClientCredentials: return(await RunValidationAsync(ValidateClientCredentialsRequestAsync, parameters)); case OidcConstants.GrantTypes.Password: return(await RunValidationAsync(ValidateResourceOwnerCredentialRequestAsync, parameters)); case OidcConstants.GrantTypes.RefreshToken: return(await RunValidationAsync(ValidateRefreshTokenRequestAsync, parameters)); case OidcConstants.GrantTypes.DeviceCode: return(await RunValidationAsync(ValidateDeviceCodeRequestAsync, parameters)); default: return(await RunValidationAsync(ValidateExtensionGrantRequestAsync, parameters)); } }
/// <summary> /// Validates the current request. /// </summary> /// <param name="context">The context.</param> /// <returns></returns> public async Task <ClientSecretValidationResult> ValidateAsync(NameValueCollection nvc) { _logger.LogDebug("Start client validation"); var fail = new ClientSecretValidationResult { IsError = true }; var id = nvc.Get("client_id"); var secret = nvc.Get("client_secret"); ParsedSecret parsedSecret = null; // client id must be present if (id.IsPresent()) { if (id.Length > _options.InputLengthRestrictions.ClientId) { _logger.LogError("Client ID exceeds maximum length."); return(null); } if (secret.IsPresent()) { if (secret.Length > _options.InputLengthRestrictions.ClientSecret) { _logger.LogError("Client secret exceeds maximum length."); return(null); } parsedSecret = new ParsedSecret { Id = id, Credential = secret, Type = IdentityServerConstants.ParsedSecretTypes.SharedSecret }; } } if (parsedSecret == null) { await RaiseFailureEventAsync("unknown", "No client id found"); _logger.LogError("No client identifier found"); return(fail); } // load client var client = await _clients.FindEnabledClientByIdAsync(parsedSecret.Id); if (client == null) { await RaiseFailureEventAsync(parsedSecret.Id, "Unknown client"); _logger.LogError("No client with id '{clientId}' found. aborting", parsedSecret.Id); return(fail); } if (!client.RequireClientSecret) { _logger.LogDebug("Public Client - skipping secret validation success"); } else { var result = await _validator.ValidateAsync(parsedSecret, client.ClientSecrets); if (result.Success == false) { await RaiseFailureEventAsync(client.ClientId, "Invalid client secret"); _logger.LogError("Client secret validation failed for client: {clientId}.", client.ClientId); return(fail); } } _logger.LogDebug("Client validation success"); var success = new ClientSecretValidationResult { IsError = false, Client = client, Secret = parsedSecret }; await RaiseSuccessEventAsync(client.ClientId, parsedSecret.Type); return(success); }
public async Task <BackchannelAuthenticationRequestValidationResult> ValidateRequestAsync(NameValueCollection parameters, ClientSecretValidationResult clientValidationResult) { using var activity = Tracing.BasicActivitySource.StartActivity("BackchannelAuthenticationRequestValidator.ValidateRequest"); if (clientValidationResult == null) { throw new ArgumentNullException(nameof(clientValidationResult)); } _logger.LogDebug("Start backchannel authentication request validation"); _validatedRequest = new ValidatedBackchannelAuthenticationRequest { Raw = parameters ?? throw new ArgumentNullException(nameof(parameters)), Options = _options }; _validatedRequest.SetClient(clientValidationResult.Client, clientValidationResult.Secret, clientValidationResult.Confirmation); ////////////////////////////////////////////////////////// // Client must be configured for CIBA ////////////////////////////////////////////////////////// if (!clientValidationResult.Client.AllowedGrantTypes.Contains(OidcConstants.GrantTypes.Ciba)) { LogError("Client {clientId} not configured with the CIBA grant type.", clientValidationResult.Client.ClientId); return(Invalid(OidcConstants.BackchannelAuthenticationRequestErrors.UnauthorizedClient, "Unauthorized client")); } LicenseValidator.ValidateCiba(); ////////////////////////////////////////////////////////// // load request object ////////////////////////////////////////////////////////// var jwtRequest = _validatedRequest.Raw.Get(OidcConstants.BackchannelAuthenticationRequest.Request); // check length restrictions if (jwtRequest.IsPresent()) { if (jwtRequest.Length >= _options.InputLengthRestrictions.Jwt) { LogError("request value is too long"); return(Invalid(OidcConstants.AuthorizeErrors.InvalidRequestObject, "Invalid request value")); } } _validatedRequest.RequestObject = jwtRequest; ////////////////////////////////////////////////////////// // validate request object ////////////////////////////////////////////////////////// var roValidationResult = await TryValidateRequestObjectAsync(); if (!roValidationResult.Success) { return(roValidationResult.ErrorResult); } if (_validatedRequest.Client.RequireRequestObject && !_validatedRequest.RequestObjectValues.Any()) { LogError("Client is configured for RequireRequestObject but none present"); return(Invalid(OidcConstants.BackchannelAuthenticationRequestErrors.InvalidRequest)); } ////////////////////////////////////////////////////////// // scope must be present ////////////////////////////////////////////////////////// var scope = _validatedRequest.Raw.Get(OidcConstants.BackchannelAuthenticationRequest.Scope); if (scope.IsMissing()) { LogError("Missing scope"); return(Invalid(OidcConstants.BackchannelAuthenticationRequestErrors.InvalidRequest, "Missing scope")); } if (scope.Length > _options.InputLengthRestrictions.Scope) { LogError("scopes too long."); return(Invalid(OidcConstants.BackchannelAuthenticationRequestErrors.InvalidRequest, "Invalid scope")); } _validatedRequest.RequestedScopes = scope.FromSpaceSeparatedString().Distinct().ToList(); ////////////////////////////////////////////////////////// // openid scope required ////////////////////////////////////////////////////////// if (!_validatedRequest.RequestedScopes.Contains(IdentityServerConstants.StandardScopes.OpenId)) { LogError("openid scope missing."); return(Invalid(OidcConstants.BackchannelAuthenticationRequestErrors.InvalidRequest, "Missing the openid scope")); } ////////////////////////////////////////////////////////// // check for resource indicators and valid format ////////////////////////////////////////////////////////// var resourceIndicators = _validatedRequest.Raw.GetValues("resource") ?? Enumerable.Empty <string>(); if (resourceIndicators?.Any(x => x.Length > _options.InputLengthRestrictions.ResourceIndicatorMaxLength) == true) { return(Invalid(OidcConstants.BackchannelAuthenticationRequestErrors.InvalidTarget, "Resource indicator maximum length exceeded")); } if (!resourceIndicators.AreValidResourceIndicatorFormat(_logger)) { return(Invalid(OidcConstants.BackchannelAuthenticationRequestErrors.InvalidTarget, "Invalid resource indicator format")); } _validatedRequest.RequestedResourceIndiators = resourceIndicators?.ToList(); ////////////////////////////////////////////////////////// // check if scopes are valid/supported and check for resource scopes ////////////////////////////////////////////////////////// var validatedResources = await _resourceValidator.ValidateRequestedResourcesAsync(new ResourceValidationRequest { Client = _validatedRequest.Client, Scopes = _validatedRequest.RequestedScopes, ResourceIndicators = resourceIndicators, IncludeNonIsolatedApiResources = _validatedRequest.RequestedScopes.Contains(OidcConstants.StandardScopes.OfflineAccess), }); if (!validatedResources.Succeeded) { if (validatedResources.InvalidResourceIndicators.Any()) { return(Invalid(OidcConstants.BackchannelAuthenticationRequestErrors.InvalidTarget, "Invalid resource indicator")); } if (validatedResources.InvalidScopes.Any()) { return(Invalid(OidcConstants.BackchannelAuthenticationRequestErrors.InvalidScope, "Invalid scope")); } } LicenseValidator.ValidateResourceIndicators(resourceIndicators); _validatedRequest.ValidatedResources = validatedResources; ////////////////////////////////////////////////////////// // check requested_expiry ////////////////////////////////////////////////////////// var requestLifetime = _validatedRequest.Client.CibaLifetime ?? _options.Ciba.DefaultLifetime; var requestedExpiry = _validatedRequest.Raw.Get(OidcConstants.BackchannelAuthenticationRequest.RequestedExpiry); if (requestedExpiry.IsPresent()) { // Int32.MaxValue == 2147483647, which is 10 characters in length // so using 9 so we don't overflow below on the Int32.Parse if (requestedExpiry.Length > 9) { LogError("requested_expiry too long"); return(Invalid(OidcConstants.BackchannelAuthenticationRequestErrors.InvalidRequest, "Invalid requested_expiry")); } if (Int32.TryParse(requestedExpiry, out var expiryValue) && expiryValue > 0 && expiryValue <= requestLifetime) { _validatedRequest.Expiry = expiryValue; } else { LogError("requested_expiry value out of valid range"); return(Invalid(OidcConstants.BackchannelAuthenticationRequestErrors.InvalidRequest, "Invalid requested_expiry")); } } else { _validatedRequest.Expiry = requestLifetime; } ////////////////////////////////////////////////////////// // check acr_values ////////////////////////////////////////////////////////// var acrValues = _validatedRequest.Raw.Get(OidcConstants.BackchannelAuthenticationRequest.AcrValues); if (acrValues.IsPresent()) { if (acrValues.Length > _options.InputLengthRestrictions.AcrValues) { LogError("Acr values too long"); return(Invalid(OidcConstants.BackchannelAuthenticationRequestErrors.InvalidRequest, "Invalid acr_values")); } _validatedRequest.AuthenticationContextReferenceClasses = acrValues.FromSpaceSeparatedString().Distinct().ToList(); ////////////////////////////////////////////////////////// // check custom acr_values: idp and tenant ////////////////////////////////////////////////////////// var tenant = _validatedRequest.AuthenticationContextReferenceClasses.FirstOrDefault(x => x.StartsWith(KnownAcrValues.Tenant)); if (tenant != null) { _validatedRequest.AuthenticationContextReferenceClasses.Remove(tenant); tenant = tenant.Substring(KnownAcrValues.Tenant.Length); _validatedRequest.Tenant = tenant; } var idp = _validatedRequest.AuthenticationContextReferenceClasses.FirstOrDefault(x => x.StartsWith(KnownAcrValues.HomeRealm)); if (idp != null) { _validatedRequest.AuthenticationContextReferenceClasses.Remove(idp); idp = idp.Substring(KnownAcrValues.HomeRealm.Length); // check if idp is present but client does not allow it, and then ignore it if (_validatedRequest.Client.IdentityProviderRestrictions != null && _validatedRequest.Client.IdentityProviderRestrictions.Any()) { if (!_validatedRequest.Client.IdentityProviderRestrictions.Contains(idp)) { _logger.LogWarning("idp requested ({idp}) is not in client restriction list.", idp); idp = null; } } _validatedRequest.IdP = idp; } } ////////////////////////////////////////////////////////// // login hints ////////////////////////////////////////////////////////// var loginHint = _validatedRequest.Raw.Get(OidcConstants.BackchannelAuthenticationRequest.LoginHint); var loginHintToken = _validatedRequest.Raw.Get(OidcConstants.BackchannelAuthenticationRequest.LoginHintToken); var idTokenHint = _validatedRequest.Raw.Get(OidcConstants.BackchannelAuthenticationRequest.IdTokenHint); var loginHintCount = 0; if (loginHint.IsPresent()) { loginHintCount++; } if (loginHintToken.IsPresent()) { loginHintCount++; } if (idTokenHint.IsPresent()) { loginHintCount++; } if (loginHintCount == 0) { LogError("Missing login_hint_token, id_token_hint, or login_hint"); return(Invalid(OidcConstants.BackchannelAuthenticationRequestErrors.InvalidRequest, "Missing login_hint_token, id_token_hint, or login_hint")); } else if (loginHintCount > 1) { LogError("Too many of login_hint_token, id_token_hint, or login_hint"); return(Invalid(OidcConstants.BackchannelAuthenticationRequestErrors.InvalidRequest, "Too many of login_hint_token, id_token_hint, or login_hint")); } ////////////////////////////////////////////////////////// // check login_hint ////////////////////////////////////////////////////////// if (loginHint.IsPresent()) { if (loginHint.Length > _options.InputLengthRestrictions.LoginHint) { LogError("Login hint too long"); return(Invalid(OidcConstants.BackchannelAuthenticationRequestErrors.InvalidRequest, "Invalid login_hint")); } _validatedRequest.LoginHint = loginHint; } ////////////////////////////////////////////////////////// // check login_hint_token ////////////////////////////////////////////////////////// if (loginHintToken.IsPresent()) { if (loginHintToken.Length > _options.InputLengthRestrictions.LoginHintToken) { LogError("Login hint token too long"); return(Invalid(OidcConstants.BackchannelAuthenticationRequestErrors.InvalidRequest, "Invalid login_hint_token")); } _validatedRequest.LoginHintToken = loginHintToken; } ////////////////////////////////////////////////////////// // check id_token_hint ////////////////////////////////////////////////////////// if (idTokenHint.IsPresent()) { if (idTokenHint.Length > _options.InputLengthRestrictions.IdTokenHint) { LogError("id token hint too long"); return(Invalid(OidcConstants.BackchannelAuthenticationRequestErrors.InvalidRequest, "Invalid id_token_hint")); } var idTokenHintValidationResult = await _tokenValidator.ValidateIdentityTokenAsync(idTokenHint, _validatedRequest.ClientId, false); if (idTokenHintValidationResult.IsError) { LogError("id token hint failed to validate: " + idTokenHintValidationResult.Error, idTokenHintValidationResult.ErrorDescription); return(Invalid(OidcConstants.BackchannelAuthenticationRequestErrors.InvalidRequest, "Invalid id_token_hint")); } _validatedRequest.IdTokenHint = idTokenHint; _validatedRequest.IdTokenHintClaims = idTokenHintValidationResult.Claims; } ////////////////////////////////////////////////////////// // check user_code ////////////////////////////////////////////////////////// var userCode = _validatedRequest.Raw.Get(OidcConstants.BackchannelAuthenticationRequest.UserCode); if (userCode.IsPresent()) { if (userCode.Length > _options.InputLengthRestrictions.UserCode) { LogError("user_code too long"); return(Invalid(OidcConstants.BackchannelAuthenticationRequestErrors.InvalidRequest, "Invalid user_code")); } _validatedRequest.UserCode = userCode; } ////////////////////////////////////////////////////////// // check binding_message ////////////////////////////////////////////////////////// var bindingMessage = _validatedRequest.Raw.Get(OidcConstants.BackchannelAuthenticationRequest.BindingMessage); if (bindingMessage.IsPresent()) { if (bindingMessage.Length > _options.InputLengthRestrictions.BindingMessage) { LogError("binding_message too long"); return(Invalid(OidcConstants.BackchannelAuthenticationRequestErrors.InvalidBindingMessage, "Invalid binding_message")); } _validatedRequest.BindingMessage = bindingMessage; } ////////////////////////////////////////////////////////// // validate the login hint w/ custom validator ////////////////////////////////////////////////////////// var userResult = await _backchannelAuthenticationUserValidator.ValidateRequestAsync(new BackchannelAuthenticationUserValidatorContext { Client = _validatedRequest.Client, IdTokenHint = _validatedRequest.IdTokenHint, LoginHint = _validatedRequest.LoginHint, LoginHintToken = _validatedRequest.LoginHintToken, IdTokenHintClaims = _validatedRequest.IdTokenHintClaims, UserCode = _validatedRequest.UserCode, BindingMessage = _validatedRequest.BindingMessage }); if (userResult.IsError) { if (userResult.Error == OidcConstants.BackchannelAuthenticationRequestErrors.AccessDenied) { LogError("Request was denied access for that user"); return(Invalid(OidcConstants.BackchannelAuthenticationRequestErrors.AccessDenied, userResult.ErrorDescription)); } if (userResult.Error == OidcConstants.BackchannelAuthenticationRequestErrors.ExpiredLoginHintToken) { LogError("Expired login_hint_token"); return(Invalid(OidcConstants.BackchannelAuthenticationRequestErrors.ExpiredLoginHintToken, userResult.ErrorDescription ?? "Expired login_hint_token")); } if (userResult.Error == OidcConstants.BackchannelAuthenticationRequestErrors.UnknownUserId) { LogError("Unknown user id"); return(Invalid(OidcConstants.BackchannelAuthenticationRequestErrors.UnknownUserId, userResult.ErrorDescription)); } if (userResult.Error == OidcConstants.BackchannelAuthenticationRequestErrors.MissingUserCode) { LogError("Missing user_code"); return(Invalid(OidcConstants.BackchannelAuthenticationRequestErrors.MissingUserCode, userResult.ErrorDescription)); } if (userResult.Error == OidcConstants.BackchannelAuthenticationRequestErrors.InvalidUserCode) { LogError("Invalid user_code"); return(Invalid(OidcConstants.BackchannelAuthenticationRequestErrors.InvalidUserCode, userResult.ErrorDescription)); } if (userResult.Error == OidcConstants.BackchannelAuthenticationRequestErrors.InvalidBindingMessage) { LogError("Invalid binding_message"); return(Invalid(OidcConstants.BackchannelAuthenticationRequestErrors.InvalidBindingMessage, userResult.ErrorDescription)); } LogError("Unexpected error from IBackchannelAuthenticationUserValidator: {error}", userResult.Error); return(Invalid(OidcConstants.BackchannelAuthenticationRequestErrors.UnknownUserId)); } if (userResult.Subject == null || !userResult.Subject.HasClaim(x => x.Type == JwtClaimTypes.Subject)) { LogError("No subject or subject id returned from IBackchannelAuthenticationUserValidator"); return(Invalid(OidcConstants.BackchannelAuthenticationRequestErrors.UnknownUserId)); } _validatedRequest.Subject = userResult.Subject; LogSuccess(); return(new BackchannelAuthenticationRequestValidationResult(_validatedRequest)); }