From 76a432e045df8c23ca7237f260c8de22844c20a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Chalet?= Date: Mon, 13 Jan 2020 16:10:43 +0100 Subject: [PATCH] Port the challenge integration tests --- .../OpenIddictServerHandlers.cs | 2 +- ...nIddictServerAspNetCoreIntegrationTests.cs | 18 +- ...ctServerIntegrationTests.Authentication.cs | 122 ++++- ...enIddictServerIntegrationTests.Exchange.cs | 218 +++++++- .../OpenIddictServerIntegrationTests.cs | 471 ++++++++++++++++-- .../OpenIddictServerOwinIntegrationTests.cs | 15 + 6 files changed, 790 insertions(+), 56 deletions(-) diff --git a/src/OpenIddict.Server/OpenIddictServerHandlers.cs b/src/OpenIddict.Server/OpenIddictServerHandlers.cs index bee1f43c..df939bfd 100644 --- a/src/OpenIddict.Server/OpenIddictServerHandlers.cs +++ b/src/OpenIddict.Server/OpenIddictServerHandlers.cs @@ -1022,7 +1022,7 @@ namespace OpenIddict.Server case OpenIddictServerEndpointType.Verification: return default; - default: throw new InvalidOperationException("No challenge can be triggered from this endpoint."); + default: throw new InvalidOperationException("An OpenID Connect response cannot be returned from this endpoint."); } } } diff --git a/test/OpenIddict.Server.AspNetCore.IntegrationTests/OpenIddictServerAspNetCoreIntegrationTests.cs b/test/OpenIddict.Server.AspNetCore.IntegrationTests/OpenIddictServerAspNetCoreIntegrationTests.cs index 33abed4d..e0237176 100644 --- a/test/OpenIddict.Server.AspNetCore.IntegrationTests/OpenIddictServerAspNetCoreIntegrationTests.cs +++ b/test/OpenIddict.Server.AspNetCore.IntegrationTests/OpenIddictServerAspNetCoreIntegrationTests.cs @@ -5,6 +5,7 @@ */ using System; +using System.Collections.Generic; using System.Linq; using System.Security.Claims; using System.Text.Json; @@ -312,9 +313,20 @@ namespace OpenIddict.Server.AspNetCore.FunctionalTests else if (context.Request.Path == "/challenge") { - await context.ChallengeAsync( - OpenIddictServerAspNetCoreDefaults.AuthenticationScheme, - new AuthenticationProperties()); + await context.ChallengeAsync(OpenIddictServerAspNetCoreDefaults.AuthenticationScheme); + return; + } + + else if (context.Request.Path == "/challenge/custom") + { + var properties = new AuthenticationProperties(new Dictionary + { + [OpenIddictServerAspNetCoreConstants.Properties.Error] = "custom_error", + [OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] = "custom_error_description", + [OpenIddictServerAspNetCoreConstants.Properties.ErrorUri] = "custom_error_uri" + }); + + await context.ChallengeAsync(OpenIddictServerAspNetCoreDefaults.AuthenticationScheme, properties); return; } diff --git a/test/OpenIddict.Server.IntegrationTests/OpenIddictServerIntegrationTests.Authentication.cs b/test/OpenIddict.Server.IntegrationTests/OpenIddictServerIntegrationTests.Authentication.cs index 69b9b900..da8100ee 100644 --- a/test/OpenIddict.Server.IntegrationTests/OpenIddictServerIntegrationTests.Authentication.cs +++ b/test/OpenIddict.Server.IntegrationTests/OpenIddictServerIntegrationTests.Authentication.cs @@ -8,6 +8,7 @@ using System; using System.Collections.Immutable; using System.Linq; using System.Net.Http; +using System.Security.Claims; using System.Text; using System.Threading; using System.Threading.Tasks; @@ -363,7 +364,19 @@ namespace OpenIddict.Server.FunctionalTests public async Task ValidateAuthorizationRequest_ValidPromptDoesNotCauseAnError(string prompt) { // Arrange - var client = CreateClient(options => options.EnableDegradedMode()); + var client = CreateClient(options => + { + options.EnableDegradedMode(); + + options.AddEventHandler(builder => + builder.UseInlineHandler(context => + { + context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer")) + .SetClaim(Claims.Subject, "Bob le Magnifique"); + + return default; + })); + }); // Act var response = await client.PostAsync("/connect/authorize", new OpenIddictRequest @@ -429,8 +442,7 @@ namespace OpenIddict.Server.FunctionalTests // Assert Assert.Equal(Errors.InvalidRequest, response.Error); - Assert.Equal("The 'code_challenge_method' parameter " + - "cannot be used without 'code_challenge'.", response.ErrorDescription); + Assert.Equal("The 'code_challenge_method' parameter cannot be used without 'code_challenge'.", response.ErrorDescription); } [Fact] @@ -576,6 +588,8 @@ namespace OpenIddict.Server.FunctionalTests // Arrange var client = CreateClient(options => { + options.RegisterScopes("registered_scope"); + options.Services.AddSingleton(CreateApplicationManager(mock => { var application = new OpenIddictApplication(); @@ -604,7 +618,14 @@ namespace OpenIddict.Server.FunctionalTests .ReturnsAsync(ClientTypes.Public); })); - options.RegisterScopes("registered_scope"); + options.AddEventHandler(builder => + builder.UseInlineHandler(context => + { + context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer")) + .SetClaim(Claims.Subject, "Bob le Magnifique"); + + return default; + })); }); // Act @@ -632,6 +653,8 @@ namespace OpenIddict.Server.FunctionalTests { var scope = new OpenIddictScope(); + options.RegisterScopes("scope_registered_in_options"); + options.Services.AddSingleton(CreateApplicationManager(mock => { var application = new OpenIddictApplication(); @@ -657,7 +680,14 @@ namespace OpenIddict.Server.FunctionalTests .ReturnsAsync("scope_registered_in_database"); })); - options.RegisterScopes("scope_registered_in_options"); + options.AddEventHandler(builder => + builder.UseInlineHandler(context => + { + context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer")) + .SetClaim(Claims.Subject, "Bob le Magnifique"); + + return default; + })); }); // Act @@ -800,6 +830,15 @@ namespace OpenIddict.Server.FunctionalTests options.EnableDegradedMode(); options.Configure(options => options.CodeChallengeMethods.Clear()); options.Configure(options => options.CodeChallengeMethods.Add(method)); + + options.AddEventHandler(builder => + builder.UseInlineHandler(context => + { + context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer")) + .SetClaim(Claims.Subject, "Bob le Magnifique"); + + return default; + })); }); // Act @@ -1467,6 +1506,15 @@ namespace OpenIddict.Server.FunctionalTests { options.EnableDegradedMode(); + options.AddEventHandler(builder => + builder.UseInlineHandler(context => + { + context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer")) + .SetClaim(Claims.Subject, "Bob le Magnifique"); + + return default; + })); + options.AddEventHandler(builder => builder.UseInlineHandler(context => { @@ -1498,6 +1546,15 @@ namespace OpenIddict.Server.FunctionalTests { options.EnableDegradedMode(); + options.AddEventHandler(builder => + builder.UseInlineHandler(context => + { + context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer")) + .SetClaim(Claims.Subject, "Bob le Magnifique"); + + return default; + })); + options.AddEventHandler(builder => builder.UseInlineHandler(context => { @@ -1533,6 +1590,15 @@ namespace OpenIddict.Server.FunctionalTests { options.EnableDegradedMode(); + options.AddEventHandler(builder => + builder.UseInlineHandler(context => + { + context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer")) + .SetClaim(Claims.Subject, "Bob le Magnifique"); + + return default; + })); + options.AddEventHandler(builder => builder.UseInlineHandler(context => { @@ -1603,6 +1669,15 @@ namespace OpenIddict.Server.FunctionalTests { options.EnableDegradedMode(); + options.AddEventHandler(builder => + builder.UseInlineHandler(context => + { + context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer")) + .SetClaim(Claims.Subject, "Bob le Magnifique"); + + return default; + })); + options.AddEventHandler(builder => builder.UseInlineHandler(context => { @@ -1628,7 +1703,19 @@ namespace OpenIddict.Server.FunctionalTests public async Task ApplyAuthorizationResponse_FlowsStateWhenRedirectUriIsUsed() { // Arrange - var client = CreateClient(options => options.EnableDegradedMode()); + var client = CreateClient(options => + { + options.EnableDegradedMode(); + + options.AddEventHandler(builder => + builder.UseInlineHandler(context => + { + context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer")) + .SetClaim(Claims.Subject, "Bob le Magnifique"); + + return default; + })); + }); // Act var response = await client.PostAsync("/connect/authorize", new OpenIddictRequest @@ -1651,6 +1738,15 @@ namespace OpenIddict.Server.FunctionalTests { options.EnableDegradedMode(); + options.AddEventHandler(builder => + builder.UseInlineHandler(context => + { + context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer")) + .SetClaim(Claims.Subject, "Bob le Magnifique"); + + return default; + })); + options.AddEventHandler(builder => builder.UseInlineHandler(context => { @@ -1682,7 +1778,19 @@ namespace OpenIddict.Server.FunctionalTests // as validated and a signin grant is applied to return an authorization response. // Arrange - var client = CreateClient(options => options.EnableDegradedMode()); + var client = CreateClient(options => + { + options.EnableDegradedMode(); + + options.AddEventHandler(builder => + builder.UseInlineHandler(context => + { + context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer")) + .SetClaim(Claims.Subject, "Bob le Magnifique"); + + return default; + })); + }); // Act var response = await client.PostAsync("/connect/authorize", new OpenIddictRequest diff --git a/test/OpenIddict.Server.IntegrationTests/OpenIddictServerIntegrationTests.Exchange.cs b/test/OpenIddict.Server.IntegrationTests/OpenIddictServerIntegrationTests.Exchange.cs index 45dc2836..51620484 100644 --- a/test/OpenIddict.Server.IntegrationTests/OpenIddictServerIntegrationTests.Exchange.cs +++ b/test/OpenIddict.Server.IntegrationTests/OpenIddictServerIntegrationTests.Exchange.cs @@ -762,6 +762,15 @@ namespace OpenIddict.Server.FunctionalTests builder.SetOrder(ValidateIdentityModelToken.Descriptor.Order - 500); }); + + options.AddEventHandler(builder => + builder.UseInlineHandler(context => + { + context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer")) + .SetClaim(Claims.Subject, "Bob le Magnifique"); + + return default; + })); }); // Act @@ -1028,8 +1037,16 @@ namespace OpenIddict.Server.FunctionalTests var client = CreateClient(options => { options.EnableDegradedMode(); - options.RegisterScopes("registered_scope"); + + options.AddEventHandler(builder => + builder.UseInlineHandler(context => + { + context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer")) + .SetClaim(Claims.Subject, "Bob le Magnifique"); + + return default; + })); }); // Act @@ -1070,6 +1087,15 @@ namespace OpenIddict.Server.FunctionalTests options.RegisterScopes("scope_registered_in_options"); options.Services.AddSingleton(manager); + + options.AddEventHandler(builder => + builder.UseInlineHandler(context => + { + context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer")) + .SetClaim(Claims.Subject, "Bob le Magnifique"); + + return default; + })); }); // Act @@ -1664,6 +1690,15 @@ namespace OpenIddict.Server.FunctionalTests builder.SetOrder(ValidateIdentityModelToken.Descriptor.Order - 500); }); + options.AddEventHandler(builder => + builder.UseInlineHandler(context => + { + context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer")) + .SetClaim(Claims.Subject, "Bob le Magnifique"); + + return default; + })); + options.Services.AddSingleton(CreateApplicationManager(mock => { var application = new OpenIddictApplication(); @@ -1716,6 +1751,15 @@ namespace OpenIddict.Server.FunctionalTests builder.SetOrder(ValidateIdentityModelToken.Descriptor.Order - 500); }); + options.AddEventHandler(builder => + builder.UseInlineHandler(context => + { + context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer")) + .SetClaim(Claims.Subject, "Bob le Magnifique"); + + return default; + })); + options.SetRevocationEndpointUris(Array.Empty()); options.DisableTokenStorage(); options.DisableSlidingExpiration(); @@ -1761,6 +1805,15 @@ namespace OpenIddict.Server.FunctionalTests builder.SetOrder(ValidateIdentityModelToken.Descriptor.Order - 500); }); + options.AddEventHandler(builder => + builder.UseInlineHandler(context => + { + context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer")) + .SetClaim(Claims.Subject, "Bob le Magnifique"); + + return default; + })); + options.Services.AddSingleton(CreateApplicationManager(mock => { var application = new OpenIddictApplication(); @@ -1821,6 +1874,15 @@ namespace OpenIddict.Server.FunctionalTests builder.SetOrder(ValidateIdentityModelToken.Descriptor.Order - 500); }); + options.AddEventHandler(builder => + builder.UseInlineHandler(context => + { + context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer")) + .SetClaim(Claims.Subject, "Bob le Magnifique"); + + return default; + })); + options.Services.AddSingleton(manager); }); @@ -1876,6 +1938,15 @@ namespace OpenIddict.Server.FunctionalTests builder.SetOrder(ValidateIdentityModelToken.Descriptor.Order - 500); }); + options.AddEventHandler(builder => + builder.UseInlineHandler(context => + { + context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer")) + .SetClaim(Claims.Subject, "Bob le Magnifique"); + + return default; + })); + options.Services.AddSingleton(CreateApplicationManager(mock => { var application = new OpenIddictApplication(); @@ -1944,6 +2015,15 @@ namespace OpenIddict.Server.FunctionalTests builder.SetOrder(ValidateIdentityModelToken.Descriptor.Order - 500); }); + options.AddEventHandler(builder => + builder.UseInlineHandler(context => + { + context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer")) + .SetClaim(Claims.Subject, "Bob le Magnifique"); + + return default; + })); + options.Services.AddSingleton(manager); }); @@ -1995,6 +2075,15 @@ namespace OpenIddict.Server.FunctionalTests builder.SetOrder(ValidateIdentityModelToken.Descriptor.Order - 500); }); + options.AddEventHandler(builder => + builder.UseInlineHandler(context => + { + context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer")) + .SetClaim(Claims.Subject, "Bob le Magnifique"); + + return default; + })); + options.Services.AddSingleton(CreateApplicationManager(mock => { var application = new OpenIddictApplication(); @@ -2078,6 +2167,15 @@ namespace OpenIddict.Server.FunctionalTests builder.SetOrder(ValidateIdentityModelToken.Descriptor.Order - 500); }); + options.AddEventHandler(builder => + builder.UseInlineHandler(context => + { + context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer")) + .SetClaim(Claims.Subject, "Bob le Magnifique"); + + return default; + })); + options.Services.AddSingleton(CreateTokenManager(mock => { var token = new OpenIddictToken(); @@ -2170,6 +2268,15 @@ namespace OpenIddict.Server.FunctionalTests builder.SetOrder(ValidateIdentityModelToken.Descriptor.Order - 500); }); + options.AddEventHandler(builder => + builder.UseInlineHandler(context => + { + context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer")) + .SetClaim(Claims.Subject, "Bob le Magnifique"); + + return default; + })); + options.Services.AddSingleton(CreateApplicationManager(mock => { var application = new OpenIddictApplication(); @@ -2258,6 +2365,15 @@ namespace OpenIddict.Server.FunctionalTests builder.SetOrder(ValidateIdentityModelToken.Descriptor.Order - 500); }); + options.AddEventHandler(builder => + builder.UseInlineHandler(context => + { + context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer")) + .SetClaim(Claims.Subject, "Bob le Magnifique"); + + return default; + })); + options.Services.AddSingleton(manager); }); @@ -2321,6 +2437,15 @@ namespace OpenIddict.Server.FunctionalTests builder.SetOrder(ValidateIdentityModelToken.Descriptor.Order - 500); }); + options.AddEventHandler(builder => + builder.UseInlineHandler(context => + { + context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer")) + .SetClaim(Claims.Subject, "Bob le Magnifique"); + + return default; + })); + options.Services.AddSingleton(CreateApplicationManager(mock => { var application = new OpenIddictApplication(); @@ -2395,6 +2520,15 @@ namespace OpenIddict.Server.FunctionalTests builder.SetOrder(ValidateIdentityModelToken.Descriptor.Order - 500); }); + options.AddEventHandler(builder => + builder.UseInlineHandler(context => + { + context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer")) + .SetClaim(Claims.Subject, "Bob le Magnifique"); + + return default; + })); + options.Services.AddSingleton(manager); }); @@ -2444,6 +2578,15 @@ namespace OpenIddict.Server.FunctionalTests builder.SetOrder(ValidateIdentityModelToken.Descriptor.Order - 500); }); + options.AddEventHandler(builder => + builder.UseInlineHandler(context => + { + context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer")) + .SetClaim(Claims.Subject, "Bob le Magnifique"); + + return default; + })); + options.Services.AddSingleton(CreateApplicationManager(mock => { var application = new OpenIddictApplication(); @@ -2509,6 +2652,7 @@ namespace OpenIddict.Server.FunctionalTests mock.Setup(manager => manager.FindByIdAsync("18D15F73-BE2B-6867-DC01-B3C1E8AFDED0", It.IsAny())) .ReturnsAsync(new OpenIddictAuthorization()); }); + var client = CreateClient(options => { options.AddEventHandler(builder => @@ -2529,6 +2673,15 @@ namespace OpenIddict.Server.FunctionalTests builder.SetOrder(ValidateIdentityModelToken.Descriptor.Order - 500); }); + options.AddEventHandler(builder => + builder.UseInlineHandler(context => + { + context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer")) + .SetClaim(Claims.Subject, "Bob le Magnifique"); + + return default; + })); + options.Services.AddSingleton(CreateTokenManager(mock => { var token = new OpenIddictToken(); @@ -2598,6 +2751,15 @@ namespace OpenIddict.Server.FunctionalTests builder.SetOrder(ValidateIdentityModelToken.Descriptor.Order - 500); }); + options.AddEventHandler(builder => + builder.UseInlineHandler(context => + { + context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer")) + .SetClaim(Claims.Subject, "Bob le Magnifique"); + + return default; + })); + options.Services.AddSingleton(CreateApplicationManager(mock => { var application = new OpenIddictApplication(); @@ -2684,6 +2846,15 @@ namespace OpenIddict.Server.FunctionalTests builder.SetOrder(ValidateIdentityModelToken.Descriptor.Order - 500); }); + options.AddEventHandler(builder => + builder.UseInlineHandler(context => + { + context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer")) + .SetClaim(Claims.Subject, "Bob le Magnifique"); + + return default; + })); + options.Services.AddSingleton(CreateApplicationManager(mock => { var application = new OpenIddictApplication(); @@ -2765,6 +2936,15 @@ namespace OpenIddict.Server.FunctionalTests builder.SetOrder(ValidateIdentityModelToken.Descriptor.Order - 500); }); + options.AddEventHandler(builder => + builder.UseInlineHandler(context => + { + context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer")) + .SetClaim(Claims.Subject, "Bob le Magnifique"); + + return default; + })); + options.Services.AddSingleton(CreateTokenManager(mock => { var token = new OpenIddictToken(); @@ -2837,6 +3017,15 @@ namespace OpenIddict.Server.FunctionalTests builder.SetOrder(ValidateIdentityModelToken.Descriptor.Order - 500); }); + options.AddEventHandler(builder => + builder.UseInlineHandler(context => + { + context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer")) + .SetClaim(Claims.Subject, "Bob le Magnifique"); + + return default; + })); + options.Services.AddSingleton(CreateTokenManager(mock => { var token = new OpenIddictToken(); @@ -2926,6 +3115,15 @@ namespace OpenIddict.Server.FunctionalTests builder.SetOrder(ValidateIdentityModelToken.Descriptor.Order - 500); }); + options.AddEventHandler(builder => + builder.UseInlineHandler(context => + { + context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer")) + .SetClaim(Claims.Subject, "Bob le Magnifique"); + + return default; + })); + options.Services.AddSingleton(CreateApplicationManager(mock => { var application = new OpenIddictApplication(); @@ -3072,6 +3270,15 @@ namespace OpenIddict.Server.FunctionalTests { options.EnableDegradedMode(); + options.AddEventHandler(builder => + builder.UseInlineHandler(context => + { + context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer")) + .SetClaim(Claims.Subject, "Bob le Magnifique"); + + return default; + })); + options.AddEventHandler(builder => builder.UseInlineHandler(context => { @@ -3106,6 +3313,15 @@ namespace OpenIddict.Server.FunctionalTests { options.EnableDegradedMode(); + options.AddEventHandler(builder => + builder.UseInlineHandler(context => + { + context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer")) + .SetClaim(Claims.Subject, "Bob le Magnifique"); + + return default; + })); + options.AddEventHandler(builder => builder.UseInlineHandler(context => { diff --git a/test/OpenIddict.Server.IntegrationTests/OpenIddictServerIntegrationTests.cs b/test/OpenIddict.Server.IntegrationTests/OpenIddictServerIntegrationTests.cs index 90e4a71f..68594d75 100644 --- a/test/OpenIddict.Server.IntegrationTests/OpenIddictServerIntegrationTests.cs +++ b/test/OpenIddict.Server.IntegrationTests/OpenIddictServerIntegrationTests.cs @@ -5,7 +5,6 @@ */ using System; -using System.Collections.Immutable; using System.Linq; using System.Security.Claims; using System.Text; @@ -426,6 +425,236 @@ namespace OpenIddict.Server.FunctionalTests Assert.Equal("Bob le Magnifique", (string) response[Claims.Subject]); } + [Fact] + public async Task ProcessChallenge_UnknownEndpointCausesAnException() + { + // Arrange + var client = CreateClient(options => options.EnableDegradedMode()); + + // Act and assert + var exception = await Assert.ThrowsAsync(delegate + { + return client.PostAsync("/challenge", new OpenIddictRequest()); + }); + + Assert.Equal("An OpenID Connect response cannot be returned from this endpoint.", exception.Message); + } + + [Fact] + public async Task ProcessChallenge_InvalidEndpointCausesAnException() + { + // Arrange + var client = CreateClient(options => + { + options.EnableDegradedMode(); + options.SetConfigurationEndpointUris("/challenge"); + + options.AddEventHandler(builder => + builder.UseInlineHandler(context => + { + context.SkipRequest(); + + return default; + })); + }); + + // Act and assert + var exception = await Assert.ThrowsAsync(delegate + { + return client.GetAsync("/challenge"); + }); + + Assert.Equal("An OpenID Connect response cannot be returned from this endpoint.", exception.Message); + } + + [Fact] + public async Task ProcessChallenge_ReturnsDefaultErrorForAuthorizationRequestsWhenNoneIsSpecified() + { + // Arrange + var client = CreateClient(options => + { + options.EnableDegradedMode(); + options.SetAuthorizationEndpointUris("/challenge"); + + options.AddEventHandler(builder => + builder.UseInlineHandler(context => + { + context.SkipRequest(); + + return default; + })); + }); + + // Act + var response = await client.PostAsync("/challenge", new OpenIddictRequest + { + ClientId = "Fabrikam", + Nonce = "n-0S6_WzA2Mj", + RedirectUri = "http://www.fabrikam.com/path", + ResponseType = ResponseTypes.Code, + Scope = Scopes.OpenId + }); + + // Assert + Assert.Equal(Errors.AccessDenied, response.Error); + Assert.Equal("The authorization was denied by the resource owner.", response.ErrorDescription); + Assert.Null(response.ErrorUri); + } + + [Fact] + public async Task ProcessChallenge_ReturnsDefaultErrorForTokenRequestsWhenNoneIsSpecified() + { + // Arrange + var client = CreateClient(options => + { + options.EnableDegradedMode(); + options.SetTokenEndpointUris("/challenge"); + + options.AddEventHandler(builder => + builder.UseInlineHandler(context => + { + context.SkipRequest(); + + return default; + })); + }); + + // Act + var response = await client.PostAsync("/challenge", new OpenIddictRequest + { + GrantType = GrantTypes.Password, + Username = "johndoe", + Password = "A3ddj3w" + }); + + // Assert + Assert.Equal(Errors.InvalidGrant, response.Error); + Assert.Equal("The token request was rejected by the authorization server.", response.ErrorDescription); + Assert.Null(response.ErrorUri); + } + + [Fact] + public async Task ProcessChallenge_ReturnsErrorFromAuthenticationProperties() + { + // Arrange + var client = CreateClient(options => + { + options.EnableDegradedMode(); + options.SetTokenEndpointUris("/challenge/custom"); + + options.AddEventHandler(builder => + builder.UseInlineHandler(context => + { + context.SkipRequest(); + + return default; + })); + }); + + // Act + var response = await client.PostAsync("/challenge/custom", new OpenIddictRequest + { + GrantType = GrantTypes.Password, + Username = "johndoe", + Password = "A3ddj3w" + }); + + // Assert + Assert.Equal("custom_error", response.Error); + Assert.Equal("custom_error_description", response.ErrorDescription); + Assert.Equal("custom_error_uri", response.ErrorUri); + } + + [Theory] + [InlineData("custom_error", null, null)] + [InlineData("custom_error", "custom_description", null)] + [InlineData("custom_error", "custom_description", "custom_uri")] + [InlineData(null, "custom_description", null)] + [InlineData(null, "custom_description", "custom_uri")] + [InlineData(null, null, "custom_uri")] + [InlineData(null, null, null)] + public async Task ProcessChallenge_AllowsRejectingRequest(string error, string description, string uri) + { + // Arrange + var client = CreateClient(options => + { + options.EnableDegradedMode(); + options.SetTokenEndpointUris("/challenge"); + + options.AddEventHandler(builder => + builder.UseInlineHandler(context => + { + context.SkipRequest(); + + return default; + })); + + options.AddEventHandler(builder => + builder.UseInlineHandler(context => + { + context.Reject(error, description, uri); + + return default; + })); + }); + + // Act + var response = await client.PostAsync("/challenge", new OpenIddictRequest + { + GrantType = GrantTypes.Password, + Username = "johndoe", + Password = "A3ddj3w" + }); + + // Assert + Assert.Equal(error ?? Errors.InvalidRequest, response.Error); + Assert.Equal(description, response.ErrorDescription); + Assert.Equal(uri, response.ErrorUri); + } + + [Fact] + public async Task ProcessChallenge_AllowsHandlingResponse() + { + // Arrange + var client = CreateClient(options => + { + options.EnableDegradedMode(); + options.SetTokenEndpointUris("/challenge"); + + options.AddEventHandler(builder => + builder.UseInlineHandler(context => + { + context.SkipRequest(); + + return default; + })); + + options.AddEventHandler(builder => + builder.UseInlineHandler(context => + { + context.Transaction.SetProperty("custom_response", new + { + name = "Bob le Bricoleur" + }); + + context.HandleRequest(); + + return default; + })); + }); + + // Act + var response = await client.PostAsync("/challenge", new OpenIddictRequest + { + GrantType = GrantTypes.Password, + Username = "johndoe", + Password = "A3ddj3w" + }); + + // Assert + Assert.Equal("Bob le Bricoleur", (string) response["name"]); + } + [Fact] public async Task ProcessSignIn_UnknownEndpointCausesAnException() { @@ -576,6 +805,15 @@ namespace OpenIddict.Server.FunctionalTests { options.EnableDegradedMode(); + options.AddEventHandler(builder => + builder.UseInlineHandler(context => + { + context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer")) + .SetClaim(Claims.Subject, "Bob le Magnifique"); + + return default; + })); + options.AddEventHandler(builder => builder.UseInlineHandler(context => { @@ -606,21 +844,21 @@ namespace OpenIddict.Server.FunctionalTests { options.EnableDegradedMode(); - options.AddEventHandler(builder => + options.AddEventHandler(builder => builder.UseInlineHandler(context => { - Assert.Equal(new[] { "http://www.fabrikam.com/" }, context.Principal.GetResources()); + context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer")) + .SetAudiences("http://www.fabrikam.com/") + .SetScopes(Scopes.OfflineAccess) + .SetClaim(Claims.Subject, "Bob le Magnifique"); return default; })); - options.AddEventHandler(builder => + options.AddEventHandler(builder => builder.UseInlineHandler(context => { - context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer")) - .SetAudiences("http://www.fabrikam.com/") - .SetScopes(Scopes.OfflineAccess) - .SetClaim(Claims.Subject, "Bob le Magnifique"); + Assert.Equal(new[] { "http://www.fabrikam.com/" }, context.Principal.GetResources()); return default; })); @@ -647,6 +885,15 @@ namespace OpenIddict.Server.FunctionalTests { options.EnableDegradedMode(); + options.AddEventHandler(builder => + builder.UseInlineHandler(context => + { + context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer")) + .SetClaim(Claims.Subject, "Bob le Magnifique"); + + return default; + })); + options.AddEventHandler(builder => { builder.UseInlineHandler(context => @@ -690,6 +937,15 @@ namespace OpenIddict.Server.FunctionalTests { options.EnableDegradedMode(); + options.AddEventHandler(builder => + builder.UseInlineHandler(context => + { + context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer")) + .SetClaim(Claims.Subject, "Bob le Magnifique"); + + return default; + })); + options.AddEventHandler(builder => { builder.UseInlineHandler(context => @@ -813,6 +1069,15 @@ namespace OpenIddict.Server.FunctionalTests { options.EnableDegradedMode(); + options.AddEventHandler(builder => + builder.UseInlineHandler(context => + { + context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer")) + .SetClaim(Claims.Subject, "Bob le Magnifique"); + + return default; + })); + options.AddEventHandler(builder => { builder.UseInlineHandler(context => @@ -946,6 +1211,15 @@ namespace OpenIddict.Server.FunctionalTests { options.EnableDegradedMode(); + options.AddEventHandler(builder => + builder.UseInlineHandler(context => + { + context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer")) + .SetClaim(Claims.Subject, "Bob le Magnifique"); + + return default; + })); + options.AddEventHandler(builder => { builder.UseInlineHandler(context => @@ -979,6 +1253,15 @@ namespace OpenIddict.Server.FunctionalTests { options.EnableDegradedMode(); + options.AddEventHandler(builder => + builder.UseInlineHandler(context => + { + context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer")) + .SetClaim(Claims.Subject, "Bob le Magnifique"); + + return default; + })); + options.AddEventHandler(builder => { builder.UseInlineHandler(context => @@ -1013,6 +1296,15 @@ namespace OpenIddict.Server.FunctionalTests options.EnableDegradedMode(); options.AllowCustomFlow("urn:ietf:params:oauth:grant-type:custom_grant"); + options.AddEventHandler(builder => + builder.UseInlineHandler(context => + { + context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer")) + .SetClaim(Claims.Subject, "Bob le Magnifique"); + + return default; + })); + options.AddEventHandler(builder => { builder.UseInlineHandler(context => @@ -1040,7 +1332,19 @@ namespace OpenIddict.Server.FunctionalTests public async Task ProcessSignIn_ExpiresInIsReturnedWhenExpirationDateIsKnown() { // Arrange - var client = CreateClient(options => options.EnableDegradedMode()); + var client = CreateClient(options => + { + options.EnableDegradedMode(); + + options.AddEventHandler(builder => + builder.UseInlineHandler(context => + { + context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer")) + .SetClaim(Claims.Subject, "Bob le Magnifique"); + + return default; + })); + }); // Act var response = await client.PostAsync("/connect/token", new OpenIddictRequest @@ -1062,6 +1366,15 @@ namespace OpenIddict.Server.FunctionalTests { options.EnableDegradedMode(); + options.AddEventHandler(builder => + builder.UseInlineHandler(context => + { + context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer")) + .SetClaim(Claims.Subject, "Bob le Magnifique"); + + return default; + })); + options.AddEventHandler(builder => { builder.UseInlineHandler(context => @@ -1373,6 +1686,15 @@ namespace OpenIddict.Server.FunctionalTests { options.EnableDegradedMode(); + options.AddEventHandler(builder => + builder.UseInlineHandler(context => + { + context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer")) + .SetClaim(Claims.Subject, "Bob le Magnifique"); + + return default; + })); + options.AddEventHandler(builder => { builder.UseInlineHandler(context => @@ -1410,6 +1732,15 @@ namespace OpenIddict.Server.FunctionalTests { options.EnableDegradedMode(); + options.AddEventHandler(builder => + builder.UseInlineHandler(context => + { + context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer")) + .SetClaim(Claims.Subject, "Bob le Magnifique"); + + return default; + })); + options.AddEventHandler(builder => { builder.UseInlineHandler(context => @@ -1556,6 +1887,15 @@ namespace OpenIddict.Server.FunctionalTests builder.SetOrder(EvaluateReturnedTokens.Descriptor.Order + 500); }); + + options.AddEventHandler(builder => + builder.UseInlineHandler(context => + { + context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer")) + .SetClaim(Claims.Subject, "Bob le Magnifique"); + + return default; + })); }); // Act @@ -1579,6 +1919,15 @@ namespace OpenIddict.Server.FunctionalTests { options.EnableDegradedMode(); + options.AddEventHandler(builder => + builder.UseInlineHandler(context => + { + context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer")) + .SetClaim(Claims.Subject, "Bob le Magnifique"); + + return default; + })); + options.AddEventHandler(builder => { builder.UseInlineHandler(context => @@ -1614,6 +1963,15 @@ namespace OpenIddict.Server.FunctionalTests options.EnableDegradedMode(); options.AllowCustomFlow("urn:ietf:params:oauth:grant-type:custom_grant"); + options.AddEventHandler(builder => + builder.UseInlineHandler(context => + { + context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer")) + .SetClaim(Claims.Subject, "Bob le Magnifique"); + + return default; + })); + options.AddEventHandler(builder => { builder.UseInlineHandler(context => @@ -1653,6 +2011,15 @@ namespace OpenIddict.Server.FunctionalTests { options.EnableDegradedMode(); + options.AddEventHandler(builder => + builder.UseInlineHandler(context => + { + context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer")) + .SetClaim(Claims.Subject, "Bob le Magnifique"); + + return default; + })); + options.AddEventHandler(builder => builder.UseInlineHandler(context => { @@ -1685,6 +2052,15 @@ namespace OpenIddict.Server.FunctionalTests { options.EnableDegradedMode(); + options.AddEventHandler(builder => + builder.UseInlineHandler(context => + { + context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer")) + .SetClaim(Claims.Subject, "Bob le Magnifique"); + + return default; + })); + options.AddEventHandler(builder => builder.UseInlineHandler(context => { @@ -1720,15 +2096,6 @@ namespace OpenIddict.Server.FunctionalTests options.EnableDegradedMode(); options.UseRollingTokens(); - options.AddEventHandler(builder => - builder.UseInlineHandler(context => - { - Assert.Equal(new[] { Scopes.OpenId, Scopes.OfflineAccess }, context.Principal.GetScopes()); - Assert.Equal("value", context.Principal.GetClaim(Claims.Prefixes.Private + "_private_claim")); - - return default; - })); - options.AddEventHandler(builder => { builder.UseInlineHandler(context => @@ -1746,6 +2113,15 @@ namespace OpenIddict.Server.FunctionalTests builder.SetOrder(ValidateIdentityModelToken.Descriptor.Order - 500); }); + + options.AddEventHandler(builder => + builder.UseInlineHandler(context => + { + Assert.Equal(new[] { Scopes.OpenId, Scopes.OfflineAccess }, context.Principal.GetScopes()); + Assert.Equal("value", context.Principal.GetClaim(Claims.Prefixes.Private + "_private_claim")); + + return default; + })); }); // Act @@ -2716,6 +3092,15 @@ namespace OpenIddict.Server.FunctionalTests })); options.Services.AddSingleton(manager); + + options.AddEventHandler(builder => + builder.UseInlineHandler(context => + { + context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer")) + .SetClaim(Claims.Subject, "Bob le Magnifique"); + + return default; + })); }); // Act @@ -2780,6 +3165,15 @@ namespace OpenIddict.Server.FunctionalTests options.Services.AddSingleton(manager); options.DisableAuthorizationStorage(); + + options.AddEventHandler(builder => + builder.UseInlineHandler(context => + { + context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer")) + .SetClaim(Claims.Subject, "Bob le Magnifique"); + + return default; + })); }); // Act @@ -2796,6 +3190,21 @@ namespace OpenIddict.Server.FunctionalTests Mock.Get(manager).Verify(manager => manager.CreateAsync(It.IsAny(), It.IsAny()), Times.Never()); } + [Fact] + public async Task ProcessSignOut_UnknownEndpointCausesAnException() + { + // Arrange + var client = CreateClient(options => options.EnableDegradedMode()); + + // Act and assert + var exception = await Assert.ThrowsAsync(delegate + { + return client.PostAsync("/signout", new OpenIddictRequest()); + }); + + Assert.Equal("An OpenID Connect response cannot be returned from this endpoint.", exception.Message); + } + [Fact] public async Task ProcessSignOut_InvalidEndpointCausesAnException() { @@ -2951,32 +3360,6 @@ namespace OpenIddict.Server.FunctionalTests options.AddEventHandler(builder => builder.UseInlineHandler(context => default)); - - options.AddEventHandler(builder => - { - builder.UseInlineHandler(context => - { - context.Principal ??= new ClaimsPrincipal(new ClaimsIdentity("Bearer")) - .SetClaim(Claims.Subject, "Bob le Magnifique"); - - return default; - }); - - builder.SetOrder(int.MaxValue); - }); - - options.AddEventHandler(builder => - { - builder.UseInlineHandler(context => - { - context.Principal ??= new ClaimsPrincipal(new ClaimsIdentity("Bearer")) - .SetClaim(Claims.Subject, "Bob le Magnifique"); - - return default; - }); - - builder.SetOrder(int.MaxValue); - }); }); } diff --git a/test/OpenIddict.Server.Owin.IntegrationTests/OpenIddictServerOwinIntegrationTests.cs b/test/OpenIddict.Server.Owin.IntegrationTests/OpenIddictServerOwinIntegrationTests.cs index 20bc836a..3ea9ea85 100644 --- a/test/OpenIddict.Server.Owin.IntegrationTests/OpenIddictServerOwinIntegrationTests.cs +++ b/test/OpenIddict.Server.Owin.IntegrationTests/OpenIddictServerOwinIntegrationTests.cs @@ -5,12 +5,14 @@ */ using System; +using System.Collections.Generic; using System.Linq; using System.Security.Claims; using System.Text.Json; using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; using Microsoft.Owin; +using Microsoft.Owin.Security; using Microsoft.Owin.Testing; using OpenIddict.Abstractions; using OpenIddict.Server.FunctionalTests; @@ -326,6 +328,19 @@ namespace OpenIddict.Server.Owin.FunctionalTests return; } + else if (context.Request.Path == new PathString("/challenge/custom")) + { + var properties = new AuthenticationProperties(new Dictionary + { + [OpenIddictServerOwinConstants.Properties.Error] = "custom_error", + [OpenIddictServerOwinConstants.Properties.ErrorDescription] = "custom_error_description", + [OpenIddictServerOwinConstants.Properties.ErrorUri] = "custom_error_uri" + }); + + context.Authentication.Challenge(properties, OpenIddictServerOwinDefaults.AuthenticationType); + return; + } + else if (context.Request.Path == new PathString("/authenticate")) { var result = await context.Authentication.AuthenticateAsync(OpenIddictServerOwinDefaults.AuthenticationType);