public async Task <ResponseValidationResult> ValidateCodeFlowResponseAsync(AuthorizeResponse authorizeResponse, AuthorizeState state) { Logger.Debug("Validate code flow response"); var result = new ResponseValidationResult(); ////////////////////////////////////////////////////// // validate front-channel response ////////////////////////////////////////////////////// // code must be present if (authorizeResponse.Code.IsMissing()) { result.Error = "code is missing"; Logger.Error(result.Error); return(result); } if (!string.Equals(authorizeResponse.State, state.State, StringComparison.Ordinal)) { result.Error = "invalid state"; Logger.Error(result.Error); return(result); } ////////////////////////////////////////////////////// // process back-channel response ////////////////////////////////////////////////////// // redeem code for tokens var tokenResponse = await RedeemCodeAsync(authorizeResponse.Code, state); if (tokenResponse.IsError || tokenResponse.IsHttpError) { result.Error = tokenResponse.Error; return(result); } // validate token response var tokenResponseValidationResult = await ValidateTokenResponse(tokenResponse); if (!tokenResponseValidationResult.Success) { result.Error = tokenResponseValidationResult.Error; return(result); } return(new ResponseValidationResult { AuthorizeResponse = authorizeResponse, TokenResponse = tokenResponse, Claims = tokenResponseValidationResult.IdentityTokenValidationResult.Claims }); }
private async Task <LoginResult> ProcessClaimsAsync(ResponseValidationResult result) { Logger.Debug("Processing claims"); // get profile if enabled if (_options.LoadProfile) { Logger.Debug("load profile"); var userInfoResult = await GetUserInfoAsync(result.TokenResponse.AccessToken); if (!userInfoResult.Success) { return(new LoginResult(userInfoResult.Error)); } Logger.Debug("profile claims:"); Logger.LogClaims(userInfoResult.Claims); var primaryClaimTypes = result.Claims.Select(c => c.Type).Distinct(); foreach (var claim in userInfoResult.Claims.Where(c => !primaryClaimTypes.Contains(c.Type))) { result.Claims.Add(claim); } } else { Logger.Debug("don't load profile"); } // success var loginResult = new LoginResult { Claims = FilterClaims(result.Claims), AccessToken = result.TokenResponse.AccessToken, RefreshToken = result.TokenResponse.RefreshToken, AccessTokenExpiration = DateTime.Now.AddSeconds(result.TokenResponse.ExpiresIn), IdentityToken = result.TokenResponse.IdentityToken, AuthenticationTime = DateTime.Now }; if (!string.IsNullOrWhiteSpace(result.TokenResponse.RefreshToken)) { var providerInfo = await _options.GetProviderInformationAsync(); loginResult.Handler = new RefeshTokenHandler( await TokenClientFactory.CreateAsync(_options), result.TokenResponse.RefreshToken, result.TokenResponse.AccessToken); } return(loginResult); }
/// <summary> /// Validates the response. /// </summary> /// <param name="data">The response data.</param> /// <param name="state">The state.</param> /// <returns>Result of the login response validation</returns> /// <exception cref="System.InvalidOperationException">Invalid authentication style</exception> public async Task <LoginResult> ValidateResponseAsync(string data, AuthorizeState state) { Logger.Debug("Validate authorize response"); var response = new AuthorizeResponse(data); if (response.IsError) { Logger.Error(response.Error); return(new LoginResult(response.Error)); } if (string.IsNullOrEmpty(response.Code)) { var error = "Missing authorization code"; Logger.Error(error); return(new LoginResult(error)); } if (string.IsNullOrEmpty(response.State)) { var error = "Missing state"; Logger.Error(error); return(new LoginResult(error)); } if (!string.Equals(state.State, response.State, StringComparison.Ordinal)) { var error = "Invalid state"; Logger.Error(error); return(new LoginResult(error)); } ResponseValidationResult validationResult = null; if (_options.Style == OidcClientOptions.AuthenticationStyle.AuthorizationCode) { validationResult = await _validator.ValidateCodeFlowResponseAsync(response, state); } else if (_options.Style == OidcClientOptions.AuthenticationStyle.Hybrid) { validationResult = await _validator.ValidateHybridFlowResponseAsync(response, state); } else { throw new InvalidOperationException("Invalid authentication style"); } if (!validationResult.Success) { Logger.Error("Error validating response: " + validationResult.Error); return(new LoginResult { Error = validationResult.Error }); } return(await ProcessClaimsAsync(validationResult)); }
public async Task <ResponseValidationResult> ValidateHybridFlowResponseAsync(AuthorizeResponse authorizeResponse, AuthorizeState state) { Logger.Debug("Validate hybrid flow response"); var result = new ResponseValidationResult(); ////////////////////////////////////////////////////// // validate front-channel response ////////////////////////////////////////////////////// // id_token must be present if (authorizeResponse.IdentityToken.IsMissing()) { result.Error = "Missing identity token"; Logger.Error(result.Error); return(result); } // id_token must be valid var validationResult = await ValidateIdentityTokenAsync(authorizeResponse.IdentityToken); if (!validationResult.Success) { result.Error = validationResult.Error ?? "Identity token validation error"; Logger.Error(result.Error); return(result); } // nonce must be valid if (!ValidateNonce(state.Nonce, validationResult.Claims)) { result.Error = "Invalid nonce"; Logger.Error(result.Error); return(result); } // if c_hash is present, it must be valid var signingAlgorithmBits = int.Parse(validationResult.SignatureAlgorithm.Substring(2)); if (!ValidateAuthorizationCodeHash(authorizeResponse.Code, signingAlgorithmBits, validationResult.Claims)) { result.Error = "Invalid c_hash"; Logger.Error(result.Error); return(result); } ////////////////////////////////////////////////////// // process back-channel response ////////////////////////////////////////////////////// // redeem code for tokens var tokenResponse = await RedeemCodeAsync(authorizeResponse.Code, state); if (tokenResponse.IsError || tokenResponse.IsHttpError) { Logger.Error(result.Error); result.Error = tokenResponse.Error; return(result); } // validate token response var tokenResponseValidationResult = await ValidateTokenResponse(tokenResponse); if (!tokenResponseValidationResult.Success) { result.Error = tokenResponseValidationResult.Error; return(result); } return(new ResponseValidationResult { AuthorizeResponse = authorizeResponse, TokenResponse = tokenResponse, Claims = tokenResponseValidationResult.IdentityTokenValidationResult.Claims }); }