/// <summary> /// Gets the user claims from the userinfo endpoint. /// </summary> /// <param name="accessToken">The access token.</param> /// <returns>User claims</returns> public async Task <UserInfoResult> GetUserInfoAsync(string accessToken) { var providerInfo = await _options.GetProviderInformationAsync(); if (accessToken.IsMissing()) { throw new ArgumentNullException(nameof(accessToken)); } if (providerInfo.UserInfoEndpoint.IsMissing()) { throw new InvalidOperationException("No userinfo endpoint specified"); } var handler = _options.BackchannelHandler ?? new HttpClientHandler(); var userInfoClient = new UserInfoClient(new Uri(providerInfo.UserInfoEndpoint), accessToken, handler); userInfoClient.Timeout = _options.BackchannelTimeout; var userInfoResponse = await userInfoClient.GetAsync(); if (userInfoResponse.IsError) { return(new UserInfoResult { Error = userInfoResponse.ErrorMessage }); } return(new UserInfoResult { Claims = userInfoResponse.Claims.Select(c => new Claim(c.Item1, c.Item2)).ToClaims() }); }
/// <summary> /// Starts an end_session request using a browser. /// </summary> /// <param name="identityToken">The identity token.</param> /// <param name="trySilent">if set to <c>true</c> try a silent request.</param> /// <returns></returns> /// <exception cref="System.InvalidOperationException"> /// No web view defined. /// or /// no endsession_endpoint defined /// </exception> public async Task EndSessionAsync(string identityToken = null, bool trySilent = true) { if (_options.WebView == null) { throw new InvalidOperationException("No web view defined."); } string url = (await _options.GetProviderInformationAsync()).EndSessionEndpoint; if (url.IsMissing()) { throw new InvalidOperationException("no endsession_endpoint defined"); } if (!string.IsNullOrWhiteSpace(identityToken)) { url += $"?{OidcConstants.EndSessionRequest.IdTokenHint}={identityToken}" + $"&{OidcConstants.EndSessionRequest.PostLogoutRedirectUri}={_options.RedirectUri}"; } var webViewOptions = new InvokeOptions(url, _options.RedirectUri) { ResponseMode = ResponseMode.Redirect, InvisibleModeTimeout = _options.WebViewTimeout }; if (trySilent) { webViewOptions.InitialDisplayMode = DisplayMode.Hidden; } var result = await _options.WebView.InvokeAsync(webViewOptions); }
private async Task <LoginResult> ProcessClaims(AuthorizeResponse response, TokenResponse tokenResult, Claims claims) { // get profile if enabled if (_options.LoadProfile) { var userInfoResult = await GetUserInfoAsync(tokenResult.AccessToken); if (!userInfoResult.Success) { return(new LoginResult { Success = false, Error = userInfoResult.Error }); } var primaryClaimTypes = claims.Select(c => c.Type).Distinct(); foreach (var claim in userInfoResult.Claims.Where(c => !primaryClaimTypes.Contains(c.Type))) { claims.Add(claim); } } // success var loginResult = new LoginResult { Success = true, Claims = FilterClaims(claims), AccessToken = tokenResult.AccessToken, RefreshToken = tokenResult.RefreshToken, AccessTokenExpiration = DateTime.Now.AddSeconds(tokenResult.ExpiresIn), IdentityToken = response.IdentityToken, AuthenticationTime = DateTime.Now, }; if (!string.IsNullOrWhiteSpace(tokenResult.RefreshToken)) { var providerInfo = await _options.GetProviderInformationAsync(); loginResult.Handler = new RefeshTokenHandler( providerInfo.TokenEndpoint, _options.ClientId, _options.ClientSecret, tokenResult.RefreshToken, tokenResult.AccessToken); } return(loginResult); }
private async Task <IdentityTokenValidationResult> ValidateIdentityTokenAsync(string idToken) { var providerInfo = await _options.GetProviderInformationAsync(); Logger.Debug("Calling identity token validator: " + _options.IdentityTokenValidator.GetType().FullName); var validationResult = await _options.IdentityTokenValidator.ValidateAsync(idToken, _options.ClientId, providerInfo); if (validationResult.Success == false) { return(validationResult); } var claims = validationResult.Claims; Logger.Debug("identity token validation claims:"); Logger.LogClaims(claims); // validate audience var audience = claims.FindFirst(JwtClaimTypes.Audience)?.Value ?? ""; if (!string.Equals(_options.ClientId, audience, StringComparison.Ordinal)) { Logger.Error($"client id ({_options.ClientId}) does not match audience ({audience})"); return(new IdentityTokenValidationResult { Error = "invalid audience" }); } // validate issuer var issuer = claims.FindFirst(JwtClaimTypes.Issuer)?.Value ?? ""; if (!string.Equals(providerInfo.IssuerName, issuer, StringComparison.Ordinal)) { Logger.Error($"configured issuer ({providerInfo.IssuerName}) does not match token issuer ({issuer}"); return(new IdentityTokenValidationResult { Error = "invalid issuer" }); } return(validationResult); }
public async Task <LoginResult> ValidateResponseAsync(string data, AuthorizeState state) { var result = new LoginResult { Success = false }; var response = new AuthorizeResponse(data); if (response.IsError) { result.Error = response.Error; return(result); } if (string.IsNullOrEmpty(response.Code)) { result.Error = "Missing authorization code"; return(result); } if (string.IsNullOrEmpty(response.IdentityToken)) { result.Error = "Missing identity token"; return(result); } // validate identity token signature var providerInfo = await _options.GetProviderInformationAsync(); var validationResult = await _options.IdentityTokenValidator.ValidateAsync(response.IdentityToken, _options.ClientId, providerInfo); if (validationResult.Success == false) { return(new LoginResult { Success = false, Error = validationResult.Error ?? "identity token validation error" }); } var claims = validationResult.Claims; // validate audience var audience = claims.FindFirst(JwtClaimTypes.Audience)?.Value ?? ""; if (!string.Equals(_options.ClientId, audience)) { return(new LoginResult { Success = false, Error = "invalid audience" }); } // validate issuer var issuer = claims.FindFirst(JwtClaimTypes.Issuer)?.Value ?? ""; if (!string.Equals(providerInfo.IssuerName, issuer)) { return(new LoginResult { Success = false, Error = "invalid issuer" }); } // validate nonce var tokenNonce = claims.FindFirst(JwtClaimTypes.Nonce)?.Value ?? ""; if (!string.Equals(state.Nonce, tokenNonce)) { return(new LoginResult { Success = false, Error = "invalid nonce" }); } // validate c_hash var cHash = claims.FindFirst(JwtClaimTypes.AuthorizationCodeHash)?.Value ?? ""; var sha256 = HashAlgorithmProvider.OpenAlgorithm(HashAlgorithm.Sha256); var codeHash = sha256.HashData( CryptographicBuffer.CreateFromByteArray( Encoding.UTF8.GetBytes(response.Code))); byte[] codeHashArray; CryptographicBuffer.CopyToByteArray(codeHash, out codeHashArray); byte[] leftPart = new byte[16]; Array.Copy(codeHashArray, leftPart, 16); var leftPartB64 = Base64Url.Encode(leftPart); if (!leftPartB64.Equals(cHash)) { return(new LoginResult { Success = false, Error = "invalid code" }); } // redeem code for tokens var tokenResult = await RedeemCodeAsync(response.Code, state); if (tokenResult.IsError || tokenResult.IsHttpError) { return(new LoginResult { Success = false, Error = tokenResult.Error }); } // get profile if enabled if (_options.LoadProfile) { var userInfoResult = await GetUserInfoAsync(tokenResult.AccessToken); if (!userInfoResult.Success) { return(new LoginResult { Success = false, Error = userInfoResult.Error }); } var primaryClaimTypes = claims.Select(c => c.Type).Distinct(); foreach (var claim in userInfoResult.Claims.Where(c => !primaryClaimTypes.Contains(c.Type))) { claims.Add(claim); } } // success var loginResult = new LoginResult { Success = true, Claims = FilterClaims(claims), AccessToken = tokenResult.AccessToken, RefreshToken = tokenResult.RefreshToken, AccessTokenExpiration = DateTime.Now.AddSeconds(tokenResult.ExpiresIn), IdentityToken = response.IdentityToken, AuthenticationTime = DateTime.Now, }; if (!string.IsNullOrWhiteSpace(tokenResult.RefreshToken)) { loginResult.Handler = new RefeshTokenHandler( providerInfo.TokenEndpoint, _options.ClientId, _options.ClientSecret, tokenResult.RefreshToken, tokenResult.AccessToken); } return(loginResult); }