diff --git a/src/OpenIddict.Abstractions/Resources/OpenIddictResources.resx b/src/OpenIddict.Abstractions/Resources/OpenIddictResources.resx index c1ec16fa..c1ca8120 100644 --- a/src/OpenIddict.Abstractions/Resources/OpenIddictResources.resx +++ b/src/OpenIddict.Abstractions/Resources/OpenIddictResources.resx @@ -441,7 +441,7 @@ Consider using 'options.AddSigningCredentials(SigningCredentials)' instead.{Locked} - One of the specified addresses is not valid. + Endpoint addresses must be valid URLs. {Locked} @@ -476,6 +476,10 @@ Consider using 'options.AddSigningCredentials(SigningCredentials)' instead.The verification endpoint must be enabled to use the device flow. {Locked} + + Endpoint addresses cannot start with '{0}'. + {Locked} + Reference tokens cannot be used when disabling token storage. {Locked} diff --git a/src/OpenIddict.Server/OpenIddictServerBuilder.cs b/src/OpenIddict.Server/OpenIddictServerBuilder.cs index 5a2f5456..8fb6aadc 100644 --- a/src/OpenIddict.Server/OpenIddictServerBuilder.cs +++ b/src/OpenIddict.Server/OpenIddictServerBuilder.cs @@ -1112,6 +1112,11 @@ namespace Microsoft.Extensions.DependencyInjection throw new ArgumentException(SR.GetResourceString(SR.ID1071), nameof(addresses)); } + if (addresses.Any(address => address.OriginalString.StartsWith("~", StringComparison.OrdinalIgnoreCase))) + { + throw new ArgumentException(SR.FormatID1080("~"), nameof(addresses)); + } + return Configure(options => { options.AuthorizationEndpointUris.Clear(); @@ -1155,6 +1160,11 @@ namespace Microsoft.Extensions.DependencyInjection throw new ArgumentException(SR.GetResourceString(SR.ID1071), nameof(addresses)); } + if (addresses.Any(address => address.OriginalString.StartsWith("~", StringComparison.OrdinalIgnoreCase))) + { + throw new ArgumentException(SR.FormatID1080("~"), nameof(addresses)); + } + return Configure(options => { options.ConfigurationEndpointUris.Clear(); @@ -1198,6 +1208,11 @@ namespace Microsoft.Extensions.DependencyInjection throw new ArgumentException(SR.GetResourceString(SR.ID1071), nameof(addresses)); } + if (addresses.Any(address => address.OriginalString.StartsWith("~", StringComparison.OrdinalIgnoreCase))) + { + throw new ArgumentException(SR.FormatID1080("~"), nameof(addresses)); + } + return Configure(options => { options.CryptographyEndpointUris.Clear(); @@ -1241,6 +1256,11 @@ namespace Microsoft.Extensions.DependencyInjection throw new ArgumentException(SR.GetResourceString(SR.ID1071), nameof(addresses)); } + if (addresses.Any(address => address.OriginalString.StartsWith("~", StringComparison.OrdinalIgnoreCase))) + { + throw new ArgumentException(SR.FormatID1080("~"), nameof(addresses)); + } + return Configure(options => { options.DeviceEndpointUris.Clear(); @@ -1284,6 +1304,11 @@ namespace Microsoft.Extensions.DependencyInjection throw new ArgumentException(SR.GetResourceString(SR.ID1071), nameof(addresses)); } + if (addresses.Any(address => address.OriginalString.StartsWith("~", StringComparison.OrdinalIgnoreCase))) + { + throw new ArgumentException(SR.FormatID1080("~"), nameof(addresses)); + } + return Configure(options => { options.IntrospectionEndpointUris.Clear(); @@ -1327,6 +1352,11 @@ namespace Microsoft.Extensions.DependencyInjection throw new ArgumentException(SR.GetResourceString(SR.ID1071), nameof(addresses)); } + if (addresses.Any(address => address.OriginalString.StartsWith("~", StringComparison.OrdinalIgnoreCase))) + { + throw new ArgumentException(SR.FormatID1080("~"), nameof(addresses)); + } + return Configure(options => { options.LogoutEndpointUris.Clear(); @@ -1370,6 +1400,11 @@ namespace Microsoft.Extensions.DependencyInjection throw new ArgumentException(SR.GetResourceString(SR.ID1071), nameof(addresses)); } + if (addresses.Any(address => address.OriginalString.StartsWith("~", StringComparison.OrdinalIgnoreCase))) + { + throw new ArgumentException(SR.FormatID1080("~"), nameof(addresses)); + } + return Configure(options => { options.RevocationEndpointUris.Clear(); @@ -1413,6 +1448,11 @@ namespace Microsoft.Extensions.DependencyInjection throw new ArgumentException(SR.GetResourceString(SR.ID1071), nameof(addresses)); } + if (addresses.Any(address => address.OriginalString.StartsWith("~", StringComparison.OrdinalIgnoreCase))) + { + throw new ArgumentException(SR.FormatID1080("~"), nameof(addresses)); + } + return Configure(options => { options.TokenEndpointUris.Clear(); @@ -1456,6 +1496,11 @@ namespace Microsoft.Extensions.DependencyInjection throw new ArgumentException(SR.GetResourceString(SR.ID1071), nameof(addresses)); } + if (addresses.Any(address => address.OriginalString.StartsWith("~", StringComparison.OrdinalIgnoreCase))) + { + throw new ArgumentException(SR.FormatID1080("~"), nameof(addresses)); + } + return Configure(options => { options.UserinfoEndpointUris.Clear(); @@ -1499,6 +1544,11 @@ namespace Microsoft.Extensions.DependencyInjection throw new ArgumentException(SR.GetResourceString(SR.ID1071), nameof(addresses)); } + if (addresses.Any(address => address.OriginalString.StartsWith("~", StringComparison.OrdinalIgnoreCase))) + { + throw new ArgumentException(SR.FormatID1080("~"), nameof(addresses)); + } + return Configure(options => { options.VerificationEndpointUris.Clear(); diff --git a/test/OpenIddict.Server.Tests/OpenIddictServerBuilderTests.cs b/test/OpenIddict.Server.Tests/OpenIddictServerBuilderTests.cs index 0118f2e0..7c53ab23 100644 --- a/test/OpenIddict.Server.Tests/OpenIddictServerBuilderTests.cs +++ b/test/OpenIddict.Server.Tests/OpenIddictServerBuilderTests.cs @@ -8,6 +8,7 @@ using Moq; using OpenIddict.Abstractions; using Xunit; using static OpenIddict.Server.OpenIddictServerEvents; +using SR = OpenIddict.Abstractions.OpenIddictResources; namespace OpenIddict.Server.Tests { @@ -541,363 +542,419 @@ namespace OpenIddict.Server.Tests } [Fact] - public void SetConfigurationEndpointUris_ThrowsExceptionWhenAddressesIsNull() + public void DisableScopeValidation_ScopeValidationIsDisabled() { // Arrange var services = CreateServices(); var builder = CreateBuilder(services); - // Act and assert - var exception = Assert.Throws(() => builder.SetConfigurationEndpointUris(addresses: null as Uri[])); - Assert.Equal("addresses", exception.ParamName); + // Act + builder.DisableScopeValidation(); + + var options = GetOptions(services); + + // Assert + Assert.True(options.DisableScopeValidation); } [Fact] - public void SetConfigurationEndpointUris_Strings_ThrowsExceptionWhenAddressesIsNull() + public void DisableSlidingRefreshTokenExpiration_SlidingExpirationIsDisabled() { // Arrange var services = CreateServices(); var builder = CreateBuilder(services); - // Act and assert - var exception = Assert.Throws(() => builder.SetConfigurationEndpointUris(addresses: null as string[])); - Assert.Equal("addresses", exception.ParamName); + // Act + builder.DisableSlidingRefreshTokenExpiration(); + + var options = GetOptions(services); + + // Assert + Assert.True(options.DisableSlidingRefreshTokenExpiration); } - [Theory] - [InlineData(@"C:\")] - public void SetConfigurationEndpointUris_ThrowsExceptionForUri(string uri) + [Fact] + public void DisableTokenStorage_TokenStorageIsDisabled() { // Arrange var services = CreateServices(); var builder = CreateBuilder(services); - // Act and assert - var exception = Assert.Throws(() => builder.SetConfigurationEndpointUris(new Uri(uri))); - Assert.Equal("addresses", exception.ParamName); - Assert.Contains("One of the specified addresses is not valid.", exception.Message); + // Act + builder.DisableTokenStorage(); + + var options = GetOptions(services); + + // Assert + Assert.True(options.DisableTokenStorage); } [Fact] - public void SetConfigurationEndpointUris_ClearsUris() + public void DisableAccessTokenEncryption_AccessTokenEncryptionIsDisabled() { // Arrange var services = CreateServices(); var builder = CreateBuilder(services); // Act - builder.SetConfigurationEndpointUris(Array.Empty()); + builder.DisableAccessTokenEncryption(); var options = GetOptions(services); // Assert - Assert.Empty(options.ConfigurationEndpointUris); + Assert.True(options.DisableAccessTokenEncryption); } [Fact] - public void SetConfigurationEndpointUris_AddsUri() + public void AddDeviceCodeFlow_AddsDeviceCodeGrantType() { // Arrange var services = CreateServices(); var builder = CreateBuilder(services); // Act - builder.SetConfigurationEndpointUris("http://localhost/endpoint-path"); + builder.AllowDeviceCodeFlow(); var options = GetOptions(services); // Assert - Assert.Contains(new Uri("http://localhost/endpoint-path"), options.ConfigurationEndpointUris); + Assert.Contains(OpenIddictConstants.GrantTypes.DeviceCode, options.GrantTypes); } [Fact] - public void SetDeviceEndpointUris_ThrowsExceptionWhenAddressesIsNull() + public void SetAuthorizationEndpointUris_ThrowsExceptionWhenAddressesIsNull() { // Arrange var services = CreateServices(); var builder = CreateBuilder(services); // Act and assert - var exception = Assert.Throws(() => builder.SetDeviceEndpointUris(addresses: null as Uri[])); + var exception = Assert.Throws(() => builder.SetAuthorizationEndpointUris(addresses: null as Uri[])); Assert.Equal("addresses", exception.ParamName); } [Fact] - public void SetDeviceEndpointUris_Strings_ThrowsExceptionWhenAddressesIsNull() + public void SetAuthorizationEndpointUris_Strings_ThrowsExceptionWhenAddressesIsNull() { // Arrange var services = CreateServices(); var builder = CreateBuilder(services); // Act and assert - var exception = Assert.Throws(() => builder.SetDeviceEndpointUris(addresses: null as string[])); + var exception = Assert.Throws(() => builder.SetAuthorizationEndpointUris(addresses: null as string[])); Assert.Equal("addresses", exception.ParamName); } [Theory] [InlineData(@"C:\")] - public void SetDeviceEndpointUris_ThrowsExceptionForUri(string uri) + public void SetAuthorizationEndpointUris_ThrowsExceptionForMalformedUri(string uri) { // Arrange var services = CreateServices(); var builder = CreateBuilder(services); // Act and assert - var exception = Assert.Throws(() => builder.SetDeviceEndpointUris(new Uri(uri))); + var exception = Assert.Throws(() => builder.SetAuthorizationEndpointUris(new Uri(uri))); Assert.Equal("addresses", exception.ParamName); - Assert.Contains("One of the specified addresses is not valid.", exception.Message); + Assert.Contains(SR.GetResourceString(SR.ID1071), exception.Message); } - [Fact] - public void SetDeviceEndpointUris_ClearsUris() + [Theory] + [InlineData("~/path")] + public void SetAuthorizationEndpointUris_ThrowsExceptionForInvalidRelativeUri(string uri) { // Arrange var services = CreateServices(); var builder = CreateBuilder(services); - // Act - builder.SetDeviceEndpointUris(Array.Empty()); - - var options = GetOptions(services); - - // Assert - Assert.Empty(options.DeviceEndpointUris); + // Act and assert + var exception = Assert.Throws(() => builder.SetAuthorizationEndpointUris(new Uri(uri, UriKind.RelativeOrAbsolute))); + Assert.Equal("addresses", exception.ParamName); + Assert.Contains(SR.FormatID1080("~"), exception.Message); } [Fact] - public void SetDeviceEndpointUris_AddsUri() + public void SetAuthorizationEndpointUris_ClearsUris() { // Arrange var services = CreateServices(); var builder = CreateBuilder(services); // Act - builder.SetDeviceEndpointUris("http://localhost/endpoint-path"); + builder.SetAuthorizationEndpointUris(Array.Empty()); var options = GetOptions(services); // Assert - Assert.Contains(new Uri("http://localhost/endpoint-path"), options.DeviceEndpointUris); + Assert.Empty(options.AuthorizationEndpointUris); } [Fact] - public void AddDeviceCodeFlow_AddsDeviceCodeGrantType() + public void SetAuthorizationEndpointUris_AddsUri() { // Arrange var services = CreateServices(); var builder = CreateBuilder(services); // Act - builder.AllowDeviceCodeFlow(); + builder.SetAuthorizationEndpointUris("http://localhost/endpoint-path"); var options = GetOptions(services); // Assert - Assert.Contains(OpenIddictConstants.GrantTypes.DeviceCode, options.GrantTypes); + Assert.Contains(new Uri("http://localhost/endpoint-path"), options.AuthorizationEndpointUris); } [Fact] - public void SetCryptographyEndpointUris_ThrowsExceptionWhenAddressesIsNull() + public void SetConfigurationEndpointUris_ThrowsExceptionWhenAddressesIsNull() { // Arrange var services = CreateServices(); var builder = CreateBuilder(services); // Act and assert - var exception = Assert.Throws(() => builder.SetCryptographyEndpointUris(addresses: null as Uri[])); + var exception = Assert.Throws(() => builder.SetConfigurationEndpointUris(addresses: null as Uri[])); Assert.Equal("addresses", exception.ParamName); } [Fact] - public void SetCryptographyEndpointUris_Strings_ThrowsExceptionWhenAddressesIsNull() + public void SetConfigurationEndpointUris_Strings_ThrowsExceptionWhenAddressesIsNull() { // Arrange var services = CreateServices(); var builder = CreateBuilder(services); // Act and assert - var exception = Assert.Throws(() => builder.SetCryptographyEndpointUris(addresses: null as string[])); + var exception = Assert.Throws(() => builder.SetConfigurationEndpointUris(addresses: null as string[])); Assert.Equal("addresses", exception.ParamName); } [Theory] [InlineData(@"C:\")] - public void SetCryptographyEndpointUris_ThrowsExceptionForUri(string uri) + public void SetConfigurationEndpointUris_ThrowsExceptionForMalformedUri(string uri) { // Arrange var services = CreateServices(); var builder = CreateBuilder(services); // Act and assert - var exception = Assert.Throws(() => builder.SetCryptographyEndpointUris(new Uri(uri))); + var exception = Assert.Throws(() => builder.SetConfigurationEndpointUris(new Uri(uri))); Assert.Equal("addresses", exception.ParamName); - Assert.Contains("One of the specified addresses is not valid.", exception.Message); + Assert.Contains(SR.GetResourceString(SR.ID1071), exception.Message); + } + + [Theory] + [InlineData("~/path")] + public void SetConfigurationEndpointUris_ThrowsExceptionForInvalidRelativeUri(string uri) + { + // Arrange + var services = CreateServices(); + var builder = CreateBuilder(services); + + // Act and assert + var exception = Assert.Throws(() => builder.SetConfigurationEndpointUris(new Uri(uri, UriKind.RelativeOrAbsolute))); + Assert.Equal("addresses", exception.ParamName); + Assert.Contains(SR.FormatID1080("~"), exception.Message); } [Fact] - public void SetCryptographyEndpointUris_ClearsUris() + public void SetConfigurationEndpointUris_ClearsUris() { // Arrange var services = CreateServices(); var builder = CreateBuilder(services); // Act - builder.SetCryptographyEndpointUris(Array.Empty()); + builder.SetConfigurationEndpointUris(Array.Empty()); var options = GetOptions(services); // Assert - Assert.Empty(options.CryptographyEndpointUris); + Assert.Empty(options.ConfigurationEndpointUris); } [Fact] - public void SetCryptographyEndpointUris_AddsUri() + public void SetConfigurationEndpointUris_AddsUri() { // Arrange var services = CreateServices(); var builder = CreateBuilder(services); // Act - builder.SetCryptographyEndpointUris("http://localhost/endpoint-path"); + builder.SetConfigurationEndpointUris("http://localhost/endpoint-path"); var options = GetOptions(services); // Assert - Assert.Contains(new Uri("http://localhost/endpoint-path"), options.CryptographyEndpointUris); + Assert.Contains(new Uri("http://localhost/endpoint-path"), options.ConfigurationEndpointUris); } [Fact] - public void DisableScopeValidation_ScopeValidationIsDisabled() + public void SetCryptographyEndpointUris_ThrowsExceptionWhenAddressesIsNull() { // Arrange var services = CreateServices(); var builder = CreateBuilder(services); - // Act - builder.DisableScopeValidation(); + // Act and assert + var exception = Assert.Throws(() => builder.SetCryptographyEndpointUris(addresses: null as Uri[])); + Assert.Equal("addresses", exception.ParamName); + } - var options = GetOptions(services); + [Fact] + public void SetCryptographyEndpointUris_Strings_ThrowsExceptionWhenAddressesIsNull() + { + // Arrange + var services = CreateServices(); + var builder = CreateBuilder(services); - // Assert - Assert.True(options.DisableScopeValidation); + // Act and assert + var exception = Assert.Throws(() => builder.SetCryptographyEndpointUris(addresses: null as string[])); + Assert.Equal("addresses", exception.ParamName); } - [Fact] - public void DisableSlidingRefreshTokenExpiration_SlidingExpirationIsDisabled() + [Theory] + [InlineData(@"C:\")] + public void SetCryptographyEndpointUris_ThrowsExceptionForMalformedUri(string uri) { // Arrange var services = CreateServices(); var builder = CreateBuilder(services); - // Act - builder.DisableSlidingRefreshTokenExpiration(); + // Act and assert + var exception = Assert.Throws(() => builder.SetCryptographyEndpointUris(new Uri(uri))); + Assert.Equal("addresses", exception.ParamName); + Assert.Contains(SR.GetResourceString(SR.ID1071), exception.Message); + } - var options = GetOptions(services); + [Theory] + [InlineData("~/path")] + public void SetCryptographyEndpointUris_ThrowsExceptionForInvalidRelativeUri(string uri) + { + // Arrange + var services = CreateServices(); + var builder = CreateBuilder(services); - // Assert - Assert.True(options.DisableSlidingRefreshTokenExpiration); + // Act and assert + var exception = Assert.Throws(() => builder.SetCryptographyEndpointUris(new Uri(uri, UriKind.RelativeOrAbsolute))); + Assert.Equal("addresses", exception.ParamName); + Assert.Contains(SR.FormatID1080("~"), exception.Message); } [Fact] - public void DisableTokenStorage_TokenStorageIsDisabled() + public void SetCryptographyEndpointUris_ClearsUris() { // Arrange var services = CreateServices(); var builder = CreateBuilder(services); // Act - builder.DisableTokenStorage(); + builder.SetCryptographyEndpointUris(Array.Empty()); var options = GetOptions(services); // Assert - Assert.True(options.DisableTokenStorage); + Assert.Empty(options.CryptographyEndpointUris); } [Fact] - public void DisableAccessTokenEncryption_AccessTokenEncryptionIsDisabled() + public void SetCryptographyEndpointUris_AddsUri() { // Arrange var services = CreateServices(); var builder = CreateBuilder(services); // Act - builder.DisableAccessTokenEncryption(); + builder.SetCryptographyEndpointUris("http://localhost/endpoint-path"); var options = GetOptions(services); // Assert - Assert.True(options.DisableAccessTokenEncryption); + Assert.Contains(new Uri("http://localhost/endpoint-path"), options.CryptographyEndpointUris); } [Fact] - public void SetAuthorizationEndpointUris_ThrowsExceptionWhenAddressesIsNull() + public void SetDeviceEndpointUris_ThrowsExceptionWhenAddressesIsNull() { // Arrange var services = CreateServices(); var builder = CreateBuilder(services); // Act and assert - var exception = Assert.Throws(() => builder.SetAuthorizationEndpointUris(addresses: null as Uri[])); + var exception = Assert.Throws(() => builder.SetDeviceEndpointUris(addresses: null as Uri[])); Assert.Equal("addresses", exception.ParamName); } [Fact] - public void SetAuthorizationEndpointUris_Strings_ThrowsExceptionWhenAddressesIsNull() + public void SetDeviceEndpointUris_Strings_ThrowsExceptionWhenAddressesIsNull() { // Arrange var services = CreateServices(); var builder = CreateBuilder(services); // Act and assert - var exception = Assert.Throws(() => builder.SetAuthorizationEndpointUris(addresses: null as string[])); + var exception = Assert.Throws(() => builder.SetDeviceEndpointUris(addresses: null as string[])); Assert.Equal("addresses", exception.ParamName); } [Theory] [InlineData(@"C:\")] - public void SetAuthorizationEndpointUris_ThrowsExceptionForUri(string uri) + public void SetDeviceEndpointUris_ThrowsExceptionForMalformedUri(string uri) { // Arrange var services = CreateServices(); var builder = CreateBuilder(services); // Act and assert - var exception = Assert.Throws(() => builder.SetAuthorizationEndpointUris(new Uri(uri))); + var exception = Assert.Throws(() => builder.SetDeviceEndpointUris(new Uri(uri))); + Assert.Equal("addresses", exception.ParamName); + Assert.Contains(SR.GetResourceString(SR.ID1071), exception.Message); + } + + [Theory] + [InlineData("~/path")] + public void SetDeviceEndpointUris_ThrowsExceptionForInvalidRelativeUri(string uri) + { + // Arrange + var services = CreateServices(); + var builder = CreateBuilder(services); + + // Act and assert + var exception = Assert.Throws(() => builder.SetDeviceEndpointUris(new Uri(uri, UriKind.RelativeOrAbsolute))); Assert.Equal("addresses", exception.ParamName); - Assert.Contains("One of the specified addresses is not valid.", exception.Message); + Assert.Contains(SR.FormatID1080("~"), exception.Message); } [Fact] - public void SetAuthorizationEndpointUris_ClearsUris() + public void SetDeviceEndpointUris_ClearsUris() { // Arrange var services = CreateServices(); var builder = CreateBuilder(services); // Act - builder.SetAuthorizationEndpointUris(Array.Empty()); + builder.SetDeviceEndpointUris(Array.Empty()); var options = GetOptions(services); // Assert - Assert.Empty(options.AuthorizationEndpointUris); + Assert.Empty(options.DeviceEndpointUris); } [Fact] - public void SetAuthorizationEndpointUris_AddsUri() + public void SetDeviceEndpointUris_AddsUri() { // Arrange var services = CreateServices(); var builder = CreateBuilder(services); // Act - builder.SetAuthorizationEndpointUris("http://localhost/endpoint-path"); + builder.SetDeviceEndpointUris("http://localhost/endpoint-path"); var options = GetOptions(services); // Assert - Assert.Contains(new Uri("http://localhost/endpoint-path"), options.AuthorizationEndpointUris); + Assert.Contains(new Uri("http://localhost/endpoint-path"), options.DeviceEndpointUris); } [Fact] @@ -926,7 +983,7 @@ namespace OpenIddict.Server.Tests [Theory] [InlineData(@"C:\")] - public void SetIntrospectionEndpointUris_ThrowsExceptionForUri(string uri) + public void SetIntrospectionEndpointUris_ThrowsExceptionForMalformedUri(string uri) { // Arrange var services = CreateServices(); @@ -935,7 +992,21 @@ namespace OpenIddict.Server.Tests // Act and assert var exception = Assert.Throws(() => builder.SetIntrospectionEndpointUris(new Uri(uri))); Assert.Equal("addresses", exception.ParamName); - Assert.Contains("One of the specified addresses is not valid.", exception.Message); + Assert.Contains(SR.GetResourceString(SR.ID1071), exception.Message); + } + + [Theory] + [InlineData("~/path")] + public void SetIntrospectionEndpointUris_ThrowsExceptionForInvalidRelativeUri(string uri) + { + // Arrange + var services = CreateServices(); + var builder = CreateBuilder(services); + + // Act and assert + var exception = Assert.Throws(() => builder.SetIntrospectionEndpointUris(new Uri(uri, UriKind.RelativeOrAbsolute))); + Assert.Equal("addresses", exception.ParamName); + Assert.Contains(SR.FormatID1080("~"), exception.Message); } [Fact] @@ -996,7 +1067,7 @@ namespace OpenIddict.Server.Tests [Theory] [InlineData(@"C:\")] - public void SetLogoutEndpointUris_ThrowsExceptionForUri(string uri) + public void SetLogoutEndpointUris_ThrowsExceptionForMalformedUri(string uri) { // Arrange var services = CreateServices(); @@ -1005,7 +1076,21 @@ namespace OpenIddict.Server.Tests // Act and assert var exception = Assert.Throws(() => builder.SetLogoutEndpointUris(new Uri(uri))); Assert.Equal("addresses", exception.ParamName); - Assert.Contains("One of the specified addresses is not valid.", exception.Message); + Assert.Contains(SR.GetResourceString(SR.ID1071), exception.Message); + } + + [Theory] + [InlineData("~/path")] + public void SetLogoutEndpointUris_ThrowsExceptionForInvalidRelativeUri(string uri) + { + // Arrange + var services = CreateServices(); + var builder = CreateBuilder(services); + + // Act and assert + var exception = Assert.Throws(() => builder.SetLogoutEndpointUris(new Uri(uri, UriKind.RelativeOrAbsolute))); + Assert.Equal("addresses", exception.ParamName); + Assert.Contains(SR.FormatID1080("~"), exception.Message); } [Fact] @@ -1066,7 +1151,7 @@ namespace OpenIddict.Server.Tests [Theory] [InlineData(@"C:\")] - public void SetRevocationEndpointUris_ThrowsExceptionForUri(string uri) + public void SetRevocationEndpointUris_ThrowsExceptionForMalformedUri(string uri) { // Arrange var services = CreateServices(); @@ -1075,7 +1160,21 @@ namespace OpenIddict.Server.Tests // Act and assert var exception = Assert.Throws(() => builder.SetRevocationEndpointUris(new Uri(uri))); Assert.Equal("addresses", exception.ParamName); - Assert.Contains("One of the specified addresses is not valid.", exception.Message); + Assert.Contains(SR.GetResourceString(SR.ID1071), exception.Message); + } + + [Theory] + [InlineData("~/path")] + public void SetRevocationEndpointUris_ThrowsExceptionForInvalidRelativeUri(string uri) + { + // Arrange + var services = CreateServices(); + var builder = CreateBuilder(services); + + // Act and assert + var exception = Assert.Throws(() => builder.SetRevocationEndpointUris(new Uri(uri, UriKind.RelativeOrAbsolute))); + Assert.Equal("addresses", exception.ParamName); + Assert.Contains(SR.FormatID1080("~"), exception.Message); } [Fact] @@ -1136,7 +1235,7 @@ namespace OpenIddict.Server.Tests [Theory] [InlineData(@"C:\")] - public void SetTokenEndpointUris_ThrowsExceptionForUri(string uri) + public void SetTokenEndpointUris_ThrowsExceptionForMalformedUri(string uri) { // Arrange var services = CreateServices(); @@ -1145,7 +1244,21 @@ namespace OpenIddict.Server.Tests // Act and assert var exception = Assert.Throws(() => builder.SetTokenEndpointUris(new Uri(uri))); Assert.Equal("addresses", exception.ParamName); - Assert.Contains("One of the specified addresses is not valid.", exception.Message); + Assert.Contains(SR.GetResourceString(SR.ID1071), exception.Message); + } + + [Theory] + [InlineData("~/path")] + public void SetTokenEndpointUris_ThrowsExceptionForInvalidRelativeUri(string uri) + { + // Arrange + var services = CreateServices(); + var builder = CreateBuilder(services); + + // Act and assert + var exception = Assert.Throws(() => builder.SetTokenEndpointUris(new Uri(uri, UriKind.RelativeOrAbsolute))); + Assert.Equal("addresses", exception.ParamName); + Assert.Contains(SR.FormatID1080("~"), exception.Message); } [Fact] @@ -1206,7 +1319,7 @@ namespace OpenIddict.Server.Tests [Theory] [InlineData(@"C:\")] - public void SetUserinfoEndpointUris_ThrowsExceptionForUri(string uri) + public void SetUserinfoEndpointUris_ThrowsExceptionForMalformedUri(string uri) { // Arrange var services = CreateServices(); @@ -1215,7 +1328,21 @@ namespace OpenIddict.Server.Tests // Act and assert var exception = Assert.Throws(() => builder.SetUserinfoEndpointUris(new Uri(uri))); Assert.Equal("addresses", exception.ParamName); - Assert.Contains("One of the specified addresses is not valid.", exception.Message); + Assert.Contains(SR.GetResourceString(SR.ID1071), exception.Message); + } + + [Theory] + [InlineData("~/path")] + public void SetUserinfoEndpointUris_ThrowsExceptionForInvalidRelativeUri(string uri) + { + // Arrange + var services = CreateServices(); + var builder = CreateBuilder(services); + + // Act and assert + var exception = Assert.Throws(() => builder.SetUserinfoEndpointUris(new Uri(uri, UriKind.RelativeOrAbsolute))); + Assert.Equal("addresses", exception.ParamName); + Assert.Contains(SR.FormatID1080("~"), exception.Message); } [Fact] @@ -1276,7 +1403,7 @@ namespace OpenIddict.Server.Tests [Theory] [InlineData(@"C:\")] - public void SetVerificationEndpointUris_ThrowsExceptionForUri(string uri) + public void SetVerificationEndpointUris_ThrowsExceptionForMalformedUri(string uri) { // Arrange var services = CreateServices(); @@ -1285,7 +1412,21 @@ namespace OpenIddict.Server.Tests // Act and assert var exception = Assert.Throws(() => builder.SetVerificationEndpointUris(new Uri(uri))); Assert.Equal("addresses", exception.ParamName); - Assert.Contains("One of the specified addresses is not valid.", exception.Message); + Assert.Contains(SR.GetResourceString(SR.ID1071), exception.Message); + } + + [Theory] + [InlineData("~/path")] + public void SetVerificationEndpointUris_ThrowsExceptionForInvalidRelativeUri(string uri) + { + // Arrange + var services = CreateServices(); + var builder = CreateBuilder(services); + + // Act and assert + var exception = Assert.Throws(() => builder.SetVerificationEndpointUris(new Uri(uri, UriKind.RelativeOrAbsolute))); + Assert.Equal("addresses", exception.ParamName); + Assert.Contains(SR.FormatID1080("~"), exception.Message); } [Fact]