31 changed files with 5277 additions and 223 deletions
File diff suppressed because it is too large
@ -0,0 +1,471 @@ |
|||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Microsoft.IdentityModel.Protocols; |
||||
|
using Microsoft.IdentityModel.Tokens; |
||||
|
using Moq; |
||||
|
using Xunit; |
||||
|
|
||||
|
namespace OpenIddict.Client.Tests; |
||||
|
|
||||
|
public class OpenIddictClientConfigurationTests |
||||
|
{ |
||||
|
[Fact] |
||||
|
public void Constructor_ThrowsAnExceptionForNullProvider() |
||||
|
{ |
||||
|
// Arrange
|
||||
|
var provider = (IServiceProvider) null!; |
||||
|
|
||||
|
// Act and assert
|
||||
|
var exception = Assert.Throws<ArgumentNullException>(() => new OpenIddictClientConfiguration(provider)); |
||||
|
Assert.Equal("provider", exception.ParamName); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void PostConfigure_ThrowsAnExceptionForNullOptions() |
||||
|
{ |
||||
|
// Arrange
|
||||
|
var configuration = new OpenIddictClientConfiguration(new ServiceCollection().BuildServiceProvider()); |
||||
|
|
||||
|
// Act and assert
|
||||
|
var exception = Assert.Throws<ArgumentNullException>(() => configuration.PostConfigure(name: null, options: null!)); |
||||
|
Assert.Equal("options", exception.ParamName); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void PostConfigure_SetsTimeProviderToSystemWhenNotRegistered() |
||||
|
{ |
||||
|
// Arrange
|
||||
|
var configuration = new OpenIddictClientConfiguration(new ServiceCollection().BuildServiceProvider()); |
||||
|
var options = new OpenIddictClientOptions(); |
||||
|
|
||||
|
// Act
|
||||
|
configuration.PostConfigure(name: null, options); |
||||
|
|
||||
|
// Assert
|
||||
|
Assert.Same(TimeProvider.System, options.TimeProvider); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void PostConfigure_UsesRegisteredTimeProvider() |
||||
|
{ |
||||
|
// Arrange
|
||||
|
var timeProvider = new FakeTimeProvider(); |
||||
|
var services = new ServiceCollection(); |
||||
|
services.AddSingleton<TimeProvider>(timeProvider); |
||||
|
|
||||
|
var configuration = new OpenIddictClientConfiguration(services.BuildServiceProvider()); |
||||
|
var options = new OpenIddictClientOptions(); |
||||
|
|
||||
|
// Act
|
||||
|
configuration.PostConfigure(name: null, options); |
||||
|
|
||||
|
// Assert
|
||||
|
Assert.Same(timeProvider, options.TimeProvider); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void PostConfigure_DoesNotOverrideExplicitlySetTimeProvider() |
||||
|
{ |
||||
|
// Arrange
|
||||
|
var explicitProvider = new FakeTimeProvider(); |
||||
|
var registeredProvider = new FakeTimeProvider(); |
||||
|
|
||||
|
var services = new ServiceCollection(); |
||||
|
services.AddSingleton<TimeProvider>(registeredProvider); |
||||
|
|
||||
|
var configuration = new OpenIddictClientConfiguration(services.BuildServiceProvider()); |
||||
|
var options = new OpenIddictClientOptions { TimeProvider = explicitProvider }; |
||||
|
|
||||
|
// Act
|
||||
|
configuration.PostConfigure(name: null, options); |
||||
|
|
||||
|
// Assert
|
||||
|
Assert.Same(explicitProvider, options.TimeProvider); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void PostConfigure_ComputesDefaultRegistrationIdentifierAndClientType() |
||||
|
{ |
||||
|
// Arrange
|
||||
|
var configuration = new OpenIddictClientConfiguration(new ServiceCollection().BuildServiceProvider()); |
||||
|
|
||||
|
var registration = new OpenIddictClientRegistration |
||||
|
{ |
||||
|
Issuer = new Uri("https://www.contoso.com/"), |
||||
|
ClientSecret = "secret", |
||||
|
Configuration = new OpenIddictConfiguration() |
||||
|
}; |
||||
|
|
||||
|
var options = new OpenIddictClientOptions(); |
||||
|
options.Registrations.Add(registration); |
||||
|
|
||||
|
// Act
|
||||
|
configuration.PostConfigure(name: null, options); |
||||
|
|
||||
|
// Assert
|
||||
|
Assert.False(string.IsNullOrEmpty(registration.RegistrationId)); |
||||
|
Assert.Equal(ClientTypes.Confidential, registration.ClientType); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void PostConfigure_AssignsPublicClientTypeWhenNoSecretOrSigningCredentialsAreConfigured() |
||||
|
{ |
||||
|
// Arrange
|
||||
|
var configuration = new OpenIddictClientConfiguration(new ServiceCollection().BuildServiceProvider()); |
||||
|
|
||||
|
var registration = new OpenIddictClientRegistration |
||||
|
{ |
||||
|
Issuer = new Uri("https://www.contoso.com/"), |
||||
|
Configuration = new OpenIddictConfiguration() |
||||
|
}; |
||||
|
|
||||
|
var options = new OpenIddictClientOptions(); |
||||
|
options.Registrations.Add(registration); |
||||
|
|
||||
|
// Act
|
||||
|
configuration.PostConfigure(name: null, options); |
||||
|
|
||||
|
// Assert
|
||||
|
Assert.Equal(ClientTypes.Public, registration.ClientType); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void PostConfigure_AddsRedirectionUrisFromRegistrations() |
||||
|
{ |
||||
|
// Arrange
|
||||
|
var configuration = new OpenIddictClientConfiguration(new ServiceCollection().BuildServiceProvider()); |
||||
|
|
||||
|
var options = new OpenIddictClientOptions(); |
||||
|
options.Registrations.Add(new OpenIddictClientRegistration |
||||
|
{ |
||||
|
RedirectUri = new Uri("https://www.contoso.com/callback") |
||||
|
}); |
||||
|
|
||||
|
options.Registrations.Add(new OpenIddictClientRegistration |
||||
|
{ |
||||
|
PostLogoutRedirectUri = new Uri("https://www.contoso.com/logout-callback") |
||||
|
}); |
||||
|
|
||||
|
// Act
|
||||
|
configuration.PostConfigure(name: null, options); |
||||
|
|
||||
|
// Assert
|
||||
|
Assert.Contains(new Uri("https://www.contoso.com/callback"), options.RedirectionEndpointUris); |
||||
|
Assert.Contains(new Uri("https://www.contoso.com/logout-callback"), options.PostLogoutRedirectionEndpointUris); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Validate_ThrowsAnExceptionForNullOptions() |
||||
|
{ |
||||
|
// Arrange
|
||||
|
var configuration = new OpenIddictClientConfiguration(new ServiceCollection().BuildServiceProvider()); |
||||
|
|
||||
|
// Act and assert
|
||||
|
var exception = Assert.Throws<ArgumentNullException>(() => configuration.Validate(name: null, options: null!)); |
||||
|
Assert.Equal("options", exception.ParamName); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Validate_ReturnsAnErrorWhenJsonWebTokenHandlerIsMissing() |
||||
|
{ |
||||
|
// Arrange
|
||||
|
var configuration = new OpenIddictClientConfiguration(new ServiceCollection().BuildServiceProvider()); |
||||
|
var options = CreateBaseOptions(); |
||||
|
options.JsonWebTokenHandler = null!; |
||||
|
|
||||
|
// Act
|
||||
|
var result = configuration.Validate(name: null, options); |
||||
|
|
||||
|
// Assert
|
||||
|
Assert.Contains(SR.GetResourceString(SR.ID0075), result.Failures!); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Validate_ReturnsAnErrorWhenRegistrationIdentifierContainsSeparator() |
||||
|
{ |
||||
|
// Arrange
|
||||
|
var configuration = new OpenIddictClientConfiguration(new ServiceCollection().BuildServiceProvider()); |
||||
|
var options = CreateBaseOptions(); |
||||
|
|
||||
|
options.Registrations.Add(new OpenIddictClientRegistration |
||||
|
{ |
||||
|
RegistrationId = "invalid\u001eidentifier", |
||||
|
Issuer = new Uri("https://www.contoso.com/"), |
||||
|
ConfigurationManager = new StaticConfigurationManager<OpenIddictConfiguration>(new OpenIddictConfiguration()) |
||||
|
}); |
||||
|
|
||||
|
// Act
|
||||
|
var result = configuration.Validate(name: null, options); |
||||
|
|
||||
|
// Assert
|
||||
|
Assert.Contains(SR.GetResourceString(SR.ID0455), result.Failures!); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Validate_ReturnsAnErrorWhenRegistrationIdentifierIsMissing() |
||||
|
{ |
||||
|
// Arrange
|
||||
|
var configuration = new OpenIddictClientConfiguration(new ServiceCollection().BuildServiceProvider()); |
||||
|
var options = CreateBaseOptions(); |
||||
|
|
||||
|
options.Registrations.Add(new OpenIddictClientRegistration |
||||
|
{ |
||||
|
Issuer = new Uri("https://www.contoso.com/"), |
||||
|
ConfigurationManager = new StaticConfigurationManager<OpenIddictConfiguration>(new OpenIddictConfiguration()) |
||||
|
}); |
||||
|
|
||||
|
// Act
|
||||
|
var result = configuration.Validate(name: null, options); |
||||
|
|
||||
|
// Assert
|
||||
|
Assert.Contains(SR.GetResourceString(SR.ID0521), result.Failures!); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Validate_ReturnsAnErrorWhenIssuerIsInvalid() |
||||
|
{ |
||||
|
// Arrange
|
||||
|
var configuration = new OpenIddictClientConfiguration(new ServiceCollection().BuildServiceProvider()); |
||||
|
var options = CreateBaseOptions(); |
||||
|
|
||||
|
options.Registrations.Add(new OpenIddictClientRegistration |
||||
|
{ |
||||
|
RegistrationId = "contoso", |
||||
|
Issuer = new Uri("/relative", UriKind.Relative), |
||||
|
ConfigurationManager = new StaticConfigurationManager<OpenIddictConfiguration>(new OpenIddictConfiguration()) |
||||
|
}); |
||||
|
|
||||
|
// Act
|
||||
|
var result = configuration.Validate(name: null, options); |
||||
|
|
||||
|
// Assert
|
||||
|
Assert.Contains(SR.GetResourceString(SR.ID0136), result.Failures!); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Validate_ReturnsAnErrorWhenIssuerContainsQueryOrFragment() |
||||
|
{ |
||||
|
// Arrange
|
||||
|
var configuration = new OpenIddictClientConfiguration(new ServiceCollection().BuildServiceProvider()); |
||||
|
var options = CreateBaseOptions(); |
||||
|
|
||||
|
options.Registrations.Add(new OpenIddictClientRegistration |
||||
|
{ |
||||
|
RegistrationId = "contoso", |
||||
|
Issuer = new Uri("https://www.contoso.com/?query=parameter#fragment"), |
||||
|
ConfigurationManager = new StaticConfigurationManager<OpenIddictConfiguration>(new OpenIddictConfiguration()) |
||||
|
}); |
||||
|
|
||||
|
// Act
|
||||
|
var result = configuration.Validate(name: null, options); |
||||
|
|
||||
|
// Assert
|
||||
|
Assert.Contains(SR.GetResourceString(SR.ID0137), result.Failures!); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Validate_ReturnsAnErrorWhenRegistrationConfigurationIssuerDoesNotMatchRegistrationIssuer() |
||||
|
{ |
||||
|
// Arrange
|
||||
|
var configuration = new OpenIddictClientConfiguration(new ServiceCollection().BuildServiceProvider()); |
||||
|
var options = CreateBaseOptions(); |
||||
|
|
||||
|
options.Registrations.Add(new OpenIddictClientRegistration |
||||
|
{ |
||||
|
RegistrationId = "contoso", |
||||
|
Issuer = new Uri("https://www.contoso.com/"), |
||||
|
Configuration = new OpenIddictConfiguration { Issuer = new Uri("https://www.fabrikam.com/") }, |
||||
|
ConfigurationManager = new StaticConfigurationManager<OpenIddictConfiguration>(new OpenIddictConfiguration()) |
||||
|
}); |
||||
|
|
||||
|
// Act
|
||||
|
var result = configuration.Validate(name: null, options); |
||||
|
|
||||
|
// Assert
|
||||
|
Assert.Contains(SR.GetResourceString(SR.ID0395), result.Failures!); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Validate_ReturnsAnErrorWhenConfigurationManagerIsMissing() |
||||
|
{ |
||||
|
// Arrange
|
||||
|
var configuration = new OpenIddictClientConfiguration(new ServiceCollection().BuildServiceProvider()); |
||||
|
var options = CreateBaseOptions(); |
||||
|
|
||||
|
options.Registrations.Add(new OpenIddictClientRegistration |
||||
|
{ |
||||
|
RegistrationId = "contoso", |
||||
|
Issuer = new Uri("https://www.contoso.com/") |
||||
|
}); |
||||
|
|
||||
|
// Act
|
||||
|
var result = configuration.Validate(name: null, options); |
||||
|
|
||||
|
// Assert
|
||||
|
Assert.Contains(SR.GetResourceString(SR.ID0522), result.Failures!); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Validate_ReturnsAnErrorWhenNonStaticConfigurationManagerIsUsedWithoutRequiredHandlers() |
||||
|
{ |
||||
|
// Arrange
|
||||
|
var configuration = new OpenIddictClientConfiguration(new ServiceCollection().BuildServiceProvider()); |
||||
|
var options = CreateBaseOptions(); |
||||
|
|
||||
|
options.Registrations.Add(new OpenIddictClientRegistration |
||||
|
{ |
||||
|
RegistrationId = "contoso", |
||||
|
Issuer = new Uri("https://www.contoso.com/"), |
||||
|
ConfigurationManager = Mock.Of<IConfigurationManager<OpenIddictConfiguration>>() |
||||
|
}); |
||||
|
|
||||
|
// Act
|
||||
|
var result = configuration.Validate(name: null, options); |
||||
|
|
||||
|
// Assert
|
||||
|
Assert.Contains(SR.GetResourceString(SR.ID0313), result.Failures!); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Validate_ReturnsAnErrorWhenNoFlowIsEnabled() |
||||
|
{ |
||||
|
// Arrange
|
||||
|
var configuration = new OpenIddictClientConfiguration(new ServiceCollection().BuildServiceProvider()); |
||||
|
var options = new OpenIddictClientOptions(); |
||||
|
|
||||
|
// Act
|
||||
|
var result = configuration.Validate(name: null, options); |
||||
|
|
||||
|
// Assert
|
||||
|
Assert.Contains(SR.GetResourceString(SR.ID0076), result.Failures!); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Validate_ReturnsAnErrorWhenEndpointUrisAreNotUnique() |
||||
|
{ |
||||
|
// Arrange
|
||||
|
var configuration = new OpenIddictClientConfiguration(new ServiceCollection().BuildServiceProvider()); |
||||
|
var options = CreateBaseOptions(); |
||||
|
|
||||
|
var uri = new Uri("https://www.contoso.com/callback"); |
||||
|
options.RedirectionEndpointUris.Add(uri); |
||||
|
options.PostLogoutRedirectionEndpointUris.Add(uri); |
||||
|
|
||||
|
// Act
|
||||
|
var result = configuration.Validate(name: null, options); |
||||
|
|
||||
|
// Assert
|
||||
|
Assert.Contains(SR.GetResourceString(SR.ID0285), result.Failures!); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Validate_ReturnsAnErrorWhenRedirectionEndpointIsMissingForAuthorizationCodeGrant() |
||||
|
{ |
||||
|
// Arrange
|
||||
|
var configuration = new OpenIddictClientConfiguration(new ServiceCollection().BuildServiceProvider()); |
||||
|
var options = CreateBaseOptions(); |
||||
|
options.GrantTypes.Add(GrantTypes.AuthorizationCode); |
||||
|
|
||||
|
// Act
|
||||
|
var result = configuration.Validate(name: null, options); |
||||
|
|
||||
|
// Assert
|
||||
|
Assert.Contains(SR.GetResourceString(SR.ID0356), result.Failures!); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Validate_ReturnsAnErrorWhenStateTokenCredentialsAreMissing() |
||||
|
{ |
||||
|
// Arrange
|
||||
|
var configuration = new OpenIddictClientConfiguration(new ServiceCollection().BuildServiceProvider()); |
||||
|
var options = CreateBaseOptions(); |
||||
|
|
||||
|
options.RedirectionEndpointUris.Add(new Uri("https://www.contoso.com/callback")); |
||||
|
|
||||
|
// Act
|
||||
|
var result = configuration.Validate(name: null, options); |
||||
|
|
||||
|
// Assert
|
||||
|
Assert.Contains(SR.GetResourceString(SR.ID0357), result.Failures!); |
||||
|
Assert.Contains(SR.GetResourceString(SR.ID0358), result.Failures!); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Validate_ReturnsAnErrorWhenResponseTypeIsInconsistentWithEnabledGrantTypes() |
||||
|
{ |
||||
|
// Arrange
|
||||
|
var configuration = new OpenIddictClientConfiguration(new ServiceCollection().BuildServiceProvider()); |
||||
|
var options = CreateBaseOptions(); |
||||
|
options.ResponseTypes.Add(ResponseTypes.Code); |
||||
|
|
||||
|
// Act
|
||||
|
var result = configuration.Validate(name: null, options); |
||||
|
|
||||
|
// Assert
|
||||
|
Assert.Contains(SR.FormatID0281(ResponseTypes.Code), result.Failures!); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Validate_SucceedsForConsistentMinimalConfiguration() |
||||
|
{ |
||||
|
// Arrange
|
||||
|
var configuration = new OpenIddictClientConfiguration(new ServiceCollection().BuildServiceProvider()); |
||||
|
var options = CreateBaseOptions(); |
||||
|
|
||||
|
options.Registrations.Add(new OpenIddictClientRegistration |
||||
|
{ |
||||
|
RegistrationId = "contoso", |
||||
|
Issuer = new Uri("https://www.contoso.com/"), |
||||
|
ConfigurationManager = new StaticConfigurationManager<OpenIddictConfiguration>(new OpenIddictConfiguration()) |
||||
|
}); |
||||
|
|
||||
|
// Act
|
||||
|
var result = configuration.Validate(name: null, options); |
||||
|
|
||||
|
// Assert
|
||||
|
Assert.True(result.Succeeded); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Validate_ReturnsAnErrorWhenRegistrationIdentifiersAreDuplicated() |
||||
|
{ |
||||
|
// Arrange
|
||||
|
var configuration = new OpenIddictClientConfiguration(new ServiceCollection().BuildServiceProvider()); |
||||
|
var options = CreateBaseOptions(); |
||||
|
|
||||
|
var manager = new StaticConfigurationManager<OpenIddictConfiguration>(new OpenIddictConfiguration()); |
||||
|
|
||||
|
options.Registrations.Add(new OpenIddictClientRegistration |
||||
|
{ |
||||
|
RegistrationId = "duplicate", |
||||
|
Issuer = new Uri("https://www.contoso.com/"), |
||||
|
ConfigurationManager = manager |
||||
|
}); |
||||
|
|
||||
|
options.Registrations.Add(new OpenIddictClientRegistration |
||||
|
{ |
||||
|
RegistrationId = "DUPLICATE", |
||||
|
Issuer = new Uri("https://www.fabrikam.com/"), |
||||
|
ConfigurationManager = manager |
||||
|
}); |
||||
|
|
||||
|
// Act
|
||||
|
var result = configuration.Validate(name: null, options); |
||||
|
|
||||
|
// Assert
|
||||
|
Assert.Contains(SR.GetResourceString(SR.ID0347), result.Failures!); |
||||
|
} |
||||
|
|
||||
|
private static OpenIddictClientOptions CreateBaseOptions() |
||||
|
{ |
||||
|
var options = new OpenIddictClientOptions |
||||
|
{ |
||||
|
TimeProvider = TimeProvider.System |
||||
|
}; |
||||
|
|
||||
|
options.GrantTypes.Add(GrantTypes.ClientCredentials); |
||||
|
|
||||
|
return options; |
||||
|
} |
||||
|
|
||||
|
private sealed class FakeTimeProvider : TimeProvider; |
||||
|
} |
||||
@ -0,0 +1,555 @@ |
|||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Microsoft.IdentityModel.Tokens; |
||||
|
using Xunit; |
||||
|
|
||||
|
namespace OpenIddict.Server.Tests; |
||||
|
|
||||
|
public class OpenIddictServerConfigurationTests |
||||
|
{ |
||||
|
[Fact] |
||||
|
public void Constructor_ThrowsAnExceptionForNullProvider() |
||||
|
{ |
||||
|
// Arrange
|
||||
|
var provider = (IServiceProvider) null!; |
||||
|
|
||||
|
// Act and assert
|
||||
|
var exception = Assert.Throws<ArgumentNullException>(() => new OpenIddictServerConfiguration(provider)); |
||||
|
Assert.Equal("provider", exception.ParamName); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void PostConfigure_ThrowsAnExceptionForNullOptions() |
||||
|
{ |
||||
|
// Arrange
|
||||
|
var configuration = new OpenIddictServerConfiguration(new ServiceCollection().BuildServiceProvider()); |
||||
|
|
||||
|
// Act and assert
|
||||
|
var exception = Assert.Throws<ArgumentNullException>(() => configuration.PostConfigure(name: null, options: null!)); |
||||
|
Assert.Equal("options", exception.ParamName); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void PostConfigure_SetsTimeProviderToSystemWhenNotRegistered() |
||||
|
{ |
||||
|
// Arrange
|
||||
|
var configuration = new OpenIddictServerConfiguration(new ServiceCollection().BuildServiceProvider()); |
||||
|
var options = new OpenIddictServerOptions(); |
||||
|
|
||||
|
// Act
|
||||
|
configuration.PostConfigure(name: null, options); |
||||
|
|
||||
|
// Assert
|
||||
|
Assert.Same(TimeProvider.System, options.TimeProvider); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void PostConfigure_UsesRegisteredTimeProvider() |
||||
|
{ |
||||
|
// Arrange
|
||||
|
var timeProvider = new FakeTimeProvider(); |
||||
|
var services = new ServiceCollection(); |
||||
|
services.AddSingleton<TimeProvider>(timeProvider); |
||||
|
|
||||
|
var configuration = new OpenIddictServerConfiguration(services.BuildServiceProvider()); |
||||
|
var options = new OpenIddictServerOptions(); |
||||
|
|
||||
|
// Act
|
||||
|
configuration.PostConfigure(name: null, options); |
||||
|
|
||||
|
// Assert
|
||||
|
Assert.Same(timeProvider, options.TimeProvider); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void PostConfigure_DoesNotOverrideExplicitlySetTimeProvider() |
||||
|
{ |
||||
|
// Arrange
|
||||
|
var explicitProvider = new FakeTimeProvider(); |
||||
|
var registeredProvider = new FakeTimeProvider(); |
||||
|
|
||||
|
var services = new ServiceCollection(); |
||||
|
services.AddSingleton<TimeProvider>(registeredProvider); |
||||
|
|
||||
|
var configuration = new OpenIddictServerConfiguration(services.BuildServiceProvider()); |
||||
|
var options = new OpenIddictServerOptions { TimeProvider = explicitProvider }; |
||||
|
|
||||
|
// Act
|
||||
|
configuration.PostConfigure(name: null, options); |
||||
|
|
||||
|
// Assert
|
||||
|
Assert.Same(explicitProvider, options.TimeProvider); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void PostConfigure_DisablesFeaturesWhenDegradedModeIsEnabled() |
||||
|
{ |
||||
|
// Arrange
|
||||
|
var configuration = new OpenIddictServerConfiguration(new ServiceCollection().BuildServiceProvider()); |
||||
|
var options = new OpenIddictServerOptions |
||||
|
{ |
||||
|
EnableDegradedMode = true, |
||||
|
EnableAuthorizationRequestCaching = true, |
||||
|
EnableEndSessionRequestCaching = true, |
||||
|
UseReferenceAccessTokens = true, |
||||
|
UseReferenceRefreshTokens = true |
||||
|
}; |
||||
|
|
||||
|
// Act
|
||||
|
configuration.PostConfigure(name: null, options); |
||||
|
|
||||
|
// Assert
|
||||
|
Assert.True(options.DisableAuthorizationStorage); |
||||
|
Assert.True(options.DisableTokenStorage); |
||||
|
Assert.True(options.DisableRollingRefreshTokens); |
||||
|
Assert.False(options.EnableAuthorizationRequestCaching); |
||||
|
Assert.False(options.EnableEndSessionRequestCaching); |
||||
|
Assert.True(options.IgnoreEndpointPermissions); |
||||
|
Assert.True(options.IgnoreGrantTypePermissions); |
||||
|
Assert.True(options.IgnoreResponseTypePermissions); |
||||
|
Assert.True(options.IgnoreScopePermissions); |
||||
|
Assert.False(options.UseReferenceAccessTokens); |
||||
|
Assert.False(options.UseReferenceRefreshTokens); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void PostConfigure_DisablesUserCodeFormattingWhenTokenStorageIsDisabled() |
||||
|
{ |
||||
|
// Arrange
|
||||
|
var configuration = new OpenIddictServerConfiguration(new ServiceCollection().BuildServiceProvider()); |
||||
|
var options = new OpenIddictServerOptions |
||||
|
{ |
||||
|
DisableTokenStorage = true |
||||
|
}; |
||||
|
|
||||
|
// Act
|
||||
|
configuration.PostConfigure(name: null, options); |
||||
|
|
||||
|
// Assert
|
||||
|
Assert.True(options.DisableRollingRefreshTokens); |
||||
|
Assert.Equal(0, options.UserCodeLength); |
||||
|
Assert.Empty(options.UserCodeCharset); |
||||
|
Assert.Null(options.UserCodeDisplayFormat); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Validate_ThrowsAnExceptionForNullOptions() |
||||
|
{ |
||||
|
// Arrange
|
||||
|
var configuration = new OpenIddictServerConfiguration(new ServiceCollection().BuildServiceProvider()); |
||||
|
|
||||
|
// Act and assert
|
||||
|
var exception = Assert.Throws<ArgumentNullException>(() => configuration.Validate(name: null, options: null!)); |
||||
|
Assert.Equal("options", exception.ParamName); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Validate_ReturnsAnErrorWhenJsonWebTokenHandlerIsMissing() |
||||
|
{ |
||||
|
// Arrange
|
||||
|
var configuration = new OpenIddictServerConfiguration(new ServiceCollection().BuildServiceProvider()); |
||||
|
var options = CreateBaseOptions(); |
||||
|
options.JsonWebTokenHandler = null!; |
||||
|
|
||||
|
// Act
|
||||
|
var result = configuration.Validate(name: null, options); |
||||
|
|
||||
|
// Assert
|
||||
|
Assert.Contains(SR.GetResourceString(SR.ID0075), result.Failures!); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Validate_ReturnsAnErrorWhenNoFlowIsEnabled() |
||||
|
{ |
||||
|
// Arrange
|
||||
|
var configuration = new OpenIddictServerConfiguration(new ServiceCollection().BuildServiceProvider()); |
||||
|
var options = CreateBaseOptions(); |
||||
|
|
||||
|
// Act
|
||||
|
var result = configuration.Validate(name: null, options); |
||||
|
|
||||
|
// Assert
|
||||
|
Assert.Contains(SR.GetResourceString(SR.ID0076), result.Failures!); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Validate_ReturnsAnErrorWhenEndpointUrisAreNotUnique() |
||||
|
{ |
||||
|
// Arrange
|
||||
|
var configuration = new OpenIddictServerConfiguration(new ServiceCollection().BuildServiceProvider()); |
||||
|
var options = CreateBaseOptions(); |
||||
|
|
||||
|
var uri = new Uri("https://www.contoso.com/connect/shared"); |
||||
|
options.AuthorizationEndpointUris.Add(uri); |
||||
|
options.TokenEndpointUris.Add(uri); |
||||
|
|
||||
|
// Act
|
||||
|
var result = configuration.Validate(name: null, options); |
||||
|
|
||||
|
// Assert
|
||||
|
Assert.Contains(SR.GetResourceString(SR.ID0285), result.Failures!); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Validate_ReturnsAnErrorWhenAuthorizationEndpointIsMissingForAuthorizationCodeGrant() |
||||
|
{ |
||||
|
// Arrange
|
||||
|
var configuration = new OpenIddictServerConfiguration(new ServiceCollection().BuildServiceProvider()); |
||||
|
var options = CreateBaseOptions(); |
||||
|
options.GrantTypes.Add(GrantTypes.AuthorizationCode); |
||||
|
|
||||
|
// Act
|
||||
|
var result = configuration.Validate(name: null, options); |
||||
|
|
||||
|
// Assert
|
||||
|
Assert.Contains(SR.GetResourceString(SR.ID0077), result.Failures!); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Validate_ReturnsAnErrorWhenTokenEndpointIsMissingForPasswordGrant() |
||||
|
{ |
||||
|
// Arrange
|
||||
|
var configuration = new OpenIddictServerConfiguration(new ServiceCollection().BuildServiceProvider()); |
||||
|
var options = CreateBaseOptions(); |
||||
|
options.GrantTypes.Add(GrantTypes.Password); |
||||
|
|
||||
|
// Act
|
||||
|
var result = configuration.Validate(name: null, options); |
||||
|
|
||||
|
// Assert
|
||||
|
Assert.Contains(SR.GetResourceString(SR.ID0079), result.Failures!); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Validate_ReturnsAnErrorWhenDeviceVerificationEndpointIsMissingForDeviceGrant() |
||||
|
{ |
||||
|
// Arrange
|
||||
|
var configuration = new OpenIddictServerConfiguration(new ServiceCollection().BuildServiceProvider()); |
||||
|
var options = CreateBaseOptions(); |
||||
|
options.GrantTypes.Add(GrantTypes.DeviceCode); |
||||
|
|
||||
|
// Act
|
||||
|
var result = configuration.Validate(name: null, options); |
||||
|
|
||||
|
// Assert
|
||||
|
Assert.Contains(SR.GetResourceString(SR.ID0080), result.Failures!); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Validate_ReturnsAnErrorWhenDeviceEndpointIsEnabledWithoutDeviceGrant() |
||||
|
{ |
||||
|
// Arrange
|
||||
|
var configuration = new OpenIddictServerConfiguration(new ServiceCollection().BuildServiceProvider()); |
||||
|
var options = CreateBaseOptions(); |
||||
|
options.DeviceAuthorizationEndpointUris.Add(new Uri("https://www.contoso.com/connect/device")); |
||||
|
|
||||
|
// Act
|
||||
|
var result = configuration.Validate(name: null, options); |
||||
|
|
||||
|
// Assert
|
||||
|
Assert.Contains(SR.GetResourceString(SR.ID0084), result.Failures!); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Validate_ReturnsAnErrorWhenNoClientAuthenticationMethodIsEnabledForNonInteractiveEndpoints() |
||||
|
{ |
||||
|
// Arrange
|
||||
|
var configuration = new OpenIddictServerConfiguration(new ServiceCollection().BuildServiceProvider()); |
||||
|
var options = CreateBaseOptions(); |
||||
|
|
||||
|
options.TokenEndpointUris.Add(new Uri("https://www.contoso.com/connect/token")); |
||||
|
options.ClientAuthenticationMethods.Clear(); |
||||
|
|
||||
|
// Act
|
||||
|
var result = configuration.Validate(name: null, options); |
||||
|
|
||||
|
// Assert
|
||||
|
Assert.Contains(SR.GetResourceString(SR.ID0419), result.Failures!); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Validate_ReturnsAnErrorWhenPrivateKeyJwtIsEnabledWithoutJwtBearerAssertionType() |
||||
|
{ |
||||
|
// Arrange
|
||||
|
var configuration = new OpenIddictServerConfiguration(new ServiceCollection().BuildServiceProvider()); |
||||
|
var options = CreateBaseOptions(); |
||||
|
|
||||
|
options.ClientAuthenticationMethods.Clear(); |
||||
|
options.ClientAuthenticationMethods.Add(ClientAuthenticationMethods.PrivateKeyJwt); |
||||
|
options.ClientAssertionTypes.Clear(); |
||||
|
|
||||
|
// Act
|
||||
|
var result = configuration.Validate(name: null, options); |
||||
|
|
||||
|
// Assert
|
||||
|
Assert.Contains(SR.FormatID0420(ClientAssertionTypes.JwtBearer, ClientAuthenticationMethods.PrivateKeyJwt), result.Failures!); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Validate_ReturnsAnErrorWhenTlsClientAuthMethodIsEnabledWithoutPolicy() |
||||
|
{ |
||||
|
// Arrange
|
||||
|
var configuration = new OpenIddictServerConfiguration(new ServiceCollection().BuildServiceProvider()); |
||||
|
var options = CreateBaseOptions(); |
||||
|
options.ClientAuthenticationMethods.Add(ClientAuthenticationMethods.TlsClientAuth); |
||||
|
|
||||
|
// Act
|
||||
|
var result = configuration.Validate(name: null, options); |
||||
|
|
||||
|
// Assert
|
||||
|
Assert.Contains(SR.GetResourceString(SR.ID0505), result.Failures!); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Validate_ReturnsAnErrorWhenSelfSignedTlsClientAuthMethodIsEnabledWithoutPolicy() |
||||
|
{ |
||||
|
// Arrange
|
||||
|
var configuration = new OpenIddictServerConfiguration(new ServiceCollection().BuildServiceProvider()); |
||||
|
var options = CreateBaseOptions(); |
||||
|
options.ClientAuthenticationMethods.Add(ClientAuthenticationMethods.SelfSignedTlsClientAuth); |
||||
|
|
||||
|
// Act
|
||||
|
var result = configuration.Validate(name: null, options); |
||||
|
|
||||
|
// Assert
|
||||
|
Assert.Contains(SR.GetResourceString(SR.ID0506), result.Failures!); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Validate_ReturnsAnErrorWhenSubjectTypesAreMissing() |
||||
|
{ |
||||
|
// Arrange
|
||||
|
var configuration = new OpenIddictServerConfiguration(new ServiceCollection().BuildServiceProvider()); |
||||
|
var options = CreateBaseOptions(); |
||||
|
options.SubjectTypes.Clear(); |
||||
|
|
||||
|
// Act
|
||||
|
var result = configuration.Validate(name: null, options); |
||||
|
|
||||
|
// Assert
|
||||
|
Assert.Contains(SR.GetResourceString(SR.ID0421), result.Failures!); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Validate_ReturnsAnErrorWhenReferenceTokensAreEnabledWithDisabledTokenStorage() |
||||
|
{ |
||||
|
// Arrange
|
||||
|
var configuration = new OpenIddictServerConfiguration(new ServiceCollection().BuildServiceProvider()); |
||||
|
var options = CreateBaseOptions(); |
||||
|
|
||||
|
options.DisableTokenStorage = true; |
||||
|
options.UseReferenceAccessTokens = true; |
||||
|
|
||||
|
// Act
|
||||
|
var result = configuration.Validate(name: null, options); |
||||
|
|
||||
|
// Assert
|
||||
|
Assert.Contains(SR.GetResourceString(SR.ID0083), result.Failures!); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Validate_ReturnsAnErrorWhenRequestCachingIsEnabledWithDisabledTokenStorage() |
||||
|
{ |
||||
|
// Arrange
|
||||
|
var configuration = new OpenIddictServerConfiguration(new ServiceCollection().BuildServiceProvider()); |
||||
|
var options = CreateBaseOptions(); |
||||
|
|
||||
|
options.DisableTokenStorage = true; |
||||
|
options.EnableAuthorizationRequestCaching = true; |
||||
|
|
||||
|
// Act
|
||||
|
var result = configuration.Validate(name: null, options); |
||||
|
|
||||
|
// Assert
|
||||
|
Assert.Contains(SR.GetResourceString(SR.ID0465), result.Failures!); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Validate_ReturnsAnErrorWhenDeviceGrantIsEnabledWithDisabledTokenStorageOutsideDegradedMode() |
||||
|
{ |
||||
|
// Arrange
|
||||
|
var configuration = new OpenIddictServerConfiguration(new ServiceCollection().BuildServiceProvider()); |
||||
|
var options = CreateBaseOptions(); |
||||
|
|
||||
|
options.DisableTokenStorage = true; |
||||
|
options.EnableDegradedMode = false; |
||||
|
options.GrantTypes.Add(GrantTypes.DeviceCode); |
||||
|
|
||||
|
// Act
|
||||
|
var result = configuration.Validate(name: null, options); |
||||
|
|
||||
|
// Assert
|
||||
|
Assert.Contains(SR.GetResourceString(SR.ID0367), result.Failures!); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Validate_ReturnsAnErrorWhenTokenExchangeGrantIsEnabledWithoutSubjectTokenTypes() |
||||
|
{ |
||||
|
// Arrange
|
||||
|
var configuration = new OpenIddictServerConfiguration(new ServiceCollection().BuildServiceProvider()); |
||||
|
var options = CreateBaseOptions(); |
||||
|
options.GrantTypes.Add(GrantTypes.TokenExchange); |
||||
|
options.SubjectTokenTypes.Clear(); |
||||
|
|
||||
|
// Act
|
||||
|
var result = configuration.Validate(name: null, options); |
||||
|
|
||||
|
// Assert
|
||||
|
Assert.Contains(SR.GetResourceString(SR.ID0486), result.Failures!); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Validate_ReturnsAnErrorWhenDefaultRequestedTokenTypeIsMissing() |
||||
|
{ |
||||
|
// Arrange
|
||||
|
var configuration = new OpenIddictServerConfiguration(new ServiceCollection().BuildServiceProvider()); |
||||
|
var options = CreateBaseOptions(); |
||||
|
options.DefaultRequestedTokenType = string.Empty; |
||||
|
|
||||
|
// Act
|
||||
|
var result = configuration.Validate(name: null, options); |
||||
|
|
||||
|
// Assert
|
||||
|
Assert.Contains(SR.GetResourceString(SR.ID0490), result.Failures!); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Validate_ReturnsAnErrorWhenDefaultRequestedTokenTypeIsNotAllowed() |
||||
|
{ |
||||
|
// Arrange
|
||||
|
var configuration = new OpenIddictServerConfiguration(new ServiceCollection().BuildServiceProvider()); |
||||
|
var options = CreateBaseOptions(); |
||||
|
options.RequestedTokenTypes.Clear(); |
||||
|
options.DefaultRequestedTokenType = TokenTypeIdentifiers.AccessToken; |
||||
|
|
||||
|
// Act
|
||||
|
var result = configuration.Validate(name: null, options); |
||||
|
|
||||
|
// Assert
|
||||
|
Assert.Contains(SR.GetResourceString(SR.ID0492), result.Failures!); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Validate_ReturnsAnErrorWhenEncryptionCredentialsAreMissing() |
||||
|
{ |
||||
|
// Arrange
|
||||
|
var configuration = new OpenIddictServerConfiguration(new ServiceCollection().BuildServiceProvider()); |
||||
|
var options = CreateBaseOptions(); |
||||
|
|
||||
|
// Act
|
||||
|
var result = configuration.Validate(name: null, options); |
||||
|
|
||||
|
// Assert
|
||||
|
Assert.Contains(SR.GetResourceString(SR.ID0085), result.Failures!); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Validate_ReturnsAnErrorWhenNoAsymmetricSigningCredentialIsRegistered() |
||||
|
{ |
||||
|
// Arrange
|
||||
|
var configuration = new OpenIddictServerConfiguration(new ServiceCollection().BuildServiceProvider()); |
||||
|
var options = CreateBaseOptions(); |
||||
|
|
||||
|
options.EncryptionCredentials.Add(new EncryptingCredentials( |
||||
|
new SymmetricSecurityKey(new byte[32]), |
||||
|
SecurityAlgorithms.Aes256KW, |
||||
|
SecurityAlgorithms.Aes256CbcHmacSha512)); |
||||
|
|
||||
|
options.SigningCredentials.Add(new SigningCredentials( |
||||
|
new SymmetricSecurityKey(new byte[32]), |
||||
|
SecurityAlgorithms.HmacSha256)); |
||||
|
|
||||
|
// Act
|
||||
|
var result = configuration.Validate(name: null, options); |
||||
|
|
||||
|
// Assert
|
||||
|
Assert.Contains(SR.GetResourceString(SR.ID0086), result.Failures!); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Validate_ReturnsAnErrorWhenMtlsEndpointAliasIsInvalid() |
||||
|
{ |
||||
|
// Arrange
|
||||
|
var configuration = new OpenIddictServerConfiguration(new ServiceCollection().BuildServiceProvider()); |
||||
|
var options = CreateBaseOptions(); |
||||
|
|
||||
|
options.MtlsTokenEndpointAliasUri = new Uri("http://www.contoso.com/connect/token", UriKind.Absolute); |
||||
|
|
||||
|
// Act
|
||||
|
var result = configuration.Validate(name: null, options); |
||||
|
|
||||
|
// Assert
|
||||
|
Assert.Contains(SR.GetResourceString(SR.ID0499), result.Failures!); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Validate_ReturnsAnErrorWhenMtlsEndpointAliasIsConfiguredWithoutEndpoint() |
||||
|
{ |
||||
|
// Arrange
|
||||
|
var configuration = new OpenIddictServerConfiguration(new ServiceCollection().BuildServiceProvider()); |
||||
|
var options = CreateBaseOptions(); |
||||
|
|
||||
|
options.MtlsTokenEndpointAliasUri = new Uri("https://www.contoso.com/connect/token", UriKind.Absolute); |
||||
|
|
||||
|
// Act
|
||||
|
var result = configuration.Validate(name: null, options); |
||||
|
|
||||
|
// Assert
|
||||
|
Assert.Contains(SR.GetResourceString(SR.ID0510), result.Failures!); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Validate_ReturnsAnErrorWhenMtlsEndpointAliasIsConfiguredWithoutIssuer() |
||||
|
{ |
||||
|
// Arrange
|
||||
|
var configuration = new OpenIddictServerConfiguration(new ServiceCollection().BuildServiceProvider()); |
||||
|
var options = CreateBaseOptions(); |
||||
|
|
||||
|
options.TokenEndpointUris.Add(new Uri("https://www.contoso.com/connect/token")); |
||||
|
options.MtlsTokenEndpointAliasUri = new Uri("https://mtls.contoso.com/connect/token", UriKind.Absolute); |
||||
|
|
||||
|
// Act
|
||||
|
var result = configuration.Validate(name: null, options); |
||||
|
|
||||
|
// Assert
|
||||
|
Assert.Contains(SR.GetResourceString(SR.ID0500), result.Failures!); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Validate_ReturnsAnErrorWhenDegradedModeIsEnabledAndCustomTokenEndpointHandlersAreMissing() |
||||
|
{ |
||||
|
// Arrange
|
||||
|
var configuration = new OpenIddictServerConfiguration(new ServiceCollection().BuildServiceProvider()); |
||||
|
var options = CreateBaseOptions(); |
||||
|
options.EnableDegradedMode = true; |
||||
|
options.TokenEndpointUris.Add(new Uri("https://www.contoso.com/connect/token")); |
||||
|
|
||||
|
// Act
|
||||
|
var result = configuration.Validate(name: null, options); |
||||
|
|
||||
|
// Assert
|
||||
|
Assert.Contains(SR.GetResourceString(SR.ID0094), result.Failures!); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Validate_ReturnsAnErrorWhenUserCodeLengthIsTooShort() |
||||
|
{ |
||||
|
// Arrange
|
||||
|
var configuration = new OpenIddictServerConfiguration(new ServiceCollection().BuildServiceProvider()); |
||||
|
var options = CreateBaseOptions(); |
||||
|
options.UserCodeLength = 5; |
||||
|
|
||||
|
// Act
|
||||
|
var result = configuration.Validate(name: null, options); |
||||
|
|
||||
|
// Assert
|
||||
|
Assert.Contains(SR.FormatID0439(6), result.Failures!); |
||||
|
} |
||||
|
|
||||
|
private static OpenIddictServerOptions CreateBaseOptions() |
||||
|
=> new() |
||||
|
{ |
||||
|
TimeProvider = TimeProvider.System |
||||
|
}; |
||||
|
|
||||
|
private sealed class FakeTimeProvider : TimeProvider; |
||||
|
} |
||||
File diff suppressed because it is too large
@ -0,0 +1,372 @@ |
|||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Microsoft.IdentityModel.Protocols; |
||||
|
using Microsoft.IdentityModel.Tokens; |
||||
|
using Moq; |
||||
|
using Xunit; |
||||
|
using static OpenIddict.Validation.OpenIddictValidationEvents; |
||||
|
|
||||
|
namespace OpenIddict.Validation.Tests; |
||||
|
|
||||
|
public class OpenIddictValidationConfigurationTests |
||||
|
{ |
||||
|
[Fact] |
||||
|
public void Constructor_ThrowsAnExceptionForNullProvider() |
||||
|
{ |
||||
|
// Arrange
|
||||
|
var provider = (IServiceProvider) null!; |
||||
|
|
||||
|
// Act and assert
|
||||
|
var exception = Assert.Throws<ArgumentNullException>(() => new OpenIddictValidationConfiguration(provider)); |
||||
|
Assert.Equal("provider", exception.ParamName); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void PostConfigure_ThrowsAnExceptionForNullOptions() |
||||
|
{ |
||||
|
// Arrange
|
||||
|
var configuration = new OpenIddictValidationConfiguration(new ServiceCollection().BuildServiceProvider()); |
||||
|
|
||||
|
// Act and assert
|
||||
|
var exception = Assert.Throws<ArgumentNullException>(() => configuration.PostConfigure(name: null, options: null!)); |
||||
|
Assert.Equal("options", exception.ParamName); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void PostConfigure_SetsTimeProviderToSystemWhenNotRegistered() |
||||
|
{ |
||||
|
// Arrange
|
||||
|
var configuration = new OpenIddictValidationConfiguration(new ServiceCollection().BuildServiceProvider()); |
||||
|
var options = new OpenIddictValidationOptions(); |
||||
|
|
||||
|
// Act
|
||||
|
configuration.PostConfigure(name: null, options); |
||||
|
|
||||
|
// Assert
|
||||
|
Assert.Same(TimeProvider.System, options.TimeProvider); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void PostConfigure_UsesRegisteredTimeProvider() |
||||
|
{ |
||||
|
// Arrange
|
||||
|
var timeProvider = new FakeTimeProvider(); |
||||
|
var services = new ServiceCollection(); |
||||
|
services.AddSingleton<TimeProvider>(timeProvider); |
||||
|
|
||||
|
var configuration = new OpenIddictValidationConfiguration(services.BuildServiceProvider()); |
||||
|
var options = new OpenIddictValidationOptions(); |
||||
|
|
||||
|
// Act
|
||||
|
configuration.PostConfigure(name: null, options); |
||||
|
|
||||
|
// Assert
|
||||
|
Assert.Same(timeProvider, options.TimeProvider); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void PostConfigure_DoesNotOverrideExplicitlySetTimeProvider() |
||||
|
{ |
||||
|
// Arrange
|
||||
|
var explicitProvider = new FakeTimeProvider(); |
||||
|
var registeredProvider = new FakeTimeProvider(); |
||||
|
|
||||
|
var services = new ServiceCollection(); |
||||
|
services.AddSingleton<TimeProvider>(registeredProvider); |
||||
|
|
||||
|
var configuration = new OpenIddictValidationConfiguration(services.BuildServiceProvider()); |
||||
|
var options = new OpenIddictValidationOptions { TimeProvider = explicitProvider }; |
||||
|
|
||||
|
// Act
|
||||
|
configuration.PostConfigure(name: null, options); |
||||
|
|
||||
|
// Assert
|
||||
|
Assert.Same(explicitProvider, options.TimeProvider); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void PostConfigure_CreatesStaticConfigurationManagerFromStaticConfiguration() |
||||
|
{ |
||||
|
// Arrange
|
||||
|
var configuration = new OpenIddictValidationConfiguration(new ServiceCollection().BuildServiceProvider()); |
||||
|
var options = new OpenIddictValidationOptions |
||||
|
{ |
||||
|
Issuer = new Uri("https://www.contoso.com/"), |
||||
|
Configuration = new OpenIddictConfiguration() |
||||
|
}; |
||||
|
|
||||
|
// Act
|
||||
|
configuration.PostConfigure(name: null, options); |
||||
|
|
||||
|
// Assert
|
||||
|
Assert.IsType<StaticConfigurationManager<OpenIddictConfiguration>>(options.ConfigurationManager); |
||||
|
Assert.Equal(options.Issuer, options.Configuration.Issuer); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void PostConfigure_AttachesEncryptionKeysToTokenValidationParameters() |
||||
|
{ |
||||
|
// Arrange
|
||||
|
var configuration = new OpenIddictValidationConfiguration(new ServiceCollection().BuildServiceProvider()); |
||||
|
var options = new OpenIddictValidationOptions(); |
||||
|
|
||||
|
var key = new SymmetricSecurityKey(new byte[32]); |
||||
|
options.EncryptionCredentials.Add(new EncryptingCredentials( |
||||
|
key, |
||||
|
SecurityAlgorithms.Aes256KW, |
||||
|
SecurityAlgorithms.Aes256CbcHmacSha512)); |
||||
|
|
||||
|
// Act
|
||||
|
configuration.PostConfigure(name: null, options); |
||||
|
|
||||
|
// Assert
|
||||
|
Assert.Contains(key, options.TokenValidationParameters.TokenDecryptionKeys); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Validate_ThrowsAnExceptionForNullOptions() |
||||
|
{ |
||||
|
// Arrange
|
||||
|
var configuration = new OpenIddictValidationConfiguration(new ServiceCollection().BuildServiceProvider()); |
||||
|
|
||||
|
// Act and assert
|
||||
|
var exception = Assert.Throws<ArgumentNullException>(() => configuration.Validate(name: null, options: null!)); |
||||
|
Assert.Equal("options", exception.ParamName); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Validate_ReturnsAnErrorWhenJsonWebTokenHandlerIsMissing() |
||||
|
{ |
||||
|
// Arrange
|
||||
|
var configuration = new OpenIddictValidationConfiguration(new ServiceCollection().BuildServiceProvider()); |
||||
|
var options = CreateBaseOptions(); |
||||
|
options.JsonWebTokenHandler = null!; |
||||
|
|
||||
|
// Act
|
||||
|
var result = configuration.Validate(name: null, options); |
||||
|
|
||||
|
// Assert
|
||||
|
Assert.Contains(SR.GetResourceString(SR.ID0075), result.Failures!); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Validate_ReturnsAnErrorWhenNoIssuerOrConfigurationInformationIsProvided() |
||||
|
{ |
||||
|
// Arrange
|
||||
|
var configuration = new OpenIddictValidationConfiguration(new ServiceCollection().BuildServiceProvider()); |
||||
|
var options = CreateBaseOptions(); |
||||
|
|
||||
|
// Act
|
||||
|
var result = configuration.Validate(name: null, options); |
||||
|
|
||||
|
// Assert
|
||||
|
Assert.Contains(SR.GetResourceString(SR.ID0128), result.Failures!); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Validate_ReturnsAnErrorWhenIssuerIsInvalid() |
||||
|
{ |
||||
|
// Arrange
|
||||
|
var configuration = new OpenIddictValidationConfiguration(new ServiceCollection().BuildServiceProvider()); |
||||
|
var options = CreateBaseOptions(); |
||||
|
|
||||
|
options.Issuer = new Uri("/relative", UriKind.Relative); |
||||
|
|
||||
|
// Act
|
||||
|
var result = configuration.Validate(name: null, options); |
||||
|
|
||||
|
// Assert
|
||||
|
Assert.Contains(SR.GetResourceString(SR.ID0136), result.Failures!); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Validate_ReturnsAnErrorWhenIssuerContainsQueryOrFragment() |
||||
|
{ |
||||
|
// Arrange
|
||||
|
var configuration = new OpenIddictValidationConfiguration(new ServiceCollection().BuildServiceProvider()); |
||||
|
var options = CreateBaseOptions(); |
||||
|
options.Issuer = new Uri("https://www.contoso.com/?query=parameter#fragment"); |
||||
|
|
||||
|
// Act
|
||||
|
var result = configuration.Validate(name: null, options); |
||||
|
|
||||
|
// Assert
|
||||
|
Assert.Contains(SR.GetResourceString(SR.ID0137), result.Failures!); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Validate_ReturnsAnErrorWhenConfigurationIssuerDoesNotMatchOptionsIssuer() |
||||
|
{ |
||||
|
// Arrange
|
||||
|
var configuration = new OpenIddictValidationConfiguration(new ServiceCollection().BuildServiceProvider()); |
||||
|
var options = CreateBaseOptions(); |
||||
|
|
||||
|
options.Issuer = new Uri("https://www.contoso.com/"); |
||||
|
options.Configuration = new OpenIddictConfiguration |
||||
|
{ |
||||
|
Issuer = new Uri("https://www.fabrikam.com/") |
||||
|
}; |
||||
|
|
||||
|
// Act
|
||||
|
var result = configuration.Validate(name: null, options); |
||||
|
|
||||
|
// Assert
|
||||
|
Assert.Contains(SR.GetResourceString(SR.ID0394), result.Failures!); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Validate_ReturnsAnErrorWhenConfigurationManagerIsMissing() |
||||
|
{ |
||||
|
// Arrange
|
||||
|
var configuration = new OpenIddictValidationConfiguration(new ServiceCollection().BuildServiceProvider()); |
||||
|
var options = CreateBaseOptions(); |
||||
|
options.Issuer = new Uri("https://www.contoso.com/"); |
||||
|
|
||||
|
// Act
|
||||
|
var result = configuration.Validate(name: null, options); |
||||
|
|
||||
|
// Assert
|
||||
|
Assert.Contains(SR.GetResourceString(SR.ID0523), result.Failures!); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Validate_ReturnsAnErrorWhenNonStaticConfigurationManagerIsUsedWithoutRequiredHandlers() |
||||
|
{ |
||||
|
// Arrange
|
||||
|
var configuration = new OpenIddictValidationConfiguration(new ServiceCollection().BuildServiceProvider()); |
||||
|
var options = CreateBaseOptions(); |
||||
|
|
||||
|
options.Issuer = new Uri("https://www.contoso.com/"); |
||||
|
options.ConfigurationManager = Mock.Of<IConfigurationManager<OpenIddictConfiguration>>(); |
||||
|
|
||||
|
// Act
|
||||
|
var result = configuration.Validate(name: null, options); |
||||
|
|
||||
|
// Assert
|
||||
|
Assert.Contains(SR.GetResourceString(SR.ID0135), result.Failures!); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Validate_ReturnsAnErrorWhenIntrospectionHandlersAreMissing() |
||||
|
{ |
||||
|
// Arrange
|
||||
|
var configuration = new OpenIddictValidationConfiguration(new ServiceCollection().BuildServiceProvider()); |
||||
|
var options = CreateBaseOptions(); |
||||
|
|
||||
|
options.ValidationType = OpenIddictValidationType.Introspection; |
||||
|
options.Issuer = new Uri("https://www.contoso.com/"); |
||||
|
options.ConfigurationEndpoint = new Uri("https://www.contoso.com/.well-known/openid-configuration"); |
||||
|
options.ClientId = "client_id"; |
||||
|
options.ClientSecret = "client_secret"; |
||||
|
options.ConfigurationManager = new StaticConfigurationManager<OpenIddictConfiguration>(new OpenIddictConfiguration()); |
||||
|
|
||||
|
// Act
|
||||
|
var result = configuration.Validate(name: null, options); |
||||
|
|
||||
|
// Assert
|
||||
|
Assert.Contains(SR.GetResourceString(SR.ID0129), result.Failures!); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Validate_ReturnsAnErrorWhenIntrospectionIssuerAndConfigurationEndpointAreMissing() |
||||
|
{ |
||||
|
// Arrange
|
||||
|
var configuration = new OpenIddictValidationConfiguration(new ServiceCollection().BuildServiceProvider()); |
||||
|
var options = CreateBaseOptions(); |
||||
|
|
||||
|
options.ValidationType = OpenIddictValidationType.Introspection; |
||||
|
options.ClientId = "client_id"; |
||||
|
options.ClientSecret = "client_secret"; |
||||
|
options.ConfigurationManager = new StaticConfigurationManager<OpenIddictConfiguration>(new OpenIddictConfiguration()); |
||||
|
options.Handlers.Add(OpenIddictValidationHandlerDescriptor.CreateBuilder<ApplyIntrospectionRequestContext>() |
||||
|
.UseSingletonHandler<CustomIntrospectionHandler>().Build()); |
||||
|
|
||||
|
// Act
|
||||
|
var result = configuration.Validate(name: null, options); |
||||
|
|
||||
|
// Assert
|
||||
|
Assert.Contains(SR.GetResourceString(SR.ID0130), result.Failures!); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Validate_ReturnsAnErrorWhenIntrospectionClientCredentialsAreMissing() |
||||
|
{ |
||||
|
// Arrange
|
||||
|
var configuration = new OpenIddictValidationConfiguration(new ServiceCollection().BuildServiceProvider()); |
||||
|
var options = CreateBaseOptions(); |
||||
|
|
||||
|
options.ValidationType = OpenIddictValidationType.Introspection; |
||||
|
options.Issuer = new Uri("https://www.contoso.com/"); |
||||
|
options.ConfigurationEndpoint = new Uri("https://www.contoso.com/.well-known/openid-configuration"); |
||||
|
options.ConfigurationManager = new StaticConfigurationManager<OpenIddictConfiguration>(new OpenIddictConfiguration()); |
||||
|
|
||||
|
// Act
|
||||
|
var result = configuration.Validate(name: null, options); |
||||
|
|
||||
|
// Assert
|
||||
|
Assert.Contains(SR.GetResourceString(SR.ID0131), result.Failures!); |
||||
|
Assert.Contains(SR.GetResourceString(SR.ID0132), result.Failures!); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Validate_ReturnsAnErrorWhenAuthorizationOrTokenEntryValidationIsEnabledInIntrospectionMode() |
||||
|
{ |
||||
|
// Arrange
|
||||
|
var configuration = new OpenIddictValidationConfiguration(new ServiceCollection().BuildServiceProvider()); |
||||
|
var options = CreateBaseOptions(); |
||||
|
|
||||
|
options.ValidationType = OpenIddictValidationType.Introspection; |
||||
|
options.Issuer = new Uri("https://www.contoso.com/"); |
||||
|
options.ConfigurationEndpoint = new Uri("https://www.contoso.com/.well-known/openid-configuration"); |
||||
|
options.ClientId = "client_id"; |
||||
|
options.ClientSecret = "client_secret"; |
||||
|
options.EnableAuthorizationEntryValidation = true; |
||||
|
options.EnableTokenEntryValidation = true; |
||||
|
options.ConfigurationManager = new StaticConfigurationManager<OpenIddictConfiguration>(new OpenIddictConfiguration()); |
||||
|
|
||||
|
// Act
|
||||
|
var result = configuration.Validate(name: null, options); |
||||
|
|
||||
|
// Assert
|
||||
|
Assert.Contains(SR.GetResourceString(SR.ID0133), result.Failures!); |
||||
|
Assert.Contains(SR.GetResourceString(SR.ID0134), result.Failures!); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Validate_SucceedsForValidIntrospectionConfigurationUsingClientAssertion() |
||||
|
{ |
||||
|
// Arrange
|
||||
|
var configuration = new OpenIddictValidationConfiguration(new ServiceCollection().BuildServiceProvider()); |
||||
|
var options = CreateBaseOptions(); |
||||
|
|
||||
|
options.ValidationType = OpenIddictValidationType.Introspection; |
||||
|
options.Issuer = new Uri("https://www.contoso.com/"); |
||||
|
options.ConfigurationEndpoint = new Uri("https://www.contoso.com/.well-known/openid-configuration"); |
||||
|
options.ClientId = "client_id"; |
||||
|
options.ConfigurationManager = new StaticConfigurationManager<OpenIddictConfiguration>(new OpenIddictConfiguration()); |
||||
|
options.SigningCredentials.Add(new SigningCredentials( |
||||
|
new SymmetricSecurityKey(new byte[32]), |
||||
|
SecurityAlgorithms.HmacSha256)); |
||||
|
|
||||
|
options.Handlers.Add(OpenIddictValidationHandlerDescriptor.CreateBuilder<ApplyIntrospectionRequestContext>() |
||||
|
.UseSingletonHandler<CustomIntrospectionHandler>().Build()); |
||||
|
|
||||
|
// Act
|
||||
|
var result = configuration.Validate(name: null, options); |
||||
|
|
||||
|
// Assert
|
||||
|
Assert.True(result.Succeeded); |
||||
|
} |
||||
|
|
||||
|
private static OpenIddictValidationOptions CreateBaseOptions() |
||||
|
=> new() |
||||
|
{ |
||||
|
TimeProvider = TimeProvider.System |
||||
|
}; |
||||
|
|
||||
|
private sealed class CustomIntrospectionHandler : IOpenIddictValidationHandler<ApplyIntrospectionRequestContext> |
||||
|
{ |
||||
|
public ValueTask HandleAsync(ApplyIntrospectionRequestContext context) => ValueTask.CompletedTask; |
||||
|
} |
||||
|
|
||||
|
private sealed class FakeTimeProvider : TimeProvider; |
||||
|
} |
||||
Loading…
Reference in new issue