From 56a66f42fe1d8496e8032dc5766ff98ba40e2824 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Chalet?= Date: Fri, 4 Nov 2016 12:03:19 +0100 Subject: [PATCH] Introduce new OpenIddictBuilder methods and add the corresponding unit tests --- .../Managers/OpenIddictScopeManager.cs | 2 +- src/OpenIddict.Core/OpenIddictBuilder.cs | 168 +++- .../OpenIddictBuilderTests.cs | 809 ++++++++++++++++++ test/OpenIddict.Core.Tests/project.json | 4 + 4 files changed, 958 insertions(+), 25 deletions(-) create mode 100644 test/OpenIddict.Core.Tests/OpenIddictBuilderTests.cs diff --git a/src/OpenIddict.Core/Managers/OpenIddictScopeManager.cs b/src/OpenIddict.Core/Managers/OpenIddictScopeManager.cs index ce748f66..1d82e02a 100644 --- a/src/OpenIddict.Core/Managers/OpenIddictScopeManager.cs +++ b/src/OpenIddict.Core/Managers/OpenIddictScopeManager.cs @@ -20,7 +20,7 @@ namespace OpenIddict { public OpenIddictScopeManager( [NotNull] IServiceProvider services, [NotNull] IOpenIddictScopeStore store, - [NotNull] ILogger> logger) { + [NotNull] ILogger> logger) { Context = services?.GetService()?.HttpContext; Logger = logger; Store = store; diff --git a/src/OpenIddict.Core/OpenIddictBuilder.cs b/src/OpenIddict.Core/OpenIddictBuilder.cs index 7247834f..df168812 100644 --- a/src/OpenIddict.Core/OpenIddictBuilder.cs +++ b/src/OpenIddict.Core/OpenIddictBuilder.cs @@ -82,13 +82,25 @@ namespace Microsoft.AspNetCore.Builder { /// /// The type of the custom manager. /// The . - public virtual OpenIddictBuilder AddApplicationManager() { + public OpenIddictBuilder AddApplicationManager() where TManager : class + => AddApplicationManager(typeof(TManager)); + + /// + /// Adds a custom application manager. + /// + /// The type of the custom manager. + /// The . + public virtual OpenIddictBuilder AddApplicationManager([NotNull] Type type) { + if (type == null) { + throw new ArgumentNullException(nameof(type)); + } + var contract = typeof(OpenIddictApplicationManager<>).MakeGenericType(ApplicationType); - if (!contract.IsAssignableFrom(typeof(TManager))) { + if (!contract.IsAssignableFrom(type)) { throw new InvalidOperationException("Custom managers must be derived from OpenIddictApplicationManager."); } - Services.AddScoped(contract, typeof(TManager)); + Services.AddScoped(contract, type); return this; } @@ -98,13 +110,25 @@ namespace Microsoft.AspNetCore.Builder { /// /// The type of the custom store. /// The . - public virtual OpenIddictBuilder AddApplicationStore() { + public OpenIddictBuilder AddApplicationStore() where TStore : class + => AddApplicationStore(typeof(TStore)); + + /// + /// Adds a custom application store. + /// + /// The type of the custom store. + /// The . + public virtual OpenIddictBuilder AddApplicationStore([NotNull] Type type) { + if (type == null) { + throw new ArgumentNullException(nameof(type)); + } + var contract = typeof(IOpenIddictApplicationStore<>).MakeGenericType(ApplicationType); - if (!contract.IsAssignableFrom(typeof(TStore))) { + if (!contract.IsAssignableFrom(type)) { throw new InvalidOperationException("Custom stores must implement IOpenIddictApplicationStore."); } - Services.AddScoped(contract, typeof(TStore)); + Services.AddScoped(contract, type); return this; } @@ -114,13 +138,25 @@ namespace Microsoft.AspNetCore.Builder { /// /// The type of the custom manager. /// The . - public virtual OpenIddictBuilder AddAuthorizationManager() { + public OpenIddictBuilder AddAuthorizationManager() where TManager : class + => AddAuthorizationManager(typeof(TManager)); + + /// + /// Adds a custom authorization manager. + /// + /// The type of the custom manager. + /// The . + public virtual OpenIddictBuilder AddAuthorizationManager([NotNull] Type type) { + if (type == null) { + throw new ArgumentNullException(nameof(type)); + } + var contract = typeof(OpenIddictAuthorizationManager<>).MakeGenericType(AuthorizationType); - if (!contract.IsAssignableFrom(typeof(TManager))) { + if (!contract.IsAssignableFrom(type)) { throw new InvalidOperationException("Custom managers must be derived from OpenIddictAuthorizationManager."); } - Services.AddScoped(contract, typeof(TManager)); + Services.AddScoped(contract, type); return this; } @@ -130,13 +166,25 @@ namespace Microsoft.AspNetCore.Builder { /// /// The type of the custom store. /// The . - public virtual OpenIddictBuilder AddAuthorizationStore() { + public OpenIddictBuilder AddAuthorizationStore() where TStore : class + => AddAuthorizationStore(typeof(TStore)); + + /// + /// Adds a custom authorization store. + /// + /// The type of the custom store. + /// The . + public virtual OpenIddictBuilder AddAuthorizationStore([NotNull] Type type) { + if (type == null) { + throw new ArgumentNullException(nameof(type)); + } + var contract = typeof(IOpenIddictAuthorizationStore<>).MakeGenericType(AuthorizationType); - if (!contract.IsAssignableFrom(typeof(TStore))) { + if (!contract.IsAssignableFrom(type)) { throw new InvalidOperationException("Custom stores must implement IOpenIddictAuthorizationStore."); } - Services.AddScoped(contract, typeof(TStore)); + Services.AddScoped(contract, type); return this; } @@ -146,13 +194,25 @@ namespace Microsoft.AspNetCore.Builder { /// /// The type of the custom manager. /// The . - public virtual OpenIddictBuilder AddScopeManager() { + public OpenIddictBuilder AddScopeManager() where TManager : class + => AddScopeManager(typeof(TManager)); + + /// + /// Adds a custom scope manager. + /// + /// The type of the custom manager. + /// The . + public virtual OpenIddictBuilder AddScopeManager([NotNull] Type type) { + if (type == null) { + throw new ArgumentNullException(nameof(type)); + } + var contract = typeof(OpenIddictScopeManager<>).MakeGenericType(ScopeType); - if (!contract.IsAssignableFrom(typeof(TManager))) { + if (!contract.IsAssignableFrom(type)) { throw new InvalidOperationException("Custom managers must be derived from OpenIddictScopeManager."); } - Services.AddScoped(contract, typeof(TManager)); + Services.AddScoped(contract, type); return this; } @@ -162,13 +222,25 @@ namespace Microsoft.AspNetCore.Builder { /// /// The type of the custom store. /// The . - public virtual OpenIddictBuilder AddScopeStore() { + public OpenIddictBuilder AddScopeStore() where TStore : class + => AddScopeStore(typeof(TStore)); + + /// + /// Adds a custom scope store. + /// + /// The type of the custom store. + /// The . + public virtual OpenIddictBuilder AddScopeStore([NotNull] Type type) { + if (type == null) { + throw new ArgumentNullException(nameof(type)); + } + var contract = typeof(IOpenIddictScopeStore<>).MakeGenericType(ScopeType); - if (!contract.IsAssignableFrom(typeof(TStore))) { + if (!contract.IsAssignableFrom(type)) { throw new InvalidOperationException("Custom stores must implement IOpenIddictScopeStore."); } - Services.AddScoped(contract, typeof(TStore)); + Services.AddScoped(contract, type); return this; } @@ -178,13 +250,25 @@ namespace Microsoft.AspNetCore.Builder { /// /// The type of the custom manager. /// The . - public virtual OpenIddictBuilder AddTokenManager() { + public OpenIddictBuilder AddTokenManager() where TManager : class + => AddTokenManager(typeof(TManager)); + + /// + /// Adds a custom token manager. + /// + /// The type of the custom manager. + /// The . + public virtual OpenIddictBuilder AddTokenManager([NotNull] Type type) { + if (type == null) { + throw new ArgumentNullException(nameof(type)); + } + var contract = typeof(OpenIddictTokenManager<>).MakeGenericType(TokenType); - if (!contract.IsAssignableFrom(typeof(TManager))) { + if (!contract.IsAssignableFrom(type)) { throw new InvalidOperationException("Custom managers must be derived from OpenIddictTokenManager."); } - Services.AddScoped(contract, typeof(TManager)); + Services.AddScoped(contract, type); return this; } @@ -194,13 +278,25 @@ namespace Microsoft.AspNetCore.Builder { /// /// The type of the custom store. /// The . - public virtual OpenIddictBuilder AddTokenStore() { + public OpenIddictBuilder AddTokenStore() where TStore : class + => AddTokenStore(typeof(TStore)); + + /// + /// Adds a custom token store. + /// + /// The type of the custom store. + /// The . + public virtual OpenIddictBuilder AddTokenStore([NotNull] Type type) { + if (type == null) { + throw new ArgumentNullException(nameof(type)); + } + var contract = typeof(IOpenIddictTokenStore<>).MakeGenericType(TokenType); - if (!contract.IsAssignableFrom(typeof(TStore))) { + if (!contract.IsAssignableFrom(type)) { throw new InvalidOperationException("Custom stores must implement IOpenIddictTokenStore."); } - Services.AddScoped(contract, typeof(TStore)); + Services.AddScoped(contract, type); return this; } @@ -468,6 +564,10 @@ namespace Microsoft.AspNetCore.Builder { /// The relative path of the authorization endpoint. /// The . public virtual OpenIddictBuilder EnableAuthorizationEndpoint(PathString path) { + if (!path.HasValue) { + throw new ArgumentException("The path cannot be empty.", nameof(path)); + } + return Configure(options => options.AuthorizationEndpointPath = path); } @@ -477,6 +577,10 @@ namespace Microsoft.AspNetCore.Builder { /// The relative path of the logout endpoint. /// The . public virtual OpenIddictBuilder EnableIntrospectionEndpoint(PathString path) { + if (!path.HasValue) { + throw new ArgumentException("The path cannot be empty.", nameof(path)); + } + return Configure(options => options.IntrospectionEndpointPath = path); } @@ -486,6 +590,10 @@ namespace Microsoft.AspNetCore.Builder { /// The relative path of the logout endpoint. /// The . public virtual OpenIddictBuilder EnableLogoutEndpoint(PathString path) { + if (!path.HasValue) { + throw new ArgumentException("The path cannot be empty.", nameof(path)); + } + return Configure(options => options.LogoutEndpointPath = path); } @@ -495,6 +603,10 @@ namespace Microsoft.AspNetCore.Builder { /// The relative path of the revocation endpoint. /// The . public virtual OpenIddictBuilder EnableRevocationEndpoint(PathString path) { + if (!path.HasValue) { + throw new ArgumentException("The path cannot be empty.", nameof(path)); + } + return Configure(options => options.RevocationEndpointPath = path); } @@ -504,6 +616,10 @@ namespace Microsoft.AspNetCore.Builder { /// The relative path of the token endpoint. /// The . public virtual OpenIddictBuilder EnableTokenEndpoint(PathString path) { + if (!path.HasValue) { + throw new ArgumentException("The path cannot be empty.", nameof(path)); + } + return Configure(options => options.TokenEndpointPath = path); } @@ -513,6 +629,10 @@ namespace Microsoft.AspNetCore.Builder { /// The relative path of the userinfo endpoint. /// The . public virtual OpenIddictBuilder EnableUserinfoEndpoint(PathString path) { + if (!path.HasValue) { + throw new ArgumentException("The path cannot be empty.", nameof(path)); + } + return Configure(options => options.UserinfoEndpointPath = path); } diff --git a/test/OpenIddict.Core.Tests/OpenIddictBuilderTests.cs b/test/OpenIddict.Core.Tests/OpenIddictBuilderTests.cs new file mode 100644 index 00000000..49e309eb --- /dev/null +++ b/test/OpenIddict.Core.Tests/OpenIddictBuilderTests.cs @@ -0,0 +1,809 @@ +using System; +using System.IdentityModel.Tokens.Jwt; +using System.Reflection; +using AspNet.Security.OpenIdConnect.Extensions; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.DataProtection; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using Microsoft.IdentityModel.Tokens; +using Moq; +using Xunit; + +namespace OpenIddict.Core.Tests { + public class OpenIddictBuilderTests { + [Fact] + public void Configure_OptionsAreCorrectlyAmended() { + // Arrange + var services = new ServiceCollection(); + services.AddOptions(); + + var builder = new OpenIddictBuilder(services); + + // Act + builder.Configure(configuration => configuration.Description.DisplayName = "OpenIddict"); + + var provider = services.BuildServiceProvider(); + var options = provider.GetRequiredService>(); + + // Assert + Assert.Equal("OpenIddict", options.Value.Description.DisplayName); + } + + [Fact] + public void AddApplicationManager_ThrowsAnExceptionForInvalidManager() { + // Arrange + var services = new ServiceCollection(); + services.AddOptions(); + + var builder = new OpenIddictBuilder(services); + builder.ApplicationType = typeof(object); + + // Act and assert + var exception = Assert.Throws(() => builder.AddApplicationManager(typeof(object))); + + Assert.Equal("Custom managers must be derived from OpenIddictApplicationManager.", exception.Message); + } + + [Fact] + public void AddApplicationManager_OverridesDefaultManager() { + // Arrange + var services = new ServiceCollection(); + services.AddOptions(); + + var builder = new OpenIddictBuilder(services); + builder.ApplicationType = typeof(object); + + var type = new Mock>( + Mock.Of(), + Mock.Of>(), + Mock.Of>>()).Object.GetType(); + + // Act + builder.AddApplicationManager(type); + + var provider = services.BuildServiceProvider(); + var manager = provider.GetRequiredService>(); + + // Assert + Assert.IsType(type, manager); + } + + [Fact] + public void AddApplicationStore_ThrowsAnExceptionForInvalidStore() { + // Arrange + var services = new ServiceCollection(); + services.AddOptions(); + + var builder = new OpenIddictBuilder(services); + builder.ApplicationType = typeof(object); + + // Act and assert + var exception = Assert.Throws(() => builder.AddApplicationStore(typeof(object))); + + Assert.Equal("Custom stores must implement IOpenIddictApplicationStore.", exception.Message); + } + + [Fact] + public void AddApplicationStore_OverridesDefaultManager() { + // Arrange + var services = new ServiceCollection(); + services.AddOptions(); + + var builder = new OpenIddictBuilder(services); + builder.ApplicationType = typeof(object); + + var type = Mock.Of>().GetType(); + + // Act + builder.AddApplicationStore(type); + + var provider = services.BuildServiceProvider(); + var store = provider.GetRequiredService>(); + + // Assert + Assert.IsType(type, store); + } + + [Fact] + public void AddAuthorizationManager_ThrowsAnExceptionForInvalidManager() { + // Arrange + var services = new ServiceCollection(); + services.AddOptions(); + + var builder = new OpenIddictBuilder(services); + builder.AuthorizationType = typeof(object); + + // Act and assert + var exception = Assert.Throws(() => builder.AddAuthorizationManager(typeof(object))); + + Assert.Equal("Custom managers must be derived from OpenIddictAuthorizationManager.", exception.Message); + } + + [Fact] + public void AddAuthorizationManager_OverridesDefaultManager() { + // Arrange + var services = new ServiceCollection(); + services.AddOptions(); + + var builder = new OpenIddictBuilder(services); + builder.AuthorizationType = typeof(object); + + var type = new Mock>( + Mock.Of(), + Mock.Of>(), + Mock.Of>>()).Object.GetType(); + + // Act + builder.AddAuthorizationManager(type); + + var provider = services.BuildServiceProvider(); + var manager = provider.GetRequiredService>(); + + // Assert + Assert.IsType(type, manager); + } + + [Fact] + public void AddAuthorizationStore_ThrowsAnExceptionForInvalidStore() { + // Arrange + var services = new ServiceCollection(); + services.AddOptions(); + + var builder = new OpenIddictBuilder(services); + builder.AuthorizationType = typeof(object); + + // Act and assert + var exception = Assert.Throws(() => builder.AddAuthorizationStore(typeof(object))); + + Assert.Equal("Custom stores must implement IOpenIddictAuthorizationStore.", exception.Message); + } + + [Fact] + public void AddAuthorizationStore_OverridesDefaultManager() { + // Arrange + var services = new ServiceCollection(); + services.AddOptions(); + + var builder = new OpenIddictBuilder(services); + builder.AuthorizationType = typeof(object); + + var type = Mock.Of>().GetType(); + + // Act + builder.AddAuthorizationStore(type); + + var provider = services.BuildServiceProvider(); + var store = provider.GetRequiredService>(); + + // Assert + Assert.IsType(type, store); + } + + [Fact] + public void AddScopeManager_ThrowsAnExceptionForInvalidManager() { + // Arrange + var services = new ServiceCollection(); + services.AddOptions(); + + var builder = new OpenIddictBuilder(services); + builder.ScopeType = typeof(object); + + // Act and assert + var exception = Assert.Throws(() => builder.AddScopeManager(typeof(object))); + + Assert.Equal("Custom managers must be derived from OpenIddictScopeManager.", exception.Message); + } + + [Fact] + public void AddScopeManager_OverridesDefaultManager() { + // Arrange + var services = new ServiceCollection(); + services.AddOptions(); + + var builder = new OpenIddictBuilder(services); + builder.ScopeType = typeof(object); + + var type = new Mock>( + Mock.Of(), + Mock.Of>(), + Mock.Of>>()).Object.GetType(); + + // Act + builder.AddScopeManager(type); + + var provider = services.BuildServiceProvider(); + var manager = provider.GetRequiredService>(); + + // Assert + Assert.IsType(type, manager); + } + + [Fact] + public void AddScopeStore_ThrowsAnExceptionForInvalidStore() { + // Arrange + var services = new ServiceCollection(); + services.AddOptions(); + + var builder = new OpenIddictBuilder(services); + builder.ScopeType = typeof(object); + + // Act and assert + var exception = Assert.Throws(() => builder.AddScopeStore(typeof(object))); + + Assert.Equal("Custom stores must implement IOpenIddictScopeStore.", exception.Message); + } + + [Fact] + public void AddScopeStore_OverridesDefaultManager() { + // Arrange + var services = new ServiceCollection(); + services.AddOptions(); + + var builder = new OpenIddictBuilder(services); + builder.ScopeType = typeof(object); + + var type = Mock.Of>().GetType(); + + // Act + builder.AddScopeStore(type); + + var provider = services.BuildServiceProvider(); + var store = provider.GetRequiredService>(); + + // Assert + Assert.IsType(type, store); + } + + [Fact] + public void AddTokenManager_ThrowsAnExceptionForInvalidManager() { + // Arrange + var services = new ServiceCollection(); + services.AddOptions(); + + var builder = new OpenIddictBuilder(services); + builder.TokenType = typeof(object); + + // Act and assert + var exception = Assert.Throws(() => builder.AddTokenManager(typeof(object))); + + Assert.Equal("Custom managers must be derived from OpenIddictTokenManager.", exception.Message); + } + + [Fact] + public void AddTokenManager_OverridesDefaultManager() { + // Arrange + var services = new ServiceCollection(); + services.AddOptions(); + + var builder = new OpenIddictBuilder(services); + builder.TokenType = typeof(object); + + var type = new Mock>( + Mock.Of(), + Mock.Of>(), + Mock.Of>>()).Object.GetType(); + + // Act + builder.AddTokenManager(type); + + var provider = services.BuildServiceProvider(); + var manager = provider.GetRequiredService>(); + + // Assert + Assert.IsType(type, manager); + } + + [Fact] + public void AddTokenStore_ThrowsAnExceptionForInvalidStore() { + // Arrange + var services = new ServiceCollection(); + services.AddOptions(); + + var builder = new OpenIddictBuilder(services); + builder.TokenType = typeof(object); + + // Act and assert + var exception = Assert.Throws(() => builder.AddTokenStore(typeof(object))); + + Assert.Equal("Custom stores must implement IOpenIddictTokenStore.", exception.Message); + } + + [Fact] + public void AddTokenStore_OverridesDefaultManager() { + // Arrange + var services = new ServiceCollection(); + services.AddOptions(); + + var builder = new OpenIddictBuilder(services); + builder.TokenType = typeof(object); + + var type = Mock.Of>().GetType(); + + // Act + builder.AddTokenStore(type); + + var provider = services.BuildServiceProvider(); + var store = provider.GetRequiredService>(); + + // Assert + Assert.IsType(type, store); + } + + [Fact] + public void AddEphemeralSigningKey_SigningKeyIsCorrectlyAdded() { + // Arrange + var services = new ServiceCollection(); + services.AddOptions(); + + var builder = new OpenIddictBuilder(services); + + // Act + builder.AddEphemeralSigningKey(); + + var provider = services.BuildServiceProvider(); + var options = provider.GetRequiredService>(); + + // Assert + Assert.Equal(1, options.Value.SigningCredentials.Count); + } + + [Theory] + [InlineData(SecurityAlgorithms.RsaSha256Signature)] + [InlineData(SecurityAlgorithms.RsaSha384Signature)] + [InlineData(SecurityAlgorithms.RsaSha512Signature)] +#if SUPPORTS_ECDSA + [InlineData(SecurityAlgorithms.EcdsaSha256Signature)] + [InlineData(SecurityAlgorithms.EcdsaSha384Signature)] + [InlineData(SecurityAlgorithms.EcdsaSha512Signature)] +#endif + public void AddEphemeralSigningKey_SigningCredentialsUseSpecifiedAlgorithm(string algorithm) { + // Arrange + var services = new ServiceCollection(); + services.AddOptions(); + + var builder = new OpenIddictBuilder(services); + + // Act + builder.AddEphemeralSigningKey(algorithm); + + var provider = services.BuildServiceProvider(); + var options = provider.GetRequiredService>(); + var credentials = options.Value.SigningCredentials[0]; + + // Assert + Assert.Equal(algorithm, credentials.Algorithm); + } + + [Theory] + [InlineData(SecurityAlgorithms.HmacSha256Signature)] + [InlineData(SecurityAlgorithms.RsaSha256Signature)] +#if SUPPORTS_ECDSA + [InlineData(SecurityAlgorithms.EcdsaSha256Signature)] + [InlineData(SecurityAlgorithms.EcdsaSha384Signature)] + [InlineData(SecurityAlgorithms.EcdsaSha512Signature)] +#endif + public void AddSigningKey_SigningKeyIsCorrectlyAdded(string algorithm) { + // Arrange + var services = new ServiceCollection(); + services.AddOptions(); + + var builder = new OpenIddictBuilder(services); + + var factory = Mock.Of(mock => + mock.IsSupportedAlgorithm(algorithm, It.IsAny())); + + var key = Mock.Of(mock => mock.CryptoProviderFactory == factory); + + // Act + builder.AddSigningKey(key); + + var provider = services.BuildServiceProvider(); + var options = provider.GetRequiredService>(); + + // Assert + Assert.Same(key, options.Value.SigningCredentials[0].Key); + } + + [Fact] + public void AddSigningCertificate_SigningKeyIsCorrectlyAdded() { + // Arrange + var services = new ServiceCollection(); + services.AddOptions(); + + var builder = new OpenIddictBuilder(services); + + // Act + builder.AddSigningCertificate( + assembly: typeof(OpenIddictBuilderTests).GetTypeInfo().Assembly, + resource: "OpenIddict.Core.Tests.Certificate.pfx", + password: "OpenIddict"); + + var provider = services.BuildServiceProvider(); + var options = provider.GetRequiredService>(); + + // Assert + Assert.IsType(typeof(X509SecurityKey), options.Value.SigningCredentials[0].Key); + } + + [Fact] + public void AllowAuthorizationCodeFlow_CodeFlowIsAddedToGrantTypes() { + // Arrange + var services = new ServiceCollection(); + services.AddOptions(); + + var builder = new OpenIddictBuilder(services); + + // Act + builder.AllowAuthorizationCodeFlow(); + + var provider = services.BuildServiceProvider(); + var options = provider.GetRequiredService>(); + + // Assert + Assert.Contains(OpenIdConnectConstants.GrantTypes.AuthorizationCode, options.Value.GrantTypes); + } + + [Fact] + public void AllowClientCredentialsFlow_ClientCredentialsFlowIsAddedToGrantTypes() { + // Arrange + var services = new ServiceCollection(); + services.AddOptions(); + + var builder = new OpenIddictBuilder(services); + + // Act + builder.AllowClientCredentialsFlow(); + + var provider = services.BuildServiceProvider(); + var options = provider.GetRequiredService>(); + + // Assert + Assert.Contains(OpenIdConnectConstants.GrantTypes.ClientCredentials, options.Value.GrantTypes); + } + + [Fact] + public void AllowCustomFlow_CustomFlowIsAddedToGrantTypes() { + // Arrange + var services = new ServiceCollection(); + services.AddOptions(); + + var builder = new OpenIddictBuilder(services); + + // Act + builder.AllowCustomFlow("urn:ietf:params:oauth:grant-type:custom_grant"); + + var provider = services.BuildServiceProvider(); + var options = provider.GetRequiredService>(); + + // Assert + Assert.Contains("urn:ietf:params:oauth:grant-type:custom_grant", options.Value.GrantTypes); + } + + [Fact] + public void AllowImplicitFlow_ImplicitFlowIsAddedToGrantTypes() { + // Arrange + var services = new ServiceCollection(); + services.AddOptions(); + + var builder = new OpenIddictBuilder(services); + + // Act + builder.AllowImplicitFlow(); + + var provider = services.BuildServiceProvider(); + var options = provider.GetRequiredService>(); + + // Assert + Assert.Contains(OpenIdConnectConstants.GrantTypes.Implicit, options.Value.GrantTypes); + } + + [Fact] + public void AllowPasswordFlow_PasswordFlowIsAddedToGrantTypes() { + // Arrange + var services = new ServiceCollection(); + services.AddOptions(); + + var builder = new OpenIddictBuilder(services); + + // Act + builder.AllowPasswordFlow(); + + var provider = services.BuildServiceProvider(); + var options = provider.GetRequiredService>(); + + // Assert + Assert.Contains(OpenIdConnectConstants.GrantTypes.Password, options.Value.GrantTypes); + } + + [Fact] + public void AllowRefreshTokenFlow_RefreshTokenFlowIsAddedToGrantTypes() { + // Arrange + var services = new ServiceCollection(); + services.AddOptions(); + + var builder = new OpenIddictBuilder(services); + + // Act + builder.AllowRefreshTokenFlow(); + + var provider = services.BuildServiceProvider(); + var options = provider.GetRequiredService>(); + + // Assert + Assert.Contains(OpenIdConnectConstants.GrantTypes.RefreshToken, options.Value.GrantTypes); + } + + [Fact] + public void DisableConfigurationEndpoint_ConfigurationEndpointIsDisabled() { + // Arrange + var services = new ServiceCollection(); + services.AddOptions(); + + var builder = new OpenIddictBuilder(services); + + // Act + builder.DisableConfigurationEndpoint(); + + var provider = services.BuildServiceProvider(); + var options = provider.GetRequiredService>(); + + // Assert + Assert.Equal(PathString.Empty, options.Value.ConfigurationEndpointPath); + } + + [Fact] + public void DisableCryptographyEndpoint_CryptographyEndpointIsDisabled() { + // Arrange + var services = new ServiceCollection(); + services.AddOptions(); + + var builder = new OpenIddictBuilder(services); + + // Act + builder.DisableCryptographyEndpoint(); + + var provider = services.BuildServiceProvider(); + var options = provider.GetRequiredService>(); + + // Assert + Assert.Equal(PathString.Empty, options.Value.CryptographyEndpointPath); + } + + [Fact] + public void EnableAuthorizationEndpoint_AuthorizationEndpointIsEnabled() { + // Arrange + var services = new ServiceCollection(); + services.AddOptions(); + + var builder = new OpenIddictBuilder(services); + + // Act + builder.EnableAuthorizationEndpoint("/endpoint-path"); + + var provider = services.BuildServiceProvider(); + var options = provider.GetRequiredService>(); + + // Assert + Assert.Equal("/endpoint-path", options.Value.AuthorizationEndpointPath); + } + + [Fact] + public void EnableIntrospectionEndpoint_IntrospectionEndpointIsEnabled() { + // Arrange + var services = new ServiceCollection(); + services.AddOptions(); + + var builder = new OpenIddictBuilder(services); + + // Act + builder.EnableIntrospectionEndpoint("/endpoint-path"); + + var provider = services.BuildServiceProvider(); + var options = provider.GetRequiredService>(); + + // Assert + Assert.Equal("/endpoint-path", options.Value.IntrospectionEndpointPath); + } + + [Fact] + public void EnableLogoutEndpoint_LogoutEndpointIsEnabled() { + // Arrange + var services = new ServiceCollection(); + services.AddOptions(); + + var builder = new OpenIddictBuilder(services); + + // Act + builder.EnableLogoutEndpoint("/endpoint-path"); + + var provider = services.BuildServiceProvider(); + var options = provider.GetRequiredService>(); + + // Assert + Assert.Equal("/endpoint-path", options.Value.LogoutEndpointPath); + } + + [Fact] + public void EnableRevocationEndpoint_RevocationEndpointIsEnabled() { + // Arrange + var services = new ServiceCollection(); + services.AddOptions(); + + var builder = new OpenIddictBuilder(services); + + // Act + builder.EnableRevocationEndpoint("/endpoint-path"); + + var provider = services.BuildServiceProvider(); + var options = provider.GetRequiredService>(); + + // Assert + Assert.Equal("/endpoint-path", options.Value.RevocationEndpointPath); + } + + [Fact] + public void EnableTokenEndpoint_TokenEndpointIsEnabled() { + // Arrange + var services = new ServiceCollection(); + services.AddOptions(); + + var builder = new OpenIddictBuilder(services); + + // Act + builder.EnableTokenEndpoint("/endpoint-path"); + + var provider = services.BuildServiceProvider(); + var options = provider.GetRequiredService>(); + + // Assert + Assert.Equal("/endpoint-path", options.Value.TokenEndpointPath); + } + + [Fact] + public void EnableUserinfoEndpoint_UserinfoEndpointIsEnabled() { + // Arrange + var services = new ServiceCollection(); + services.AddOptions(); + + var builder = new OpenIddictBuilder(services); + + // Act + builder.EnableUserinfoEndpoint("/endpoint-path"); + + var provider = services.BuildServiceProvider(); + var options = provider.GetRequiredService>(); + + // Assert + Assert.Equal("/endpoint-path", options.Value.UserinfoEndpointPath); + } + + [Fact] + public void RequireClientIdentification_ClientIdentificationIsEnforced() { + // Arrange + var services = new ServiceCollection(); + services.AddOptions(); + + var builder = new OpenIddictBuilder(services); + + // Act + builder.RequireClientIdentification(); + + var provider = services.BuildServiceProvider(); + var options = provider.GetRequiredService>(); + + // Assert + Assert.True(options.Value.RequireClientIdentification); + } + + [Fact] + public void SetAccessTokenLifetime_DefaultAccessTokenLifetimeIsReplaced() { + // Arrange + var services = new ServiceCollection(); + services.AddOptions(); + + var builder = new OpenIddictBuilder(services); + + // Act + builder.SetAccessTokenLifetime(TimeSpan.FromMinutes(42)); + + var provider = services.BuildServiceProvider(); + var options = provider.GetRequiredService>(); + + // Assert + Assert.Equal(TimeSpan.FromMinutes(42), options.Value.AccessTokenLifetime); + } + + [Fact] + public void SetAuthorizationCodeLifetime_DefaultAuthorizationCodeLifetimeIsReplaced() { + // Arrange + var services = new ServiceCollection(); + services.AddOptions(); + + var builder = new OpenIddictBuilder(services); + + // Act + builder.SetAuthorizationCodeLifetime(TimeSpan.FromMinutes(42)); + + var provider = services.BuildServiceProvider(); + var options = provider.GetRequiredService>(); + + // Assert + Assert.Equal(TimeSpan.FromMinutes(42), options.Value.AuthorizationCodeLifetime); + } + + [Fact] + public void SetIdentityTokenLifetime_DefaultIdentityTokenLifetimeIsReplaced() { + // Arrange + var services = new ServiceCollection(); + services.AddOptions(); + + var builder = new OpenIddictBuilder(services); + + // Act + builder.SetIdentityTokenLifetime(TimeSpan.FromMinutes(42)); + + var provider = services.BuildServiceProvider(); + var options = provider.GetRequiredService>(); + + // Assert + Assert.Equal(TimeSpan.FromMinutes(42), options.Value.IdentityTokenLifetime); + } + + [Fact] + public void SetRefreshTokenLifetime_DefaultRefreshTokenLifetimeIsReplaced() { + // Arrange + var services = new ServiceCollection(); + services.AddOptions(); + + var builder = new OpenIddictBuilder(services); + + // Act + builder.SetRefreshTokenLifetime(TimeSpan.FromMinutes(42)); + + var provider = services.BuildServiceProvider(); + var options = provider.GetRequiredService>(); + + // Assert + Assert.Equal(TimeSpan.FromMinutes(42), options.Value.RefreshTokenLifetime); + } + + [Fact] + public void UseDataProtectionProvider_DefaultProviderIsReplaced() { + // Arrange + var services = new ServiceCollection(); + services.AddOptions(); + + var builder = new OpenIddictBuilder(services); + + // Act + builder.UseDataProtectionProvider(new EphemeralDataProtectionProvider()); + + var provider = services.BuildServiceProvider(); + var options = provider.GetRequiredService>(); + + // Assert + Assert.IsType(typeof(EphemeralDataProtectionProvider), options.Value.DataProtectionProvider); + } + + [Fact] + public void UseJsonWebTokens_AccessTokenHandlerIsCorrectlySet() { + // Arrange + var services = new ServiceCollection(); + services.AddOptions(); + + var builder = new OpenIddictBuilder(services); + + // Act + builder.UseJsonWebTokens(); + + var provider = services.BuildServiceProvider(); + var options = provider.GetRequiredService>(); + + // Assert + Assert.IsType(typeof(JwtSecurityTokenHandler), options.Value.AccessTokenHandler); + } + } +} diff --git a/test/OpenIddict.Core.Tests/project.json b/test/OpenIddict.Core.Tests/project.json index 7fcc2490..2748ca54 100644 --- a/test/OpenIddict.Core.Tests/project.json +++ b/test/OpenIddict.Core.Tests/project.json @@ -20,6 +20,10 @@ "frameworks": { "netcoreapp1.0": { + "buildOptions": { + "define": [ "SUPPORTS_ECDSA" ] + }, + "dependencies": { "Microsoft.NETCore.App": { "type": "platform", "version": "1.0.0" } },