From e0975fb283bcb4c2c3755b4e370d677afc1a4d04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Chalet?= Date: Mon, 12 Feb 2018 15:52:01 +0100 Subject: [PATCH] Update the introspection endpoint to only accept access tokens with an explicit audience attached --- .../OpenIddictProvider.Introspection.cs | 56 ++- .../OpenIddictProviderTests.Introspection.cs | 335 +------------- .../OpenIddictProviderTests.Serialization.cs | 415 ++++++------------ 3 files changed, 203 insertions(+), 603 deletions(-) diff --git a/src/OpenIddict/OpenIddictProvider.Introspection.cs b/src/OpenIddict/OpenIddictProvider.Introspection.cs index 2508f3f4..d1f3c76e 100644 --- a/src/OpenIddict/OpenIddictProvider.Introspection.cs +++ b/src/OpenIddict/OpenIddictProvider.Introspection.cs @@ -120,40 +120,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 a1150489..3e877e90 100644 --- a/test/OpenIddict.Tests/OpenIddictProviderTests.Introspection.cs +++ b/test/OpenIddict.Tests/OpenIddictProviderTests.Introspection.cs @@ -229,8 +229,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); @@ -241,9 +244,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>(); @@ -289,7 +291,7 @@ namespace OpenIddict.Tests } [Fact] - public async Task HandleIntrospectionRequest_AuthorizationCodeRevocationIsIgnoredWhenTokenRevocationIsDisabled() + public async Task HandleIntrospectionRequest_RequestIsRejectedWhenAudienceIsMissing() { // Arrange var identity = new ClaimsIdentity(OpenIdConnectServerDefaults.AuthenticationScheme); @@ -301,7 +303,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>(); @@ -328,11 +330,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()); @@ -346,11 +344,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); @@ -361,8 +360,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>(); @@ -389,11 +389,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()); @@ -407,11 +403,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); @@ -467,7 +464,7 @@ namespace OpenIddict.Tests } [Fact] - public async Task HandleIntrospectionRequest_RequestIsRejectedWhenAccessTokenIsInvalid() + public async Task HandleIntrospectionRequest_RequestIsRejectedWhenReferenceTokenIsInvalid() { // Arrange var identity = new ClaimsIdentity(OpenIdConnectServerDefaults.AuthenticationScheme); @@ -478,6 +475,7 @@ namespace OpenIddict.Tests new AuthenticationProperties(), OpenIdConnectServerDefaults.AuthenticationScheme); + ticket.SetAudiences("Fabrikam"); ticket.SetTokenId("3E228451-1555-46F7-A471-951EFBA23A56"); ticket.SetTokenUsage(OpenIdConnectConstants.TokenUsages.AccessToken); @@ -550,298 +548,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 09ce5023..12f310aa 100644 --- a/test/OpenIddict.Tests/OpenIddictProviderTests.Serialization.cs +++ b/test/OpenIddict.Tests/OpenIddictProviderTests.Serialization.cs @@ -89,6 +89,7 @@ namespace OpenIddict.Tests new AuthenticationProperties(), OpenIdConnectServerDefaults.AuthenticationScheme); + ticket.SetAudiences("Fabrikam"); ticket.SetTokenId("3E228451-1555-46F7-A471-951EFBA23A56"); ticket.SetTokenUsage(OpenIdConnectConstants.TokenUsages.AccessToken); @@ -354,6 +355,7 @@ namespace OpenIddict.Tests new AuthenticationProperties(), OpenIdConnectServerDefaults.AuthenticationScheme); + ticket.SetAudiences("Fabrikam"); ticket.SetTokenId("3E228451-1555-46F7-A471-951EFBA23A56"); var format = new Mock>(); @@ -459,7 +461,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())) @@ -479,17 +485,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()); @@ -507,6 +514,7 @@ namespace OpenIddict.Tests new AuthenticationProperties(), OpenIdConnectServerDefaults.AuthenticationScheme); + ticket.SetPresenters("Fabrikam"); ticket.SetTokenId("3E228451-1555-46F7-A471-951EFBA23A56"); var format = new Mock>(); @@ -538,7 +546,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())) @@ -550,22 +562,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()); @@ -596,7 +609,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())) @@ -614,17 +631,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()); @@ -658,7 +676,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())) @@ -676,17 +698,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()); @@ -725,7 +748,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())) @@ -745,17 +772,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()); @@ -774,6 +802,8 @@ namespace OpenIddict.Tests new AuthenticationProperties(), OpenIdConnectServerDefaults.AuthenticationScheme); + ticket.SetPresenters("Fabrikam"); + var format = new Mock>(); format.Setup(mock => mock.Unprotect("2YotnFZFEjr1zCsicMWpAA")) @@ -815,7 +845,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())) @@ -841,22 +875,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()); } @@ -887,7 +919,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())) @@ -903,17 +939,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] @@ -935,7 +972,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())) @@ -951,17 +992,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()); } @@ -978,6 +1020,7 @@ namespace OpenIddict.Tests new AuthenticationProperties(), OpenIdConnectServerDefaults.AuthenticationScheme); + ticket.SetPresenters("Fabrikam"); ticket.SetTokenId("3E228451-1555-46F7-A471-951EFBA23A56"); var format = new Mock>(); @@ -1015,7 +1058,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())) @@ -1039,19 +1086,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()); @@ -1094,17 +1139,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()); @@ -1145,24 +1188,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); @@ -1171,16 +1196,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()); @@ -1203,24 +1226,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(); @@ -1229,17 +1234,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()); @@ -1265,24 +1268,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(); @@ -1291,17 +1276,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()); @@ -1332,24 +1315,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(); @@ -1360,17 +1325,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()); @@ -1422,24 +1385,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(); @@ -1456,19 +1401,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()); @@ -1494,41 +1434,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] @@ -1542,41 +1462,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()); } @@ -1622,24 +1522,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 => @@ -1654,19 +1536,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());