From ff293e1481172e1e0301ac82882826c69273a124 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Chalet?= Date: Thu, 12 Oct 2017 12:42:43 +0200 Subject: [PATCH 1/3] Update README.md --- README.md | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index d0db6382..04417933 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ OpenIddict is based on OpenIddict fully supports the **[code/implicit/hybrid flows](http://openid.net/specs/openid-connect-core-1_0.html)** and the **[client credentials/resource owner password grants](https://tools.ietf.org/html/rfc6749)**. You can also create your own custom grant types. -Note: OpenIddict uses **[Entity Framework Core](https://github.com/aspnet/EntityFramework)** by default, but you can also provide your own store. +Note: OpenIddict natively supports **[Entity Framework Core](https://github.com/aspnet/EntityFramework)** and **[Entity Framework 6](https://github.com/aspnet/EntityFramework6)** out-of-the-box, but you can also provide your own stores. > Note: **the OpenIddict 2.x packages are only compatible with ASP.NET Core 2.x**. > If your application targets ASP.NET Core 1.x, use the OpenIddict 1.x packages. @@ -124,7 +124,7 @@ public void ConfigureServices(IServiceCollection services) [Configuration and options](https://github.com/openiddict/core/wiki/Configuration-and-options) in the project wiki. - - **Make sure the authentication middleware is registered before all the other middleware, including `app.UseMvc()`: + - **Make sure the authentication middleware is registered before all the other middleware, including `app.UseMvc()`**: ```csharp public void Configure(IApplicationBuilder app) @@ -135,7 +135,7 @@ public void Configure(IApplicationBuilder app) } ``` - - **Update your Entity Framework context registration to register the OpenIddict entities**: + - **Update your Entity Framework Core context registration to register the OpenIddict entities**: ```csharp services.AddDbContext(options => @@ -218,13 +218,14 @@ using (var scope = app.ApplicationServices.GetRequiredService Date: Thu, 12 Oct 2017 13:10:25 +0200 Subject: [PATCH 2/3] Update the OpenIddictBuilder methods documentation and reword the exception messages --- src/OpenIddict.Core/OpenIddictBuilder.cs | 64 ++++++++++++------- .../OpenIddictBuilderTests.cs | 16 ++--- 2 files changed, 48 insertions(+), 32 deletions(-) diff --git a/src/OpenIddict.Core/OpenIddictBuilder.cs b/src/OpenIddict.Core/OpenIddictBuilder.cs index a1af2bc2..8b0f8dfe 100644 --- a/src/OpenIddict.Core/OpenIddictBuilder.cs +++ b/src/OpenIddict.Core/OpenIddictBuilder.cs @@ -62,7 +62,8 @@ namespace Microsoft.Extensions.DependencyInjection public IServiceCollection Services { get; } /// - /// Adds a custom application manager. + /// Adds a custom application manager derived from + /// . /// /// The type of the custom manager. /// The . @@ -70,7 +71,8 @@ namespace Microsoft.Extensions.DependencyInjection => AddApplicationManager(typeof(TManager)); /// - /// Adds a custom application manager. + /// Adds a custom application manager derived from + /// . /// /// The type of the custom manager. /// The . @@ -84,7 +86,7 @@ namespace Microsoft.Extensions.DependencyInjection var contract = typeof(OpenIddictApplicationManager<>).MakeGenericType(ApplicationType); if (!contract.IsAssignableFrom(type)) { - throw new InvalidOperationException("Custom managers must be derived from OpenIddictApplicationManager."); + throw new InvalidOperationException("The specified type is invalid."); } Services.AddScoped(contract, type); @@ -93,7 +95,8 @@ namespace Microsoft.Extensions.DependencyInjection } /// - /// Adds a custom application store. + /// Adds a custom application store derived from + /// . /// /// The type of the custom store. /// The . @@ -101,7 +104,8 @@ namespace Microsoft.Extensions.DependencyInjection => AddApplicationStore(typeof(TStore)); /// - /// Adds a custom application store. + /// Adds a custom application store derived from + /// . /// /// The type of the custom store. /// The . @@ -115,7 +119,7 @@ namespace Microsoft.Extensions.DependencyInjection var contract = typeof(IOpenIddictApplicationStore<>).MakeGenericType(ApplicationType); if (!contract.IsAssignableFrom(type)) { - throw new InvalidOperationException("Custom stores must implement IOpenIddictApplicationStore."); + throw new InvalidOperationException("The specified type is invalid."); } Services.AddScoped(contract, type); @@ -124,7 +128,8 @@ namespace Microsoft.Extensions.DependencyInjection } /// - /// Adds a custom authorization manager. + /// Adds a custom authorization manager derived from + /// . /// /// The type of the custom manager. /// The . @@ -132,7 +137,8 @@ namespace Microsoft.Extensions.DependencyInjection => AddAuthorizationManager(typeof(TManager)); /// - /// Adds a custom authorization manager. + /// Adds a custom authorization manager derived from + /// . /// /// The type of the custom manager. /// The . @@ -146,7 +152,7 @@ namespace Microsoft.Extensions.DependencyInjection var contract = typeof(OpenIddictAuthorizationManager<>).MakeGenericType(AuthorizationType); if (!contract.IsAssignableFrom(type)) { - throw new InvalidOperationException("Custom managers must be derived from OpenIddictAuthorizationManager."); + throw new InvalidOperationException("The specified type is invalid."); } Services.AddScoped(contract, type); @@ -155,7 +161,8 @@ namespace Microsoft.Extensions.DependencyInjection } /// - /// Adds a custom authorization store. + /// Adds a custom authorization store derived from + /// . /// /// The type of the custom store. /// The . @@ -163,7 +170,8 @@ namespace Microsoft.Extensions.DependencyInjection => AddAuthorizationStore(typeof(TStore)); /// - /// Adds a custom authorization store. + /// Adds a custom authorization store derived from + /// . /// /// The type of the custom store. /// The . @@ -177,7 +185,7 @@ namespace Microsoft.Extensions.DependencyInjection var contract = typeof(IOpenIddictAuthorizationStore<>).MakeGenericType(AuthorizationType); if (!contract.IsAssignableFrom(type)) { - throw new InvalidOperationException("Custom stores must implement IOpenIddictAuthorizationStore."); + throw new InvalidOperationException("The specified type is invalid."); } Services.AddScoped(contract, type); @@ -186,7 +194,8 @@ namespace Microsoft.Extensions.DependencyInjection } /// - /// Adds a custom scope manager. + /// Adds a custom scope manager derived from + /// . /// /// The type of the custom manager. /// The . @@ -194,7 +203,8 @@ namespace Microsoft.Extensions.DependencyInjection => AddScopeManager(typeof(TManager)); /// - /// Adds a custom scope manager. + /// Adds a custom scope manager derived from + /// . /// /// The type of the custom manager. /// The . @@ -208,7 +218,7 @@ namespace Microsoft.Extensions.DependencyInjection var contract = typeof(OpenIddictScopeManager<>).MakeGenericType(ScopeType); if (!contract.IsAssignableFrom(type)) { - throw new InvalidOperationException("Custom managers must be derived from OpenIddictScopeManager."); + throw new InvalidOperationException("The specified type is invalid."); } Services.AddScoped(contract, type); @@ -217,7 +227,8 @@ namespace Microsoft.Extensions.DependencyInjection } /// - /// Adds a custom scope store. + /// Adds a custom scope store derived from + /// . /// /// The type of the custom store. /// The . @@ -225,7 +236,8 @@ namespace Microsoft.Extensions.DependencyInjection => AddScopeStore(typeof(TStore)); /// - /// Adds a custom scope store. + /// Adds a custom scope store derived from + /// . /// /// The type of the custom store. /// The . @@ -239,7 +251,7 @@ namespace Microsoft.Extensions.DependencyInjection var contract = typeof(IOpenIddictScopeStore<>).MakeGenericType(ScopeType); if (!contract.IsAssignableFrom(type)) { - throw new InvalidOperationException("Custom stores must implement IOpenIddictScopeStore."); + throw new InvalidOperationException("The specified type is invalid."); } Services.AddScoped(contract, type); @@ -248,7 +260,8 @@ namespace Microsoft.Extensions.DependencyInjection } /// - /// Adds a custom token manager. + /// Adds a custom token manager derived from + /// . /// /// The type of the custom manager. /// The . @@ -256,7 +269,8 @@ namespace Microsoft.Extensions.DependencyInjection => AddTokenManager(typeof(TManager)); /// - /// Adds a custom token manager. + /// Adds a custom token manager derived from + /// . /// /// The type of the custom manager. /// The . @@ -270,7 +284,7 @@ namespace Microsoft.Extensions.DependencyInjection var contract = typeof(OpenIddictTokenManager<>).MakeGenericType(TokenType); if (!contract.IsAssignableFrom(type)) { - throw new InvalidOperationException("Custom managers must be derived from OpenIddictTokenManager."); + throw new InvalidOperationException("The specified type is invalid."); } Services.AddScoped(contract, type); @@ -279,7 +293,8 @@ namespace Microsoft.Extensions.DependencyInjection } /// - /// Adds a custom token store. + /// Adds a custom token store derived from + /// . /// /// The type of the custom store. /// The . @@ -287,7 +302,8 @@ namespace Microsoft.Extensions.DependencyInjection => AddTokenStore(typeof(TStore)); /// - /// Adds a custom token store. + /// Adds a custom token store derived from + /// . /// /// The type of the custom store. /// The . @@ -301,7 +317,7 @@ namespace Microsoft.Extensions.DependencyInjection var contract = typeof(IOpenIddictTokenStore<>).MakeGenericType(TokenType); if (!contract.IsAssignableFrom(type)) { - throw new InvalidOperationException("Custom stores must implement IOpenIddictTokenStore."); + throw new InvalidOperationException("The specified type is invalid."); } Services.AddScoped(contract, type); diff --git a/test/OpenIddict.Core.Tests/OpenIddictBuilderTests.cs b/test/OpenIddict.Core.Tests/OpenIddictBuilderTests.cs index 6ef5830b..c547ad8e 100644 --- a/test/OpenIddict.Core.Tests/OpenIddictBuilderTests.cs +++ b/test/OpenIddict.Core.Tests/OpenIddictBuilderTests.cs @@ -27,7 +27,7 @@ namespace OpenIddict.Core.Tests // Act and assert var exception = Assert.Throws(() => builder.AddApplicationManager(typeof(object))); - Assert.Equal("Custom managers must be derived from OpenIddictApplicationManager.", exception.Message); + Assert.Equal("The specified type is invalid.", exception.Message); } [Fact] @@ -67,7 +67,7 @@ namespace OpenIddict.Core.Tests // Act and assert var exception = Assert.Throws(() => builder.AddApplicationStore(typeof(object))); - Assert.Equal("Custom stores must implement IOpenIddictApplicationStore.", exception.Message); + Assert.Equal("The specified type is invalid.", exception.Message); } [Fact] @@ -105,7 +105,7 @@ namespace OpenIddict.Core.Tests // Act and assert var exception = Assert.Throws(() => builder.AddAuthorizationManager(typeof(object))); - Assert.Equal("Custom managers must be derived from OpenIddictAuthorizationManager.", exception.Message); + Assert.Equal("The specified type is invalid.", exception.Message); } [Fact] @@ -145,7 +145,7 @@ namespace OpenIddict.Core.Tests // Act and assert var exception = Assert.Throws(() => builder.AddAuthorizationStore(typeof(object))); - Assert.Equal("Custom stores must implement IOpenIddictAuthorizationStore.", exception.Message); + Assert.Equal("The specified type is invalid.", exception.Message); } [Fact] @@ -183,7 +183,7 @@ namespace OpenIddict.Core.Tests // Act and assert var exception = Assert.Throws(() => builder.AddScopeManager(typeof(object))); - Assert.Equal("Custom managers must be derived from OpenIddictScopeManager.", exception.Message); + Assert.Equal("The specified type is invalid.", exception.Message); } [Fact] @@ -223,7 +223,7 @@ namespace OpenIddict.Core.Tests // Act and assert var exception = Assert.Throws(() => builder.AddScopeStore(typeof(object))); - Assert.Equal("Custom stores must implement IOpenIddictScopeStore.", exception.Message); + Assert.Equal("The specified type is invalid.", exception.Message); } [Fact] @@ -261,7 +261,7 @@ namespace OpenIddict.Core.Tests // Act and assert var exception = Assert.Throws(() => builder.AddTokenManager(typeof(object))); - Assert.Equal("Custom managers must be derived from OpenIddictTokenManager.", exception.Message); + Assert.Equal("The specified type is invalid.", exception.Message); } [Fact] @@ -301,7 +301,7 @@ namespace OpenIddict.Core.Tests // Act and assert var exception = Assert.Throws(() => builder.AddTokenStore(typeof(object))); - Assert.Equal("Custom stores must implement IOpenIddictTokenStore.", exception.Message); + Assert.Equal("The specified type is invalid.", exception.Message); } [Fact] From 820eedfd44a6a7370cbee3e55f201ff17189e385 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Chalet?= Date: Thu, 12 Oct 2017 14:29:02 +0200 Subject: [PATCH 3/3] Ensure that a refresh_token is correctly returned for grant_type=authorization_code requests --- src/OpenIddict/OpenIddictProvider.Signin.cs | 8 ++- .../OpenIddictProviderTests.Signin.cs | 72 +++++++++++++++++++ 2 files changed, 78 insertions(+), 2 deletions(-) diff --git a/src/OpenIddict/OpenIddictProvider.Signin.cs b/src/OpenIddict/OpenIddictProvider.Signin.cs index 3f8dc9d2..72c38136 100644 --- a/src/OpenIddict/OpenIddictProvider.Signin.cs +++ b/src/OpenIddict/OpenIddictProvider.Signin.cs @@ -64,10 +64,14 @@ namespace OpenIddict context.IncludeIdentityToken = context.Ticket.HasScope(OpenIdConnectConstants.Scopes.OpenId); } + context.IncludeRefreshToken = context.Ticket.HasScope(OpenIdConnectConstants.Scopes.OfflineAccess); + // Always include a refresh token for grant_type=refresh_token requests if // rolling tokens are enabled and if the offline_access scope was specified. - context.IncludeRefreshToken = context.Request.IsRefreshTokenGrantType() && options.UseRollingTokens && - context.Ticket.HasScope(OpenIdConnectConstants.Scopes.OfflineAccess); + if (context.Request.IsRefreshTokenGrantType()) + { + context.IncludeRefreshToken &= options.UseRollingTokens; + } // If token revocation was explicitly disabled, // none of the following security routines apply. diff --git a/test/OpenIddict.Tests/OpenIddictProviderTests.Signin.cs b/test/OpenIddict.Tests/OpenIddictProviderTests.Signin.cs index aeac45c2..f7788d64 100644 --- a/test/OpenIddict.Tests/OpenIddictProviderTests.Signin.cs +++ b/test/OpenIddict.Tests/OpenIddictProviderTests.Signin.cs @@ -91,6 +91,78 @@ namespace OpenIddict.Tests value.Properties.Items["custom_property_in_original_ticket"] == "original_value" && value.Properties.Items["custom_property_in_new_ticket"] == "new_value"))); } + + [Fact] + public async Task ProcessSigninResponse_RefreshTokenIsIssuedForAuthorizationCodeRequestsWhenRollingTokensAreEnabled() + { + // 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.SetPresenters("Fabrikam"); + ticket.SetTokenId("3E228451-1555-46F7-A471-951EFBA23A56"); + ticket.SetTokenUsage(OpenIdConnectConstants.TokenUsages.AuthorizationCode); + ticket.SetScopes(OpenIdConnectConstants.Scopes.OpenId, OpenIdConnectConstants.Scopes.OfflineAccess); + + var format = new Mock>(); + + format.Setup(mock => mock.Unprotect("SplxlOBeZQQYbYS6WxSbIA")) + .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.IsRedeemedAsync(token, It.IsAny())) + .ReturnsAsync(false); + + instance.Setup(mock => mock.IsValidAsync(token, It.IsAny())) + .ReturnsAsync(true); + }); + + 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.GetClientTypeAsync(application, It.IsAny())) + .ReturnsAsync(OpenIddictConstants.ClientTypes.Public); + })); + + builder.Services.AddSingleton(manager); + + builder.UseRollingTokens(); + + builder.Configure(options => options.AuthorizationCodeFormat = format.Object); + }); + + var client = new OpenIdConnectClient(server.CreateClient()); + + // Act + var response = await client.PostAsync(TokenEndpoint, new OpenIdConnectRequest + { + ClientId = "Fabrikam", + Code = "SplxlOBeZQQYbYS6WxSbIA", + GrantType = OpenIdConnectConstants.GrantTypes.AuthorizationCode, + RedirectUri = "http://www.fabrikam.com/path" + }); + + // Assert + Assert.NotNull(response.RefreshToken); + } + [Fact] public async Task ProcessSigninResponse_RefreshTokenIsAlwaysIssuedWhenRollingTokensAreEnabled() {