public async Task StoreAuthorizationCodeAsync_should_persist_grant() { var code1 = new AuthorizationCode() { ClientId = "test", CreationTime = DateTime.UtcNow, Lifetime = 10, Subject = _user, CodeChallenge = "challenge", RedirectUri = "http://client/cb", Nonce = "nonce", RequestedScopes = new string[] { "scope1", "scope2" } }; var handle = await _codes.StoreAuthorizationCodeAsync(code1); var code2 = await _codes.GetAuthorizationCodeAsync(handle); code1.ClientId.Should().Be(code2.ClientId); code1.CreationTime.Should().Be(code2.CreationTime); code1.Lifetime.Should().Be(code2.Lifetime); code1.Subject.GetSubjectId().Should().Be(code2.Subject.GetSubjectId()); code1.CodeChallenge.Should().Be(code2.CodeChallenge); code1.RedirectUri.Should().Be(code2.RedirectUri); code1.Nonce.Should().Be(code2.Nonce); code1.RequestedScopes.Should().BeEquivalentTo(code2.RequestedScopes); }
private async Task <TokenRequestValidationResult> ValidateAuthorizationCodeRequestAsync(NameValueCollection parameters) { _logger.LogDebug("Start validation of authorization code token request"); ///////////////////////////////////////////// // check if client is authorized for grant type ///////////////////////////////////////////// if (!_validatedRequest.Client.AllowedGrantTypes.ToList().Contains(GrantType.AuthorizationCode) && !_validatedRequest.Client.AllowedGrantTypes.ToList().Contains(GrantType.Hybrid)) { LogError("Client not authorized for code flow"); return(Invalid(OidcConstants.TokenErrors.UnauthorizedClient)); } ///////////////////////////////////////////// // validate authorization code ///////////////////////////////////////////// var code = parameters.Get(OidcConstants.TokenRequest.Code); if (code.IsMissing()) { LogError("Authorization code is missing"); return(Invalid(OidcConstants.TokenErrors.InvalidGrant)); } if (code.Length > _options.InputLengthRestrictions.AuthorizationCode) { LogError("Authorization code is too long"); return(Invalid(OidcConstants.TokenErrors.InvalidGrant)); } _validatedRequest.AuthorizationCodeHandle = code; var authZcode = await _authorizationCodeStore.GetAuthorizationCodeAsync(code); if (authZcode == null) { LogError("Invalid authorization code: {code}", code); return(Invalid(OidcConstants.TokenErrors.InvalidGrant)); } await _authorizationCodeStore.RemoveAuthorizationCodeAsync(code); if (authZcode.CreationTime.HasExceeded(authZcode.Lifetime, _options.UtcNow)) { LogError("Authorization code expired: {code}", code); return(Invalid(OidcConstants.TokenErrors.InvalidGrant)); } ///////////////////////////////////////////// // populate session id ///////////////////////////////////////////// if (authZcode.SessionId.IsPresent()) { _validatedRequest.SessionId = authZcode.SessionId; } ///////////////////////////////////////////// // validate client binding ///////////////////////////////////////////// if (authZcode.ClientId != _validatedRequest.Client.ClientId) { LogError("Client {0} is trying to use a code from client {1}", _validatedRequest.Client.ClientId, authZcode.ClientId); return(Invalid(OidcConstants.TokenErrors.InvalidGrant)); } ///////////////////////////////////////////// // validate code expiration ///////////////////////////////////////////// if (authZcode.CreationTime.HasExceeded(_validatedRequest.Client.AuthorizationCodeLifetime, _options.UtcNow)) { LogError("Authorization code is expired"); return(Invalid(OidcConstants.TokenErrors.InvalidGrant)); } _validatedRequest.AuthorizationCode = authZcode; ///////////////////////////////////////////// // validate redirect_uri ///////////////////////////////////////////// var redirectUri = parameters.Get(OidcConstants.TokenRequest.RedirectUri); if (redirectUri.IsMissing()) { LogError("Redirect URI is missing"); return(Invalid(OidcConstants.TokenErrors.UnauthorizedClient)); } if (redirectUri.Equals(_validatedRequest.AuthorizationCode.RedirectUri, StringComparison.Ordinal) == false) { LogError("Invalid redirect_uri: {redirectUri}", redirectUri); return(Invalid(OidcConstants.TokenErrors.UnauthorizedClient)); } ///////////////////////////////////////////// // validate scopes are present ///////////////////////////////////////////// if (_validatedRequest.AuthorizationCode.RequestedScopes == null || !_validatedRequest.AuthorizationCode.RequestedScopes.Any()) { LogError("Authorization code has no associated scopes"); return(Invalid(OidcConstants.TokenErrors.InvalidRequest)); } ///////////////////////////////////////////// // validate PKCE parameters ///////////////////////////////////////////// var codeVerifier = parameters.Get(OidcConstants.TokenRequest.CodeVerifier); if (_validatedRequest.Client.RequirePkce || _validatedRequest.AuthorizationCode.CodeChallenge.IsPresent()) { _logger.LogDebug("Client required a proof key for code exchange. Starting PKCE validation"); var proofKeyResult = ValidateAuthorizationCodeWithProofKeyParameters(codeVerifier, _validatedRequest.AuthorizationCode); if (proofKeyResult.IsError) { return(proofKeyResult); } _validatedRequest.CodeVerifier = codeVerifier; } else { if (codeVerifier.IsPresent()) { LogError("Unexpected code_verifier: {codeVerifier}. This happens when the client is trying to use PKCE, but it is not enabled. Set RequirePkce to true.", codeVerifier); return(Invalid(OidcConstants.TokenErrors.InvalidGrant)); } } ///////////////////////////////////////////// // make sure user is enabled ///////////////////////////////////////////// var isActiveCtx = new IsActiveContext(_validatedRequest.AuthorizationCode.Subject, _validatedRequest.Client, IdentityServerConstants.ProfileIsActiveCallers.AuthorizationCodeValidation); await _profile.IsActiveAsync(isActiveCtx); if (isActiveCtx.IsActive == false) { LogError("User has been disabled: {subjectId}", _validatedRequest.AuthorizationCode.Subject.GetSubjectId()); return(Invalid(OidcConstants.TokenErrors.InvalidGrant)); } _logger.LogDebug("Validation of authorization code token request success"); return(Valid()); }
public async Task RemoveAllGrantsAsync_should_remove_all_grants() { await _userConsent.StoreUserConsentAsync(new Consent() { ClientId = "client1", SubjectId = "123", Scopes = new string[] { "foo1", "foo2" } }); await _userConsent.StoreUserConsentAsync(new Consent() { ClientId = "client2", SubjectId = "123", Scopes = new string[] { "foo3" } }); await _userConsent.StoreUserConsentAsync(new Consent() { ClientId = "client1", SubjectId = "456", Scopes = new string[] { "foo3" } }); await _referenceTokens.StoreReferenceTokenAsync("key1", new Token() { ClientId = "client1", Audiences = { "aud" }, CreationTime = DateTime.Now, Type = "type", Claims = new List <Claim> { new Claim("sub", "123"), new Claim("scope", "bar1"), new Claim("scope", "bar2"), }, }); await _referenceTokens.StoreReferenceTokenAsync("key2", new Token() { ClientId = "client2", Audiences = { "aud" }, CreationTime = DateTime.Now, Type = "type", Claims = new List <Claim> { new Claim("sub", "123"), new Claim("scope", "bar3"), }, }); await _referenceTokens.StoreReferenceTokenAsync("key3", new Token() { ClientId = "client1", Audiences = { "aud" }, CreationTime = DateTime.Now, Type = "type", Claims = new List <Claim> { new Claim("sub", "456"), new Claim("scope", "bar3"), }, }); await _refreshTokens.StoreRefreshTokenAsync("key4", new RefreshToken() { CreationTime = DateTime.Now, Lifetime = 10, AccessToken = new Token { ClientId = "client1", Audiences = { "aud" }, CreationTime = DateTime.Now, Type = "type", Claims = new List <Claim> { new Claim("sub", "123"), new Claim("scope", "baz1"), new Claim("scope", "baz2") } }, Version = 1 }); await _refreshTokens.StoreRefreshTokenAsync("key5", new RefreshToken() { CreationTime = DateTime.Now, Lifetime = 10, AccessToken = new Token { ClientId = "client1", Audiences = { "aud" }, CreationTime = DateTime.Now, Type = "type", Claims = new List <Claim> { new Claim("sub", "456"), new Claim("scope", "baz3"), } }, Version = 1 }); await _refreshTokens.StoreRefreshTokenAsync("key6", new RefreshToken() { CreationTime = DateTime.Now, Lifetime = 10, AccessToken = new Token { ClientId = "client2", Audiences = { "aud" }, CreationTime = DateTime.Now, Type = "type", Claims = new List <Claim> { new Claim("sub", "123"), new Claim("scope", "baz3"), } }, Version = 1 }); await _codes.StoreAuthorizationCodeAsync("key7", new AuthorizationCode() { ClientId = "client1", CreationTime = DateTime.Now, Lifetime = 10, Subject = _user, CodeChallenge = "challenge", RedirectUri = "http://client/cb", Nonce = "nonce", RequestedScopes = new string[] { "quux1", "quux2" } }); await _codes.StoreAuthorizationCodeAsync("key8", new AuthorizationCode() { ClientId = "client2", CreationTime = DateTime.Now, Lifetime = 10, Subject = _user, CodeChallenge = "challenge", RedirectUri = "http://client/cb", Nonce = "nonce", RequestedScopes = new string[] { "quux3" } }); await _codes.StoreAuthorizationCodeAsync("key9", new AuthorizationCode() { ClientId = "client1", CreationTime = DateTime.Now, Lifetime = 10, Subject = IdentityServerPrincipal.Create("456", "alice"), CodeChallenge = "challenge", RedirectUri = "http://client/cb", Nonce = "nonce", RequestedScopes = new string[] { "quux3" } }); await _subject.RemoveAllGrantsAsync("123", "client1"); (await _referenceTokens.GetReferenceTokenAsync("key1")).Should().BeNull(); (await _referenceTokens.GetReferenceTokenAsync("key2")).Should().NotBeNull(); (await _referenceTokens.GetReferenceTokenAsync("key3")).Should().NotBeNull(); (await _refreshTokens.GetRefreshTokenAsync("key4")).Should().BeNull(); (await _refreshTokens.GetRefreshTokenAsync("key5")).Should().NotBeNull(); (await _refreshTokens.GetRefreshTokenAsync("key6")).Should().NotBeNull(); (await _codes.GetAuthorizationCodeAsync("key7")).Should().BeNull(); (await _codes.GetAuthorizationCodeAsync("key8")).Should().NotBeNull(); (await _codes.GetAuthorizationCodeAsync("key9")).Should().NotBeNull(); }
public async Task RemoveAllGrantsAsync_should_remove_all_grants() { await _userConsent.StoreUserConsentAsync(new Consent() { ClientId = "client1", SubjectId = "123", Scopes = new string[] { "foo1", "foo2" } }); await _userConsent.StoreUserConsentAsync(new Consent() { ClientId = "client2", SubjectId = "123", Scopes = new string[] { "foo3" } }); await _userConsent.StoreUserConsentAsync(new Consent() { ClientId = "client1", SubjectId = "456", Scopes = new string[] { "foo3" } }); var handle1 = await _referenceTokens.StoreReferenceTokenAsync(new Token() { ClientId = "client1", Audiences = { "aud" }, CreationTime = DateTime.UtcNow, Lifetime = 10, Type = "type", Claims = new List <Claim> { new Claim("sub", "123"), new Claim("scope", "bar1"), new Claim("scope", "bar2") } }); var handle2 = await _referenceTokens.StoreReferenceTokenAsync(new Token() { ClientId = "client2", Audiences = { "aud" }, CreationTime = DateTime.UtcNow, Lifetime = 10, Type = "type", Claims = new List <Claim> { new Claim("sub", "123"), new Claim("scope", "bar3") } }); var handle3 = await _referenceTokens.StoreReferenceTokenAsync(new Token() { ClientId = "client1", Audiences = { "aud" }, CreationTime = DateTime.UtcNow, Lifetime = 10, Type = "type", Claims = new List <Claim> { new Claim("sub", "456"), new Claim("scope", "bar3") } }); var handle4 = await _refreshTokens.StoreRefreshTokenAsync(new RefreshToken() { CreationTime = DateTime.UtcNow, Lifetime = 10, AccessToken = new Token { ClientId = "client1", Audiences = { "aud" }, CreationTime = DateTime.UtcNow, Type = "type", Claims = new List <Claim> { new Claim("sub", "123"), new Claim("scope", "baz1"), new Claim("scope", "baz2") } }, Version = 1 }); var handle5 = await _refreshTokens.StoreRefreshTokenAsync(new RefreshToken() { CreationTime = DateTime.UtcNow, Lifetime = 10, AccessToken = new Token { ClientId = "client1", Audiences = { "aud" }, CreationTime = DateTime.UtcNow, Type = "type", Claims = new List <Claim> { new Claim("sub", "456"), new Claim("scope", "baz3") } }, Version = 1 }); var handle6 = await _refreshTokens.StoreRefreshTokenAsync(new RefreshToken() { CreationTime = DateTime.UtcNow, Lifetime = 10, AccessToken = new Token { ClientId = "client2", Audiences = { "aud" }, CreationTime = DateTime.UtcNow, Type = "type", Claims = new List <Claim> { new Claim("sub", "123"), new Claim("scope", "baz3") } }, Version = 1 }); var handle7 = await _codes.StoreAuthorizationCodeAsync(new AuthorizationCode() { ClientId = "client1", CreationTime = DateTime.UtcNow, Lifetime = 10, Subject = _user, CodeChallenge = "challenge", RedirectUri = "http://client/cb", Nonce = "nonce", RequestedScopes = new string[] { "quux1", "quux2" } }); var handle8 = await _codes.StoreAuthorizationCodeAsync(new AuthorizationCode() { ClientId = "client2", CreationTime = DateTime.UtcNow, Lifetime = 10, Subject = _user, CodeChallenge = "challenge", RedirectUri = "http://client/cb", Nonce = "nonce", RequestedScopes = new string[] { "quux3" } }); var handle9 = await _codes.StoreAuthorizationCodeAsync(new AuthorizationCode() { ClientId = "client1", CreationTime = DateTime.UtcNow, Lifetime = 10, Subject = new IdentityServerUser("456").CreatePrincipal(), CodeChallenge = "challenge", RedirectUri = "http://client/cb", Nonce = "nonce", RequestedScopes = new string[] { "quux3" } }); await _subject.RemoveAllGrantsAsync("123", "client1"); (await _referenceTokens.GetReferenceTokenAsync(handle1)).Should().BeNull(); (await _referenceTokens.GetReferenceTokenAsync(handle2)).Should().NotBeNull(); (await _referenceTokens.GetReferenceTokenAsync(handle3)).Should().NotBeNull(); (await _refreshTokens.GetRefreshTokenAsync(handle4)).Should().BeNull(); (await _refreshTokens.GetRefreshTokenAsync(handle5)).Should().NotBeNull(); (await _refreshTokens.GetRefreshTokenAsync(handle6)).Should().NotBeNull(); (await _codes.GetAuthorizationCodeAsync(handle7)).Should().BeNull(); (await _codes.GetAuthorizationCodeAsync(handle8)).Should().NotBeNull(); (await _codes.GetAuthorizationCodeAsync(handle9)).Should().NotBeNull(); }
private async Task <TokenRequestValidationResult> ValidateAuthorizationCodeRequestAsync(NameValueCollection parameters) { _logger.LogDebug("Start validation of authorization code token request"); ///////////////////////////////////////////// // check if client is authorized for grant type ///////////////////////////////////////////// if (!_validatedRequest.Client.AllowedGrantTypes.ToList().Contains(GrantType.AuthorizationCode) && !_validatedRequest.Client.AllowedGrantTypes.ToList().Contains(GrantType.Hybrid)) { LogError("Client not authorized for code flow"); return(Invalid(OidcConstants.TokenErrors.UnauthorizedClient)); } ///////////////////////////////////////////// // validate authorization code ///////////////////////////////////////////// var code = parameters.Get(OidcConstants.TokenRequest.Code); if (code.IsMissing()) { LogError("Authorization code is missing"); return(Invalid(OidcConstants.TokenErrors.InvalidGrant)); } if (code.Length > _options.InputLengthRestrictions.AuthorizationCode) { LogError("Authorization code is too long"); return(Invalid(OidcConstants.TokenErrors.InvalidGrant)); } _validatedRequest.AuthorizationCodeHandle = code; var authZcode = await _authorizationCodeStore.GetAuthorizationCodeAsync(code); if (authZcode == null) { LogError("Invalid authorization code", new { code }); return(Invalid(OidcConstants.TokenErrors.InvalidGrant)); } ///////////////////////////////////////////// // validate client binding ///////////////////////////////////////////// if (authZcode.ClientId != _validatedRequest.Client.ClientId) { LogError("Client is trying to use a code from a different client", new { clientId = _validatedRequest.Client.ClientId, codeClient = authZcode.ClientId }); return(Invalid(OidcConstants.TokenErrors.InvalidGrant)); } // remove code from store // todo: set to consumed in the future? await _authorizationCodeStore.RemoveAuthorizationCodeAsync(code); if (authZcode.CreationTime.HasExceeded(authZcode.Lifetime, _clock.UtcNow.UtcDateTime)) { LogError("Authorization code expired", new { code }); return(Invalid(OidcConstants.TokenErrors.InvalidGrant)); } ///////////////////////////////////////////// // populate session id ///////////////////////////////////////////// if (authZcode.SessionId.IsPresent()) { _validatedRequest.SessionId = authZcode.SessionId; } ///////////////////////////////////////////// // validate code expiration ///////////////////////////////////////////// if (authZcode.CreationTime.HasExceeded(_validatedRequest.Client.AuthorizationCodeLifetime, _clock.UtcNow.UtcDateTime)) { LogError("Authorization code is expired"); return(Invalid(OidcConstants.TokenErrors.InvalidGrant)); } _validatedRequest.AuthorizationCode = authZcode; _validatedRequest.Subject = authZcode.Subject; ///////////////////////////////////////////// // validate redirect_uri ///////////////////////////////////////////// var redirectUri = parameters.Get(OidcConstants.TokenRequest.RedirectUri); if (redirectUri.IsMissing()) { LogError("Redirect URI is missing"); return(Invalid(OidcConstants.TokenErrors.UnauthorizedClient)); } if (redirectUri.Equals(_validatedRequest.AuthorizationCode.RedirectUri, StringComparison.Ordinal) == false) { LogError("Invalid redirect_uri", new { redirectUri, expectedRedirectUri = _validatedRequest.AuthorizationCode.RedirectUri }); return(Invalid(OidcConstants.TokenErrors.InvalidGrant)); } ///////////////////////////////////////////// // validate scopes are present ///////////////////////////////////////////// if (_validatedRequest.AuthorizationCode.RequestedScopes == null || !_validatedRequest.AuthorizationCode.RequestedScopes.Any()) { LogError("Authorization code has no associated scopes"); return(Invalid(OidcConstants.TokenErrors.InvalidRequest)); } ////////////////////////////////////////////////////////// // resource indicator ////////////////////////////////////////////////////////// if (_validatedRequest.RequestedResourceIndicator != null && _validatedRequest.AuthorizationCode.RequestedResourceIndicators?.Any() == true && !_validatedRequest.AuthorizationCode.RequestedResourceIndicators.Contains(_validatedRequest.RequestedResourceIndicator)) { return(Invalid(OidcConstants.AuthorizeErrors.InvalidTarget, "Resource indicator does not match any resource indicator in the original authorize request.")); } ////////////////////////////////////////////////////////// // resource and scope validation ////////////////////////////////////////////////////////// var validatedResources = await _resourceValidator.ValidateRequestedResourcesAsync(new ResourceValidationRequest { Client = _validatedRequest.Client, Scopes = _validatedRequest.AuthorizationCode.RequestedScopes, ResourceIndicators = _validatedRequest.AuthorizationCode.RequestedResourceIndicators, // if we are issuing a refresh token, then we need to allow the non-isolated resource IncludeNonIsolatedApiResources = _validatedRequest.AuthorizationCode.RequestedScopes.Contains(OidcConstants.StandardScopes.OfflineAccess) }); if (!validatedResources.Succeeded) { if (validatedResources.InvalidResourceIndicators.Any()) { return(Invalid(OidcConstants.AuthorizeErrors.InvalidTarget, "Invalid resource indicator.")); } if (validatedResources.InvalidScopes.Any()) { return(Invalid(OidcConstants.AuthorizeErrors.InvalidScope, "Invalid scope.")); } } LicenseValidator.ValidateResourceIndicators(_validatedRequest.RequestedResourceIndicator); _validatedRequest.ValidatedResources = validatedResources.FilterByResourceIndicator(_validatedRequest.RequestedResourceIndicator); ///////////////////////////////////////////// // validate PKCE parameters ///////////////////////////////////////////// var codeVerifier = parameters.Get(OidcConstants.TokenRequest.CodeVerifier); if (_validatedRequest.Client.RequirePkce || _validatedRequest.AuthorizationCode.CodeChallenge.IsPresent()) { _logger.LogDebug("Client required a proof key for code exchange. Starting PKCE validation"); var proofKeyResult = ValidateAuthorizationCodeWithProofKeyParameters(codeVerifier, _validatedRequest.AuthorizationCode); if (proofKeyResult.IsError) { return(proofKeyResult); } _validatedRequest.CodeVerifier = codeVerifier; } else { if (codeVerifier.IsPresent()) { LogError("Unexpected code_verifier: {codeVerifier}. This happens when the client is trying to use PKCE, but it is not enabled. Set RequirePkce to true.", codeVerifier); return(Invalid(OidcConstants.TokenErrors.InvalidGrant)); } } ///////////////////////////////////////////// // make sure user is enabled ///////////////////////////////////////////// var isActiveCtx = new IsActiveContext(_validatedRequest.AuthorizationCode.Subject, _validatedRequest.Client, IdentityServerConstants.ProfileIsActiveCallers.AuthorizationCodeValidation); await _profile.IsActiveAsync(isActiveCtx); if (isActiveCtx.IsActive == false) { LogError("User has been disabled", new { subjectId = _validatedRequest.AuthorizationCode.Subject.GetSubjectId() }); return(Invalid(OidcConstants.TokenErrors.InvalidGrant)); } _logger.LogDebug("Validation of authorization code token request success"); return(Valid()); }