diff --git a/OpenIddict.sln b/OpenIddict.sln
index c491c42c..04bc4413 100644
--- a/OpenIddict.sln
+++ b/OpenIddict.sln
@@ -101,6 +101,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenIddict.Server.AspNetCor
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenIddict.Server.Owin.IntegrationTests", "test\OpenIddict.Server.Owin.IntegrationTests\OpenIddict.Server.Owin.IntegrationTests.csproj", "{E62124D4-3660-4590-B4D1-787168BBBEDD}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenIddict.Server.Tests", "test\OpenIddict.Server.Tests\OpenIddict.Server.Tests.csproj", "{D94B10D3-3DD3-4829-B305-17C48833AB33}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -235,6 +237,10 @@ Global
{E62124D4-3660-4590-B4D1-787168BBBEDD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E62124D4-3660-4590-B4D1-787168BBBEDD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E62124D4-3660-4590-B4D1-787168BBBEDD}.Release|Any CPU.Build.0 = Release|Any CPU
+ {D94B10D3-3DD3-4829-B305-17C48833AB33}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {D94B10D3-3DD3-4829-B305-17C48833AB33}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {D94B10D3-3DD3-4829-B305-17C48833AB33}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {D94B10D3-3DD3-4829-B305-17C48833AB33}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -272,6 +278,7 @@ Global
{0947C388-31DD-45C0-8DD2-61582C648F07} = {5FC71D6A-A994-4F62-977F-88A7D25379D7}
{FBFDB9E2-4A44-4B90-B896-E094BFC05C03} = {5FC71D6A-A994-4F62-977F-88A7D25379D7}
{E62124D4-3660-4590-B4D1-787168BBBEDD} = {5FC71D6A-A994-4F62-977F-88A7D25379D7}
+ {D94B10D3-3DD3-4829-B305-17C48833AB33} = {5FC71D6A-A994-4F62-977F-88A7D25379D7}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {A710059F-0466-4D48-9B3A-0EF4F840B616}
diff --git a/test/OpenIddict.Server.Tests/Certificate.pfx b/test/OpenIddict.Server.Tests/Certificate.pfx
new file mode 100644
index 00000000..8c05f9d4
Binary files /dev/null and b/test/OpenIddict.Server.Tests/Certificate.pfx differ
diff --git a/test/OpenIddict.Server.Tests/OpenIddict.Server.Tests.csproj b/test/OpenIddict.Server.Tests/OpenIddict.Server.Tests.csproj
new file mode 100644
index 00000000..89a37682
--- /dev/null
+++ b/test/OpenIddict.Server.Tests/OpenIddict.Server.Tests.csproj
@@ -0,0 +1,31 @@
+
+
+
+ net461;net472;netcoreapp2.1;netcoreapp3.1
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ $(DefineConstants);SUPPORTS_ECDSA
+ $(DefineConstants);SUPPORTS_CERTIFICATE_GENERATION
+
+
+
diff --git a/test/OpenIddict.Server.Tests/OpenIddictServerBuilderTests.cs b/test/OpenIddict.Server.Tests/OpenIddictServerBuilderTests.cs
new file mode 100644
index 00000000..b2b0369c
--- /dev/null
+++ b/test/OpenIddict.Server.Tests/OpenIddictServerBuilderTests.cs
@@ -0,0 +1,1838 @@
+using System;
+using System.Linq;
+using System.Reflection;
+using System.Security.Cryptography.X509Certificates;
+using System.Threading.Tasks;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Options;
+using Microsoft.IdentityModel.Tokens;
+using Moq;
+using OpenIddict.Abstractions;
+using Xunit;
+using static OpenIddict.Server.OpenIddictServerEvents;
+
+namespace OpenIddict.Server.Tests
+{
+ public class OpenIddictServerBuilderTests
+ {
+ [Fact]
+ public void Constructor_ThrowsAnExceptionForNullServices()
+ {
+ // Arrange
+ var services = (IServiceCollection)null;
+
+ // Act and assert
+ var exception = Assert.Throws(() => new OpenIddictServerBuilder(services));
+
+ Assert.Equal("services", exception.ParamName);
+ }
+
+ [Fact]
+ public void AddEventHandler_ThrowsAnExceptionWhenConfigurationIsNull()
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+ Action> configuration = null;
+
+ // Act & Assert
+ var exception = Assert.Throws(() => builder.AddEventHandler(configuration));
+ Assert.Equal(nameof(configuration), exception.ParamName);
+ }
+
+ [Fact]
+ public void AddEventHandler_ThrowsAnExceptionWhenDescriptorIsNull()
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+ OpenIddictServerHandlerDescriptor descriptor = null;
+
+ // Act & Assert
+ var exception = Assert.Throws(() => builder.AddEventHandler(descriptor));
+ Assert.Equal(nameof(descriptor), exception.ParamName);
+ }
+
+ [Fact]
+ public void AddEventHandler_HandlerIsAttached()
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+
+ // Act
+ builder.AddEventHandler(x =>
+ {
+ x.UseSingletonHandler();
+ });
+
+ // Assert
+ Assert.Contains(services, service => service.ServiceType == typeof(CustomHandler));
+ }
+
+ [Fact]
+ public void AddEventHandler_HandlerInstanceIsRegistered()
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+
+ // Act
+ builder.AddEventHandler(x =>
+ {
+ x.UseSingletonHandler(new CustomHandler());
+ });
+
+ // Assert
+ Assert.Contains(services, service =>
+ service.ServiceType == typeof(CustomHandler) &&
+ service.ImplementationInstance?.GetType() == typeof(CustomHandler) &&
+ service.Lifetime == ServiceLifetime.Singleton);
+ }
+
+ [Fact]
+ public void AddEventHandler_SingletonHandlerIsRegisteredAsASingleton()
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+
+ // Act
+ builder.AddEventHandler(x =>
+ {
+ x.UseSingletonHandler();
+ });
+
+ // Assert
+ Assert.Contains(services, service =>
+ service.ServiceType == typeof(CustomHandler) &&
+ service.Lifetime == ServiceLifetime.Singleton);
+ }
+
+ [Fact]
+ public void AddEventHandler_ScopedHandlerIsRegisteredAsScoped()
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+
+ // Act
+ builder.AddEventHandler(x =>
+ {
+ x.UseScopedHandler();
+ });
+
+ // Assert
+ Assert.Contains(services, service =>
+ service.ServiceType == typeof(CustomHandler) &&
+ service.Lifetime == ServiceLifetime.Scoped);
+ }
+
+ [Fact]
+ public void AddEncryptionCredentials_ThrowsExceptionWhenCredentialsAreNull()
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+ EncryptingCredentials credentials = null;
+
+ // Act & Assert
+ var exception = Assert.Throws(() => builder.AddEncryptionCredentials(credentials));
+ Assert.Equal(nameof(credentials), exception.ParamName);
+ }
+
+ [Fact]
+ public void AddEncryptionKey_ThrowsExceptionWhenKeyIsNull()
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+ SecurityKey key = null;
+
+ // Act & Assert
+ var exception = Assert.Throws(() => builder.AddEncryptionKey(key));
+ Assert.Equal(nameof(key), exception.ParamName);
+ }
+
+ [Fact]
+ public void AddEncryptionKey_ThrowsExceptionWhenAsymmetricKeyPrivateKeyIsMissing()
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+ var key = new Mock();
+ key.SetupGet(x => x.PrivateKeyStatus).Returns(PrivateKeyStatus.DoesNotExist);
+
+ // Act & Assert
+ var exception = Assert.Throws(() => builder.AddEncryptionKey(key.Object));
+ Assert.Equal("The asymmetric encryption key doesn't contain the required private key.", exception.Message);
+ }
+
+ [Fact]
+ public void RemoveEventHandler_ThrowsAnExceptionWhenDescriptorIsNull()
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+ OpenIddictServerHandlerDescriptor descriptor = null;
+
+ // Act & Assert
+ var exception = Assert.Throws(() => builder.RemoveEventHandler(descriptor));
+ Assert.Equal(nameof(descriptor), exception.ParamName);
+ }
+
+ [Fact]
+ public void RemoveEventHandler_RemovesService()
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+
+ OpenIddictServerHandlerDescriptor descriptor = OpenIddictServerHandlerDescriptor.CreateBuilder().UseSingletonHandler().Build();
+ builder.AddEventHandler(descriptor);
+
+ // Act
+ builder.RemoveEventHandler(descriptor);
+ var options = GetOptions(services);
+
+ // Assert
+ Assert.DoesNotContain(services, x => x.ServiceType == descriptor.ServiceDescriptor.ServiceType);
+ Assert.DoesNotContain(options.CustomHandlers, x => x.ServiceDescriptor.ServiceType == descriptor.ServiceDescriptor.ServiceType);
+ Assert.DoesNotContain(options.DefaultHandlers, x => x.ServiceDescriptor.ServiceType == descriptor.ServiceDescriptor.ServiceType);
+ }
+
+ [Fact]
+ public void Configure_OptionsAreCorrectlyAmended()
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+
+ // Act
+ builder.Configure(configuration => configuration.AccessTokenLifetime = TimeSpan.FromDays(1));
+
+ var options = GetOptions(services);
+
+ // Assert
+ Assert.Equal(TimeSpan.FromDays(1), options.AccessTokenLifetime);
+ }
+
+ [Fact]
+ public void Configure_ThrowsAnExceptionWhenConfigurationIsNull()
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+ Action configuration = null;
+
+ // Act & Assert
+ var exception = Assert.Throws(() => builder.Configure(configuration));
+ Assert.Equal(nameof(configuration), exception.ParamName);
+ }
+
+ [Fact]
+ public void AddDevelopmentSigningCertificate_ThrowsAnExceptionForNullSubject()
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+
+ // Act and assert
+ var exception = Assert.Throws(delegate
+ {
+ builder.AddDevelopmentSigningCertificate(subject: null);
+ });
+
+ Assert.Equal("subject", exception.ParamName);
+ }
+
+ [Fact]
+ public void AddDevelopmentEncryptionCertificate_ThrowsAnExceptionForNullSubject()
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+ X500DistinguishedName subject = null;
+
+ // Act & Assert
+ var exception = Assert.Throws(() => builder.AddDevelopmentEncryptionCertificate(subject));
+ Assert.Equal(nameof(subject), exception.ParamName);
+ }
+
+#if SUPPORTS_CERTIFICATE_GENERATION
+ [Fact]
+ public void AddDevelopmentSigningCertificate_CanGenerateCertificate()
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+
+ // Act
+ builder.AddDevelopmentSigningCertificate();
+
+ var options = GetOptions(services);
+
+ // Assert
+ Assert.Equal(1, options.SigningCredentials.Count);
+ Assert.Equal(SecurityAlgorithms.RsaSha256, options.SigningCredentials[0].Algorithm);
+ Assert.NotNull(options.SigningCredentials[0].Kid);
+ }
+#else
+ [Fact]
+ public void AddDevelopmentSigningCertificate_ThrowsAnExceptionOnUnsupportedPlatforms()
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+
+ // Act and assert
+ var exception = Assert.Throws(delegate
+ {
+ builder.AddDevelopmentSigningCertificate();
+ return GetOptions(services);
+ });
+
+ Assert.Equal("X.509 certificate generation is not supported on this platform.", exception.Message);
+ }
+#endif
+
+ [Fact]
+ public void AddEphemeralSigningKey_SigningKeyIsCorrectlyAdded()
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+
+ // Act
+ builder.AddEphemeralSigningKey();
+
+ var options = GetOptions(services);
+
+ // Assert
+ Assert.Equal(1, options.SigningCredentials.Count);
+ }
+
+ [Theory]
+ [InlineData(SecurityAlgorithms.RsaSha256)]
+ [InlineData(SecurityAlgorithms.RsaSha384)]
+ [InlineData(SecurityAlgorithms.RsaSha512)]
+#if SUPPORTS_ECDSA
+ [InlineData(SecurityAlgorithms.EcdsaSha256)]
+ [InlineData(SecurityAlgorithms.EcdsaSha384)]
+ [InlineData(SecurityAlgorithms.EcdsaSha512)]
+#endif
+ public void AddEphemeralSigningKey_SigningCredentialsUseSpecifiedAlgorithm(string algorithm)
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+
+ // Act
+ builder.AddEphemeralSigningKey(algorithm);
+
+ var options = GetOptions(services);
+ var credentials = options.SigningCredentials[0];
+
+ // Assert
+ Assert.Equal(algorithm, credentials.Algorithm);
+ }
+
+ //[Fact]
+ //public void AddEncryptingKey_EncryptingKeyIsCorrectlyAdded()
+ //{
+ // // Arrange
+ // var services = CreateServices();
+ // var builder = CreateBuilder(services);
+
+ // var factory = Mock.Of(mock =>
+ // mock.IsSupportedAlgorithm(SecurityAlgorithms.Aes256KW, It.IsAny()));
+
+ // var key = Mock.Of(mock => mock.CryptoProviderFactory == factory);
+
+ // // Act
+ // builder.AddEncryptingKey(key);
+
+ // var options = GetOptions(services);
+
+ // // Assert
+ // Assert.Same(key, options.EncryptingCredentials[0].Key);
+ //}
+
+ [Theory]
+ [InlineData(SecurityAlgorithms.HmacSha256)]
+ [InlineData(SecurityAlgorithms.RsaSha256)]
+#if SUPPORTS_ECDSA
+ [InlineData(SecurityAlgorithms.EcdsaSha256)]
+ [InlineData(SecurityAlgorithms.EcdsaSha384)]
+ [InlineData(SecurityAlgorithms.EcdsaSha512)]
+#endif
+ public void AddSigningKey_SigningKeyIsCorrectlyAdded(string algorithm)
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+
+ var factory = Mock.Of(mock =>
+ mock.IsSupportedAlgorithm(algorithm, It.IsAny()));
+
+ var key = Mock.Of(mock => mock.CryptoProviderFactory == factory);
+
+ // Act
+ builder.AddSigningKey(key);
+
+ var options = GetOptions(services);
+
+ // Assert
+ Assert.Same(key, options.SigningCredentials[0].Key);
+ }
+
+ [Fact]
+ public void AddSigningCertificate_SigningKeyIsCorrectlyAdded()
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+
+ // Act
+ builder.AddSigningCertificate(
+ assembly: typeof(OpenIddictServerBuilderTests).GetTypeInfo().Assembly,
+ resource: "OpenIddict.Server.Tests.Certificate.pfx",
+ password: "OpenIddict");
+
+ var options = GetOptions(services);
+
+ // Assert
+ Assert.IsType(options.SigningCredentials[0].Key);
+ }
+
+ [Fact]
+ public void AllowAuthorizationCodeFlow_CodeFlowIsAddedToGrantTypes()
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+
+ // Act
+ builder.AllowAuthorizationCodeFlow();
+
+ var options = GetOptions(services);
+
+ // Assert
+ Assert.Contains(OpenIddictConstants.GrantTypes.AuthorizationCode, options.GrantTypes);
+ }
+
+ [Fact]
+ public void AllowClientCredentialsFlow_ClientCredentialsFlowIsAddedToGrantTypes()
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+
+ // Act
+ builder.AllowClientCredentialsFlow();
+
+ var options = GetOptions(services);
+
+ // Assert
+ Assert.Contains(OpenIddictConstants.GrantTypes.ClientCredentials, options.GrantTypes);
+ }
+
+ [Fact]
+ public void AllowCustomFlow_CustomFlowIsAddedToGrantTypes()
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+
+ // Act
+ builder.AllowCustomFlow("urn:ietf:params:oauth:grant-type:custom_grant");
+
+ var options = GetOptions(services);
+
+ // Assert
+ Assert.Contains("urn:ietf:params:oauth:grant-type:custom_grant", options.GrantTypes);
+ }
+
+ [Theory]
+ [InlineData(null)]
+ [InlineData("")]
+ public void AllowCustomFlow_ThrowsAnExceptionForType(string type)
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+
+ // Act & Assert
+ var exception = Assert.Throws(() => builder.AllowCustomFlow(type));
+ Assert.Equal(nameof(type), exception.ParamName);
+ Assert.Contains("The grant type cannot be null or empty.", exception.Message);
+ }
+
+ [Fact]
+ public void AllowImplicitFlow_ImplicitFlowIsAddedToGrantTypes()
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+
+ // Act
+ builder.AllowImplicitFlow();
+
+ var options = GetOptions(services);
+
+ // Assert
+ Assert.Contains(OpenIddictConstants.GrantTypes.Implicit, options.GrantTypes);
+ }
+
+ [Fact]
+ public void AllowPasswordFlow_PasswordFlowIsAddedToGrantTypes()
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+
+ // Act
+ builder.AllowPasswordFlow();
+
+ var options = GetOptions(services);
+
+ // Assert
+ Assert.Contains(OpenIddictConstants.GrantTypes.Password, options.GrantTypes);
+ }
+
+ [Fact]
+ public void AllowRefreshTokenFlow_RefreshTokenFlowIsAddedToGrantTypes()
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+
+ // Act
+ builder.AllowRefreshTokenFlow();
+
+ var options = GetOptions(services);
+
+ // Assert
+ Assert.Contains(OpenIddictConstants.GrantTypes.RefreshToken, options.GrantTypes);
+ }
+
+ [Fact]
+ public void DisableAuthorizationStorage_AuthorizationStorageIsDisabled()
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+
+ // Act
+ builder.DisableAuthorizationStorage();
+
+ var options = GetOptions(services);
+
+ // Assert
+ Assert.True(options.DisableAuthorizationStorage);
+ }
+
+ [Fact]
+ public void SetConfigurationEndpointUris_ThrowsExceptionWhenAddressesIsNull()
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+ Uri[] addresses = null;
+
+ // Act & Assert
+ var exception = Assert.Throws(() => builder.SetConfigurationEndpointUris(addresses));
+ Assert.Equal(nameof(addresses), exception.ParamName);
+ }
+
+ [Fact]
+ public void SetConfigurationEndpointUris_Strings_ThrowsExceptionWhenAddressesIsNull()
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+ string[] addresses = null;
+
+ // Act & Assert
+ var exception = Assert.Throws(() => builder.SetConfigurationEndpointUris(addresses));
+ Assert.Equal(nameof(addresses), exception.ParamName);
+ }
+
+ public const string InvalidUriString = @"C:\";
+
+ [Theory]
+ [InlineData(InvalidUriString)]
+ public void SetConfigurationEndpointUris_ThrowsExceptionForUri(string uri)
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+ Uri[] addresses = { new Uri(uri), };
+
+ // Act & Assert
+ var exception = Assert.Throws(() => builder.SetConfigurationEndpointUris(addresses));
+ Assert.Equal(nameof(addresses), exception.ParamName);
+ Assert.Contains("One of the specified addresses is not valid.", exception.Message);
+ }
+
+ [Fact]
+ public void SetConfigurationEndpointUris_ClearsUris()
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+
+ // Act
+ builder.SetConfigurationEndpointUris(Array.Empty());
+
+ var options = GetOptions(services);
+
+ // Assert
+ Assert.Empty(options.ConfigurationEndpointUris);
+ }
+
+ [Fact]
+ public void SetConfigurationEndpointUris_AddsUri()
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+
+ // Act
+ builder.SetConfigurationEndpointUris("http://localhost/endpoint-path");
+
+ var options = GetOptions(services);
+
+ // Assert
+ Assert.Contains(new Uri("http://localhost/endpoint-path"), options.ConfigurationEndpointUris);
+ }
+
+ [Fact]
+ public void SetDeviceEndpointUris_ThrowsExceptionWhenAddressesIsNull()
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+ Uri[] addresses = null;
+
+ // Act & Assert
+ var exception = Assert.Throws(() => builder.SetDeviceEndpointUris(addresses));
+ Assert.Equal(nameof(addresses), exception.ParamName);
+ }
+
+ [Fact]
+ public void SetDeviceEndpointUris_Strings_ThrowsExceptionWhenAddressesIsNull()
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+ string[] addresses = null;
+
+ // Act & Assert
+ var exception = Assert.Throws(() => builder.SetDeviceEndpointUris(addresses));
+ Assert.Equal(nameof(addresses), exception.ParamName);
+ }
+
+ [Theory]
+ [InlineData(InvalidUriString)]
+ public void SetDeviceEndpointUris_ThrowsExceptionForUri(string uri)
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+ Uri[] addresses = { new Uri(uri), };
+
+ // Act & Assert
+ var exception = Assert.Throws(() => builder.SetDeviceEndpointUris(addresses));
+ Assert.Equal(nameof(addresses), exception.ParamName);
+ Assert.Contains("One of the specified addresses is not valid.", exception.Message);
+ }
+
+ [Fact]
+ public void SetDeviceEndpointUris_ClearsUris()
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+
+ // Act
+ builder.SetDeviceEndpointUris(Array.Empty());
+
+ var options = GetOptions(services);
+
+ // Assert
+ Assert.Empty(options.DeviceEndpointUris);
+ }
+
+ [Fact]
+ public void SetDeviceEndpointUris_AddsUri()
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+
+ // Act
+ builder.SetDeviceEndpointUris("http://localhost/endpoint-path");
+
+ var options = GetOptions(services);
+
+ // Assert
+ Assert.Contains(new Uri("http://localhost/endpoint-path"), options.DeviceEndpointUris);
+ }
+
+ [Fact]
+ public void AddDeviceCodeFlow_AddsDeviceCodeGrantType()
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+
+ // Act
+ builder.AllowDeviceCodeFlow();
+
+ var options = GetOptions(services);
+
+ // Assert
+ Assert.Contains(OpenIddictConstants.GrantTypes.DeviceCode, options.GrantTypes);
+ }
+
+ [Fact]
+ public void SetCryptographyEndpointUris_ThrowsExceptionWhenAddressesIsNull()
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+ Uri[] addresses = null;
+
+ // Act & Assert
+ var exception = Assert.Throws(() => builder.SetCryptographyEndpointUris(addresses));
+ Assert.Equal(nameof(addresses), exception.ParamName);
+ }
+
+ [Fact]
+ public void SetCryptographyEndpointUris_Strings_ThrowsExceptionWhenAddressesIsNull()
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+ string[] addresses = null;
+
+ // Act & Assert
+ var exception = Assert.Throws(() => builder.SetCryptographyEndpointUris(addresses));
+ Assert.Equal(nameof(addresses), exception.ParamName);
+ }
+
+ [Theory]
+ [InlineData(InvalidUriString)]
+ public void SetCryptographyEndpointUris_ThrowsExceptionForUri(string uri)
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+ Uri[] addresses = { new Uri(uri), };
+
+ // Act & Assert
+ var exception = Assert.Throws(() => builder.SetCryptographyEndpointUris(addresses));
+ Assert.Equal(nameof(addresses), exception.ParamName);
+ Assert.Contains("One of the specified addresses is not valid.", exception.Message);
+ }
+
+ [Fact]
+ public void SetCryptographyEndpointUris_ClearsUris()
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+
+ // Act
+ builder.SetCryptographyEndpointUris(Array.Empty());
+
+ var options = GetOptions(services);
+
+ // Assert
+ Assert.Empty(options.CryptographyEndpointUris);
+ }
+
+ [Fact]
+ public void SetCryptographyEndpointUris_AddsUri()
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+
+ // Act
+ builder.SetCryptographyEndpointUris("http://localhost/endpoint-path");
+
+ var options = GetOptions(services);
+
+ // Assert
+ Assert.Contains(new Uri("http://localhost/endpoint-path"), options.CryptographyEndpointUris);
+ }
+
+ [Fact]
+ public void DisableSlidingExpiration_SlidingExpirationIsDisabled()
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+
+ // Act
+ builder.DisableSlidingExpiration();
+
+ var options = GetOptions(services);
+
+ // Assert
+ Assert.False(options.UseSlidingExpiration);
+ }
+
+ [Fact]
+ public void DisableTokenStorage_TokenStorageIsDisabled()
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+
+ // Act
+ builder.DisableTokenStorage();
+
+ var options = GetOptions(services);
+
+ // Assert
+ Assert.True(options.DisableTokenStorage);
+ }
+
+ [Fact]
+ public void DisableAccessTokenEncryption_AccessTokenEncryptionIsDisabled()
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+
+ // Act
+ builder.DisableAccessTokenEncryption();
+
+ var options = GetOptions(services);
+
+ // Assert
+ Assert.True(options.DisableAccessTokenEncryption);
+ }
+
+ [Fact]
+ public void SetAuthorizationEndpointUris_ThrowsExceptionWhenAddressesIsNull()
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+ Uri[] addresses = null;
+
+ // Act & Assert
+ var exception = Assert.Throws(() => builder.SetAuthorizationEndpointUris(addresses));
+ Assert.Equal(nameof(addresses), exception.ParamName);
+ }
+
+ [Fact]
+ public void SetAuthorizationEndpointUris_Strings_ThrowsExceptionWhenAddressesIsNull()
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+ string[] addresses = null;
+
+ // Act & Assert
+ var exception = Assert.Throws(() => builder.SetAuthorizationEndpointUris(addresses));
+ Assert.Equal(nameof(addresses), exception.ParamName);
+ }
+
+ [Theory]
+ [InlineData(InvalidUriString)]
+ public void SetAuthorizationEndpointUris_ThrowsExceptionForUri(string uri)
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+ Uri[] addresses = { new Uri(uri), };
+
+ // Act & Assert
+ var exception = Assert.Throws(() => builder.SetAuthorizationEndpointUris(addresses));
+ Assert.Equal(nameof(addresses), exception.ParamName);
+ Assert.Contains("One of the specified addresses is not valid.", exception.Message);
+ }
+
+ [Fact]
+ public void SetAuthorizationEndpointUris_ClearsUris()
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+
+ // Act
+ builder.SetAuthorizationEndpointUris(Array.Empty());
+
+ var options = GetOptions(services);
+
+ // Assert
+ Assert.Empty(options.AuthorizationEndpointUris);
+ }
+
+ [Fact]
+ public void SetAuthorizationEndpointUris_AddsUri()
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+
+ // Act
+ builder.SetAuthorizationEndpointUris("http://localhost/endpoint-path");
+
+ var options = GetOptions(services);
+
+ // Assert
+ Assert.Contains(new Uri("http://localhost/endpoint-path"), options.AuthorizationEndpointUris);
+ }
+
+ [Fact]
+ public void SetIntrospectionEndpointUris_ThrowsExceptionWhenAddressesIsNull()
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+ Uri[] addresses = null;
+
+ // Act & Assert
+ var exception = Assert.Throws(() => builder.SetIntrospectionEndpointUris(addresses));
+ Assert.Equal(nameof(addresses), exception.ParamName);
+ }
+
+ [Fact]
+ public void SetIntrospectionEndpointUris_Strings_ThrowsExceptionWhenAddressesIsNull()
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+ string[] addresses = null;
+
+ // Act & Assert
+ var exception = Assert.Throws(() => builder.SetIntrospectionEndpointUris(addresses));
+ Assert.Equal(nameof(addresses), exception.ParamName);
+ }
+
+ [Theory]
+ [InlineData(InvalidUriString)]
+ public void SetIntrospectionEndpointUris_ThrowsExceptionForUri(string uri)
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+ Uri[] addresses = { new Uri(uri), };
+
+ // Act & Assert
+ var exception = Assert.Throws(() => builder.SetIntrospectionEndpointUris(addresses));
+ Assert.Equal(nameof(addresses), exception.ParamName);
+ Assert.Contains("One of the specified addresses is not valid.", exception.Message);
+ }
+
+ [Fact]
+ public void SetIntrospectionEndpointUris_ClearsUris()
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+
+ // Act
+ builder.SetIntrospectionEndpointUris(Array.Empty());
+
+ var options = GetOptions(services);
+
+ // Assert
+ Assert.Empty(options.IntrospectionEndpointUris);
+ }
+
+ [Fact]
+ public void SetIntrospectionEndpointUris_AddsUri()
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+
+ // Act
+ builder.SetIntrospectionEndpointUris("http://localhost/endpoint-path");
+
+ var options = GetOptions(services);
+
+ // Assert
+ Assert.Contains(new Uri("http://localhost/endpoint-path"), options.IntrospectionEndpointUris);
+ }
+
+ [Fact]
+ public void SetLogoutEndpointUris_ThrowsExceptionWhenAddressesIsNull()
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+ Uri[] addresses = null;
+
+ // Act & Assert
+ var exception = Assert.Throws(() => builder.SetLogoutEndpointUris(addresses));
+ Assert.Equal(nameof(addresses), exception.ParamName);
+ }
+
+ [Fact]
+ public void SetLogoutEndpointUris_Strings_ThrowsExceptionWhenAddressesIsNull()
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+ string[] addresses = null;
+
+ // Act & Assert
+ var exception = Assert.Throws(() => builder.SetLogoutEndpointUris(addresses));
+ Assert.Equal(nameof(addresses), exception.ParamName);
+ }
+
+ [Theory]
+ [InlineData(InvalidUriString)]
+ public void SetLogoutEndpointUris_ThrowsExceptionForUri(string uri)
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+ Uri[] addresses = { new Uri(uri), };
+
+ // Act & Assert
+ var exception = Assert.Throws(() => builder.SetLogoutEndpointUris(addresses));
+ Assert.Equal(nameof(addresses), exception.ParamName);
+ Assert.Contains("One of the specified addresses is not valid.", exception.Message);
+ }
+
+ [Fact]
+ public void SetLogoutEndpointUris_ClearsUris()
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+
+ // Act
+ builder.SetLogoutEndpointUris(Array.Empty());
+
+ var options = GetOptions(services);
+
+ // Assert
+ Assert.Empty(options.LogoutEndpointUris);
+ }
+
+ [Fact]
+ public void SetLogoutEndpointUris_AddsUri()
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+
+ // Act
+ builder.SetLogoutEndpointUris("http://localhost/endpoint-path");
+
+ var options = GetOptions(services);
+
+ // Assert
+ Assert.Contains(new Uri("http://localhost/endpoint-path"), options.LogoutEndpointUris);
+ }
+
+ //[Fact]
+ //public void EnableRequestCaching_RequestCachingIsEnabled()
+ //{
+ // // Arrange
+ // var services = CreateServices();
+ // var builder = CreateBuilder(services);
+
+ // // Act
+ // builder.EnableRequestCaching();
+
+ // var options = GetOptions(services);
+
+ // // Assert
+ // Assert.True(options.EnableRequestCaching);
+ //}
+
+ [Fact]
+ public void SetRevocationEndpointUris_ThrowsExceptionWhenAddressesIsNull()
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+ Uri[] addresses = null;
+
+ // Act & Assert
+ var exception = Assert.Throws(() => builder.SetRevocationEndpointUris(addresses));
+ Assert.Equal(nameof(addresses), exception.ParamName);
+ }
+
+ [Fact]
+ public void SetRevocationEndpointUris_Strings_ThrowsExceptionWhenAddressesIsNull()
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+ string[] addresses = null;
+
+ // Act & Assert
+ var exception = Assert.Throws(() => builder.SetRevocationEndpointUris(addresses));
+ Assert.Equal(nameof(addresses), exception.ParamName);
+ }
+
+ [Theory]
+ [InlineData(InvalidUriString)]
+ public void SetRevocationEndpointUris_ThrowsExceptionForUri(string uri)
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+ Uri[] addresses = { new Uri(uri), };
+
+ // Act & Assert
+ var exception = Assert.Throws(() => builder.SetRevocationEndpointUris(addresses));
+ Assert.Equal(nameof(addresses), exception.ParamName);
+ Assert.Contains("One of the specified addresses is not valid.", exception.Message);
+ }
+
+ [Fact]
+ public void SetRevocationEndpointUris_ClearsUris()
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+
+ // Act
+ builder.SetRevocationEndpointUris(Array.Empty());
+
+ var options = GetOptions(services);
+
+ // Assert
+ Assert.Empty(options.RevocationEndpointUris);
+ }
+
+ [Fact]
+ public void SetRevocationEndpointUris_AddsUri()
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+
+ // Act
+ builder.SetRevocationEndpointUris("http://localhost/endpoint-path");
+
+ var options = GetOptions(services);
+
+ // Assert
+ Assert.Contains(new Uri("http://localhost/endpoint-path"), options.RevocationEndpointUris);
+ }
+
+ [Fact]
+ public void DisableScopeValidation_ScopeValidationIsDisabled()
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+
+ // Act
+ builder.DisableScopeValidation();
+
+ var options = GetOptions(services);
+
+ // Assert
+ Assert.True(options.DisableScopeValidation);
+ }
+
+ [Fact]
+ public void SetTokenEndpointUris_ThrowsExceptionWhenAddressesIsNull()
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+ Uri[] addresses = null;
+
+ // Act & Assert
+ var exception = Assert.Throws(() => builder.SetTokenEndpointUris(addresses));
+ Assert.Equal(nameof(addresses), exception.ParamName);
+ }
+
+ [Fact]
+ public void SetTokenEndpointUris_Strings_ThrowsExceptionWhenAddressesIsNull()
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+ string[] addresses = null;
+
+ // Act & Assert
+ var exception = Assert.Throws(() => builder.SetTokenEndpointUris(addresses));
+ Assert.Equal(nameof(addresses), exception.ParamName);
+ }
+
+ [Theory]
+ [InlineData(InvalidUriString)]
+ public void SetTokenEndpointUris_ThrowsExceptionForUri(string uri)
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+ Uri[] addresses = { new Uri(uri), };
+
+ // Act & Assert
+ var exception = Assert.Throws(() => builder.SetTokenEndpointUris(addresses));
+ Assert.Equal(nameof(addresses), exception.ParamName);
+ Assert.Contains("One of the specified addresses is not valid.", exception.Message);
+ }
+
+ [Fact]
+ public void SetTokenEndpointUris_ClearsUris()
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+
+ // Act
+ builder.SetTokenEndpointUris(Array.Empty());
+
+ var options = GetOptions(services);
+
+ // Assert
+ Assert.Empty(options.TokenEndpointUris);
+ }
+
+ [Fact]
+ public void SetTokenEndpointUris_AddsUri()
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+
+ // Act
+ builder.SetTokenEndpointUris("http://localhost/endpoint-path");
+
+ var options = GetOptions(services);
+
+ // Assert
+ Assert.Contains(new Uri("http://localhost/endpoint-path"), options.TokenEndpointUris);
+ }
+
+ [Fact]
+ public void SetUserinfoEndpointUris_ThrowsExceptionWhenAddressesIsNull()
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+ Uri[] addresses = null;
+
+ // Act & Assert
+ var exception = Assert.Throws(() => builder.SetUserinfoEndpointUris(addresses));
+ Assert.Equal(nameof(addresses), exception.ParamName);
+ }
+
+ [Fact]
+ public void SetUserinfoEndpointUris_Strings_ThrowsExceptionWhenAddressesIsNull()
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+ string[] addresses = null;
+
+ // Act & Assert
+ var exception = Assert.Throws(() => builder.SetUserinfoEndpointUris(addresses));
+ Assert.Equal(nameof(addresses), exception.ParamName);
+ }
+
+ [Theory]
+ [InlineData(InvalidUriString)]
+ public void SetUserinfoEndpointUris_ThrowsExceptionForUri(string uri)
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+ Uri[] addresses = {new Uri(uri), };
+
+ // Act & Assert
+ var exception = Assert.Throws(() => builder.SetUserinfoEndpointUris(addresses));
+ Assert.Equal(nameof(addresses), exception.ParamName);
+ Assert.Contains("One of the specified addresses is not valid.", exception.Message);
+ }
+
+ [Fact]
+ public void SetUserinfoEndpointUris_ClearsUris()
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+
+ // Act
+ builder.SetUserinfoEndpointUris(Array.Empty());
+
+ var options = GetOptions(services);
+
+ // Assert
+ Assert.Empty(options.UserinfoEndpointUris);
+ }
+
+ [Fact]
+ public void SetUserinfoEndpointUris_AddsUri()
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+
+ // Act
+ builder.SetUserinfoEndpointUris("http://localhost/endpoint-path");
+
+ var options = GetOptions(services);
+
+ // Assert
+ Assert.Contains(new Uri("http://localhost/endpoint-path"), options.UserinfoEndpointUris);
+ }
+
+ [Fact]
+ public void AcceptAnonymousClients_ClientIdentificationIsOptional()
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+
+ // Act
+ builder.AcceptAnonymousClients();
+
+ var options = GetOptions(services);
+
+ // Assert
+ Assert.True(options.AcceptAnonymousClients);
+ }
+
+ [Fact]
+ public void SetAccessTokenLifetime_DefaultAccessTokenLifetimeIsReplaced()
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+
+ // Act
+ builder.SetAccessTokenLifetime(TimeSpan.FromMinutes(42));
+
+ var options = GetOptions(services);
+
+ // Assert
+ Assert.Equal(TimeSpan.FromMinutes(42), options.AccessTokenLifetime);
+ }
+
+ [Fact]
+ public void SetAccessTokenLifetime_AccessTokenLifetimeCanBeSetToNull()
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+
+ // Act
+ builder.SetAccessTokenLifetime(null);
+
+ var options = GetOptions(services);
+
+ // Assert
+ Assert.Null(options.AccessTokenLifetime);
+ }
+
+ [Fact]
+ public void SetAuthorizationCodeLifetime_DefaultAuthorizationCodeLifetimeIsReplaced()
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+
+ // Act
+ builder.SetAuthorizationCodeLifetime(TimeSpan.FromMinutes(42));
+
+ var options = GetOptions(services);
+
+ // Assert
+ Assert.Equal(TimeSpan.FromMinutes(42), options.AuthorizationCodeLifetime);
+ }
+
+ [Fact]
+ public void SetAuthorizationCodeLifetime_AuthorizationCodeLifetimeCanBeSetToNull()
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+
+ // Act
+ builder.SetAuthorizationCodeLifetime(null);
+
+ var options = GetOptions(services);
+
+ // Assert
+ Assert.Null(options.AuthorizationCodeLifetime);
+ }
+
+ [Fact]
+ public void SetIdentityTokenLifetime_DefaultIdentityTokenLifetimeIsReplaced()
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+
+ // Act
+ builder.SetIdentityTokenLifetime(TimeSpan.FromMinutes(42));
+
+ var options = GetOptions(services);
+
+ // Assert
+ Assert.Equal(TimeSpan.FromMinutes(42), options.IdentityTokenLifetime);
+ }
+
+ [Fact]
+ public void SetIdentityTokenLifetime_IdentityTokenLifetimeCanBeSetToNull()
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+
+ // Act
+ builder.SetIdentityTokenLifetime(null);
+
+ var options = GetOptions(services);
+
+ // Assert
+ Assert.Null(options.IdentityTokenLifetime);
+ }
+
+ [Fact]
+ public void SetDeviceCodeLifetimeLifetime_DefaultDeviceCodeLifetimeIsReplaced()
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+
+ // Act
+ builder.SetDeviceCodeLifetime(TimeSpan.FromMinutes(42));
+
+ var options = GetOptions(services);
+
+ // Assert
+ Assert.Equal(TimeSpan.FromMinutes(42), options.DeviceCodeLifetime);
+ }
+
+ [Fact]
+ public void SetDeviceCodeLifetimeLifetime_DeviceCodeLifetimeCanBeSetToNull()
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+
+ // Act
+ builder.SetDeviceCodeLifetime(null);
+
+ var options = GetOptions(services);
+
+ // Assert
+ Assert.Null(options.DeviceCodeLifetime);
+ }
+
+ [Fact]
+ public void SetUserCodeLifetime_DefaultUserCodeLifetimeIsReplaced()
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+
+ // Act
+ builder.SetUserCodeLifetime(TimeSpan.FromMinutes(42));
+
+ var options = GetOptions(services);
+
+ // Assert
+ Assert.Equal(TimeSpan.FromMinutes(42), options.UserCodeLifetime);
+ }
+
+ [Fact]
+ public void SetUserCodeLifetime_UserLifetimeCanBeSetToNull()
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+
+ // Act
+ builder.SetUserCodeLifetime(null);
+
+ var options = GetOptions(services);
+
+ // Assert
+ Assert.Null(options.UserCodeLifetime);
+ }
+
+ [Fact]
+ public void SetRefreshTokenLifetime_DefaultRefreshTokenLifetimeIsReplaced()
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+
+ // Act
+ builder.SetRefreshTokenLifetime(TimeSpan.FromMinutes(42));
+
+ var options = GetOptions(services);
+
+ // Assert
+ Assert.Equal(TimeSpan.FromMinutes(42), options.RefreshTokenLifetime);
+ }
+
+ [Fact]
+ public void SetRefreshTokenLifetime_RefreshTokenLifetimeCanBeSetToNull()
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+
+ // Act
+ builder.SetRefreshTokenLifetime(null);
+
+ var options = GetOptions(services);
+
+ // Assert
+ Assert.Null(options.RefreshTokenLifetime);
+ }
+
+ //[Fact]
+ //public void SetRequestCachingPolicy_ThrowsAnExceptionForNullPolicy()
+ //{
+ // // Arrange
+ // var services = CreateServices();
+ // var builder = CreateBuilder(services);
+
+ // // Act and assert
+ // var exception = Assert.Throws(() => builder.SetRequestCachingPolicy(null));
+
+ // Assert.Equal("policy", exception.ParamName);
+ //}
+
+ //[Fact]
+ //public void SetRequestCachingPolicy_PolicyIsUpdated()
+ //{
+ // // Arrange
+ // var services = CreateServices();
+ // var builder = CreateBuilder(services);
+
+ // var policy = new DistributedCacheEntryOptions
+ // {
+ // AbsoluteExpirationRelativeToNow = TimeSpan.FromDays(42),
+ // SlidingExpiration = TimeSpan.FromSeconds(42)
+ // };
+
+ // // Act
+ // builder.SetRequestCachingPolicy(policy);
+
+ // var options = GetOptions(services);
+
+ // // Assert
+ // Assert.Same(policy, options.RequestCachingPolicy);
+ //}
+
+ //[Fact]
+ //public void UseDataProtectionProvider_DefaultProviderIsReplaced()
+ //{
+ // // Arrange
+ // var services = CreateServices();
+ // var builder = CreateBuilder(services);
+
+ // // Act
+ // builder.UseDataProtectionProvider(new EphemeralDataProtectionProvider());
+
+ // var options = GetOptions(services);
+
+ // // Assert
+ // Assert.IsType(options.DataProtectionProvider);
+ //}
+
+ //[Fact]
+ //public void UseJsonWebTokens_AccessTokenHandlerIsCorrectlySet()
+ //{
+ // // Arrange
+ // var services = CreateServices();
+ // var builder = CreateBuilder(services);
+
+ // // Act
+ // builder.UseJsonWebTokens();
+
+ // var options = GetOptions(services);
+
+ // // Assert
+ // Assert.IsType(options.AccessTokenHandler);
+ //}
+
+ [Fact]
+ public void SetIssuer_ThrowsAnExceptionForNullIssuer()
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+
+ // Act and assert
+ var exception = Assert.Throws(() => builder.SetIssuer(null));
+
+ Assert.Equal("address", exception.ParamName);
+ }
+
+ [Fact]
+ public void SetIssuer_AddressIsReplaced()
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+
+ // Act
+ builder.SetIssuer(new Uri("http://www.fabrikam.com/"));
+
+ var options = GetOptions(services);
+
+ // Assert
+ Assert.Equal(new Uri("http://www.fabrikam.com/"), options.Issuer);
+ }
+
+ [Fact]
+ public void RegisterClaims_ClaimsAreAdded()
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+
+ // Act
+ builder.RegisterClaims("custom_claim_1", "custom_claim_2");
+
+ var options = GetOptions(services);
+
+ // Assert
+ Assert.Contains("custom_claim_1", options.Claims);
+ Assert.Contains("custom_claim_2", options.Claims);
+ }
+
+ [Fact]
+ public void RegisterClaims_ThrowsAnExceptionForNullClaims()
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+ string[] claims = null;
+
+ // Act & Assert
+ var exception = Assert.Throws(() => builder.RegisterClaims(claims));
+ Assert.Equal(nameof(claims), exception.ParamName);
+ }
+
+ [Theory]
+ [InlineData(null)]
+ [InlineData("")]
+ public void RegisterClaims_ThrowsAnExceptionForClaim(string claim)
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+ string[] claims = { claim };
+
+ // Act & Assert
+ var exception = Assert.Throws(() => builder.RegisterClaims(claims));
+ Assert.Equal(nameof(claims), exception.ParamName);
+ Assert.Contains("Claims cannot be null or empty.", exception.Message);
+ }
+
+ [Fact]
+ public void RegisterScopes_ScopesAreAdded()
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+
+ // Act
+ builder.RegisterScopes("custom_scope_1", "custom_scope_2");
+
+ var options = GetOptions(services);
+
+ // Assert
+ Assert.Contains("custom_scope_1", options.Scopes);
+ Assert.Contains("custom_scope_2", options.Scopes);
+ }
+
+ [Fact]
+ public void RegisterScopes_ThrowsAnExceptionForNullScopes()
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+ string[] scopes = null;
+
+ // Act & Assert
+ var exception = Assert.Throws(() => builder.RegisterScopes(scopes));
+ Assert.Equal(nameof(scopes), exception.ParamName);
+ }
+
+ [Theory]
+ [InlineData(null)]
+ [InlineData("")]
+ public void RegisterScopes_ThrowsAnExceptionForScope(string scope)
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+ string[] scopes = { scope };
+
+ // Act & Assert
+ var exception = Assert.Throws(() => builder.RegisterScopes(scopes));
+ Assert.Equal(nameof(scopes), exception.ParamName);
+ Assert.Contains("Scopes cannot be null or empty.", exception.Message);
+ }
+
+ [Fact]
+ public void UseReferenceTokens_ReferenceTokensAreEnabled()
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+
+ // Act
+ builder.UseReferenceTokens();
+
+ var options = GetOptions(services);
+
+ // Assert
+ Assert.True(options.UseReferenceTokens);
+ }
+
+ [Fact]
+ public void SetVerificationEndpointUris_ThrowsExceptionWhenNullAddresses()
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+ Uri[] addresses = null;
+
+ // Act & Assert
+ var exception = Assert.Throws(() => builder.SetVerificationEndpointUris(addresses));
+ Assert.Equal(nameof(addresses), exception.ParamName);
+ }
+
+ [Fact]
+ public void SetVerificationEndpointUris_Strings_ThrowsExceptionWhenNullAddresses()
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+ string[] addresses = null;
+
+ // Act & Assert
+ var exception = Assert.Throws(() => builder.SetVerificationEndpointUris(addresses));
+ Assert.Equal(nameof(addresses), exception.ParamName);
+ }
+
+ [Fact]
+ public void SetVerificationEndpointUris_Strings_AddedUriIsRelativeOrAbsoluteUriKind()
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+ string[] addresses = {"http://localhost/verify"};
+
+ // Act
+ builder.SetVerificationEndpointUris(addresses);
+
+ var options = GetOptions(services);
+
+ // Assert
+ Assert.True(options.VerificationEndpointUris[0].IsAbsoluteUri);
+ }
+
+ [Theory]
+ [InlineData(InvalidUriString)]
+ public void SetVerificationEndpointUris_ThrowsExceptionForUri(string uri)
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+ Uri[] addresses = { new Uri(uri)};
+
+ // Act & Assert
+ var exception = Assert.Throws(() => builder.SetVerificationEndpointUris(addresses));
+ Assert.Equal(nameof(addresses), exception.ParamName);
+ Assert.Contains("One of the specified addresses is not valid.", exception.Message);
+ }
+
+ [Fact]
+ public void SetVerificationEndpointUris_ClearsExistingUris()
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+ Uri[] addresses = Array.Empty();
+
+ // Act
+ builder.SetVerificationEndpointUris(addresses);
+
+ var options = GetOptions(services);
+
+ // Assert
+ Assert.Empty(options.VerificationEndpointUris);
+ }
+
+ [Theory]
+ [InlineData("http://localhost/verify")]
+ [InlineData("http://localhost/verify-1")]
+ [InlineData("http://localhost/verification")]
+ [InlineData("http://localhost/verification-1")]
+ public void SetVerificationEndpointUris_AddsUri(string uri)
+ {
+ // Arrange
+ var services = CreateServices();
+ var builder = CreateBuilder(services);
+ Uri[] addresses = { new Uri(uri), };
+
+ // Act
+ builder.SetVerificationEndpointUris(addresses);
+
+ var options = GetOptions(services);
+
+ // Assert
+ Assert.Contains(addresses[0], options.VerificationEndpointUris);
+ }
+
+ private static IServiceCollection CreateServices()
+ {
+ return new ServiceCollection().AddOptions();
+ }
+
+ private static OpenIddictServerBuilder CreateBuilder(IServiceCollection services)
+ => new OpenIddictServerBuilder(services);
+
+ private static OpenIddictServerOptions GetOptions(IServiceCollection services)
+ {
+ var provider = services.BuildServiceProvider();
+
+ var options = provider.GetRequiredService>();
+ //return options.Get(OpenIddictServerDefaults.AuthenticationScheme);
+ return options.Value;
+ }
+
+ private class CustomContext : BaseContext
+ {
+ ///
+ /// Creates a new instance of the class.
+ ///
+ public CustomContext(OpenIddictServerTransaction transaction) : base(transaction) { }
+ }
+
+ private class CustomHandler : IOpenIddictServerHandler
+ {
+ ///
+ /// Processes the event.
+ ///
+ /// The context associated with the event to process.
+ ///
+ /// A that can be used to monitor the asynchronous operation.
+ ///
+ public ValueTask HandleAsync(CustomContext context)
+ {
+ return new ValueTask();
+ }
+ }
+ }
+}
\ No newline at end of file