diff --git a/src/OpenIddict/OpenIddictProvider.Introspection.cs b/src/OpenIddict/OpenIddictProvider.Introspection.cs index 9366609f..150d18c5 100644 --- a/src/OpenIddict/OpenIddictProvider.Introspection.cs +++ b/src/OpenIddict/OpenIddictProvider.Introspection.cs @@ -127,40 +127,58 @@ namespace OpenIddict var identifier = context.Ticket.GetTokenId(); Debug.Assert(!string.IsNullOrEmpty(identifier), "The authentication ticket should contain a token identifier."); - // Note: the OpenID Connect server middleware allows authorized presenters (e.g relying parties) to introspect access tokens - // but OpenIddict uses a stricter policy that only allows resource servers to use the introspection endpoint, unless the ticket - // doesn't have any audience: in this case, the caller is allowed to introspect the token even if it's not listed as a valid audience. - if (context.Ticket.IsAccessToken() && context.Ticket.HasAudience() && !context.Ticket.HasAudience(context.Request.ClientId)) + if (!context.Ticket.IsAccessToken()) { - logger.LogWarning("The client application '{ClientId}' is not allowed to introspect the access " + - "token '{Identifier}' because it's not listed as a valid audience.", - context.Request.ClientId, identifier); + logger.LogError("The token '{Identifier}' is not an access token and thus cannot be introspected.", identifier); context.Active = false; return; } - if (options.DisableTokenRevocation) + // Note: the OpenID Connect server middleware allows authorized presenters (e.g relying parties) to introspect + // tokens but OpenIddict uses a stricter policy that only allows resource servers to use the introspection endpoint. + // For that, an error is automatically returned if no explicit audience is attached to the authentication ticket. + if (!context.Ticket.HasAudience()) { + logger.LogError("The token '{Identifier}' doesn't have any audience attached " + + "and cannot be introspected. To add an audience, use the " + + "'ticket.SetResources(...)' extension when creating the ticket.", identifier); + + context.Active = false; + + return; + } + + if (!context.Ticket.HasAudience(context.Request.ClientId)) + { + logger.LogError("The client application '{ClientId}' is not allowed to introspect the access " + + "token '{Identifier}' because it's not listed as a valid audience.", + context.Request.ClientId, identifier); + + context.Active = false; + return; } - // When the received ticket is revocable, ensure it is still valid. - if (options.UseReferenceTokens || context.Ticket.IsAuthorizationCode() || context.Ticket.IsRefreshToken()) + // If the received token is not a reference access token, + // skip the additional reference token validation checks. + if (!options.UseReferenceTokens) { - // Retrieve the token from the request properties. If it's marked as invalid, return active = false. - var token = context.Request.GetProperty($"{OpenIddictConstants.Properties.Token}:{identifier}"); - Debug.Assert(token != null, "The token shouldn't be null."); + return; + } - if (!await tokens.IsValidAsync(token)) - { - logger.LogInformation("The token '{Identifier}' was declared as inactive because it was revoked.", identifier); + // Retrieve the token from the request properties. If it's marked as invalid, return active = false. + var token = context.Request.GetProperty($"{OpenIddictConstants.Properties.Token}:{identifier}"); + Debug.Assert(token != null, "The token shouldn't be null."); - context.Active = false; + if (!await tokens.IsValidAsync(token)) + { + logger.LogInformation("The token '{Identifier}' was declared as inactive because it was revoked.", identifier); + + context.Active = false; - return; - } + return; } } } diff --git a/test/OpenIddict.Tests/OpenIddictProviderTests.Introspection.cs b/test/OpenIddict.Tests/OpenIddictProviderTests.Introspection.cs index 23e92e59..90dd3671 100644 --- a/test/OpenIddict.Tests/OpenIddictProviderTests.Introspection.cs +++ b/test/OpenIddict.Tests/OpenIddictProviderTests.Introspection.cs @@ -231,8 +231,11 @@ namespace OpenIddict.Tests Mock.Get(manager).Verify(mock => mock.ValidateClientSecretAsync(application, "7Fjfp0ZBr1KtDRbnfVdmIw", It.IsAny()), Times.Once()); } - [Fact] - public async Task HandleIntrospectionRequest_RequestIsRejectedWhenClientIsNotAValidAudience() + [Theory] + [InlineData(OpenIdConnectConstants.TokenUsages.AuthorizationCode)] + [InlineData(OpenIdConnectConstants.TokenUsages.IdToken)] + [InlineData(OpenIdConnectConstants.TokenUsages.RefreshToken)] + public async Task HandleIntrospectionRequest_RequestIsRejectedWhenTokenIsNotAnAccessToken(string type) { // Arrange var identity = new ClaimsIdentity(OpenIdConnectServerDefaults.AuthenticationScheme); @@ -243,9 +246,8 @@ namespace OpenIddict.Tests new AuthenticationProperties(), OpenIdConnectServerDefaults.AuthenticationScheme); - ticket.SetAudiences("Contoso"); ticket.SetTokenId("3E228451-1555-46F7-A471-951EFBA23A56"); - ticket.SetTokenUsage(OpenIdConnectConstants.TokenUsages.AccessToken); + ticket.SetTokenUsage(type); var format = new Mock>(); @@ -291,7 +293,7 @@ namespace OpenIddict.Tests } [Fact] - public async Task HandleIntrospectionRequest_AuthorizationCodeRevocationIsIgnoredWhenTokenRevocationIsDisabled() + public async Task HandleIntrospectionRequest_RequestIsRejectedWhenAudienceIsMissing() { // Arrange var identity = new ClaimsIdentity(OpenIdConnectServerDefaults.AuthenticationScheme); @@ -303,7 +305,7 @@ namespace OpenIddict.Tests OpenIdConnectServerDefaults.AuthenticationScheme); ticket.SetTokenId("3E228451-1555-46F7-A471-951EFBA23A56"); - ticket.SetTokenUsage(OpenIdConnectConstants.TokenUsages.AuthorizationCode); + ticket.SetTokenUsage(OpenIdConnectConstants.TokenUsages.AccessToken); var format = new Mock>(); @@ -330,11 +332,7 @@ namespace OpenIddict.Tests .ReturnsAsync(true); })); - builder.Configure(options => options.AuthorizationCodeFormat = format.Object); - builder.Configure(options => options.RevocationEndpointPath = PathString.Empty); - - builder.DisableTokenRevocation(); - builder.DisableSlidingExpiration(); + builder.Configure(options => options.AccessTokenFormat = format.Object); }); var client = new OpenIdConnectClient(server.CreateClient()); @@ -348,11 +346,12 @@ namespace OpenIddict.Tests }); // Assert - Assert.True((bool) response[OpenIdConnectConstants.Claims.Active]); + Assert.Single(response.GetParameters()); + Assert.False((bool) response[OpenIdConnectConstants.Claims.Active]); } [Fact] - public async Task HandleIntrospectionRequest_RefreshTokenRevocationIsIgnoredWhenTokenRevocationIsDisabled() + public async Task HandleIntrospectionRequest_RequestIsRejectedWhenClientIsNotAValidAudience() { // Arrange var identity = new ClaimsIdentity(OpenIdConnectServerDefaults.AuthenticationScheme); @@ -363,8 +362,9 @@ namespace OpenIddict.Tests new AuthenticationProperties(), OpenIdConnectServerDefaults.AuthenticationScheme); + ticket.SetAudiences("Contoso"); ticket.SetTokenId("3E228451-1555-46F7-A471-951EFBA23A56"); - ticket.SetTokenUsage(OpenIdConnectConstants.TokenUsages.AuthorizationCode); + ticket.SetTokenUsage(OpenIdConnectConstants.TokenUsages.AccessToken); var format = new Mock>(); @@ -391,11 +391,7 @@ namespace OpenIddict.Tests .ReturnsAsync(true); })); - builder.Configure(options => options.AuthorizationCodeFormat = format.Object); - builder.Configure(options => options.RevocationEndpointPath = PathString.Empty); - - builder.DisableTokenRevocation(); - builder.DisableSlidingExpiration(); + builder.Configure(options => options.AccessTokenFormat = format.Object); }); var client = new OpenIdConnectClient(server.CreateClient()); @@ -409,11 +405,12 @@ namespace OpenIddict.Tests }); // Assert - Assert.True((bool) response[OpenIdConnectConstants.Claims.Active]); + Assert.Single(response.GetParameters()); + Assert.False((bool) response[OpenIdConnectConstants.Claims.Active]); } [Fact] - public async Task HandleIntrospectionRequest_RequestIsRejectedWhenAccessTokenIsUnknown() + public async Task HandleIntrospectionRequest_RequestIsRejectedWhenReferenceTokenIsUnknown() { // Arrange var identity = new ClaimsIdentity(OpenIdConnectServerDefaults.AuthenticationScheme); @@ -469,7 +466,7 @@ namespace OpenIddict.Tests } [Fact] - public async Task HandleIntrospectionRequest_RequestIsRejectedWhenAccessTokenIsInvalid() + public async Task HandleIntrospectionRequest_RequestIsRejectedWhenReferenceTokenIsInvalid() { // Arrange var identity = new ClaimsIdentity(OpenIdConnectServerDefaults.AuthenticationScheme); @@ -480,6 +477,7 @@ namespace OpenIddict.Tests new AuthenticationProperties(), OpenIdConnectServerDefaults.AuthenticationScheme); + ticket.SetAudiences("Fabrikam"); ticket.SetTokenId("3E228451-1555-46F7-A471-951EFBA23A56"); ticket.SetTokenUsage(OpenIdConnectConstants.TokenUsages.AccessToken); @@ -552,298 +550,5 @@ namespace OpenIddict.Tests Mock.Get(manager).Verify(mock => mock.FindByReferenceIdAsync("QaTk2f6UPe9trKismGBJr0OIs0KqpvNrqRsJqGuJAAI", It.IsAny()), Times.Once()); Mock.Get(manager).Verify(mock => mock.IsValidAsync(token, It.IsAny()), Times.Once()); } - - [Fact] - public async Task HandleIntrospectionRequest_RequestIsRejectedWhenAuthorizationCodeIsUnknown() - { - // Arrange - var identity = new ClaimsIdentity(OpenIdConnectServerDefaults.AuthenticationScheme); - identity.AddClaim(OpenIdConnectConstants.Claims.Subject, "Bob le Bricoleur"); - - var ticket = new AuthenticationTicket( - new ClaimsPrincipal(identity), - new AuthenticationProperties(), - OpenIdConnectServerDefaults.AuthenticationScheme); - - ticket.SetTokenId("3E228451-1555-46F7-A471-951EFBA23A56"); - ticket.SetTokenUsage(OpenIdConnectConstants.TokenUsages.AuthorizationCode); - - var format = new Mock>(); - - format.Setup(mock => mock.Unprotect("2YotnFZFEjr1zCsicMWpAA")) - .Returns(ticket); - - var manager = CreateTokenManager(instance => - { - instance.Setup(mock => mock.FindByIdAsync("3E228451-1555-46F7-A471-951EFBA23A56", It.IsAny())) - .ReturnsAsync(value: null); - }); - - var server = CreateAuthorizationServer(builder => - { - builder.Services.AddSingleton(CreateApplicationManager(instance => - { - var application = new OpenIddictApplication(); - - instance.Setup(mock => mock.FindByClientIdAsync("Fabrikam", It.IsAny())) - .ReturnsAsync(application); - - instance.Setup(mock => mock.HasPermissionAsync(application, - OpenIddictConstants.Permissions.Endpoints.Introspection, It.IsAny())) - .ReturnsAsync(true); - - instance.Setup(mock => mock.GetClientTypeAsync(application, It.IsAny())) - .ReturnsAsync(OpenIddictConstants.ClientTypes.Confidential); - - instance.Setup(mock => mock.ValidateClientSecretAsync(application, "7Fjfp0ZBr1KtDRbnfVdmIw", It.IsAny())) - .ReturnsAsync(true); - })); - - builder.Services.AddSingleton(manager); - - builder.Configure(options => options.AuthorizationCodeFormat = format.Object); - }); - - var client = new OpenIdConnectClient(server.CreateClient()); - - // Act - var response = await client.PostAsync(IntrospectionEndpoint, new OpenIdConnectRequest - { - ClientId = "Fabrikam", - ClientSecret = "7Fjfp0ZBr1KtDRbnfVdmIw", - Token = "2YotnFZFEjr1zCsicMWpAA" - }); - - // Assert - Assert.Single(response.GetParameters()); - Assert.False((bool) response[OpenIdConnectConstants.Claims.Active]); - - Mock.Get(manager).Verify(mock => mock.FindByIdAsync("3E228451-1555-46F7-A471-951EFBA23A56", It.IsAny()), Times.Once()); - } - - [Fact] - public async Task HandleIntrospectionRequest_RequestIsRejectedWhenAuthorizationCodeIsInvalid() - { - // Arrange - var identity = new ClaimsIdentity(OpenIdConnectServerDefaults.AuthenticationScheme); - identity.AddClaim(OpenIdConnectConstants.Claims.Subject, "Bob le Bricoleur"); - - var ticket = new AuthenticationTicket( - new ClaimsPrincipal(identity), - new AuthenticationProperties(), - OpenIdConnectServerDefaults.AuthenticationScheme); - - ticket.SetTokenId("3E228451-1555-46F7-A471-951EFBA23A56"); - ticket.SetTokenUsage(OpenIdConnectConstants.TokenUsages.AuthorizationCode); - - var format = new Mock>(); - - format.Setup(mock => mock.Unprotect("2YotnFZFEjr1zCsicMWpAA")) - .Returns(ticket); - - var token = new OpenIddictToken(); - - var manager = CreateTokenManager(instance => - { - instance.Setup(mock => mock.FindByIdAsync("3E228451-1555-46F7-A471-951EFBA23A56", It.IsAny())) - .ReturnsAsync(token); - - instance.Setup(mock => mock.GetIdAsync(token, It.IsAny())) - .ReturnsAsync("3E228451-1555-46F7-A471-951EFBA23A56"); - - instance.Setup(mock => mock.IsValidAsync(token, It.IsAny())) - .ReturnsAsync(false); - }); - - var server = CreateAuthorizationServer(builder => - { - builder.Services.AddSingleton(CreateApplicationManager(instance => - { - var application = new OpenIddictApplication(); - - instance.Setup(mock => mock.FindByClientIdAsync("Fabrikam", It.IsAny())) - .ReturnsAsync(application); - - instance.Setup(mock => mock.HasPermissionAsync(application, - OpenIddictConstants.Permissions.Endpoints.Introspection, It.IsAny())) - .ReturnsAsync(true); - - instance.Setup(mock => mock.GetClientTypeAsync(application, It.IsAny())) - .ReturnsAsync(OpenIddictConstants.ClientTypes.Confidential); - - instance.Setup(mock => mock.ValidateClientSecretAsync(application, "7Fjfp0ZBr1KtDRbnfVdmIw", It.IsAny())) - .ReturnsAsync(true); - })); - - builder.Services.AddSingleton(manager); - - builder.Configure(options => options.AuthorizationCodeFormat = format.Object); - }); - - var client = new OpenIdConnectClient(server.CreateClient()); - - // Act - var response = await client.PostAsync(IntrospectionEndpoint, new OpenIdConnectRequest - { - ClientId = "Fabrikam", - ClientSecret = "7Fjfp0ZBr1KtDRbnfVdmIw", - Token = "2YotnFZFEjr1zCsicMWpAA" - }); - - // Assert - Assert.Single(response.GetParameters()); - Assert.False((bool) response[OpenIdConnectConstants.Claims.Active]); - - Mock.Get(manager).Verify(mock => mock.FindByIdAsync("3E228451-1555-46F7-A471-951EFBA23A56", It.IsAny()), Times.Once()); - Mock.Get(manager).Verify(mock => mock.IsValidAsync(token, It.IsAny()), Times.Once()); - } - - [Fact] - public async Task HandleIntrospectionRequest_RequestIsRejectedWhenRefreshTokenIsUnknown() - { - // Arrange - var identity = new ClaimsIdentity(OpenIdConnectServerDefaults.AuthenticationScheme); - identity.AddClaim(OpenIdConnectConstants.Claims.Subject, "Bob le Bricoleur"); - - var ticket = new AuthenticationTicket( - new ClaimsPrincipal(identity), - new AuthenticationProperties(), - OpenIdConnectServerDefaults.AuthenticationScheme); - - ticket.SetTokenId("3E228451-1555-46F7-A471-951EFBA23A56"); - ticket.SetTokenUsage(OpenIdConnectConstants.TokenUsages.RefreshToken); - - var format = new Mock>(); - - format.Setup(mock => mock.Unprotect("2YotnFZFEjr1zCsicMWpAA")) - .Returns(ticket); - - var manager = CreateTokenManager(instance => - { - instance.Setup(mock => mock.FindByIdAsync("3E228451-1555-46F7-A471-951EFBA23A56", It.IsAny())) - .ReturnsAsync(value: null); - }); - - var server = CreateAuthorizationServer(builder => - { - builder.Services.AddSingleton(CreateApplicationManager(instance => - { - var application = new OpenIddictApplication(); - - instance.Setup(mock => mock.FindByClientIdAsync("Fabrikam", It.IsAny())) - .ReturnsAsync(application); - - instance.Setup(mock => mock.HasPermissionAsync(application, - OpenIddictConstants.Permissions.Endpoints.Introspection, It.IsAny())) - .ReturnsAsync(true); - - instance.Setup(mock => mock.GetClientTypeAsync(application, It.IsAny())) - .ReturnsAsync(OpenIddictConstants.ClientTypes.Confidential); - - instance.Setup(mock => mock.GetIdAsync(application, It.IsAny())) - .ReturnsAsync("3E228451-1555-46F7-A471-951EFBA23A56"); - - instance.Setup(mock => mock.ValidateClientSecretAsync(application, "7Fjfp0ZBr1KtDRbnfVdmIw", It.IsAny())) - .ReturnsAsync(true); - })); - - builder.Services.AddSingleton(manager); - - builder.Configure(options => options.RefreshTokenFormat = format.Object); - }); - - var client = new OpenIdConnectClient(server.CreateClient()); - - // Act - var response = await client.PostAsync(IntrospectionEndpoint, new OpenIdConnectRequest - { - ClientId = "Fabrikam", - ClientSecret = "7Fjfp0ZBr1KtDRbnfVdmIw", - Token = "2YotnFZFEjr1zCsicMWpAA" - }); - - // Assert - Assert.Single(response.GetParameters()); - Assert.False((bool) response[OpenIdConnectConstants.Claims.Active]); - - Mock.Get(manager).Verify(mock => mock.FindByIdAsync("3E228451-1555-46F7-A471-951EFBA23A56", It.IsAny()), Times.Once()); - } - - [Fact] - public async Task HandleIntrospectionRequest_RequestIsRejectedWhenRefreshTokenIsInvalid() - { - // Arrange - var identity = new ClaimsIdentity(OpenIdConnectServerDefaults.AuthenticationScheme); - identity.AddClaim(OpenIdConnectConstants.Claims.Subject, "Bob le Bricoleur"); - - var ticket = new AuthenticationTicket( - new ClaimsPrincipal(identity), - new AuthenticationProperties(), - OpenIdConnectServerDefaults.AuthenticationScheme); - - ticket.SetTokenId("3E228451-1555-46F7-A471-951EFBA23A56"); - ticket.SetTokenUsage(OpenIdConnectConstants.TokenUsages.RefreshToken); - - var format = new Mock>(); - - format.Setup(mock => mock.Unprotect("2YotnFZFEjr1zCsicMWpAA")) - .Returns(ticket); - - var token = new OpenIddictToken(); - - var manager = CreateTokenManager(instance => - { - instance.Setup(mock => mock.FindByIdAsync("3E228451-1555-46F7-A471-951EFBA23A56", It.IsAny())) - .ReturnsAsync(token); - - instance.Setup(mock => mock.GetIdAsync(token, It.IsAny())) - .ReturnsAsync("3E228451-1555-46F7-A471-951EFBA23A56"); - - instance.Setup(mock => mock.IsValidAsync(token, It.IsAny())) - .ReturnsAsync(false); - }); - - var server = CreateAuthorizationServer(builder => - { - builder.Services.AddSingleton(CreateApplicationManager(instance => - { - var application = new OpenIddictApplication(); - - instance.Setup(mock => mock.FindByClientIdAsync("Fabrikam", It.IsAny())) - .ReturnsAsync(application); - - instance.Setup(mock => mock.HasPermissionAsync(application, - OpenIddictConstants.Permissions.Endpoints.Introspection, It.IsAny())) - .ReturnsAsync(true); - - instance.Setup(mock => mock.GetClientTypeAsync(application, It.IsAny())) - .ReturnsAsync(OpenIddictConstants.ClientTypes.Confidential); - - instance.Setup(mock => mock.ValidateClientSecretAsync(application, "7Fjfp0ZBr1KtDRbnfVdmIw", It.IsAny())) - .ReturnsAsync(true); - })); - - builder.Services.AddSingleton(manager); - - builder.Configure(options => options.RefreshTokenFormat = format.Object); - }); - - var client = new OpenIdConnectClient(server.CreateClient()); - - // Act - var response = await client.PostAsync(IntrospectionEndpoint, new OpenIdConnectRequest - { - ClientId = "Fabrikam", - ClientSecret = "7Fjfp0ZBr1KtDRbnfVdmIw", - Token = "2YotnFZFEjr1zCsicMWpAA" - }); - - // Assert - Assert.Single(response.GetParameters()); - Assert.False((bool) response[OpenIdConnectConstants.Claims.Active]); - - Mock.Get(manager).Verify(mock => mock.FindByIdAsync("3E228451-1555-46F7-A471-951EFBA23A56", It.IsAny()), Times.Once()); - Mock.Get(manager).Verify(mock => mock.IsValidAsync(token, It.IsAny()), Times.Once()); - } } } diff --git a/test/OpenIddict.Tests/OpenIddictProviderTests.Serialization.cs b/test/OpenIddict.Tests/OpenIddictProviderTests.Serialization.cs index 2a8eacef..5e47b499 100644 --- a/test/OpenIddict.Tests/OpenIddictProviderTests.Serialization.cs +++ b/test/OpenIddict.Tests/OpenIddictProviderTests.Serialization.cs @@ -91,6 +91,7 @@ namespace OpenIddict.Tests new AuthenticationProperties(), OpenIdConnectServerDefaults.AuthenticationScheme); + ticket.SetAudiences("Fabrikam"); ticket.SetTokenId("3E228451-1555-46F7-A471-951EFBA23A56"); ticket.SetTokenUsage(OpenIdConnectConstants.TokenUsages.AccessToken); @@ -356,6 +357,7 @@ namespace OpenIddict.Tests new AuthenticationProperties(), OpenIdConnectServerDefaults.AuthenticationScheme); + ticket.SetAudiences("Fabrikam"); ticket.SetTokenId("3E228451-1555-46F7-A471-951EFBA23A56"); var format = new Mock>(); @@ -461,7 +463,11 @@ namespace OpenIddict.Tests .ReturnsAsync(application); instance.Setup(mock => mock.HasPermissionAsync(application, - OpenIddictConstants.Permissions.Endpoints.Introspection, It.IsAny())) + OpenIddictConstants.Permissions.Endpoints.Token, It.IsAny())) + .ReturnsAsync(true); + + instance.Setup(mock => mock.HasPermissionAsync(application, + OpenIddictConstants.Permissions.GrantTypes.AuthorizationCode, It.IsAny())) .ReturnsAsync(true); instance.Setup(mock => mock.GetClientTypeAsync(application, It.IsAny())) @@ -481,17 +487,18 @@ namespace OpenIddict.Tests var client = new OpenIdConnectClient(server.CreateClient()); // Act - var response = await client.PostAsync(IntrospectionEndpoint, new OpenIdConnectRequest + var response = await client.PostAsync(TokenEndpoint, new OpenIdConnectRequest { ClientId = "Fabrikam", ClientSecret = "7Fjfp0ZBr1KtDRbnfVdmIw", - Token = "2YotnFZFEjr1zCsicMWpAA", - TokenTypeHint = OpenIdConnectConstants.TokenTypeHints.AuthorizationCode + Code = "2YotnFZFEjr1zCsicMWpAA", + GrantType = OpenIdConnectConstants.GrantTypes.AuthorizationCode, + RedirectUri = "http://www.fabrikam.com/path" }); // Assert - Assert.Single(response.GetParameters()); - Assert.False((bool) response[OpenIdConnectConstants.Claims.Active]); + Assert.Equal(OpenIdConnectConstants.Errors.InvalidGrant, response.Error); + Assert.Equal("The specified authorization code is invalid.", response.ErrorDescription); format.Verify(mock => mock.Unprotect("2YotnFZFEjr1zCsicMWpAA"), Times.Never()); Mock.Get(manager).Verify(mock => mock.FindByIdAsync("3E228451-1555-46F7-A471-951EFBA23A56", It.IsAny()), Times.Never()); @@ -509,6 +516,7 @@ namespace OpenIddict.Tests new AuthenticationProperties(), OpenIdConnectServerDefaults.AuthenticationScheme); + ticket.SetPresenters("Fabrikam"); ticket.SetTokenId("3E228451-1555-46F7-A471-951EFBA23A56"); var format = new Mock>(); @@ -540,7 +548,11 @@ namespace OpenIddict.Tests .ReturnsAsync(application); instance.Setup(mock => mock.HasPermissionAsync(application, - OpenIddictConstants.Permissions.Endpoints.Introspection, It.IsAny())) + OpenIddictConstants.Permissions.Endpoints.Token, It.IsAny())) + .ReturnsAsync(true); + + instance.Setup(mock => mock.HasPermissionAsync(application, + OpenIddictConstants.Permissions.GrantTypes.AuthorizationCode, It.IsAny())) .ReturnsAsync(true); instance.Setup(mock => mock.GetClientTypeAsync(application, It.IsAny())) @@ -552,22 +564,23 @@ namespace OpenIddict.Tests builder.Services.AddSingleton(manager); - builder.Configure(options => options.RefreshTokenFormat = format.Object); + builder.Configure(options => options.AuthorizationCodeFormat = format.Object); }); var client = new OpenIdConnectClient(server.CreateClient()); // Act - var response = await client.PostAsync(IntrospectionEndpoint, new OpenIdConnectRequest + var response = await client.PostAsync(TokenEndpoint, new OpenIdConnectRequest { ClientId = "Fabrikam", ClientSecret = "7Fjfp0ZBr1KtDRbnfVdmIw", - Token = "2YotnFZFEjr1zCsicMWpAA", - TokenTypeHint = OpenIdConnectConstants.TokenTypeHints.AuthorizationCode + Code = "2YotnFZFEjr1zCsicMWpAA", + GrantType = OpenIdConnectConstants.GrantTypes.AuthorizationCode, + RedirectUri = "http://www.fabrikam.com/path" }); // Assert - Assert.True((bool) response[OpenIdConnectConstants.Claims.Active]); + Assert.NotNull(response.AccessToken); format.Verify(mock => mock.Unprotect("2YotnFZFEjr1zCsicMWpAA"), Times.Once()); Mock.Get(manager).Verify(mock => mock.FindByReferenceIdAsync(It.IsAny(), It.IsAny()), Times.Never()); @@ -598,7 +611,11 @@ namespace OpenIddict.Tests .ReturnsAsync(application); instance.Setup(mock => mock.HasPermissionAsync(application, - OpenIddictConstants.Permissions.Endpoints.Introspection, It.IsAny())) + OpenIddictConstants.Permissions.Endpoints.Token, It.IsAny())) + .ReturnsAsync(true); + + instance.Setup(mock => mock.HasPermissionAsync(application, + OpenIddictConstants.Permissions.GrantTypes.AuthorizationCode, It.IsAny())) .ReturnsAsync(true); instance.Setup(mock => mock.GetClientTypeAsync(application, It.IsAny())) @@ -616,17 +633,18 @@ namespace OpenIddict.Tests var client = new OpenIdConnectClient(server.CreateClient()); // Act - var response = await client.PostAsync(IntrospectionEndpoint, new OpenIdConnectRequest + var response = await client.PostAsync(TokenEndpoint, new OpenIdConnectRequest { ClientId = "Fabrikam", ClientSecret = "7Fjfp0ZBr1KtDRbnfVdmIw", - Token = "HQnldPTjH_9m85GcS-5PPYaCxmJTt1umxOa2y9ggVUQ", - TokenTypeHint = OpenIdConnectConstants.TokenTypeHints.AuthorizationCode + Code = "HQnldPTjH_9m85GcS-5PPYaCxmJTt1umxOa2y9ggVUQ", + GrantType = OpenIdConnectConstants.GrantTypes.AuthorizationCode, + RedirectUri = "http://www.fabrikam.com/path" }); // Assert - Assert.Single(response.GetParameters()); - Assert.False((bool) response[OpenIdConnectConstants.Claims.Active]); + Assert.Equal(OpenIdConnectConstants.Errors.InvalidGrant, response.Error); + Assert.Equal("The specified authorization code is invalid.", response.ErrorDescription); Mock.Get(manager).Verify(mock => mock.FindByReferenceIdAsync("HQnldPTjH_9m85GcS-5PPYaCxmJTt1umxOa2y9ggVUQ", It.IsAny()), Times.Once()); Mock.Get(manager).Verify(mock => mock.GetIdAsync(token, It.IsAny()), Times.AtLeastOnce()); @@ -660,7 +678,11 @@ namespace OpenIddict.Tests .ReturnsAsync(application); instance.Setup(mock => mock.HasPermissionAsync(application, - OpenIddictConstants.Permissions.Endpoints.Introspection, It.IsAny())) + OpenIddictConstants.Permissions.Endpoints.Token, It.IsAny())) + .ReturnsAsync(true); + + instance.Setup(mock => mock.HasPermissionAsync(application, + OpenIddictConstants.Permissions.GrantTypes.AuthorizationCode, It.IsAny())) .ReturnsAsync(true); instance.Setup(mock => mock.GetClientTypeAsync(application, It.IsAny())) @@ -678,17 +700,18 @@ namespace OpenIddict.Tests var client = new OpenIdConnectClient(server.CreateClient()); // Act - var response = await client.PostAsync(IntrospectionEndpoint, new OpenIdConnectRequest + var response = await client.PostAsync(TokenEndpoint, new OpenIdConnectRequest { ClientId = "Fabrikam", ClientSecret = "7Fjfp0ZBr1KtDRbnfVdmIw", - Token = "HQnldPTjH_9m85GcS-5PPYaCxmJTt1umxOa2y9ggVUQ", - TokenTypeHint = OpenIdConnectConstants.TokenTypeHints.AuthorizationCode + Code = "HQnldPTjH_9m85GcS-5PPYaCxmJTt1umxOa2y9ggVUQ", + GrantType = OpenIdConnectConstants.GrantTypes.AuthorizationCode, + RedirectUri = "http://www.fabrikam.com/path" }); // Assert - Assert.Single(response.GetParameters()); - Assert.False((bool) response[OpenIdConnectConstants.Claims.Active]); + Assert.Equal(OpenIdConnectConstants.Errors.InvalidGrant, response.Error); + Assert.Equal("The specified authorization code is invalid.", response.ErrorDescription); Mock.Get(manager).Verify(mock => mock.FindByReferenceIdAsync("HQnldPTjH_9m85GcS-5PPYaCxmJTt1umxOa2y9ggVUQ", It.IsAny()), Times.Once()); Mock.Get(manager).Verify(mock => mock.GetIdAsync(token, It.IsAny()), Times.AtLeastOnce()); @@ -727,7 +750,11 @@ namespace OpenIddict.Tests .ReturnsAsync(application); instance.Setup(mock => mock.HasPermissionAsync(application, - OpenIddictConstants.Permissions.Endpoints.Introspection, It.IsAny())) + OpenIddictConstants.Permissions.Endpoints.Token, It.IsAny())) + .ReturnsAsync(true); + + instance.Setup(mock => mock.HasPermissionAsync(application, + OpenIddictConstants.Permissions.GrantTypes.AuthorizationCode, It.IsAny())) .ReturnsAsync(true); instance.Setup(mock => mock.GetClientTypeAsync(application, It.IsAny())) @@ -747,17 +774,18 @@ namespace OpenIddict.Tests var client = new OpenIdConnectClient(server.CreateClient()); // Act - var response = await client.PostAsync(IntrospectionEndpoint, new OpenIdConnectRequest + var response = await client.PostAsync(TokenEndpoint, new OpenIdConnectRequest { ClientId = "Fabrikam", ClientSecret = "7Fjfp0ZBr1KtDRbnfVdmIw", - Token = "HQnldPTjH_9m85GcS-5PPYaCxmJTt1umxOa2y9ggVUQ", - TokenTypeHint = OpenIdConnectConstants.TokenTypeHints.AuthorizationCode + Code = "HQnldPTjH_9m85GcS-5PPYaCxmJTt1umxOa2y9ggVUQ", + GrantType = OpenIdConnectConstants.GrantTypes.AuthorizationCode, + RedirectUri = "http://www.fabrikam.com/path" }); // Assert - Assert.Single(response.GetParameters()); - Assert.False((bool) response[OpenIdConnectConstants.Claims.Active]); + Assert.Equal(OpenIdConnectConstants.Errors.InvalidGrant, response.Error); + Assert.Equal("The specified authorization code is invalid.", response.ErrorDescription); Mock.Get(manager).Verify(mock => mock.FindByReferenceIdAsync("HQnldPTjH_9m85GcS-5PPYaCxmJTt1umxOa2y9ggVUQ", It.IsAny()), Times.Once()); Mock.Get(manager).Verify(mock => mock.GetIdAsync(token, It.IsAny()), Times.AtLeastOnce()); @@ -776,6 +804,8 @@ namespace OpenIddict.Tests new AuthenticationProperties(), OpenIdConnectServerDefaults.AuthenticationScheme); + ticket.SetPresenters("Fabrikam"); + var format = new Mock>(); format.Setup(mock => mock.Unprotect("2YotnFZFEjr1zCsicMWpAA")) @@ -817,7 +847,11 @@ namespace OpenIddict.Tests .ReturnsAsync(application); instance.Setup(mock => mock.HasPermissionAsync(application, - OpenIddictConstants.Permissions.Endpoints.Introspection, It.IsAny())) + OpenIddictConstants.Permissions.Endpoints.Token, It.IsAny())) + .ReturnsAsync(true); + + instance.Setup(mock => mock.HasPermissionAsync(application, + OpenIddictConstants.Permissions.GrantTypes.AuthorizationCode, It.IsAny())) .ReturnsAsync(true); instance.Setup(mock => mock.GetClientTypeAsync(application, It.IsAny())) @@ -843,22 +877,20 @@ namespace OpenIddict.Tests var client = new OpenIdConnectClient(server.CreateClient()); // Act - var response = await client.PostAsync(IntrospectionEndpoint, new OpenIdConnectRequest + var response = await client.PostAsync(TokenEndpoint, new OpenIdConnectRequest { ClientId = "Fabrikam", ClientSecret = "7Fjfp0ZBr1KtDRbnfVdmIw", - Token = "HQnldPTjH_9m85GcS-5PPYaCxmJTt1umxOa2y9ggVUQ", - TokenTypeHint = OpenIdConnectConstants.TokenTypeHints.AuthorizationCode + Code = "HQnldPTjH_9m85GcS-5PPYaCxmJTt1umxOa2y9ggVUQ", + GrantType = OpenIdConnectConstants.GrantTypes.AuthorizationCode, + RedirectUri = "http://www.fabrikam.com/path" }); // Assert - Assert.True((bool) response[OpenIdConnectConstants.Claims.Active]); - Assert.Equal("3E228451-1555-46F7-A471-951EFBA23A56", response[OpenIdConnectConstants.Claims.JwtId]); - Assert.Equal(1483228800, (long) response[OpenIdConnectConstants.Claims.IssuedAt]); - Assert.Equal(1484006400, (long) response[OpenIdConnectConstants.Claims.ExpiresAt]); + Assert.NotNull(response.AccessToken); Mock.Get(manager).Verify(mock => mock.FindByReferenceIdAsync("HQnldPTjH_9m85GcS-5PPYaCxmJTt1umxOa2y9ggVUQ", It.IsAny()), Times.Once()); - Mock.Get(manager).Verify(mock => mock.GetIdAsync(token, It.IsAny()), Times.Once()); + Mock.Get(manager).Verify(mock => mock.GetIdAsync(token, It.IsAny()), Times.AtLeastOnce()); format.Verify(mock => mock.Unprotect("2YotnFZFEjr1zCsicMWpAA"), Times.Once()); } @@ -889,7 +921,11 @@ namespace OpenIddict.Tests .ReturnsAsync(application); instance.Setup(mock => mock.HasPermissionAsync(application, - OpenIddictConstants.Permissions.Endpoints.Introspection, It.IsAny())) + OpenIddictConstants.Permissions.Endpoints.Token, It.IsAny())) + .ReturnsAsync(true); + + instance.Setup(mock => mock.HasPermissionAsync(application, + OpenIddictConstants.Permissions.GrantTypes.AuthorizationCode, It.IsAny())) .ReturnsAsync(true); instance.Setup(mock => mock.GetClientTypeAsync(application, It.IsAny())) @@ -905,17 +941,18 @@ namespace OpenIddict.Tests var client = new OpenIdConnectClient(server.CreateClient()); // Act - var response = await client.PostAsync(IntrospectionEndpoint, new OpenIdConnectRequest + var response = await client.PostAsync(TokenEndpoint, new OpenIdConnectRequest { ClientId = "Fabrikam", ClientSecret = "7Fjfp0ZBr1KtDRbnfVdmIw", - Token = "2YotnFZFEjr1zCsicMWpAA", - TokenTypeHint = OpenIdConnectConstants.TokenTypeHints.AuthorizationCode + Code = "2YotnFZFEjr1zCsicMWpAA", + GrantType = OpenIdConnectConstants.GrantTypes.AuthorizationCode, + RedirectUri = "http://www.fabrikam.com/path" }); // Assert - Assert.Single(response.GetParameters()); - Assert.False((bool) response[OpenIdConnectConstants.Claims.Active]); + Assert.Equal(OpenIdConnectConstants.Errors.InvalidGrant, response.Error); + Assert.Equal("The specified authorization code is invalid.", response.ErrorDescription); } [Fact] @@ -937,7 +974,11 @@ namespace OpenIddict.Tests .ReturnsAsync(application); instance.Setup(mock => mock.HasPermissionAsync(application, - OpenIddictConstants.Permissions.Endpoints.Introspection, It.IsAny())) + OpenIddictConstants.Permissions.Endpoints.Token, It.IsAny())) + .ReturnsAsync(true); + + instance.Setup(mock => mock.HasPermissionAsync(application, + OpenIddictConstants.Permissions.GrantTypes.AuthorizationCode, It.IsAny())) .ReturnsAsync(true); instance.Setup(mock => mock.GetClientTypeAsync(application, It.IsAny())) @@ -953,17 +994,18 @@ namespace OpenIddict.Tests var client = new OpenIdConnectClient(server.CreateClient()); // Act - var response = await client.PostAsync(IntrospectionEndpoint, new OpenIdConnectRequest + var response = await client.PostAsync(TokenEndpoint, new OpenIdConnectRequest { ClientId = "Fabrikam", ClientSecret = "7Fjfp0ZBr1KtDRbnfVdmIw", - Token = "2YotnFZFEjr1zCsicMWpAA", - TokenTypeHint = OpenIdConnectConstants.TokenTypeHints.AuthorizationCode + Code = "2YotnFZFEjr1zCsicMWpAA", + GrantType = OpenIdConnectConstants.GrantTypes.AuthorizationCode, + RedirectUri = "http://www.fabrikam.com/path" }); // Assert - Assert.Single(response.GetParameters()); - Assert.False((bool) response[OpenIdConnectConstants.Claims.Active]); + Assert.Equal(OpenIdConnectConstants.Errors.InvalidGrant, response.Error); + Assert.Equal("The specified authorization code is invalid.", response.ErrorDescription); format.Verify(mock => mock.Unprotect("2YotnFZFEjr1zCsicMWpAA"), Times.Once()); } @@ -980,6 +1022,7 @@ namespace OpenIddict.Tests new AuthenticationProperties(), OpenIdConnectServerDefaults.AuthenticationScheme); + ticket.SetPresenters("Fabrikam"); ticket.SetTokenId("3E228451-1555-46F7-A471-951EFBA23A56"); var format = new Mock>(); @@ -1017,7 +1060,11 @@ namespace OpenIddict.Tests .ReturnsAsync(application); instance.Setup(mock => mock.HasPermissionAsync(application, - OpenIddictConstants.Permissions.Endpoints.Introspection, It.IsAny())) + OpenIddictConstants.Permissions.Endpoints.Token, It.IsAny())) + .ReturnsAsync(true); + + instance.Setup(mock => mock.HasPermissionAsync(application, + OpenIddictConstants.Permissions.GrantTypes.AuthorizationCode, It.IsAny())) .ReturnsAsync(true); instance.Setup(mock => mock.GetClientTypeAsync(application, It.IsAny())) @@ -1041,19 +1088,17 @@ namespace OpenIddict.Tests var client = new OpenIdConnectClient(server.CreateClient()); // Act - var response = await client.PostAsync(IntrospectionEndpoint, new OpenIdConnectRequest + var response = await client.PostAsync(TokenEndpoint, new OpenIdConnectRequest { ClientId = "Fabrikam", ClientSecret = "7Fjfp0ZBr1KtDRbnfVdmIw", - Token = "2YotnFZFEjr1zCsicMWpAA", - TokenTypeHint = OpenIdConnectConstants.TokenTypeHints.AuthorizationCode + Code = "2YotnFZFEjr1zCsicMWpAA", + GrantType = OpenIdConnectConstants.GrantTypes.AuthorizationCode, + RedirectUri = "http://www.fabrikam.com/path" }); // Assert - Assert.True((bool) response[OpenIdConnectConstants.Claims.Active]); - Assert.Equal("3E228451-1555-46F7-A471-951EFBA23A56", response[OpenIdConnectConstants.Claims.JwtId]); - Assert.Equal(1483228800, (long) response[OpenIdConnectConstants.Claims.IssuedAt]); - Assert.Equal(1484006400, (long) response[OpenIdConnectConstants.Claims.ExpiresAt]); + Assert.NotNull(response.AccessToken); Mock.Get(manager).Verify(mock => mock.FindByIdAsync("3E228451-1555-46F7-A471-951EFBA23A56", It.IsAny()), Times.Once()); format.Verify(mock => mock.Unprotect("2YotnFZFEjr1zCsicMWpAA"), Times.Once()); @@ -1096,17 +1141,15 @@ namespace OpenIddict.Tests var client = new OpenIdConnectClient(server.CreateClient()); // Act - var response = await client.PostAsync(IntrospectionEndpoint, new OpenIdConnectRequest + var response = await client.PostAsync(TokenEndpoint, new OpenIdConnectRequest { - ClientId = "Fabrikam", - ClientSecret = "7Fjfp0ZBr1KtDRbnfVdmIw", - Token = "2YotnFZFEjr1zCsicMWpAA", - TokenTypeHint = OpenIdConnectConstants.TokenTypeHints.RefreshToken + GrantType = OpenIdConnectConstants.GrantTypes.RefreshToken, + RefreshToken = "2YotnFZFEjr1zCsicMWpAA" }); // Assert - Assert.Single(response.GetParameters()); - Assert.False((bool) response[OpenIdConnectConstants.Claims.Active]); + Assert.Equal(OpenIdConnectConstants.Errors.InvalidGrant, response.Error); + Assert.Equal("The specified refresh token is invalid.", response.ErrorDescription); format.Verify(mock => mock.Unprotect("2YotnFZFEjr1zCsicMWpAA"), Times.Never()); Mock.Get(manager).Verify(mock => mock.FindByIdAsync("3E228451-1555-46F7-A471-951EFBA23A56", It.IsAny()), Times.Never()); @@ -1147,24 +1190,6 @@ namespace OpenIddict.Tests var server = CreateAuthorizationServer(builder => { - builder.Services.AddSingleton(CreateApplicationManager(instance => - { - var application = new OpenIddictApplication(); - - instance.Setup(mock => mock.FindByClientIdAsync("Fabrikam", It.IsAny())) - .ReturnsAsync(application); - - instance.Setup(mock => mock.HasPermissionAsync(application, - OpenIddictConstants.Permissions.Endpoints.Introspection, It.IsAny())) - .ReturnsAsync(true); - - instance.Setup(mock => mock.GetClientTypeAsync(application, It.IsAny())) - .ReturnsAsync(OpenIddictConstants.ClientTypes.Confidential); - - instance.Setup(mock => mock.ValidateClientSecretAsync(application, "7Fjfp0ZBr1KtDRbnfVdmIw", It.IsAny())) - .ReturnsAsync(true); - })); - builder.Services.AddSingleton(manager); builder.Configure(options => options.RefreshTokenFormat = format.Object); @@ -1173,16 +1198,14 @@ namespace OpenIddict.Tests var client = new OpenIdConnectClient(server.CreateClient()); // Act - var response = await client.PostAsync(IntrospectionEndpoint, new OpenIdConnectRequest + var response = await client.PostAsync(TokenEndpoint, new OpenIdConnectRequest { - ClientId = "Fabrikam", - ClientSecret = "7Fjfp0ZBr1KtDRbnfVdmIw", - Token = "2YotnFZFEjr1zCsicMWpAA", - TokenTypeHint = OpenIdConnectConstants.TokenTypeHints.RefreshToken + GrantType = OpenIdConnectConstants.GrantTypes.RefreshToken, + RefreshToken = "2YotnFZFEjr1zCsicMWpAA" }); // Assert - Assert.True((bool) response[OpenIdConnectConstants.Claims.Active]); + Assert.NotNull(response.AccessToken); format.Verify(mock => mock.Unprotect("2YotnFZFEjr1zCsicMWpAA"), Times.Once()); Mock.Get(manager).Verify(mock => mock.FindByReferenceIdAsync(It.IsAny(), It.IsAny()), Times.Never()); @@ -1205,24 +1228,6 @@ namespace OpenIddict.Tests var server = CreateAuthorizationServer(builder => { - builder.Services.AddSingleton(CreateApplicationManager(instance => - { - var application = new OpenIddictApplication(); - - instance.Setup(mock => mock.FindByClientIdAsync("Fabrikam", It.IsAny())) - .ReturnsAsync(application); - - instance.Setup(mock => mock.HasPermissionAsync(application, - OpenIddictConstants.Permissions.Endpoints.Introspection, It.IsAny())) - .ReturnsAsync(true); - - instance.Setup(mock => mock.GetClientTypeAsync(application, It.IsAny())) - .ReturnsAsync(OpenIddictConstants.ClientTypes.Confidential); - - instance.Setup(mock => mock.ValidateClientSecretAsync(application, "7Fjfp0ZBr1KtDRbnfVdmIw", It.IsAny())) - .ReturnsAsync(true); - })); - builder.Services.AddSingleton(manager); builder.UseReferenceTokens(); @@ -1231,17 +1236,15 @@ namespace OpenIddict.Tests var client = new OpenIdConnectClient(server.CreateClient()); // Act - var response = await client.PostAsync(IntrospectionEndpoint, new OpenIdConnectRequest + var response = await client.PostAsync(TokenEndpoint, new OpenIdConnectRequest { - ClientId = "Fabrikam", - ClientSecret = "7Fjfp0ZBr1KtDRbnfVdmIw", - Token = "HQnldPTjH_9m85GcS-5PPYaCxmJTt1umxOa2y9ggVUQ", - TokenTypeHint = OpenIdConnectConstants.TokenTypeHints.RefreshToken + GrantType = OpenIdConnectConstants.GrantTypes.RefreshToken, + RefreshToken = "HQnldPTjH_9m85GcS-5PPYaCxmJTt1umxOa2y9ggVUQ" }); // Assert - Assert.Single(response.GetParameters()); - Assert.False((bool) response[OpenIdConnectConstants.Claims.Active]); + Assert.Equal(OpenIdConnectConstants.Errors.InvalidGrant, response.Error); + Assert.Equal("The specified refresh token is invalid.", response.ErrorDescription); Mock.Get(manager).Verify(mock => mock.FindByReferenceIdAsync("HQnldPTjH_9m85GcS-5PPYaCxmJTt1umxOa2y9ggVUQ", It.IsAny()), Times.Once()); Mock.Get(manager).Verify(mock => mock.GetIdAsync(token, It.IsAny()), Times.AtLeastOnce()); @@ -1267,24 +1270,6 @@ namespace OpenIddict.Tests var server = CreateAuthorizationServer(builder => { - builder.Services.AddSingleton(CreateApplicationManager(instance => - { - var application = new OpenIddictApplication(); - - instance.Setup(mock => mock.FindByClientIdAsync("Fabrikam", It.IsAny())) - .ReturnsAsync(application); - - instance.Setup(mock => mock.HasPermissionAsync(application, - OpenIddictConstants.Permissions.Endpoints.Introspection, It.IsAny())) - .ReturnsAsync(true); - - instance.Setup(mock => mock.GetClientTypeAsync(application, It.IsAny())) - .ReturnsAsync(OpenIddictConstants.ClientTypes.Confidential); - - instance.Setup(mock => mock.ValidateClientSecretAsync(application, "7Fjfp0ZBr1KtDRbnfVdmIw", It.IsAny())) - .ReturnsAsync(true); - })); - builder.Services.AddSingleton(manager); builder.UseReferenceTokens(); @@ -1293,17 +1278,15 @@ namespace OpenIddict.Tests var client = new OpenIdConnectClient(server.CreateClient()); // Act - var response = await client.PostAsync(IntrospectionEndpoint, new OpenIdConnectRequest + var response = await client.PostAsync(TokenEndpoint, new OpenIdConnectRequest { - ClientId = "Fabrikam", - ClientSecret = "7Fjfp0ZBr1KtDRbnfVdmIw", - Token = "HQnldPTjH_9m85GcS-5PPYaCxmJTt1umxOa2y9ggVUQ", - TokenTypeHint = OpenIdConnectConstants.TokenTypeHints.RefreshToken + GrantType = OpenIdConnectConstants.GrantTypes.RefreshToken, + RefreshToken = "HQnldPTjH_9m85GcS-5PPYaCxmJTt1umxOa2y9ggVUQ" }); // Assert - Assert.Single(response.GetParameters()); - Assert.False((bool) response[OpenIdConnectConstants.Claims.Active]); + Assert.Equal(OpenIdConnectConstants.Errors.InvalidGrant, response.Error); + Assert.Equal("The specified refresh token is invalid.", response.ErrorDescription); Mock.Get(manager).Verify(mock => mock.FindByReferenceIdAsync("HQnldPTjH_9m85GcS-5PPYaCxmJTt1umxOa2y9ggVUQ", It.IsAny()), Times.Once()); Mock.Get(manager).Verify(mock => mock.GetIdAsync(token, It.IsAny()), Times.AtLeastOnce()); @@ -1334,24 +1317,6 @@ namespace OpenIddict.Tests var server = CreateAuthorizationServer(builder => { - builder.Services.AddSingleton(CreateApplicationManager(instance => - { - var application = new OpenIddictApplication(); - - instance.Setup(mock => mock.FindByClientIdAsync("Fabrikam", It.IsAny())) - .ReturnsAsync(application); - - instance.Setup(mock => mock.HasPermissionAsync(application, - OpenIddictConstants.Permissions.Endpoints.Introspection, It.IsAny())) - .ReturnsAsync(true); - - instance.Setup(mock => mock.GetClientTypeAsync(application, It.IsAny())) - .ReturnsAsync(OpenIddictConstants.ClientTypes.Confidential); - - instance.Setup(mock => mock.ValidateClientSecretAsync(application, "7Fjfp0ZBr1KtDRbnfVdmIw", It.IsAny())) - .ReturnsAsync(true); - })); - builder.Services.AddSingleton(manager); builder.UseReferenceTokens(); @@ -1362,17 +1327,15 @@ namespace OpenIddict.Tests var client = new OpenIdConnectClient(server.CreateClient()); // Act - var response = await client.PostAsync(IntrospectionEndpoint, new OpenIdConnectRequest + var response = await client.PostAsync(TokenEndpoint, new OpenIdConnectRequest { - ClientId = "Fabrikam", - ClientSecret = "7Fjfp0ZBr1KtDRbnfVdmIw", - Token = "HQnldPTjH_9m85GcS-5PPYaCxmJTt1umxOa2y9ggVUQ", - TokenTypeHint = OpenIdConnectConstants.TokenTypeHints.RefreshToken + GrantType = OpenIdConnectConstants.GrantTypes.RefreshToken, + RefreshToken = "HQnldPTjH_9m85GcS-5PPYaCxmJTt1umxOa2y9ggVUQ" }); // Assert - Assert.Single(response.GetParameters()); - Assert.False((bool) response[OpenIdConnectConstants.Claims.Active]); + Assert.Equal(OpenIdConnectConstants.Errors.InvalidGrant, response.Error); + Assert.Equal("The specified refresh token is invalid.", response.ErrorDescription); Mock.Get(manager).Verify(mock => mock.FindByReferenceIdAsync("HQnldPTjH_9m85GcS-5PPYaCxmJTt1umxOa2y9ggVUQ", It.IsAny()), Times.Once()); Mock.Get(manager).Verify(mock => mock.GetIdAsync(token, It.IsAny()), Times.AtLeastOnce()); @@ -1424,24 +1387,6 @@ namespace OpenIddict.Tests var server = CreateAuthorizationServer(builder => { - builder.Services.AddSingleton(CreateApplicationManager(instance => - { - var application = new OpenIddictApplication(); - - instance.Setup(mock => mock.FindByClientIdAsync("Fabrikam", It.IsAny())) - .ReturnsAsync(application); - - instance.Setup(mock => mock.HasPermissionAsync(application, - OpenIddictConstants.Permissions.Endpoints.Introspection, It.IsAny())) - .ReturnsAsync(true); - - instance.Setup(mock => mock.GetClientTypeAsync(application, It.IsAny())) - .ReturnsAsync(OpenIddictConstants.ClientTypes.Confidential); - - instance.Setup(mock => mock.ValidateClientSecretAsync(application, "7Fjfp0ZBr1KtDRbnfVdmIw", It.IsAny())) - .ReturnsAsync(true); - })); - builder.Services.AddSingleton(manager); builder.UseReferenceTokens(); @@ -1458,19 +1403,14 @@ namespace OpenIddict.Tests var client = new OpenIdConnectClient(server.CreateClient()); // Act - var response = await client.PostAsync(IntrospectionEndpoint, new OpenIdConnectRequest + var response = await client.PostAsync(TokenEndpoint, new OpenIdConnectRequest { - ClientId = "Fabrikam", - ClientSecret = "7Fjfp0ZBr1KtDRbnfVdmIw", - Token = "HQnldPTjH_9m85GcS-5PPYaCxmJTt1umxOa2y9ggVUQ", - TokenTypeHint = OpenIdConnectConstants.TokenTypeHints.RefreshToken + GrantType = OpenIdConnectConstants.GrantTypes.RefreshToken, + RefreshToken = "HQnldPTjH_9m85GcS-5PPYaCxmJTt1umxOa2y9ggVUQ" }); // Assert - Assert.True((bool) response[OpenIdConnectConstants.Claims.Active]); - Assert.Equal("3E228451-1555-46F7-A471-951EFBA23A56", response[OpenIdConnectConstants.Claims.JwtId]); - Assert.Equal(1483228800, (long) response[OpenIdConnectConstants.Claims.IssuedAt]); - Assert.Equal(1484006400, (long) response[OpenIdConnectConstants.Claims.ExpiresAt]); + Assert.NotNull(response.AccessToken); Mock.Get(manager).Verify(mock => mock.FindByReferenceIdAsync("HQnldPTjH_9m85GcS-5PPYaCxmJTt1umxOa2y9ggVUQ", It.IsAny()), Times.Once()); Mock.Get(manager).Verify(mock => mock.GetIdAsync(token, It.IsAny()), Times.Once()); @@ -1496,41 +1436,21 @@ namespace OpenIddict.Tests var server = CreateAuthorizationServer(builder => { - builder.Services.AddSingleton(CreateApplicationManager(instance => - { - var application = new OpenIddictApplication(); - - instance.Setup(mock => mock.FindByClientIdAsync("Fabrikam", It.IsAny())) - .ReturnsAsync(application); - - instance.Setup(mock => mock.HasPermissionAsync(application, - OpenIddictConstants.Permissions.Endpoints.Introspection, It.IsAny())) - .ReturnsAsync(true); - - instance.Setup(mock => mock.GetClientTypeAsync(application, It.IsAny())) - .ReturnsAsync(OpenIddictConstants.ClientTypes.Confidential); - - instance.Setup(mock => mock.ValidateClientSecretAsync(application, "7Fjfp0ZBr1KtDRbnfVdmIw", It.IsAny())) - .ReturnsAsync(true); - })); - builder.Configure(options => options.RefreshTokenFormat = format.Object); }); var client = new OpenIdConnectClient(server.CreateClient()); // Act - var response = await client.PostAsync(IntrospectionEndpoint, new OpenIdConnectRequest + var response = await client.PostAsync(TokenEndpoint, new OpenIdConnectRequest { - ClientId = "Fabrikam", - ClientSecret = "7Fjfp0ZBr1KtDRbnfVdmIw", - Token = "2YotnFZFEjr1zCsicMWpAA", - TokenTypeHint = OpenIdConnectConstants.TokenTypeHints.RefreshToken + GrantType = OpenIdConnectConstants.GrantTypes.RefreshToken, + RefreshToken = "2YotnFZFEjr1zCsicMWpAA" }); // Assert - Assert.Single(response.GetParameters()); - Assert.False((bool) response[OpenIdConnectConstants.Claims.Active]); + Assert.Equal(OpenIdConnectConstants.Errors.InvalidGrant, response.Error); + Assert.Equal("The specified refresh token is invalid.", response.ErrorDescription); } [Fact] @@ -1544,41 +1464,21 @@ namespace OpenIddict.Tests var server = CreateAuthorizationServer(builder => { - builder.Services.AddSingleton(CreateApplicationManager(instance => - { - var application = new OpenIddictApplication(); - - instance.Setup(mock => mock.FindByClientIdAsync("Fabrikam", It.IsAny())) - .ReturnsAsync(application); - - instance.Setup(mock => mock.HasPermissionAsync(application, - OpenIddictConstants.Permissions.Endpoints.Introspection, It.IsAny())) - .ReturnsAsync(true); - - instance.Setup(mock => mock.GetClientTypeAsync(application, It.IsAny())) - .ReturnsAsync(OpenIddictConstants.ClientTypes.Confidential); - - instance.Setup(mock => mock.ValidateClientSecretAsync(application, "7Fjfp0ZBr1KtDRbnfVdmIw", It.IsAny())) - .ReturnsAsync(true); - })); - builder.Configure(options => options.RefreshTokenFormat = format.Object); }); var client = new OpenIdConnectClient(server.CreateClient()); // Act - var response = await client.PostAsync(IntrospectionEndpoint, new OpenIdConnectRequest + var response = await client.PostAsync(TokenEndpoint, new OpenIdConnectRequest { - ClientId = "Fabrikam", - ClientSecret = "7Fjfp0ZBr1KtDRbnfVdmIw", - Token = "2YotnFZFEjr1zCsicMWpAA", - TokenTypeHint = OpenIdConnectConstants.TokenTypeHints.RefreshToken + GrantType = OpenIdConnectConstants.GrantTypes.RefreshToken, + RefreshToken = "2YotnFZFEjr1zCsicMWpAA" }); // Assert - Assert.Single(response.GetParameters()); - Assert.False((bool) response[OpenIdConnectConstants.Claims.Active]); + Assert.Equal(OpenIdConnectConstants.Errors.InvalidGrant, response.Error); + Assert.Equal("The specified refresh token is invalid.", response.ErrorDescription); format.Verify(mock => mock.Unprotect("2YotnFZFEjr1zCsicMWpAA"), Times.Once()); } @@ -1624,24 +1524,6 @@ namespace OpenIddict.Tests var server = CreateAuthorizationServer(builder => { - builder.Services.AddSingleton(CreateApplicationManager(instance => - { - var application = new OpenIddictApplication(); - - instance.Setup(mock => mock.FindByClientIdAsync("Fabrikam", It.IsAny())) - .ReturnsAsync(application); - - instance.Setup(mock => mock.HasPermissionAsync(application, - OpenIddictConstants.Permissions.Endpoints.Introspection, It.IsAny())) - .ReturnsAsync(true); - - instance.Setup(mock => mock.GetClientTypeAsync(application, It.IsAny())) - .ReturnsAsync(OpenIddictConstants.ClientTypes.Confidential); - - instance.Setup(mock => mock.ValidateClientSecretAsync(application, "7Fjfp0ZBr1KtDRbnfVdmIw", It.IsAny())) - .ReturnsAsync(true); - })); - builder.Services.AddSingleton(manager); builder.Configure(options => @@ -1656,19 +1538,14 @@ namespace OpenIddict.Tests var client = new OpenIdConnectClient(server.CreateClient()); // Act - var response = await client.PostAsync(IntrospectionEndpoint, new OpenIdConnectRequest + var response = await client.PostAsync(TokenEndpoint, new OpenIdConnectRequest { - ClientId = "Fabrikam", - ClientSecret = "7Fjfp0ZBr1KtDRbnfVdmIw", - Token = "2YotnFZFEjr1zCsicMWpAA", - TokenTypeHint = OpenIdConnectConstants.TokenTypeHints.RefreshToken + GrantType = OpenIdConnectConstants.GrantTypes.RefreshToken, + RefreshToken = "2YotnFZFEjr1zCsicMWpAA" }); // Assert - Assert.True((bool) response[OpenIdConnectConstants.Claims.Active]); - Assert.Equal("3E228451-1555-46F7-A471-951EFBA23A56", response[OpenIdConnectConstants.Claims.JwtId]); - Assert.Equal(1483228800, (long) response[OpenIdConnectConstants.Claims.IssuedAt]); - Assert.Equal(1484006400, (long) response[OpenIdConnectConstants.Claims.ExpiresAt]); + Assert.NotNull(response.AccessToken); Mock.Get(manager).Verify(mock => mock.FindByIdAsync("3E228451-1555-46F7-A471-951EFBA23A56", It.IsAny()), Times.Once()); format.Verify(mock => mock.Unprotect("2YotnFZFEjr1zCsicMWpAA"), Times.Once());