/// <summary> /// Custom validation logic for identity tokens. /// </summary> /// <param name="result">The validation result so far.</param> /// <returns> /// The validation result /// </returns> public virtual async Task <TokenValidationResult> ValidateIdentityTokenAsync(TokenValidationResult result) { // make sure user is still active (if sub claim is present) var subClaim = result.Claims.FirstOrDefault(c => c.Type == JwtClaimTypes.Subject); if (subClaim != null) { var principal = Principal.Create("tokenvalidator", result.Claims.ToArray()); var isActiveCtx = new IsActiveContext(principal, result.Client, IdentityServerConstants.ProfileIsActiveCallers.IdentityTokenValidation); await Profile.IsActiveAsync(isActiveCtx); if (isActiveCtx.IsActive == false) { Logger.LogError("User marked as not active: {subject}", subClaim.Value); result.IsError = true; result.Error = OidcConstants.ProtectedResourceErrors.InvalidToken; result.Claims = null; return(result); } } return(result); }
public virtual TokenResponse CreateTokenResponseFromAuthorizationCode(StoredGrant handle, IStoredGrantManager handleManager) { var resourceOwner = Principal.Create( "OAuth2", handle.ResourceOwner.ToClaims().ToArray()); var validatedRequest = new ValidatedRequest { Client = handle.Client, Application = handle.Application, Scopes = handle.Scopes }; var response = CreateTokenResponse(validatedRequest, resourceOwner); if (handle.CreateRefreshToken) { var refreshTokenHandle = StoredGrant.CreateRefreshTokenHandle( resourceOwner.GetSubject(), handle.Client, handle.Application, resourceOwner.Claims, handle.Scopes, handle.RefreshTokenExpiration.Value); handleManager.Add(refreshTokenHandle); response.RefreshToken = refreshTokenHandle.GrantId; } handleManager.Delete(handle.GrantId); return(response); }
public async Task <Dictionary <string, object> > ProcessAsync(string subject, IEnumerable <string> scopes) { Logger.Info("Creating userinfo response"); var profileData = new Dictionary <string, object>(); var requestedClaimTypes = await GetRequestedClaimTypesAsync(scopes); var principal = Principal.Create("UserInfo", new Claim("sub", subject)); IEnumerable <Claim> profileClaims; if (requestedClaimTypes.IncludeAllClaims) { Logger.InfoFormat("Requested claim types: all"); profileClaims = await _users.GetProfileDataAsync(principal); } else { Logger.InfoFormat("Requested claim types: {0}", requestedClaimTypes.ClaimTypes.ToSpaceSeparatedString()); profileClaims = await _users.GetProfileDataAsync(principal, requestedClaimTypes.ClaimTypes); } if (profileClaims != null) { profileData = profileClaims.ToClaimsDictionary(); Logger.InfoFormat("Profile service returned to the following claim types: {0}", profileClaims.Select(c => c.Type).ToSpaceSeparatedString()); } else { Logger.InfoFormat("Profile service returned no claims (null)"); } return(profileData); }
/// <summary> /// Validates a userinfo request. /// </summary> /// <param name="accessToken">The access token.</param> /// <returns></returns> /// <exception cref="System.NotImplementedException"></exception> public async Task <UserInfoRequestValidationResult> ValidateRequestAsync(string accessToken) { using var activity = Tracing.BasicActivitySource.StartActivity("UserInfoRequestValidator.ValidateRequest"); // the access token needs to be valid and have at least the openid scope var tokenResult = await _tokenValidator.ValidateAccessTokenAsync( accessToken, IdentityServerConstants.StandardScopes.OpenId); if (tokenResult.IsError) { return(new UserInfoRequestValidationResult { IsError = true, Error = tokenResult.Error }); } // the token must have a one sub claim var subClaim = tokenResult.Claims.SingleOrDefault(c => c.Type == JwtClaimTypes.Subject); if (subClaim == null) { _logger.LogError("Token contains no sub claim"); return(new UserInfoRequestValidationResult { IsError = true, Error = OidcConstants.ProtectedResourceErrors.InvalidToken }); } // create subject from incoming access token var claims = tokenResult.Claims.Where(x => !Constants.Filters.ProtocolClaimsFilter.Contains(x.Type)); var subject = Principal.Create("UserInfo", claims.ToArray()); // make sure user is still active var isActiveContext = new IsActiveContext(subject, tokenResult.Client, IdentityServerConstants.ProfileIsActiveCallers.UserInfoRequestValidation); await _profile.IsActiveAsync(isActiveContext); if (isActiveContext.IsActive == false) { _logger.LogError("User is not active: {sub}", subject.GetSubjectId()); return(new UserInfoRequestValidationResult { IsError = true, Error = OidcConstants.ProtectedResourceErrors.InvalidToken }); } return(new UserInfoRequestValidationResult { IsError = false, TokenValidationResult = tokenResult, Subject = subject }); }
public void Init() { DataProtectection.Instance = new NoProtection(); _testConfig = new TestAuthorizationServerConfiguration(); _client = Principal.Create("Test", new Claim("client_id", "client"), new Claim("secret", "secret")); }
public Task <ClaimsPrincipal> ValidateAsync(ValidatedTokenRequest request, IUserService users) { if (request.GrantType == "assertionType" && request.Assertion == "assertion") { return(Task.FromResult(Principal.Create("Assertion", new Claim("sub", "bob")))); } ; return(Task.FromResult <ClaimsPrincipal>(null)); }
public void CreateAuthenticatedPrincipal() { var p = Principal.Create("Test", new Claim(ClaimTypes.Name, "test")); Assert.IsTrue(p.Identity.IsAuthenticated); Assert.AreEqual <string>(p.Identities.First().AuthenticationType, "Test"); Assert.AreEqual <int>(p.Identities.Count(), 1); Assert.AreEqual <int>(p.Identities.First().Claims.Count(), 1); }
public Task <ClaimsPrincipal> ValidateAsync(ValidatedTokenRequest request) { if (request.GrantType == "customGrant") { return(Task.FromResult(Principal.Create("CustomGrant", new Claim("sub", "bob")))); } ; return(Task.FromResult <ClaimsPrincipal>(null)); }
/// <summary> /// Custom validation logic for access tokens. /// </summary> /// <param name="result">The validation result so far.</param> /// <returns> /// The validation result /// </returns> public virtual async Task <TokenValidationResult> ValidateAccessTokenAsync(TokenValidationResult result) { if (result.IsError) { return(result); } // make sure user is still active (if sub claim is present) var subClaim = result.Claims.FirstOrDefault(c => c.Type == Constants.ClaimTypes.Subject); if (subClaim != null) { var principal = Principal.Create("tokenvalidator", result.Claims.ToArray()); if (result.ReferenceTokenId.IsPresent()) { principal.Identities.First().AddClaim(new Claim(Constants.ClaimTypes.ReferenceTokenId, result.ReferenceTokenId)); } var isActiveCtx = new IsActiveContext(principal, result.Client); await _users.IsActiveAsync(isActiveCtx); if (isActiveCtx.IsActive == false) { Logger.Warn("User marked as not active: " + subClaim.Value); result.IsError = true; result.Error = Constants.ProtectedResourceErrors.InvalidToken; result.Claims = null; return(result); } } // make sure client is still active (if client_id claim is present) var clientClaim = result.Claims.FirstOrDefault(c => c.Type == Constants.ClaimTypes.ClientId); if (clientClaim != null) { var client = await _clients.FindClientByIdAsync(clientClaim.Value); if (client == null || client.Enabled == false) { Logger.Warn("Client deleted or disabled: " + clientClaim.Value); result.IsError = true; result.Error = Constants.ProtectedResourceErrors.InvalidToken; result.Claims = null; return(result); } } return(result); }
public override ClaimsPrincipal Authenticate(string resourceName, ClaimsPrincipal incomingPrincipal) { var subject = GetSubject(incomingPrincipal); var claims = new List <Claim> { new Claim(Constants.ClaimTypes.Subject, subject) }; claims.AddRange(AddInternalClaims(subject)); return(Principal.Create("AuthorizationServer", claims.ToArray())); }
private async Task <IEndpointResult> ProcessUserInfoRequestAsync(HttpContext context) { _logger.LogDebug("Start userinfo request"); var tokenUsageResult = await _tokenUsageValidator.ValidateAsync(context); if (tokenUsageResult.TokenFound == false) { var error = "No access token found."; _logger.LogError(error); await RaiseFailureEventAsync(error); return(Error(OidcConstants.ProtectedResourceErrors.InvalidToken)); } _logger.LogDebug("Token found: {bearerTokenUsageType}", tokenUsageResult.UsageType.ToString()); var tokenResult = await _tokenValidator.ValidateAccessTokenAsync( tokenUsageResult.Token, Constants.StandardScopes.OpenId); if (tokenResult.IsError) { _logger.LogError(tokenResult.Error); await RaiseFailureEventAsync(tokenResult.Error); return(Error(tokenResult.Error)); } // pass scopes/claims to profile service var claims = tokenResult.Claims.Where(x => !Constants.Filters.ProtocolClaimsFilter.Contains(x.Type)); var subject = Principal.Create("UserInfo", claims.ToArray()); if (subject.FindFirst(JwtClaimTypes.Subject) == null) { var error = "Token contains no sub claim"; _logger.LogError(error); await RaiseFailureEventAsync(error); return(Error(OidcConstants.ProtectedResourceErrors.InvalidToken)); } var scopes = tokenResult.Claims.Where(c => c.Type == JwtClaimTypes.Scope).Select(c => c.Value); var payload = await _generator.ProcessAsync(subject, scopes, tokenResult.Client); _logger.LogDebug("End userinfo request"); await RaiseSuccessEventAsync(); return(new UserInfoResult(payload)); }
public async Task <Dictionary <string, object> > ProcessAsync(string subject, IEnumerable <string> scopes, Client client) { _logger.LogTrace("Creating userinfo response"); var profileData = new Dictionary <string, object>(); var requestedClaimTypes = await GetRequestedClaimTypesAsync(scopes); var principal = Principal.Create("UserInfo", new Claim("sub", subject)); IEnumerable <Claim> profileClaims; if (requestedClaimTypes.IncludeAllClaims) { _logger.LogInformation("Requested claim types: all"); var context = new ProfileDataRequestContext( principal, client, Constants.ProfileDataCallers.UserInfoEndpoint); await _profile.GetProfileDataAsync(context); profileClaims = context.IssuedClaims; } else { _logger.LogInformation("Requested claim types: {types}", requestedClaimTypes.ClaimTypes.ToSpaceSeparatedString()); var context = new ProfileDataRequestContext( principal, client, Constants.ProfileDataCallers.UserInfoEndpoint, requestedClaimTypes.ClaimTypes); await _profile.GetProfileDataAsync(context); profileClaims = context.IssuedClaims; } if (profileClaims != null) { profileData = profileClaims.ToClaimsDictionary(); _logger.LogInformation("Profile service returned to the following claim types: {types}", profileClaims.Select(c => c.Type).ToSpaceSeparatedString()); } else { _logger.LogInformation("Profile service returned no claims (null)"); } return(profileData); }
public override ClaimsPrincipal Authenticate(string resourceName, ClaimsPrincipal incomingPrincipal) { if (!incomingPrincipal.Identity.IsAuthenticated) { return(base.Authenticate(resourceName, incomingPrincipal)); } var name = incomingPrincipal.Identity.Name; return(Principal.Create( "Custom", new Claim(ClaimTypes.Name, name + " (transformed)"))); }
public void Init() { DataProtectection.Instance = new NoProtection(); _testConfig = new TestAuthorizationServerConfiguration(); _storedGrantManager = new TestTokenHandleManager("abc", "client", "https://validredirect"); _clientManager = new TestClientManager() { Id = "client", Secret = "secret", OAuthFlow = OAuthFlow.Client, AllowRefreshTokens = false }; _client = Principal.Create("Test", new Claim("client_id", "client"), new Claim("secret", "secret")); }
public void CreateAuthenticatedPrincipalWithEmptyRoles() { var p = Principal.Create("Test", new Claim(ClaimTypes.Name, "test")); var roles = Principal.CreateRoles(new string[] { }); p.Identities.First().AddClaims(roles); Assert.IsTrue(p.Identity.IsAuthenticated); Assert.AreEqual <string>(p.Identities.First().AuthenticationType, "Test"); Assert.AreEqual <int>(p.Identities.Count(), 1); Assert.AreEqual <int>(p.Identities.First().Claims.Count(), 1); }
public void Init() { DataProtectection.Instance = new NoProtection(); _testConfig = new TestAuthorizationServerConfiguration(); _client = Principal.Create( "Test", new Claim("client_id", "codeclient"), new Claim("secret", "secret")); _handleManager = new TestTokenHandleManager( "abc", "codeclient", "https://validredirect"); }
/// <summary> /// Creates a principal from the subject id and additional claims /// </summary> /// <param name="subjectId">Subject ID</param> /// <param name="additionalClaims">Additional claims</param> /// <returns>ClaimsPrincipal</returns> public static ClaimsPrincipal FromSubjectId(string subjectId, IEnumerable <Claim> additionalClaims = null) { var claims = new List <Claim> { new Claim(Constants.ClaimTypes.Subject, subjectId) }; if (additionalClaims != null) { claims.AddRange(additionalClaims); } return(Principal.Create(Constants.PrimaryAuthenticationType, claims.Distinct(new ClaimComparer()).ToArray())); }
/// <summary> /// Custom validation logic for access tokens. /// </summary> /// <param name="result">The validation result so far.</param> /// <returns> /// The validation result /// </returns> public async Task <TokenValidationResult> ValidateAccessTokenAsync(TokenValidationResult result) { if (result.IsError) { return(result); } // make sure user is still active (if sub claim is present) var subClaim = result.Claims.FirstOrDefault(c => c.Type == Constants.ClaimTypes.Subject); if (subClaim != null) { var principal = Principal.Create("tokenvalidator", result.Claims.ToArray()); if (result.ReferenceTokenId.IsPresent()) { principal.Identities.First().AddClaim(new Claim(Constants.ClaimTypes.ReferenceTokenId, result.ReferenceTokenId)); } if (await _users.IsActiveAsync(principal) == false) { result.IsError = true; result.Error = Constants.ProtectedResourceErrors.ExpiredToken; result.Claims = null; return(result); } } // make sure client is still active (if client_id claim is present) var clientClaim = result.Claims.FirstOrDefault(c => c.Type == Constants.ClaimTypes.ClientId); if (clientClaim != null) { var client = await _clients.FindClientByIdAsync(clientClaim.Value); if (client == null || client.Enabled == false) { result.IsError = true; result.Error = Constants.ProtectedResourceErrors.ExpiredToken; result.Claims = null; return(result); } } return(result); }
public override ClaimsPrincipal Authenticate(string resourceName, ClaimsPrincipal incomingPrincipal) { if (!incomingPrincipal.Identity.IsAuthenticated) { return(base.Authenticate(resourceName, incomingPrincipal)); } var name = GetName(incomingPrincipal); var role = GetRole(incomingPrincipal); var principal = Principal.Create("Windows", name, role); EstablishSession(principal); return(principal); }
public HttpResponseMessage Get() { Tracing.Start("OIDC UserInfo endpoint"); var details = new RequestDetails { IsOpenIdRequest = true }; var scopeClaims = ClaimsPrincipal.Current.FindAll(OAuth2Constants.Scope).ToList(); var requestedClaims = ClaimsPrincipal.Current.FindAll("requestclaim").ToList(); if (scopeClaims.Count > 0) { var scopes = new List <string>(scopeClaims.Select(sc => sc.Value)); details.OpenIdScopes = scopes; } if (requestedClaims.Count > 0) { var requestClaims = new RequestClaimCollection(); requestedClaims.ForEach(rc => requestClaims.Add(new RequestClaim(rc.Value))); details.ClaimsRequested = true; details.RequestClaims = requestClaims; } var principal = Principal.Create("OpenIdConnect", new Claim(ClaimTypes.Name, ClaimsPrincipal.Current.FindFirst(ClaimTypes.NameIdentifier).Value)); var claims = ClaimsRepository.GetClaims(principal, details); var dictionary = new Dictionary <string, string>(); foreach (var claim in claims) { if (!dictionary.ContainsKey(claim.Type)) { dictionary.Add(claim.Type, claim.Value); } else { var currentValue = dictionary[claim.Type]; dictionary[claim.Type] = currentValue += ("," + claim.Value); } } return(Request.CreateResponse <Dictionary <string, string> >(HttpStatusCode.OK, dictionary, "application/json")); }
public async Task <DeviceAuthorizationResponse> Generate(DeviceAuthorizationRequestValidationResult validationResult) { var authorizationCode = new TrustedDeviceAuthorizationCode { ClientId = validationResult.Client.ClientId, CodeChallenge = validationResult.CodeChallenge.Sha256(), CreationTime = SystemClock.UtcNow.UtcDateTime, DeviceId = validationResult.Device.DeviceId, InteractionMode = validationResult.InteractionMode, Lifetime = validationResult.Client.AuthorizationCodeLifetime, RequestedScopes = validationResult.RequestedScopes, Subject = Principal.Create("TrustedDevice", new Claim(JwtClaimTypes.Subject, validationResult.UserId)) }; var challenge = await CodeChallengeStore.GenerateChallenge(authorizationCode); return(new DeviceAuthorizationResponse { Challenge = challenge }); }
public IActionResult LogIn() { ResponseModel Result = new ResponseModel(); LogInModel account = new LogInModel() { Account_Account = Request.Form["Account_Account"], Account_Password = Request.Form["Account_Password"] }; AccountModel user; try{ if (ModelState.IsValid) { user = Principal.Create(account.Account_Account, account.Account_Password, ConfigHelper.ConnectionString); SetUserSession(user); Result.HttpStatus = "1"; Result.Message = "ok"; } } catch (LogInException ex) { Result.HttpStatus = ex.Key; Result.Message = ex.Message; } catch (Exception ex) { switch (ex.Source) { case "MySql.Data": Result.HttpStatus = "510"; Result.Message = "伺服器發生錯誤。"; break; default: Result.HttpStatus = "0"; Result.Message = ex.Message; break; } } return(Json(Result)); }
/// <summary> /// Validates a userinfo request. /// </summary> /// <param name="accessToken">The access token.</param> /// <returns></returns> /// <exception cref="System.NotImplementedException"></exception> public async Task <UserInfoRequestValidationResult> ValidateRequestAsync(string accessToken) { // the access token needs to be valid and have at least the openid scope var tokenResult = await _tokenValidator.ValidateAccessTokenAsync( accessToken, IdentityServerConstants.StandardScopes.OpenId); if (tokenResult.IsError) { return(new UserInfoRequestValidationResult { IsError = true, Error = tokenResult.Error }); } // the token must have a one sub claim var subClaim = tokenResult.Claims.SingleOrDefault(c => c.Type == JwtClaimTypes.Subject); if (subClaim == null) { _logger.LogError("Token contains no sub claim"); return(new UserInfoRequestValidationResult { IsError = true, Error = OidcConstants.ProtectedResourceErrors.InvalidToken }); } // create subject from incoming access token var claims = tokenResult.Claims.Where(x => !Constants.Filters.ProtocolClaimsFilter.Contains(x.Type)); var subject = Principal.Create("UserInfo", claims.ToArray()); return(new UserInfoRequestValidationResult { IsError = false, TokenValidationResult = tokenResult, Subject = subject }); }
public void Refresh_Token_Create_New() { Claim[] claims = { new Claim("client_id", "MobileAppShop"), new Claim("secret", "12345678") }; ClaimsPrincipal claimsPrinciple = Principal.Create("Test", claims); Thread.CurrentPrincipal = claimsPrinciple; TokenRequest tokenRequest = new TokenRequest() { Grant_Type = "refresh_token", Refresh_Token = "MyFavouriteRefrehToken1234" }; var response = _TokenController.Post("Test Application 1", tokenRequest); TokenResponse tokenResponse; response.TryGetContentValue <TokenResponse>(out tokenResponse); Assert.IsTrue(response.IsSuccessStatusCode == true); Assert.IsFalse(string.IsNullOrEmpty(tokenResponse.AccessToken)); }
/// <summary> /// Custom validation logic for identity tokens. /// </summary> /// <param name="result">The validation result so far.</param> /// <returns> /// The validation result /// </returns> public async Task <TokenValidationResult> ValidateIdentityTokenAsync(TokenValidationResult result) { // make sure user is still active (if sub claim is present) var subClaim = result.Claims.FirstOrDefault(c => c.Type == Constants.ClaimTypes.Subject); if (subClaim != null) { var principal = Principal.Create("tokenvalidator", result.Claims.ToArray()); if (await _users.IsActiveAsync(principal) == false) { result.IsError = true; result.Error = Constants.ProtectedResourceErrors.ExpiredToken; result.Claims = null; return(result); } } return(result); }
public void Create_Token() { Claim[] claims = { new Claim("client_id", "MobileAppShop"), new Claim("secret", "12345678") }; ClaimsPrincipal claimsPrinciple = Principal.Create("Test", claims); Thread.CurrentPrincipal = claimsPrinciple; TokenRequest tokenRequest = new TokenRequest() { Grant_Type = "password", UserName = "******", Password = "******", Scope = "read", }; var response = _TokenController.Post("Test Application 1", tokenRequest); TokenResponse tokenResponse; response.TryGetContentValue <TokenResponse>(out tokenResponse); Assert.IsTrue(response.IsSuccessStatusCode == true); Assert.IsFalse(string.IsNullOrEmpty(tokenResponse.AccessToken)); }
public virtual TokenResponse CreateTokenResponseFromRefreshToken(StoredGrant handle, IStoredGrantManager handleManager) { var resourceOwner = Principal.Create( "OAuth2", handle.ResourceOwner.ToClaims().ToArray()); if (DateTime.UtcNow > handle.Expiration) { throw new InvalidOperationException("Refresh token has expired."); } var validatedRequest = new ValidatedRequest { Client = handle.Client, Application = handle.Application, Scopes = handle.Scopes, }; var response = CreateTokenResponse(validatedRequest, resourceOwner); response.RefreshToken = handle.GrantId; return(response); }
public async Task <TokenValidationResult> ValidateIdentityTokenAsync(string token, string clientId = null, bool validateLifetime = true) { _logger.LogDebug("Start identity token validation"); if (token.Length > _options.InputLengthRestrictions.Jwt) { _logger.LogError("JWT too long"); return(Invalid(OidcConstants.ProtectedResourceErrors.InvalidToken)); } if (clientId.IsMissing()) { clientId = GetClientIdFromJwt(token); if (clientId.IsMissing()) { _logger.LogError("No clientId supplied, can't find id in identity token."); return(Invalid(OidcConstants.ProtectedResourceErrors.InvalidToken)); } } _log.ClientId = clientId; _log.ValidateLifetime = validateLifetime; var client = await _clients.FindEnabledClientByIdAsync(clientId); if (client == null) { _logger.LogError("Unknown or disabled client: {clientId}.", clientId); return(Invalid(OidcConstants.ProtectedResourceErrors.InvalidToken)); } _log.ClientName = client.ClientName; _logger.LogDebug("Client found: {clientId} / {clientName}", client.ClientId, client.ClientName); var keys = await _keys.GetValidationKeysAsync(); var result = await ValidateJwtAsync(token, clientId, keys, validateLifetime); result.Client = client; if (result.IsError) { LogError("Error validating JWT"); return(result); } _log.Claims = result.Claims.ToClaimsDictionary(); // make sure user is still active (if sub claim is present) var subClaim = result.Claims.FirstOrDefault(c => c.Type == JwtClaimTypes.Subject); if (subClaim != null) { var principal = Principal.Create("tokenvalidator", result.Claims.ToArray()); var isActiveCtx = new IsActiveContext(principal, result.Client, IdentityServerConstants.ProfileIsActiveCallers.IdentityTokenValidation); await _profile.IsActiveAsync(isActiveCtx); if (isActiveCtx.IsActive == false) { _logger.LogError("User marked as not active: {subject}", subClaim.Value); result.IsError = true; result.Error = OidcConstants.ProtectedResourceErrors.InvalidToken; result.Claims = null; return(result); } } _logger.LogDebug("Calling into custom token validator: {type}", _customValidator.GetType().FullName); var customResult = await _customValidator.ValidateIdentityTokenAsync(result); if (customResult.IsError) { LogError("Custom validator failed: " + (customResult.Error ?? "unknown")); return(customResult); } _log.Claims = customResult.Claims.ToClaimsDictionary(); LogSuccess(); return(customResult); }
public override async Task <CompleteRegistrationRequestValidationResult> Validate(NameValueCollection parameters, string accessToken = null) { Logger.LogDebug($"[{nameof(CompleteRegistrationRequestValidator)}] Started trusted device registration request validation."); // The access token needs to be valid and have at least the openid scope. var tokenValidationResult = await TokenValidator.ValidateAccessTokenAsync(accessToken, IdentityServerConstants.StandardScopes.OpenId); if (tokenValidationResult.IsError) { return(Error(tokenValidationResult.Error, "Provided access token is not valid.")); } // The access token must have at lease a 'sub' and 'client_id' claim. var claimsToValidate = new[] { JwtClaimTypes.Subject, JwtClaimTypes.ClientId }; foreach (var claim in claimsToValidate) { var claimValue = tokenValidationResult.Claims.SingleOrDefault(x => x.Type == claim)?.Value; if (string.IsNullOrWhiteSpace(claimValue)) { return(Error(OidcConstants.ProtectedResourceErrors.InvalidToken, $"Access token must contain the '{claim}' claim.")); } } // Get 'code' parameter and retrieve it from the store. var code = parameters.Get(RegistrationRequestParameters.Code); if (string.IsNullOrWhiteSpace(code)) { return(Error(OidcConstants.TokenErrors.InvalidGrant, $"Parameter '{nameof(RegistrationRequestParameters.Code)}' is not specified.")); } var authorizationCode = await CodeChallengeStore.GetAuthorizationCode(code); if (authorizationCode == null) { return(Error(OidcConstants.TokenErrors.InvalidGrant, "Authorization code is invalid.")); } // Validate that the consumer specified all required parameters. var parametersToValidate = new List <string> { RegistrationRequestParameters.CodeSignature, RegistrationRequestParameters.CodeVerifier, RegistrationRequestParameters.DeviceId, RegistrationRequestParameters.DevicePlatform }; if (authorizationCode.InteractionMode == InteractionMode.Fingerprint) { parametersToValidate.Add(RegistrationRequestParameters.PublicKey); } if (authorizationCode.InteractionMode == InteractionMode.Pin) { parametersToValidate.Add(RegistrationRequestParameters.Pin); } var otpAuthenticatedValue = tokenValidationResult.Claims.FirstOrDefault(x => x.Type == BasicClaimTypes.OtpAuthenticated)?.Value; var otpAuthenticated = !string.IsNullOrWhiteSpace(otpAuthenticatedValue) && bool.Parse(otpAuthenticatedValue); if (!otpAuthenticated) { parametersToValidate.Add(RegistrationRequestParameters.OtpCode); } foreach (var parameter in parametersToValidate) { var parameterValue = parameters.Get(parameter); if (string.IsNullOrWhiteSpace(parameterValue)) { return(Error(OidcConstants.TokenErrors.InvalidGrant, $"Parameter '{parameter}' is not specified.")); } } var isValidPlatform = Enum.TryParse(typeof(DevicePlatform), parameters.Get(RegistrationRequestParameters.DevicePlatform), out var platform); if (!isValidPlatform) { return(Error(OidcConstants.TokenErrors.InvalidRequest, $"Parameter '{nameof(RegistrationRequestParameters.DevicePlatform)}' does not have a valid value.")); } // Load client and validate that it allows the 'password' flow. var client = await LoadClient(tokenValidationResult); if (client == null) { return(Error(OidcConstants.AuthorizeErrors.UnauthorizedClient, $"Client is unknown or not enabled.")); } if (client.AllowedGrantTypes.Except(Constants.RequiredGrantTypes).Any()) { return(Error(OidcConstants.AuthorizeErrors.UnauthorizedClient, $"Client not authorized any of the following grant types: {string.Join(", ", Constants.RequiredGrantTypes)}")); } // Validate authorization code against code verifier given by the client. var codeVerifier = parameters.Get(RegistrationRequestParameters.CodeVerifier); var authorizationCodeValidationResult = await ValidateAuthorizationCode(code, authorizationCode, codeVerifier, parameters.Get(RegistrationRequestParameters.DeviceId), client); if (authorizationCodeValidationResult.IsError) { return(Error(authorizationCodeValidationResult.Error, authorizationCodeValidationResult.ErrorDescription)); } // Validate given public key against signature for fingerprint. string publicKey = null; if (authorizationCode.InteractionMode == InteractionMode.Fingerprint) { publicKey = parameters.Get(RegistrationRequestParameters.PublicKey); var codeSignature = parameters.Get(RegistrationRequestParameters.CodeSignature); var publicKeyValidationResult = ValidateSignature(publicKey, code, codeSignature); if (publicKeyValidationResult.IsError) { return(Error(publicKeyValidationResult.Error, publicKeyValidationResult.ErrorDescription)); } } // Find requested scopes. var requestedScopes = tokenValidationResult.Claims.Where(claim => claim.Type == JwtClaimTypes.Scope).Select(claim => claim.Value).ToList(); // Create principal from incoming access token excluding protocol claims. var claims = tokenValidationResult.Claims.Where(x => !Constants.ProtocolClaimsFilter.Contains(x.Type)); var principal = Principal.Create("TrustedDevice", claims.ToArray()); var userId = tokenValidationResult.Claims.Single(x => x.Type == JwtClaimTypes.Subject).Value; // Validate OTP code, if needed. if (!otpAuthenticated) { var totpResult = await TotpService.Verify( principal : principal, code : parameters.Get(RegistrationRequestParameters.OtpCode), purpose : Constants.TrustedDeviceOtpPurpose(userId, authorizationCode.DeviceId) ); if (!totpResult.Success) { return(Error(totpResult.Error)); } } // Finally return result. return(new CompleteRegistrationRequestValidationResult { IsError = false, Client = client, DeviceId = authorizationCode.DeviceId, DeviceName = parameters.Get(RegistrationRequestParameters.DeviceName), DevicePlatform = (DevicePlatform)platform, InteractionMode = authorizationCode.InteractionMode, Pin = parameters.Get(RegistrationRequestParameters.Pin), Principal = principal, PublicKey = publicKey, RequestedScopes = requestedScopes, UserId = userId }); }
private async Task <ResponseValidationResult> ProcessCodeFlowResponseAsync( AuthorizeResponse authorizeResponse, AuthorizeState state, Parameters backChannelParameters, CancellationToken cancellationToken) { _logger.LogTrace("ProcessCodeFlowResponseAsync"); ////////////////////////////////////////////////////// // process back-channel response ////////////////////////////////////////////////////// // redeem code for tokens var tokenResponse = await RedeemCodeAsync(authorizeResponse.Code, state, backChannelParameters, cancellationToken); if (tokenResponse.IsError) { return(new ResponseValidationResult($"Error redeeming code: {tokenResponse.Error ?? "no error code"} / {tokenResponse.ErrorDescription ?? "no description"}")); } if (tokenResponse.HttpStatusCode != HttpStatusCode.OK) { return(new ResponseValidationResult($"Error redeeming code: {tokenResponse.Raw}")); } // validate token response var tokenResponseValidationResult = await ValidateTokenResponseAsync(tokenResponse, state, requireIdentityToken : false, cancellationToken : cancellationToken); if (tokenResponseValidationResult.IsError) { return(new ResponseValidationResult($"Error validating token response: {tokenResponseValidationResult.Error}")); } return(new ResponseValidationResult { AuthorizeResponse = authorizeResponse, TokenResponse = tokenResponse, User = tokenResponseValidationResult?.IdentityTokenValidationResult?.User ?? Principal.Create(_options.Authority) }); }