Browse Source

Implement client authentication support for the PAR endpoint

pull/2342/head
Kévin Chalet 1 year ago
parent
commit
91a68c161a
  1. 3
      sandbox/OpenIddict.Sandbox.AspNetCore.Server/Worker.cs
  2. 142
      src/OpenIddict.Client.SystemNetHttp/OpenIddictClientSystemNetHttpHandlers.cs
  3. 13
      src/OpenIddict.Client/OpenIddictClientHandlers.cs
  4. 17
      src/OpenIddict.Server/OpenIddictServerHandlers.cs
  5. 175
      test/OpenIddict.Server.IntegrationTests/OpenIddictServerIntegrationTests.Authentication.cs

3
sandbox/OpenIddict.Sandbox.AspNetCore.Server/Worker.cs

@ -139,7 +139,6 @@ public class Worker : IHostedService
{ {
ApplicationType = ApplicationTypes.Web, ApplicationType = ApplicationTypes.Web,
ClientId = "mvc", ClientId = "mvc",
ClientSecret = "901564A5-E7FE-42CB-B10D-61EF6A8F3654",
ClientType = ClientTypes.Confidential, ClientType = ClientTypes.Confidential,
ConsentType = ConsentTypes.Systematic, ConsentType = ConsentTypes.Systematic,
DisplayName = "MVC client application", DisplayName = "MVC client application",
@ -165,6 +164,8 @@ public class Worker : IHostedService
""")) """))
} }
}, },
#else
ClientSecret = "901564A5-E7FE-42CB-B10D-61EF6A8F3654",
#endif #endif
RedirectUris = RedirectUris =
{ {

142
src/OpenIddict.Client.SystemNetHttp/OpenIddictClientSystemNetHttpHandlers.cs

@ -36,6 +36,7 @@ public static partial class OpenIddictClientSystemNetHttpHandlers
* Challenge processing: * Challenge processing:
*/ */
AttachNonDefaultDeviceAuthorizationEndpointClientAuthenticationMethod.Descriptor, AttachNonDefaultDeviceAuthorizationEndpointClientAuthenticationMethod.Descriptor,
AttachNonDefaultPushedAuthorizationEndpointClientAuthenticationMethod.Descriptor,
/* /*
* Introspection processing: * Introspection processing:
@ -290,7 +291,15 @@ public static partial class OpenIddictClientSystemNetHttpHandlers
_ => context.Options.ClientAuthenticationMethods.Intersect(context.Registration.ClientAuthenticationMethods, StringComparer.Ordinal).ToList() _ => context.Options.ClientAuthenticationMethods.Intersect(context.Registration.ClientAuthenticationMethods, StringComparer.Ordinal).ToList()
}, },
Server: context.Configuration.DeviceAuthorizationEndpointAuthMethodsSupported) switch // Note: if the authorization server doesn't support the OpenIddict-specific
// "device_authorization_request_endpoint_auth_methods_supported" node,
// fall back to the "token_endpoint_auth_methods_supported" node,
// which is the same logic as for the pushed authorization endpoint.
Server: context.Configuration.DeviceAuthorizationEndpointAuthMethodsSupported.Count switch
{
0 => context.Configuration.TokenEndpointAuthMethodsSupported,
_ => context.Configuration.DeviceAuthorizationEndpointAuthMethodsSupported,
}) switch
{ {
// If a TLS client authentication certificate could be resolved and both the // If a TLS client authentication certificate could be resolved and both the
// client and the server explicitly support tls_client_auth, always prefer it. // client and the server explicitly support tls_client_auth, always prefer it.
@ -365,6 +374,137 @@ public static partial class OpenIddictClientSystemNetHttpHandlers
} }
} }
/// <summary>
/// Contains the logic responsible for negotiating the best pushed authorization endpoint
/// client authentication method supported by both the client and the authorization server.
/// </summary>
public sealed class AttachNonDefaultPushedAuthorizationEndpointClientAuthenticationMethod : IOpenIddictClientHandler<ProcessChallengeContext>
{
private readonly IOptionsMonitor<OpenIddictClientSystemNetHttpOptions> _options;
public AttachNonDefaultPushedAuthorizationEndpointClientAuthenticationMethod(
IOptionsMonitor<OpenIddictClientSystemNetHttpOptions> options)
=> _options = options ?? throw new ArgumentNullException(nameof(options));
/// <summary>
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictClientHandlerDescriptor Descriptor { get; }
= OpenIddictClientHandlerDescriptor.CreateBuilder<ProcessChallengeContext>()
.AddFilter<RequirePushedAuthorizationRequest>()
.UseSingletonHandler<AttachNonDefaultPushedAuthorizationEndpointClientAuthenticationMethod>()
.SetOrder(AttachPushedAuthorizationEndpointClientAuthenticationMethod.Descriptor.Order - 500)
.SetType(OpenIddictClientHandlerType.BuiltIn)
.Build();
/// <inheritdoc/>
public ValueTask HandleAsync(ProcessChallengeContext context)
{
if (context is null)
{
throw new ArgumentNullException(nameof(context));
}
// If an explicit client authentication method was attached, don't overwrite it.
if (!string.IsNullOrEmpty(context.PushedAuthorizationEndpointClientAuthenticationMethod))
{
return default;
}
context.PushedAuthorizationEndpointClientAuthenticationMethod = (
// Note: if client authentication methods are explicitly listed in the client registration, only use
// the client authentication methods that are both listed and enabled in the global client options.
// Otherwise, always default to the client authentication methods that have been enabled globally.
Client: context.Registration.ClientAuthenticationMethods.Count switch
{
0 => context.Options.ClientAuthenticationMethods as ICollection<string>,
_ => context.Options.ClientAuthenticationMethods.Intersect(context.Registration.ClientAuthenticationMethods, StringComparer.Ordinal).ToList()
},
// Note: if the authorization server doesn't support the OpenIddict-specific
// "pushed_authorization_request_endpoint_auth_methods_supported" node, fall back to
// the "token_endpoint_auth_methods_supported" node, as required by the specification.
//
// See https://datatracker.ietf.org/doc/html/rfc9126#section-2 for more information.
Server: context.Configuration.PushedAuthorizationEndpointAuthMethodsSupported.Count switch
{
0 => context.Configuration.TokenEndpointAuthMethodsSupported,
_ => context.Configuration.PushedAuthorizationEndpointAuthMethodsSupported,
}) switch
{
// If a TLS client authentication certificate could be resolved and both the
// client and the server explicitly support tls_client_auth, always prefer it.
({ Count: > 0 } client, { Count: > 0 } server) when
client.Contains(ClientAuthenticationMethods.TlsClientAuth) &&
server.Contains(ClientAuthenticationMethods.TlsClientAuth) &&
(context.Configuration.MtlsPushedAuthorizationEndpoint ?? context.Configuration.PushedAuthorizationEndpoint) is Uri endpoint &&
string.Equals(endpoint.Scheme, Uri.UriSchemeHttps, StringComparison.OrdinalIgnoreCase) &&
_options.CurrentValue.TlsClientAuthenticationCertificateSelector(context.Registration) is not null
=> ClientAuthenticationMethods.TlsClientAuth,
// If a self-signed TLS client authentication certificate could be resolved and both
// the client and the server explicitly support self_signed_tls_client_auth, use it.
({ Count: > 0 } client, { Count: > 0 } server) when
client.Contains(ClientAuthenticationMethods.SelfSignedTlsClientAuth) &&
server.Contains(ClientAuthenticationMethods.SelfSignedTlsClientAuth) &&
(context.Configuration.MtlsPushedAuthorizationEndpoint ?? context.Configuration.PushedAuthorizationEndpoint) is Uri endpoint &&
string.Equals(endpoint.Scheme, Uri.UriSchemeHttps, StringComparison.OrdinalIgnoreCase) &&
_options.CurrentValue.SelfSignedTlsClientAuthenticationCertificateSelector(context.Registration) is not null
=> ClientAuthenticationMethods.SelfSignedTlsClientAuth,
// If at least one asymmetric signing key was attached to the client registration
// and both the client and the server explicitly support private_key_jwt, use it.
({ Count: > 0 } client, { Count: > 0 } server) when
client.Contains(ClientAuthenticationMethods.PrivateKeyJwt) &&
server.Contains(ClientAuthenticationMethods.PrivateKeyJwt) &&
context.Registration.SigningCredentials.Exists(static credentials => credentials.Key is AsymmetricSecurityKey)
=> ClientAuthenticationMethods.PrivateKeyJwt,
// If a client secret was attached to the client registration and both the client and
// the server explicitly support client_secret_post, prefer it to basic authentication.
({ Count: > 0 } client, { Count: > 0 } server) when !string.IsNullOrEmpty(context.Registration.ClientSecret) &&
client.Contains(ClientAuthenticationMethods.ClientSecretPost) &&
server.Contains(ClientAuthenticationMethods.ClientSecretPost)
=> ClientAuthenticationMethods.ClientSecretPost,
// The OAuth 2.0 specification recommends sending the client credentials using basic authentication.
// However, this authentication method is known to have severe compatibility/interoperability issues:
//
// - While restricted to clients that have been given a secret (i.e confidential clients) by the
// specification, basic authentication is also sometimes required by server implementations for
// public clients that don't have a client secret: in this case, an empty password is used and
// the client identifier is sent alone in the Authorization header (instead of being sent using
// the standard "client_id" parameter present in the request body).
//
// - While the OAuth 2.0 specification requires that the client credentials be formURL-encoded
// before being base64-encoded, many implementations are known to implement a non-standard
// encoding scheme, where neither the client_id nor the client_secret are formURL-encoded.
//
// To guarantee that the OpenIddict implementation can be used with most servers implementions,
// basic authentication is only used when a client secret is present and the server configuration
// doesn't list any supported client authentication method or doesn't support client_secret_post.
//
// If client_secret_post is not listed or if the server returned an empty methods list,
// client_secret_basic is always used, as it MUST be implemented by all OAuth 2.0 servers.
//
// See https://tools.ietf.org/html/rfc8414#section-2
// and https://tools.ietf.org/html/rfc6749#section-2.3.1 for more information.
({ Count: > 0 } client, { Count: > 0 } server) when !string.IsNullOrEmpty(context.Registration.ClientSecret) &&
client.Contains(ClientAuthenticationMethods.ClientSecretBasic) &&
server.Contains(ClientAuthenticationMethods.ClientSecretBasic)
=> ClientAuthenticationMethods.ClientSecretBasic,
({ Count: > 0 } client, { Count: 0 }) when !string.IsNullOrEmpty(context.Registration.ClientSecret) &&
client.Contains(ClientAuthenticationMethods.ClientSecretBasic)
=> ClientAuthenticationMethods.ClientSecretBasic,
_ => null
};
return default;
}
}
/// <summary> /// <summary>
/// Contains the logic responsible for negotiating the best introspection endpoint client /// Contains the logic responsible for negotiating the best introspection endpoint client
/// authentication method supported by both the client and the authorization server. /// authentication method supported by both the client and the authorization server.

13
src/OpenIddict.Client/OpenIddictClientHandlers.cs

@ -5847,7 +5847,15 @@ public static partial class OpenIddictClientHandlers
_ => context.Options.ClientAuthenticationMethods.Intersect(context.Registration.ClientAuthenticationMethods, StringComparer.Ordinal).ToList() _ => context.Options.ClientAuthenticationMethods.Intersect(context.Registration.ClientAuthenticationMethods, StringComparer.Ordinal).ToList()
}, },
Server: context.Configuration.DeviceAuthorizationEndpointAuthMethodsSupported) switch // Note: if the authorization server doesn't support the OpenIddict-specific
// "device_authorization_request_endpoint_auth_methods_supported" node,
// fall back to the "token_endpoint_auth_methods_supported" node,
// which is the same logic as for the pushed authorization endpoint.
Server: context.Configuration.DeviceAuthorizationEndpointAuthMethodsSupported.Count switch
{
0 => context.Configuration.TokenEndpointAuthMethodsSupported,
_ => context.Configuration.DeviceAuthorizationEndpointAuthMethodsSupported,
}) switch
{ {
// If at least one signing key was attached to the client registration and both // If at least one signing key was attached to the client registration and both
// the client and the server explicitly support private_key_jwt, always prefer it. // the client and the server explicitly support private_key_jwt, always prefer it.
@ -6163,9 +6171,8 @@ public static partial class OpenIddictClientHandlers
/// </summary> /// </summary>
public static OpenIddictClientHandlerDescriptor Descriptor { get; } public static OpenIddictClientHandlerDescriptor Descriptor { get; }
= OpenIddictClientHandlerDescriptor.CreateBuilder<ProcessChallengeContext>() = OpenIddictClientHandlerDescriptor.CreateBuilder<ProcessChallengeContext>()
.AddFilter<RequireDeviceAuthorizationRequest>()
.UseSingletonHandler<EvaluateGeneratedChallengeClientAssertion>() .UseSingletonHandler<EvaluateGeneratedChallengeClientAssertion>()
.SetOrder(AttachDeviceAuthorizationRequestParameters.Descriptor.Order + 1_000) .SetOrder(AttachPushedAuthorizationRequestParameters.Descriptor.Order + 1_000)
.SetType(OpenIddictClientHandlerType.BuiltIn) .SetType(OpenIddictClientHandlerType.BuiltIn)
.Build(); .Build();

17
src/OpenIddict.Server/OpenIddictServerHandlers.cs

@ -332,7 +332,8 @@ public static partial class OpenIddictServerHandlers
// By default, client assertions are not required, but they are extracted and validated if // By default, client assertions are not required, but they are extracted and validated if
// present and invalid client assertions are always automatically rejected by OpenIddict. // present and invalid client assertions are always automatically rejected by OpenIddict.
OpenIddictServerEndpointType.DeviceAuthorization or OpenIddictServerEndpointType.Introspection or OpenIddictServerEndpointType.DeviceAuthorization or OpenIddictServerEndpointType.Introspection or
OpenIddictServerEndpointType.Revocation or OpenIddictServerEndpointType.Token OpenIddictServerEndpointType.PushedAuthorization or OpenIddictServerEndpointType.Revocation or
OpenIddictServerEndpointType.Token
=> (true, false, true, true), => (true, false, true, true),
_ => (false, false, false, false) _ => (false, false, false, false)
@ -483,7 +484,8 @@ public static partial class OpenIddictServerHandlers
(context.ClientAssertion, context.ClientAssertionType) = context.EndpointType switch (context.ClientAssertion, context.ClientAssertionType) = context.EndpointType switch
{ {
OpenIddictServerEndpointType.DeviceAuthorization or OpenIddictServerEndpointType.Introspection or OpenIddictServerEndpointType.DeviceAuthorization or OpenIddictServerEndpointType.Introspection or
OpenIddictServerEndpointType.Revocation or OpenIddictServerEndpointType.Token OpenIddictServerEndpointType.PushedAuthorization or OpenIddictServerEndpointType.Revocation or
OpenIddictServerEndpointType.Token
when context.ExtractClientAssertion when context.ExtractClientAssertion
=> (context.Request.ClientAssertion, context.Request.ClientAssertionType), => (context.Request.ClientAssertion, context.Request.ClientAssertionType),
@ -1032,6 +1034,12 @@ public static partial class OpenIddictServerHandlers
case OpenIddictServerEndpointType.Revocation when context.Options.AcceptAnonymousClients: case OpenIddictServerEndpointType.Revocation when context.Options.AcceptAnonymousClients:
case OpenIddictServerEndpointType.Token when context.Options.AcceptAnonymousClients: case OpenIddictServerEndpointType.Token when context.Options.AcceptAnonymousClients:
return; return;
// Note: despite being conceptually similar to the token endpoint, the pushed authorization
// endpoint deliberately doesn't allow anonymous clients, as a client_id is always required
// for both regular authorization requests and pushed authorization requests.
//
// See https://datatracker.ietf.org/doc/html/rfc9126#section-2.1 for more information.
} }
context.Logger.LogInformation(6220, SR.GetResourceString(SR.ID6220), Parameters.ClientId); context.Logger.LogInformation(6220, SR.GetResourceString(SR.ID6220), Parameters.ClientId);
@ -1063,7 +1071,8 @@ public static partial class OpenIddictServerHandlers
{ {
// For non-interactive endpoints, return "invalid_client" instead of "invalid_request". // For non-interactive endpoints, return "invalid_client" instead of "invalid_request".
OpenIddictServerEndpointType.DeviceAuthorization or OpenIddictServerEndpointType.Introspection or OpenIddictServerEndpointType.DeviceAuthorization or OpenIddictServerEndpointType.Introspection or
OpenIddictServerEndpointType.Revocation or OpenIddictServerEndpointType.Token OpenIddictServerEndpointType.PushedAuthorization or OpenIddictServerEndpointType.Revocation or
OpenIddictServerEndpointType.Token
=> Errors.InvalidClient, => Errors.InvalidClient,
_ => Errors.InvalidRequest _ => Errors.InvalidRequest
@ -1117,7 +1126,6 @@ public static partial class OpenIddictServerHandlers
if (context.EndpointType is OpenIddictServerEndpointType.Authorization or if (context.EndpointType is OpenIddictServerEndpointType.Authorization or
OpenIddictServerEndpointType.EndSession or OpenIddictServerEndpointType.EndSession or
OpenIddictServerEndpointType.EndUserVerification or OpenIddictServerEndpointType.EndUserVerification or
OpenIddictServerEndpointType.PushedAuthorization or
OpenIddictServerEndpointType.UserInfo) OpenIddictServerEndpointType.UserInfo)
{ {
return; return;
@ -1227,7 +1235,6 @@ public static partial class OpenIddictServerHandlers
if (context.EndpointType is OpenIddictServerEndpointType.Authorization or if (context.EndpointType is OpenIddictServerEndpointType.Authorization or
OpenIddictServerEndpointType.EndSession or OpenIddictServerEndpointType.EndSession or
OpenIddictServerEndpointType.EndUserVerification or OpenIddictServerEndpointType.EndUserVerification or
OpenIddictServerEndpointType.PushedAuthorization or
OpenIddictServerEndpointType.UserInfo) OpenIddictServerEndpointType.UserInfo)
{ {
return; return;

175
test/OpenIddict.Server.IntegrationTests/OpenIddictServerIntegrationTests.Authentication.cs

@ -3214,6 +3214,130 @@ public abstract partial class OpenIddictServerIntegrationTests
Assert.Equal(SR.FormatID8000(SR.ID2029), response.ErrorUri); Assert.Equal(SR.FormatID8000(SR.ID2029), response.ErrorUri);
} }
[Fact]
public async Task ValidatePushedAuthorizationRequest_ClientSecretCannotBeUsedByPublicClients()
{
// Arrange
var application = new OpenIddictApplication();
var manager = CreateApplicationManager(mock =>
{
mock.Setup(manager => manager.FindByClientIdAsync("Fabrikam", It.IsAny<CancellationToken>()))
.ReturnsAsync(application);
mock.Setup(manager => manager.HasClientTypeAsync(application, ClientTypes.Public, It.IsAny<CancellationToken>()))
.ReturnsAsync(true);
});
await using var server = await CreateServerAsync(options =>
{
options.Services.AddSingleton(manager);
});
await using var client = await server.CreateClientAsync();
// Act
var response = await client.PostAsync("/connect/par", new OpenIddictRequest
{
ClientId = "Fabrikam",
ClientSecret = "7Fjfp0ZBr1KtDRbnfVdmIw",
RedirectUri = "http://www.fabrikam.com/path",
ResponseType = ResponseTypes.Code
});
// Assert
Assert.Equal(Errors.InvalidClient, response.Error);
Assert.Equal(SR.FormatID2053(Parameters.ClientSecret), response.ErrorDescription);
Assert.Equal(SR.FormatID8000(SR.ID2053), response.ErrorUri);
Mock.Get(manager).Verify(manager => manager.FindByClientIdAsync("Fabrikam", It.IsAny<CancellationToken>()), Times.AtLeastOnce());
Mock.Get(manager).Verify(manager => manager.HasClientTypeAsync(application, ClientTypes.Public, It.IsAny<CancellationToken>()), Times.Once());
}
[Fact]
public async Task ValidatePushedAuthorizationRequest_ClientSecretIsRequiredForNonPublicClients()
{
// Arrange
var application = new OpenIddictApplication();
var manager = CreateApplicationManager(mock =>
{
mock.Setup(manager => manager.FindByClientIdAsync("Fabrikam", It.IsAny<CancellationToken>()))
.ReturnsAsync(application);
mock.Setup(manager => manager.HasClientTypeAsync(application, ClientTypes.Public, It.IsAny<CancellationToken>()))
.ReturnsAsync(false);
});
await using var server = await CreateServerAsync(options =>
{
options.Services.AddSingleton(manager);
});
await using var client = await server.CreateClientAsync();
// Act
var response = await client.PostAsync("/connect/par", new OpenIddictRequest
{
ClientId = "Fabrikam",
ClientSecret = null,
RedirectUri = "http://www.fabrikam.com/path",
ResponseType = ResponseTypes.Code
});
// Assert
Assert.Equal(Errors.InvalidClient, response.Error);
Assert.Equal(SR.FormatID2054(Parameters.ClientSecret), response.ErrorDescription);
Assert.Equal(SR.FormatID8000(SR.ID2054), response.ErrorUri);
Mock.Get(manager).Verify(manager => manager.FindByClientIdAsync("Fabrikam", It.IsAny<CancellationToken>()), Times.AtLeastOnce());
Mock.Get(manager).Verify(manager => manager.HasClientTypeAsync(application, ClientTypes.Public, It.IsAny<CancellationToken>()), Times.Once());
}
[Fact]
public async Task ValidatePushedAuthorizationRequest_RequestIsRejectedWhenClientCredentialsAreInvalid()
{
// Arrange
var application = new OpenIddictApplication();
var manager = CreateApplicationManager(mock =>
{
mock.Setup(manager => manager.FindByClientIdAsync("Fabrikam", It.IsAny<CancellationToken>()))
.ReturnsAsync(application);
mock.Setup(manager => manager.HasClientTypeAsync(application, ClientTypes.Public, It.IsAny<CancellationToken>()))
.ReturnsAsync(false);
mock.Setup(manager => manager.ValidateClientSecretAsync(application, "7Fjfp0ZBr1KtDRbnfVdmIw", It.IsAny<CancellationToken>()))
.ReturnsAsync(false);
});
await using var server = await CreateServerAsync(options =>
{
options.Services.AddSingleton(manager);
});
await using var client = await server.CreateClientAsync();
// Act
var response = await client.PostAsync("/connect/par", new OpenIddictRequest
{
ClientId = "Fabrikam",
ClientSecret = "7Fjfp0ZBr1KtDRbnfVdmIw",
RedirectUri = "http://www.fabrikam.com/path",
ResponseType = ResponseTypes.Code
});
// Assert
Assert.Equal(Errors.InvalidClient, response.Error);
Assert.Equal(SR.GetResourceString(SR.ID2055), response.ErrorDescription);
Assert.Equal(SR.FormatID8000(SR.ID2055), response.ErrorUri);
Mock.Get(manager).Verify(manager => manager.FindByClientIdAsync("Fabrikam", It.IsAny<CancellationToken>()), Times.AtLeastOnce());
Mock.Get(manager).Verify(manager => manager.HasClientTypeAsync(application, ClientTypes.Public, It.IsAny<CancellationToken>()), Times.AtLeastOnce());
Mock.Get(manager).Verify(manager => manager.ValidateClientSecretAsync(application, "7Fjfp0ZBr1KtDRbnfVdmIw", It.IsAny<CancellationToken>()), Times.Once());
}
[Fact] [Fact]
public async Task ValidatePushedAuthorizationRequest_MissingRedirectUriCausesAnErrorForOpenIdRequests() public async Task ValidatePushedAuthorizationRequest_MissingRedirectUriCausesAnErrorForOpenIdRequests()
{ {
@ -4186,7 +4310,7 @@ public abstract partial class OpenIddictServerIntegrationTests
}); });
// Assert // Assert
Assert.Equal(Errors.InvalidRequest, response.Error); Assert.Equal(Errors.InvalidClient, response.Error);
Assert.Equal(SR.FormatID2052(Parameters.ClientId), response.ErrorDescription); Assert.Equal(SR.FormatID2052(Parameters.ClientId), response.ErrorDescription);
Assert.Equal(SR.FormatID8000(SR.ID2052), response.ErrorUri); Assert.Equal(SR.FormatID8000(SR.ID2052), response.ErrorUri);
@ -4233,6 +4357,9 @@ public abstract partial class OpenIddictServerIntegrationTests
mock.Setup(manager => manager.FindByClientIdAsync("Fabrikam", It.IsAny<CancellationToken>())) mock.Setup(manager => manager.FindByClientIdAsync("Fabrikam", It.IsAny<CancellationToken>()))
.ReturnsAsync(application); .ReturnsAsync(application);
mock.Setup(manager => manager.HasClientTypeAsync(application, ClientTypes.Public, It.IsAny<CancellationToken>()))
.ReturnsAsync(true);
mock.Setup(manager => manager.ValidateRedirectUriAsync(application, "http://www.fabrikam.com/path", It.IsAny<CancellationToken>())) mock.Setup(manager => manager.ValidateRedirectUriAsync(application, "http://www.fabrikam.com/path", It.IsAny<CancellationToken>()))
.ReturnsAsync(true); .ReturnsAsync(true);
@ -4274,6 +4401,9 @@ public abstract partial class OpenIddictServerIntegrationTests
mock.Setup(manager => manager.FindByClientIdAsync("Fabrikam", It.IsAny<CancellationToken>())) mock.Setup(manager => manager.FindByClientIdAsync("Fabrikam", It.IsAny<CancellationToken>()))
.ReturnsAsync(application); .ReturnsAsync(application);
mock.Setup(manager => manager.HasClientTypeAsync(application, ClientTypes.Public, It.IsAny<CancellationToken>()))
.ReturnsAsync(true);
mock.Setup(manager => manager.GetPermissionsAsync(application, It.IsAny<CancellationToken>())) mock.Setup(manager => manager.GetPermissionsAsync(application, It.IsAny<CancellationToken>()))
.ReturnsAsync(["rst:" + type]); .ReturnsAsync(["rst:" + type]);
@ -4337,6 +4467,9 @@ public abstract partial class OpenIddictServerIntegrationTests
mock.Setup(manager => manager.HasClientTypeAsync(application, ClientTypes.Confidential, It.IsAny<CancellationToken>())) mock.Setup(manager => manager.HasClientTypeAsync(application, ClientTypes.Confidential, It.IsAny<CancellationToken>()))
.ReturnsAsync(true); .ReturnsAsync(true);
mock.Setup(manager => manager.ValidateClientSecretAsync(application, "7Fjfp0ZBr1KtDRbnfVdmIw", It.IsAny<CancellationToken>()))
.ReturnsAsync(true);
mock.Setup(manager => manager.GetPermissionsAsync(application, It.IsAny<CancellationToken>())) mock.Setup(manager => manager.GetPermissionsAsync(application, It.IsAny<CancellationToken>()))
.ReturnsAsync([]); .ReturnsAsync([]);
}); });
@ -4352,6 +4485,7 @@ public abstract partial class OpenIddictServerIntegrationTests
var response = await client.PostAsync("/connect/par", new OpenIddictRequest var response = await client.PostAsync("/connect/par", new OpenIddictRequest
{ {
ClientId = "Fabrikam", ClientId = "Fabrikam",
ClientSecret = "7Fjfp0ZBr1KtDRbnfVdmIw",
Nonce = "n-0S6_WzA2Mj", Nonce = "n-0S6_WzA2Mj",
RedirectUri = "http://www.fabrikam.com/path", RedirectUri = "http://www.fabrikam.com/path",
ResponseType = type, ResponseType = type,
@ -4378,6 +4512,9 @@ public abstract partial class OpenIddictServerIntegrationTests
mock.Setup(manager => manager.FindByClientIdAsync("Fabrikam", It.IsAny<CancellationToken>())) mock.Setup(manager => manager.FindByClientIdAsync("Fabrikam", It.IsAny<CancellationToken>()))
.ReturnsAsync(application); .ReturnsAsync(application);
mock.Setup(manager => manager.HasClientTypeAsync(application, ClientTypes.Public, It.IsAny<CancellationToken>()))
.ReturnsAsync(true);
mock.Setup(manager => manager.ValidateRedirectUriAsync(application, "http://www.fabrikam.com/path", It.IsAny<CancellationToken>())) mock.Setup(manager => manager.ValidateRedirectUriAsync(application, "http://www.fabrikam.com/path", It.IsAny<CancellationToken>()))
.ReturnsAsync(true); .ReturnsAsync(true);
@ -4453,6 +4590,9 @@ public abstract partial class OpenIddictServerIntegrationTests
mock.Setup(manager => manager.FindByClientIdAsync("Fabrikam", It.IsAny<CancellationToken>())) mock.Setup(manager => manager.FindByClientIdAsync("Fabrikam", It.IsAny<CancellationToken>()))
.ReturnsAsync(application); .ReturnsAsync(application);
mock.Setup(manager => manager.HasClientTypeAsync(application, ClientTypes.Public, It.IsAny<CancellationToken>()))
.ReturnsAsync(true);
mock.Setup(manager => manager.ValidateRedirectUriAsync(application, "http://www.fabrikam.com/path", It.IsAny<CancellationToken>())) mock.Setup(manager => manager.ValidateRedirectUriAsync(application, "http://www.fabrikam.com/path", It.IsAny<CancellationToken>()))
.ReturnsAsync(true); .ReturnsAsync(true);
@ -4510,6 +4650,9 @@ public abstract partial class OpenIddictServerIntegrationTests
mock.Setup(manager => manager.FindByClientIdAsync("Fabrikam", It.IsAny<CancellationToken>())) mock.Setup(manager => manager.FindByClientIdAsync("Fabrikam", It.IsAny<CancellationToken>()))
.ReturnsAsync(application); .ReturnsAsync(application);
mock.Setup(manager => manager.HasClientTypeAsync(application, ClientTypes.Public, It.IsAny<CancellationToken>()))
.ReturnsAsync(true);
mock.Setup(manager => manager.ValidateRedirectUriAsync(application, "http://www.fabrikam.com/path", It.IsAny<CancellationToken>())) mock.Setup(manager => manager.ValidateRedirectUriAsync(application, "http://www.fabrikam.com/path", It.IsAny<CancellationToken>()))
.ReturnsAsync(true); .ReturnsAsync(true);
@ -4560,6 +4703,9 @@ public abstract partial class OpenIddictServerIntegrationTests
mock.Setup(manager => manager.FindByClientIdAsync("Fabrikam", It.IsAny<CancellationToken>())) mock.Setup(manager => manager.FindByClientIdAsync("Fabrikam", It.IsAny<CancellationToken>()))
.ReturnsAsync(application); .ReturnsAsync(application);
mock.Setup(manager => manager.HasClientTypeAsync(application, ClientTypes.Public, It.IsAny<CancellationToken>()))
.ReturnsAsync(true);
mock.Setup(manager => manager.GetPermissionsAsync(application, It.IsAny<CancellationToken>())) mock.Setup(manager => manager.GetPermissionsAsync(application, It.IsAny<CancellationToken>()))
.ReturnsAsync(["rst:" + type]); .ReturnsAsync(["rst:" + type]);
@ -4617,6 +4763,9 @@ public abstract partial class OpenIddictServerIntegrationTests
mock.Setup(manager => manager.FindByClientIdAsync("Fabrikam", It.IsAny<CancellationToken>())) mock.Setup(manager => manager.FindByClientIdAsync("Fabrikam", It.IsAny<CancellationToken>()))
.ReturnsAsync(application); .ReturnsAsync(application);
mock.Setup(manager => manager.HasClientTypeAsync(application, ClientTypes.Public, It.IsAny<CancellationToken>()))
.ReturnsAsync(true);
mock.Setup(manager => manager.ValidateRedirectUriAsync(application, "http://www.fabrikam.com/path", It.IsAny<CancellationToken>())) mock.Setup(manager => manager.ValidateRedirectUriAsync(application, "http://www.fabrikam.com/path", It.IsAny<CancellationToken>()))
.ReturnsAsync(true); .ReturnsAsync(true);
@ -4667,6 +4816,9 @@ public abstract partial class OpenIddictServerIntegrationTests
mock.Setup(manager => manager.FindByClientIdAsync("Fabrikam", It.IsAny<CancellationToken>())) mock.Setup(manager => manager.FindByClientIdAsync("Fabrikam", It.IsAny<CancellationToken>()))
.ReturnsAsync(application); .ReturnsAsync(application);
mock.Setup(manager => manager.HasClientTypeAsync(application, ClientTypes.Public, It.IsAny<CancellationToken>()))
.ReturnsAsync(true);
mock.Setup(manager => manager.ValidateRedirectUriAsync(application, "http://www.fabrikam.com/path", It.IsAny<CancellationToken>())) mock.Setup(manager => manager.ValidateRedirectUriAsync(application, "http://www.fabrikam.com/path", It.IsAny<CancellationToken>()))
.ReturnsAsync(false); .ReturnsAsync(false);
}); });
@ -4706,6 +4858,9 @@ public abstract partial class OpenIddictServerIntegrationTests
mock.Setup(manager => manager.FindByClientIdAsync("Fabrikam", It.IsAny<CancellationToken>())) mock.Setup(manager => manager.FindByClientIdAsync("Fabrikam", It.IsAny<CancellationToken>()))
.ReturnsAsync(application); .ReturnsAsync(application);
mock.Setup(manager => manager.HasClientTypeAsync(application, ClientTypes.Public, It.IsAny<CancellationToken>()))
.ReturnsAsync(true);
mock.Setup(manager => manager.ValidateRedirectUriAsync(application, "http://www.fabrikam.com/path", It.IsAny<CancellationToken>())) mock.Setup(manager => manager.ValidateRedirectUriAsync(application, "http://www.fabrikam.com/path", It.IsAny<CancellationToken>()))
.ReturnsAsync(true); .ReturnsAsync(true);
@ -4762,6 +4917,9 @@ public abstract partial class OpenIddictServerIntegrationTests
mock.Setup(manager => manager.FindByClientIdAsync("Fabrikam", It.IsAny<CancellationToken>())) mock.Setup(manager => manager.FindByClientIdAsync("Fabrikam", It.IsAny<CancellationToken>()))
.ReturnsAsync(application); .ReturnsAsync(application);
mock.Setup(manager => manager.HasClientTypeAsync(application, ClientTypes.Public, It.IsAny<CancellationToken>()))
.ReturnsAsync(true);
mock.Setup(manager => manager.ValidateRedirectUriAsync(application, "http://www.fabrikam.com/path", It.IsAny<CancellationToken>())) mock.Setup(manager => manager.ValidateRedirectUriAsync(application, "http://www.fabrikam.com/path", It.IsAny<CancellationToken>()))
.ReturnsAsync(true); .ReturnsAsync(true);
@ -4814,6 +4972,9 @@ public abstract partial class OpenIddictServerIntegrationTests
mock.Setup(manager => manager.FindByClientIdAsync("Fabrikam", It.IsAny<CancellationToken>())) mock.Setup(manager => manager.FindByClientIdAsync("Fabrikam", It.IsAny<CancellationToken>()))
.ReturnsAsync(application); .ReturnsAsync(application);
mock.Setup(manager => manager.HasClientTypeAsync(application, ClientTypes.Public, It.IsAny<CancellationToken>()))
.ReturnsAsync(true);
mock.Setup(manager => manager.ValidateRedirectUriAsync(application, "http://www.fabrikam.com/path", It.IsAny<CancellationToken>())) mock.Setup(manager => manager.ValidateRedirectUriAsync(application, "http://www.fabrikam.com/path", It.IsAny<CancellationToken>()))
.ReturnsAsync(true); .ReturnsAsync(true);
@ -4860,6 +5021,9 @@ public abstract partial class OpenIddictServerIntegrationTests
mock.Setup(manager => manager.FindByClientIdAsync("Fabrikam", It.IsAny<CancellationToken>())) mock.Setup(manager => manager.FindByClientIdAsync("Fabrikam", It.IsAny<CancellationToken>()))
.ReturnsAsync(application); .ReturnsAsync(application);
mock.Setup(manager => manager.HasClientTypeAsync(application, ClientTypes.Public, It.IsAny<CancellationToken>()))
.ReturnsAsync(true);
mock.Setup(manager => manager.ValidateRedirectUriAsync(application, "http://www.fabrikam.com/path", It.IsAny<CancellationToken>())) mock.Setup(manager => manager.ValidateRedirectUriAsync(application, "http://www.fabrikam.com/path", It.IsAny<CancellationToken>()))
.ReturnsAsync(true); .ReturnsAsync(true);
@ -4914,6 +5078,9 @@ public abstract partial class OpenIddictServerIntegrationTests
mock.Setup(manager => manager.FindByClientIdAsync("Fabrikam", It.IsAny<CancellationToken>())) mock.Setup(manager => manager.FindByClientIdAsync("Fabrikam", It.IsAny<CancellationToken>()))
.ReturnsAsync(application); .ReturnsAsync(application);
mock.Setup(manager => manager.HasClientTypeAsync(application, ClientTypes.Public, It.IsAny<CancellationToken>()))
.ReturnsAsync(true);
mock.Setup(manager => manager.ValidateRedirectUriAsync(application, "http://www.fabrikam.com/path", It.IsAny<CancellationToken>())) mock.Setup(manager => manager.ValidateRedirectUriAsync(application, "http://www.fabrikam.com/path", It.IsAny<CancellationToken>()))
.ReturnsAsync(true); .ReturnsAsync(true);
@ -4968,6 +5135,9 @@ public abstract partial class OpenIddictServerIntegrationTests
mock.Setup(manager => manager.FindByClientIdAsync("Fabrikam", It.IsAny<CancellationToken>())) mock.Setup(manager => manager.FindByClientIdAsync("Fabrikam", It.IsAny<CancellationToken>()))
.ReturnsAsync(application); .ReturnsAsync(application);
mock.Setup(manager => manager.HasClientTypeAsync(application, ClientTypes.Public, It.IsAny<CancellationToken>()))
.ReturnsAsync(true);
mock.Setup(manager => manager.ValidateRedirectUriAsync(application, "http://www.fabrikam.com/path", It.IsAny<CancellationToken>())) mock.Setup(manager => manager.ValidateRedirectUriAsync(application, "http://www.fabrikam.com/path", It.IsAny<CancellationToken>()))
.ReturnsAsync(true); .ReturnsAsync(true);
@ -5137,6 +5307,9 @@ public abstract partial class OpenIddictServerIntegrationTests
mock.Setup(manager => manager.FindByClientIdAsync("Fabrikam", It.IsAny<CancellationToken>())) mock.Setup(manager => manager.FindByClientIdAsync("Fabrikam", It.IsAny<CancellationToken>()))
.ReturnsAsync(application); .ReturnsAsync(application);
mock.Setup(manager => manager.HasClientTypeAsync(application, ClientTypes.Public, It.IsAny<CancellationToken>()))
.ReturnsAsync(true);
mock.Setup(manager => manager.ValidateRedirectUriAsync(application, "http://www.fabrikam.com/path", It.IsAny<CancellationToken>())) mock.Setup(manager => manager.ValidateRedirectUriAsync(application, "http://www.fabrikam.com/path", It.IsAny<CancellationToken>()))
.ReturnsAsync(true); .ReturnsAsync(true);

Loading…
Cancel
Save