Browse Source

Refactor custom parameters handling during challenge/sign-in/sign-out

pull/1335/head
Kévin Chalet 5 years ago
parent
commit
5f154b9f05
  1. 40
      src/OpenIddict.Server.AspNetCore/OpenIddictServerAspNetCoreHandler.cs
  2. 133
      src/OpenIddict.Server.AspNetCore/OpenIddictServerAspNetCoreHandlers.cs
  3. 2
      src/OpenIddict.Server.DataProtection/OpenIddictServerDataProtectionHandlers.Protection.cs
  4. 40
      src/OpenIddict.Server.Owin/OpenIddictServerOwinHandler.cs
  5. 45
      src/OpenIddict.Server.Owin/OpenIddictServerOwinHandlers.cs
  6. 29
      src/OpenIddict.Server/OpenIddictServerEvents.cs
  7. 141
      src/OpenIddict.Server/OpenIddictServerHandlers.cs
  8. 20
      src/OpenIddict.Validation.AspNetCore/OpenIddictValidationAspNetCoreHandler.cs
  9. 48
      src/OpenIddict.Validation.AspNetCore/OpenIddictValidationAspNetCoreHandlers.cs
  10. 20
      src/OpenIddict.Validation.Owin/OpenIddictValidationOwinHandler.cs
  11. 34
      src/OpenIddict.Validation.Owin/OpenIddictValidationOwinHandlers.cs
  12. 26
      src/OpenIddict.Validation/OpenIddictValidationEvents.cs
  13. 39
      src/OpenIddict.Validation/OpenIddictValidationHandlers.cs

40
src/OpenIddict.Server.AspNetCore/OpenIddictServerAspNetCoreHandler.cs

@ -82,12 +82,10 @@ namespace OpenIddict.Server.AspNetCore
{ {
var notification = new ProcessErrorContext(transaction) var notification = new ProcessErrorContext(transaction)
{ {
Response = new OpenIddictResponse Error = context.Error ?? Errors.InvalidRequest,
{ ErrorDescription = context.ErrorDescription,
Error = context.Error ?? Errors.InvalidRequest, ErrorUri = context.ErrorUri,
ErrorDescription = context.ErrorDescription, Response = new OpenIddictResponse()
ErrorUri = context.ErrorUri
}
}; };
await _dispatcher.DispatchAsync(notification); await _dispatcher.DispatchAsync(notification);
@ -308,12 +306,10 @@ namespace OpenIddict.Server.AspNetCore
{ {
var notification = new ProcessErrorContext(transaction) var notification = new ProcessErrorContext(transaction)
{ {
Response = new OpenIddictResponse Error = context.Error ?? Errors.InvalidRequest,
{ ErrorDescription = context.ErrorDescription,
Error = context.Error ?? Errors.InvalidRequest, ErrorUri = context.ErrorUri,
ErrorDescription = context.ErrorDescription, Response = new OpenIddictResponse()
ErrorUri = context.ErrorUri
}
}; };
await _dispatcher.DispatchAsync(notification); await _dispatcher.DispatchAsync(notification);
@ -361,12 +357,10 @@ namespace OpenIddict.Server.AspNetCore
{ {
var notification = new ProcessErrorContext(transaction) var notification = new ProcessErrorContext(transaction)
{ {
Response = new OpenIddictResponse Error = context.Error ?? Errors.InvalidRequest,
{ ErrorDescription = context.ErrorDescription,
Error = context.Error ?? Errors.InvalidRequest, ErrorUri = context.ErrorUri,
ErrorDescription = context.ErrorDescription, Response = new OpenIddictResponse()
ErrorUri = context.ErrorUri
}
}; };
await _dispatcher.DispatchAsync(notification); await _dispatcher.DispatchAsync(notification);
@ -404,12 +398,10 @@ namespace OpenIddict.Server.AspNetCore
{ {
var notification = new ProcessErrorContext(transaction) var notification = new ProcessErrorContext(transaction)
{ {
Response = new OpenIddictResponse Error = context.Error ?? Errors.InvalidRequest,
{ ErrorDescription = context.ErrorDescription,
Error = context.Error ?? Errors.InvalidRequest, ErrorUri = context.ErrorUri,
ErrorDescription = context.ErrorDescription, Response = new OpenIddictResponse()
ErrorUri = context.ErrorUri
}
}; };
await _dispatcher.DispatchAsync(notification); await _dispatcher.DispatchAsync(notification);

133
src/OpenIddict.Server.AspNetCore/OpenIddictServerAspNetCoreHandlers.cs

@ -46,18 +46,17 @@ namespace OpenIddict.Server.AspNetCore
/* /*
* Challenge processing: * Challenge processing:
*/ */
AttachHostChallengeError.Descriptor, ResolveHostChallengeParameters.Descriptor,
AttachHostParameters<ProcessChallengeContext>.Descriptor,
/* /*
* Sign-in processing: * Sign-in processing:
*/ */
AttachHostParameters<ProcessSignInContext>.Descriptor, ResolveHostSignInParameters.Descriptor,
/* /*
* Sign-out processing: * Sign-out processing:
*/ */
AttachHostParameters<ProcessSignOutContext>.Descriptor) ResolveHostSignOutParameters.Descriptor)
.AddRange(Authentication.DefaultHandlers) .AddRange(Authentication.DefaultHandlers)
.AddRange(Device.DefaultHandlers) .AddRange(Device.DefaultHandlers)
.AddRange(Discovery.DefaultHandlers) .AddRange(Discovery.DefaultHandlers)
@ -296,10 +295,11 @@ namespace OpenIddict.Server.AspNetCore
} }
/// <summary> /// <summary>
/// Contains the logic responsible of attaching the error details using the ASP.NET Core authentication properties. /// Contains the logic responsible of resolving the additional sign-in parameters stored in the ASP.NET
/// Core authentication properties specified by the application that triggered the sign-in operation.
/// Note: this handler is not used when the OpenID Connect request is not initially handled by ASP.NET Core. /// Note: this handler is not used when the OpenID Connect request is not initially handled by ASP.NET Core.
/// </summary> /// </summary>
public class AttachHostChallengeError : IOpenIddictServerHandler<ProcessChallengeContext> public class ResolveHostChallengeParameters : IOpenIddictServerHandler<ProcessChallengeContext>
{ {
/// <summary> /// <summary>
/// Gets the default descriptor definition assigned to this handler. /// Gets the default descriptor definition assigned to this handler.
@ -307,8 +307,8 @@ namespace OpenIddict.Server.AspNetCore
public static OpenIddictServerHandlerDescriptor Descriptor { get; } public static OpenIddictServerHandlerDescriptor Descriptor { get; }
= OpenIddictServerHandlerDescriptor.CreateBuilder<ProcessChallengeContext>() = OpenIddictServerHandlerDescriptor.CreateBuilder<ProcessChallengeContext>()
.AddFilter<RequireHttpRequest>() .AddFilter<RequireHttpRequest>()
.UseSingletonHandler<AttachHostChallengeError>() .UseSingletonHandler<ResolveHostChallengeParameters>()
.SetOrder(AttachDefaultChallengeError.Descriptor.Order - 1_000) .SetOrder(AttachDefaultChallengeError.Descriptor.Order - 500)
.SetType(OpenIddictServerHandlerType.BuiltIn) .SetType(OpenIddictServerHandlerType.BuiltIn)
.Build(); .Build();
@ -321,12 +321,49 @@ namespace OpenIddict.Server.AspNetCore
} }
var properties = context.Transaction.GetProperty<AuthenticationProperties>(typeof(AuthenticationProperties).FullName!); var properties = context.Transaction.GetProperty<AuthenticationProperties>(typeof(AuthenticationProperties).FullName!);
if (properties is not null) if (properties is null)
{
return default;
}
if (properties.Items.TryGetValue(Properties.Error, out string? error) &&
!string.IsNullOrEmpty(error))
{ {
context.Response.Error = properties.GetString(Properties.Error); context.Parameters[Parameters.Error] = error;
context.Response.ErrorDescription = properties.GetString(Properties.ErrorDescription); }
context.Response.ErrorUri = properties.GetString(Properties.ErrorUri);
context.Response.Scope = properties.GetString(Properties.Scope); if (properties.Items.TryGetValue(Properties.ErrorDescription, out string? description) &&
!string.IsNullOrEmpty(description))
{
context.Parameters[Parameters.ErrorDescription] = description;
}
if (properties.Items.TryGetValue(Properties.ErrorUri, out string? uri) &&
!string.IsNullOrEmpty(uri))
{
context.Parameters[Parameters.ErrorUri] = uri;
}
if (properties.Items.TryGetValue(Properties.Scope, out string? scope) &&
!string.IsNullOrEmpty(scope))
{
context.Parameters[Parameters.Scope] = scope;
}
foreach (var parameter in properties.Parameters)
{
context.Parameters[parameter.Key] = parameter.Value switch
{
OpenIddictParameter value => value,
JsonElement value => new OpenIddictParameter(value),
bool value => new OpenIddictParameter(value),
int value => new OpenIddictParameter(value),
long value => new OpenIddictParameter(value),
string value => new OpenIddictParameter(value),
string[] value => new OpenIddictParameter(value),
_ => throw new InvalidOperationException(SR.GetResourceString(SR.ID0115))
};
} }
return default; return default;
@ -334,31 +371,82 @@ namespace OpenIddict.Server.AspNetCore
} }
/// <summary> /// <summary>
/// Contains the logic responsible of attaching custom parameters stored in the ASP.NET Core authentication properties. /// Contains the logic responsible of resolving the additional sign-in parameters stored in the ASP.NET
/// Core authentication properties specified by the application that triggered the sign-in operation.
/// Note: this handler is not used when the OpenID Connect request is not initially handled by ASP.NET Core. /// Note: this handler is not used when the OpenID Connect request is not initially handled by ASP.NET Core.
/// </summary> /// </summary>
public class AttachHostParameters<TContext> : IOpenIddictServerHandler<TContext> where TContext : BaseContext public class ResolveHostSignInParameters : IOpenIddictServerHandler<ProcessSignInContext>
{ {
/// <summary> /// <summary>
/// Gets the default descriptor definition assigned to this handler. /// Gets the default descriptor definition assigned to this handler.
/// </summary> /// </summary>
public static OpenIddictServerHandlerDescriptor Descriptor { get; } public static OpenIddictServerHandlerDescriptor Descriptor { get; }
= OpenIddictServerHandlerDescriptor.CreateBuilder<TContext>() = OpenIddictServerHandlerDescriptor.CreateBuilder<ProcessSignInContext>()
.AddFilter<RequireHttpRequest>() .AddFilter<RequireHttpRequest>()
.UseSingletonHandler<AttachHostParameters<TContext>>() .UseSingletonHandler<ResolveHostSignInParameters>()
.SetOrder(int.MaxValue - 150_000) .SetOrder(AttachSignInParameters.Descriptor.Order - 500)
.SetType(OpenIddictServerHandlerType.BuiltIn) .SetType(OpenIddictServerHandlerType.BuiltIn)
.Build(); .Build();
/// <inheritdoc/> /// <inheritdoc/>
public ValueTask HandleAsync(TContext context) public ValueTask HandleAsync(ProcessSignInContext context)
{ {
if (context is null) if (context is null)
{ {
throw new ArgumentNullException(nameof(context)); throw new ArgumentNullException(nameof(context));
} }
Debug.Assert(context.Transaction.Response is not null, SR.GetResourceString(SR.ID4007)); var properties = context.Transaction.GetProperty<AuthenticationProperties>(typeof(AuthenticationProperties).FullName!);
if (properties is null)
{
return default;
}
foreach (var parameter in properties.Parameters)
{
context.Parameters[parameter.Key] = parameter.Value switch
{
OpenIddictParameter value => value,
JsonElement value => new OpenIddictParameter(value),
bool value => new OpenIddictParameter(value),
int value => new OpenIddictParameter(value),
long value => new OpenIddictParameter(value),
string value => new OpenIddictParameter(value),
string[] value => new OpenIddictParameter(value),
_ => throw new InvalidOperationException(SR.GetResourceString(SR.ID0115))
};
}
return default;
}
}
/// <summary>
/// Contains the logic responsible of resolving the additional sign-out parameters stored in the ASP.NET
/// Core authentication properties specified by the application that triggered the sign-out operation.
/// Note: this handler is not used when the OpenID Connect request is not initially handled by ASP.NET Core.
/// </summary>
public class ResolveHostSignOutParameters : IOpenIddictServerHandler<ProcessSignOutContext>
{
/// <summary>
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictServerHandlerDescriptor Descriptor { get; }
= OpenIddictServerHandlerDescriptor.CreateBuilder<ProcessSignOutContext>()
.AddFilter<RequireHttpRequest>()
.UseSingletonHandler<ResolveHostSignOutParameters>()
.SetOrder(AttachSignOutParameters.Descriptor.Order - 500)
.SetType(OpenIddictServerHandlerType.BuiltIn)
.Build();
/// <inheritdoc/>
public ValueTask HandleAsync(ProcessSignOutContext context)
{
if (context is null)
{
throw new ArgumentNullException(nameof(context));
}
var properties = context.Transaction.GetProperty<AuthenticationProperties>(typeof(AuthenticationProperties).FullName!); var properties = context.Transaction.GetProperty<AuthenticationProperties>(typeof(AuthenticationProperties).FullName!);
if (properties is null) if (properties is null)
@ -368,8 +456,7 @@ namespace OpenIddict.Server.AspNetCore
foreach (var parameter in properties.Parameters) foreach (var parameter in properties.Parameters)
{ {
// Note: AddParameter() is used to ensure existing parameters are not overriden. context.Parameters[parameter.Key] = parameter.Value switch
context.Transaction.Response.AddParameter(parameter.Key, parameter.Value switch
{ {
OpenIddictParameter value => value, OpenIddictParameter value => value,
JsonElement value => new OpenIddictParameter(value), JsonElement value => new OpenIddictParameter(value),
@ -380,7 +467,7 @@ namespace OpenIddict.Server.AspNetCore
string[] value => new OpenIddictParameter(value), string[] value => new OpenIddictParameter(value),
_ => throw new InvalidOperationException(SR.GetResourceString(SR.ID0115)) _ => throw new InvalidOperationException(SR.GetResourceString(SR.ID0115))
}); };
} }
return default; return default;

2
src/OpenIddict.Server.DataProtection/OpenIddictServerDataProtectionHandlers.Protection.cs

@ -35,7 +35,7 @@ namespace OpenIddict.Server.DataProtection
ValidateDataProtectionToken.Descriptor, ValidateDataProtectionToken.Descriptor,
/* /*
* Token validation: * Token generation:
*/ */
GenerateDataProtectionToken.Descriptor); GenerateDataProtectionToken.Descriptor);

40
src/OpenIddict.Server.Owin/OpenIddictServerOwinHandler.cs

@ -91,12 +91,10 @@ namespace OpenIddict.Server.Owin
{ {
var notification = new ProcessErrorContext(transaction) var notification = new ProcessErrorContext(transaction)
{ {
Response = new OpenIddictResponse Error = context.Error ?? Errors.InvalidRequest,
{ ErrorDescription = context.ErrorDescription,
Error = context.Error ?? Errors.InvalidRequest, ErrorUri = context.ErrorUri,
ErrorDescription = context.ErrorDescription, Response = new OpenIddictResponse()
ErrorUri = context.ErrorUri
}
}; };
await _dispatcher.DispatchAsync(notification); await _dispatcher.DispatchAsync(notification);
@ -285,12 +283,10 @@ namespace OpenIddict.Server.Owin
{ {
var notification = new ProcessErrorContext(transaction) var notification = new ProcessErrorContext(transaction)
{ {
Response = new OpenIddictResponse Error = context.Error ?? Errors.InvalidRequest,
{ ErrorDescription = context.ErrorDescription,
Error = context.Error ?? Errors.InvalidRequest, ErrorUri = context.ErrorUri,
ErrorDescription = context.ErrorDescription, Response = new OpenIddictResponse()
ErrorUri = context.ErrorUri
}
}; };
await _dispatcher.DispatchAsync(notification); await _dispatcher.DispatchAsync(notification);
@ -329,12 +325,10 @@ namespace OpenIddict.Server.Owin
{ {
var notification = new ProcessErrorContext(transaction) var notification = new ProcessErrorContext(transaction)
{ {
Response = new OpenIddictResponse Error = context.Error ?? Errors.InvalidRequest,
{ ErrorDescription = context.ErrorDescription,
Error = context.Error ?? Errors.InvalidRequest, ErrorUri = context.ErrorUri,
ErrorDescription = context.ErrorDescription, Response = new OpenIddictResponse()
ErrorUri = context.ErrorUri
}
}; };
await _dispatcher.DispatchAsync(notification); await _dispatcher.DispatchAsync(notification);
@ -372,12 +366,10 @@ namespace OpenIddict.Server.Owin
{ {
var notification = new ProcessErrorContext(transaction) var notification = new ProcessErrorContext(transaction)
{ {
Response = new OpenIddictResponse Error = context.Error ?? Errors.InvalidRequest,
{ ErrorDescription = context.ErrorDescription,
Error = context.Error ?? Errors.InvalidRequest, ErrorUri = context.ErrorUri,
ErrorDescription = context.ErrorDescription, Response = new OpenIddictResponse()
ErrorUri = context.ErrorUri
}
}; };
await _dispatcher.DispatchAsync(notification); await _dispatcher.DispatchAsync(notification);

45
src/OpenIddict.Server.Owin/OpenIddictServerOwinHandlers.cs

@ -44,7 +44,7 @@ namespace OpenIddict.Server.Owin
/* /*
* Challenge processing: * Challenge processing:
*/ */
AttachHostChallengeError.Descriptor) ResolveHostChallengeParameters.Descriptor)
.AddRange(Authentication.DefaultHandlers) .AddRange(Authentication.DefaultHandlers)
.AddRange(Device.DefaultHandlers) .AddRange(Device.DefaultHandlers)
.AddRange(Discovery.DefaultHandlers) .AddRange(Discovery.DefaultHandlers)
@ -285,10 +285,11 @@ namespace OpenIddict.Server.Owin
} }
/// <summary> /// <summary>
/// Contains the logic responsible of attaching the error details using the OWIN authentication properties. /// Contains the logic responsible of resolving the additional sign-in parameters stored in the OWIN
/// authentication properties specified by the application that triggered the sign-in operation.
/// Note: this handler is not used when the OpenID Connect request is not initially handled by OWIN. /// Note: this handler is not used when the OpenID Connect request is not initially handled by OWIN.
/// </summary> /// </summary>
public class AttachHostChallengeError : IOpenIddictServerHandler<ProcessChallengeContext> public class ResolveHostChallengeParameters : IOpenIddictServerHandler<ProcessChallengeContext>
{ {
/// <summary> /// <summary>
/// Gets the default descriptor definition assigned to this handler. /// Gets the default descriptor definition assigned to this handler.
@ -296,8 +297,8 @@ namespace OpenIddict.Server.Owin
public static OpenIddictServerHandlerDescriptor Descriptor { get; } public static OpenIddictServerHandlerDescriptor Descriptor { get; }
= OpenIddictServerHandlerDescriptor.CreateBuilder<ProcessChallengeContext>() = OpenIddictServerHandlerDescriptor.CreateBuilder<ProcessChallengeContext>()
.AddFilter<RequireOwinRequest>() .AddFilter<RequireOwinRequest>()
.UseSingletonHandler<AttachHostChallengeError>() .UseSingletonHandler<ResolveHostChallengeParameters>()
.SetOrder(AttachDefaultChallengeError.Descriptor.Order - 1_000) .SetOrder(AttachChallengeParameters.Descriptor.Order - 500)
.SetType(OpenIddictServerHandlerType.BuiltIn) .SetType(OpenIddictServerHandlerType.BuiltIn)
.Build(); .Build();
@ -310,18 +311,36 @@ namespace OpenIddict.Server.Owin
} }
var properties = context.Transaction.GetProperty<AuthenticationProperties>(typeof(AuthenticationProperties).FullName!); var properties = context.Transaction.GetProperty<AuthenticationProperties>(typeof(AuthenticationProperties).FullName!);
if (properties is not null) if (properties is null)
{ {
context.Response.Error = GetProperty(properties, Properties.Error); return default;
context.Response.ErrorDescription = GetProperty(properties, Properties.ErrorDescription);
context.Response.ErrorUri = GetProperty(properties, Properties.ErrorUri);
context.Response.Scope = GetProperty(properties, Properties.Scope);
} }
return default; if (properties.Dictionary.TryGetValue(Properties.Error, out string? error) &&
!string.IsNullOrEmpty(error))
{
context.Parameters[Parameters.Error] = error;
}
if (properties.Dictionary.TryGetValue(Properties.ErrorDescription, out string? description) &&
!string.IsNullOrEmpty(description))
{
context.Parameters[Parameters.ErrorDescription] = description;
}
static string? GetProperty(AuthenticationProperties properties, string name) if (properties.Dictionary.TryGetValue(Properties.ErrorUri, out string? uri) &&
=> properties.Dictionary.TryGetValue(name, out string? value) ? value : null; !string.IsNullOrEmpty(uri))
{
context.Parameters[Parameters.ErrorUri] = uri;
}
if (properties.Dictionary.TryGetValue(Properties.Scope, out string? scope) &&
!string.IsNullOrEmpty(scope))
{
context.Parameters[Parameters.Scope] = scope;
}
return default;
} }
} }

29
src/OpenIddict.Server/OpenIddictServerEvents.cs

@ -248,6 +248,26 @@ namespace OpenIddict.Server
get => Transaction.Response!; get => Transaction.Response!;
set => Transaction.Response = value; set => Transaction.Response = value;
} }
/// <summary>
/// Gets or sets the error returned to the caller.
/// </summary>
public string? Error { get; set; }
/// <summary>
/// Gets or sets the error description returned to the caller.
/// </summary>
public string? ErrorDescription { get; set; }
/// <summary>
/// Gets or sets the error URL returned to the caller.
/// </summary>
public string? ErrorUri { get; set; }
/// <summary>
/// Gets the additional parameters returned to the caller.
/// </summary>
public Dictionary<string, OpenIddictParameter> Parameters { get; } = new(StringComparer.Ordinal);
} }
/// <summary> /// <summary>
@ -490,6 +510,11 @@ namespace OpenIddict.Server
get => Transaction.Response!; get => Transaction.Response!;
set => Transaction.Response = value; set => Transaction.Response = value;
} }
/// <summary>
/// Gets the additional parameters returned to caller.
/// </summary>
public Dictionary<string, OpenIddictParameter> Parameters { get; } = new(StringComparer.Ordinal);
} }
/// <summary> /// <summary>
@ -524,7 +549,7 @@ namespace OpenIddict.Server
} }
/// <summary> /// <summary>
/// Gets the additional parameters returned to the client application. /// Gets the additional parameters returned to caller.
/// </summary> /// </summary>
public Dictionary<string, OpenIddictParameter> Parameters { get; } = new(StringComparer.Ordinal); public Dictionary<string, OpenIddictParameter> Parameters { get; } = new(StringComparer.Ordinal);
@ -735,7 +760,7 @@ namespace OpenIddict.Server
} }
/// <summary> /// <summary>
/// Gets the additional parameters returned to the client application. /// Gets the additional parameters returned to caller.
/// </summary> /// </summary>
public Dictionary<string, OpenIddictParameter> Parameters { get; } = new(StringComparer.Ordinal); public Dictionary<string, OpenIddictParameter> Parameters { get; } = new(StringComparer.Ordinal);
} }

141
src/OpenIddict.Server/OpenIddictServerHandlers.cs

@ -49,6 +49,7 @@ namespace OpenIddict.Server
AttachDefaultChallengeError.Descriptor, AttachDefaultChallengeError.Descriptor,
RejectDeviceCodeEntry.Descriptor, RejectDeviceCodeEntry.Descriptor,
RejectUserCodeEntry.Descriptor, RejectUserCodeEntry.Descriptor,
AttachChallengeParameters.Descriptor,
/* /*
* Sign-in processing: * Sign-in processing:
@ -88,7 +89,12 @@ namespace OpenIddict.Server
* Sign-out processing: * Sign-out processing:
*/ */
ValidateSignOutDemand.Descriptor, ValidateSignOutDemand.Descriptor,
AttachSignOutParameters.Descriptor) AttachSignOutParameters.Descriptor,
/*
* Error processing:
*/
AttachErrorParameters.Descriptor)
.AddRange(Authentication.DefaultHandlers) .AddRange(Authentication.DefaultHandlers)
.AddRange(Device.DefaultHandlers) .AddRange(Device.DefaultHandlers)
@ -918,8 +924,8 @@ namespace OpenIddict.Server
} }
if (context.EndpointType is not (OpenIddictServerEndpointType.Authorization or if (context.EndpointType is not (OpenIddictServerEndpointType.Authorization or
OpenIddictServerEndpointType.Token or OpenIddictServerEndpointType.Token or
OpenIddictServerEndpointType.Userinfo or OpenIddictServerEndpointType.Userinfo or
OpenIddictServerEndpointType.Verification)) OpenIddictServerEndpointType.Verification))
{ {
throw new InvalidOperationException(SR.GetResourceString(SR.ID0006)); throw new InvalidOperationException(SR.GetResourceString(SR.ID0006));
@ -952,38 +958,47 @@ namespace OpenIddict.Server
throw new ArgumentNullException(nameof(context)); throw new ArgumentNullException(nameof(context));
} }
context.Response.Error ??= context.EndpointType switch if (!context.Parameters.ContainsKey(Parameters.Error))
{ {
OpenIddictServerEndpointType.Authorization or OpenIddictServerEndpointType.Verification context.Parameters[Parameters.Error] = context.EndpointType switch
=> Errors.AccessDenied, {
OpenIddictServerEndpointType.Authorization or OpenIddictServerEndpointType.Verification
=> Errors.AccessDenied,
OpenIddictServerEndpointType.Token => Errors.InvalidGrant, OpenIddictServerEndpointType.Token => Errors.InvalidGrant,
OpenIddictServerEndpointType.Userinfo => Errors.InsufficientAccess, OpenIddictServerEndpointType.Userinfo => Errors.InsufficientAccess,
_ => throw new InvalidOperationException(SR.GetResourceString(SR.ID0006)) _ => throw new InvalidOperationException(SR.GetResourceString(SR.ID0006))
}; };
}
context.Response.ErrorDescription ??= context.EndpointType switch if (!context.Parameters.ContainsKey(Parameters.ErrorDescription))
{ {
OpenIddictServerEndpointType.Authorization or OpenIddictServerEndpointType.Verification context.Parameters[Parameters.ErrorDescription] = context.EndpointType switch
=> SR.GetResourceString(SR.ID2015), {
OpenIddictServerEndpointType.Authorization or OpenIddictServerEndpointType.Verification
=> SR.GetResourceString(SR.ID2015),
OpenIddictServerEndpointType.Token => SR.GetResourceString(SR.ID2024), OpenIddictServerEndpointType.Token => SR.GetResourceString(SR.ID2024),
OpenIddictServerEndpointType.Userinfo => SR.GetResourceString(SR.ID2025), OpenIddictServerEndpointType.Userinfo => SR.GetResourceString(SR.ID2025),
_ => throw new InvalidOperationException(SR.GetResourceString(SR.ID0006)) _ => throw new InvalidOperationException(SR.GetResourceString(SR.ID0006))
}; };
}
context.Response.ErrorUri ??= context.EndpointType switch if (!context.Parameters.ContainsKey(Parameters.ErrorUri))
{ {
OpenIddictServerEndpointType.Authorization or OpenIddictServerEndpointType.Verification context.Parameters[Parameters.ErrorUri] = context.EndpointType switch
=> SR.FormatID8000(SR.ID2015), {
OpenIddictServerEndpointType.Authorization or OpenIddictServerEndpointType.Verification
=> SR.FormatID8000(SR.ID2015),
OpenIddictServerEndpointType.Token => SR.FormatID8000(SR.ID2024), OpenIddictServerEndpointType.Token => SR.FormatID8000(SR.ID2024),
OpenIddictServerEndpointType.Userinfo => SR.FormatID8000(SR.ID2025), OpenIddictServerEndpointType.Userinfo => SR.FormatID8000(SR.ID2025),
_ => throw new InvalidOperationException(SR.GetResourceString(SR.ID0006)) _ => throw new InvalidOperationException(SR.GetResourceString(SR.ID0006))
}; };
}
return default; return default;
} }
@ -1107,6 +1122,41 @@ namespace OpenIddict.Server
} }
} }
/// <summary>
/// Contains the logic responsible of attaching the appropriate parameters to the challenge response.
/// </summary>
public class AttachChallengeParameters : IOpenIddictServerHandler<ProcessChallengeContext>
{
/// <summary>
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictServerHandlerDescriptor Descriptor { get; }
= OpenIddictServerHandlerDescriptor.CreateBuilder<ProcessChallengeContext>()
.UseSingletonHandler<AttachChallengeParameters>()
.SetOrder(RejectUserCodeEntry.Descriptor.Order + 1_000)
.SetType(OpenIddictServerHandlerType.BuiltIn)
.Build();
/// <inheritdoc/>
public ValueTask HandleAsync(ProcessChallengeContext context)
{
if (context is null)
{
throw new ArgumentNullException(nameof(context));
}
if (context.Parameters.Count > 0)
{
foreach (var parameter in context.Parameters)
{
context.Response.SetParameter(parameter.Key, parameter.Value);
}
}
return default;
}
}
/// <summary> /// <summary>
/// Contains the logic responsible of ensuring that the sign-in demand /// Contains the logic responsible of ensuring that the sign-in demand
/// is compatible with the type of the endpoint that handled the request. /// is compatible with the type of the endpoint that handled the request.
@ -1132,8 +1182,8 @@ namespace OpenIddict.Server
} }
if (context.EndpointType is not (OpenIddictServerEndpointType.Authorization or if (context.EndpointType is not (OpenIddictServerEndpointType.Authorization or
OpenIddictServerEndpointType.Device or OpenIddictServerEndpointType.Device or
OpenIddictServerEndpointType.Token or OpenIddictServerEndpointType.Token or
OpenIddictServerEndpointType.Verification)) OpenIddictServerEndpointType.Verification))
{ {
throw new InvalidOperationException(SR.GetResourceString(SR.ID0010)); throw new InvalidOperationException(SR.GetResourceString(SR.ID0010));
@ -3045,5 +3095,44 @@ namespace OpenIddict.Server
return default; return default;
} }
} }
/// <summary>
/// Contains the logic responsible of attaching the appropriate parameters to the error response.
/// </summary>
public class AttachErrorParameters : IOpenIddictServerHandler<ProcessErrorContext>
{
/// <summary>
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictServerHandlerDescriptor Descriptor { get; }
= OpenIddictServerHandlerDescriptor.CreateBuilder<ProcessErrorContext>()
.UseSingletonHandler<AttachErrorParameters>()
.SetOrder(int.MinValue + 100_000)
.SetType(OpenIddictServerHandlerType.BuiltIn)
.Build();
/// <inheritdoc/>
public ValueTask HandleAsync(ProcessErrorContext context)
{
if (context is null)
{
throw new ArgumentNullException(nameof(context));
}
context.Response.Error = context.Error;
context.Response.ErrorDescription = context.ErrorDescription;
context.Response.ErrorUri = context.ErrorUri;
if (context.Parameters.Count > 0)
{
foreach (var parameter in context.Parameters)
{
context.Response.SetParameter(parameter.Key, parameter.Value);
}
}
return default;
}
}
} }
} }

20
src/OpenIddict.Validation.AspNetCore/OpenIddictValidationAspNetCoreHandler.cs

@ -79,12 +79,10 @@ namespace OpenIddict.Validation.AspNetCore
{ {
var notification = new ProcessErrorContext(transaction) var notification = new ProcessErrorContext(transaction)
{ {
Response = new OpenIddictResponse Error = context.Error ?? Errors.InvalidRequest,
{ ErrorDescription = context.ErrorDescription,
Error = context.Error ?? Errors.InvalidRequest, ErrorUri = context.ErrorUri,
ErrorDescription = context.ErrorDescription, Response = new OpenIddictResponse()
ErrorUri = context.ErrorUri
}
}; };
await _dispatcher.DispatchAsync(notification); await _dispatcher.DispatchAsync(notification);
@ -225,12 +223,10 @@ namespace OpenIddict.Validation.AspNetCore
{ {
var notification = new ProcessErrorContext(transaction) var notification = new ProcessErrorContext(transaction)
{ {
Response = new OpenIddictResponse Error = context.Error ?? Errors.InvalidRequest,
{ ErrorDescription = context.ErrorDescription,
Error = context.Error ?? Errors.InvalidRequest, ErrorUri = context.ErrorUri,
ErrorDescription = context.ErrorDescription, Response = new OpenIddictResponse()
ErrorUri = context.ErrorUri
}
}; };
await _dispatcher.DispatchAsync(notification); await _dispatcher.DispatchAsync(notification);

48
src/OpenIddict.Validation.AspNetCore/OpenIddictValidationAspNetCoreHandlers.cs

@ -21,6 +21,7 @@ using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using Microsoft.Extensions.Primitives; using Microsoft.Extensions.Primitives;
using Microsoft.Net.Http.Headers; using Microsoft.Net.Http.Headers;
using OpenIddict.Abstractions;
using static OpenIddict.Abstractions.OpenIddictConstants; using static OpenIddict.Abstractions.OpenIddictConstants;
using static OpenIddict.Validation.AspNetCore.OpenIddictValidationAspNetCoreHandlerFilters; using static OpenIddict.Validation.AspNetCore.OpenIddictValidationAspNetCoreHandlerFilters;
using static OpenIddict.Validation.OpenIddictValidationEvents; using static OpenIddict.Validation.OpenIddictValidationEvents;
@ -325,12 +326,49 @@ namespace OpenIddict.Validation.AspNetCore
} }
var properties = context.Transaction.GetProperty<AuthenticationProperties>(typeof(AuthenticationProperties).FullName!); var properties = context.Transaction.GetProperty<AuthenticationProperties>(typeof(AuthenticationProperties).FullName!);
if (properties is not null) if (properties is null)
{ {
context.Response.Error = properties.GetString(Properties.Error); return default;
context.Response.ErrorDescription = properties.GetString(Properties.ErrorDescription); }
context.Response.ErrorUri = properties.GetString(Properties.ErrorUri);
context.Response.Scope = properties.GetString(Properties.Scope); if (properties.Items.TryGetValue(Properties.Error, out string? error) &&
!string.IsNullOrEmpty(error))
{
context.Parameters[Parameters.Error] = error;
}
if (properties.Items.TryGetValue(Properties.ErrorDescription, out string? description) &&
!string.IsNullOrEmpty(description))
{
context.Parameters[Parameters.ErrorDescription] = description;
}
if (properties.Items.TryGetValue(Properties.ErrorUri, out string? uri) &&
!string.IsNullOrEmpty(uri))
{
context.Parameters[Parameters.ErrorUri] = uri;
}
if (properties.Items.TryGetValue(Properties.Scope, out string? scope) &&
!string.IsNullOrEmpty(scope))
{
context.Parameters[Parameters.Scope] = scope;
}
foreach (var parameter in properties.Parameters)
{
context.Parameters[parameter.Key] = parameter.Value switch
{
OpenIddictParameter value => value,
JsonElement value => new OpenIddictParameter(value),
bool value => new OpenIddictParameter(value),
int value => new OpenIddictParameter(value),
long value => new OpenIddictParameter(value),
string value => new OpenIddictParameter(value),
string[] value => new OpenIddictParameter(value),
_ => throw new InvalidOperationException(SR.GetResourceString(SR.ID0115))
};
} }
return default; return default;

20
src/OpenIddict.Validation.Owin/OpenIddictValidationOwinHandler.cs

@ -91,12 +91,10 @@ namespace OpenIddict.Validation.Owin
{ {
var notification = new ProcessErrorContext(transaction) var notification = new ProcessErrorContext(transaction)
{ {
Response = new OpenIddictResponse Error = context.Error ?? Errors.InvalidRequest,
{ ErrorDescription = context.ErrorDescription,
Error = context.Error ?? Errors.InvalidRequest, ErrorUri = context.ErrorUri,
ErrorDescription = context.ErrorDescription, Response = new OpenIddictResponse()
ErrorUri = context.ErrorUri
}
}; };
await _dispatcher.DispatchAsync(notification); await _dispatcher.DispatchAsync(notification);
@ -237,12 +235,10 @@ namespace OpenIddict.Validation.Owin
{ {
var notification = new ProcessErrorContext(transaction) var notification = new ProcessErrorContext(transaction)
{ {
Response = new OpenIddictResponse Error = context.Error ?? Errors.InvalidRequest,
{ ErrorDescription = context.ErrorDescription,
Error = context.Error ?? Errors.InvalidRequest, ErrorUri = context.ErrorUri,
ErrorDescription = context.ErrorDescription, Response = new OpenIddictResponse()
ErrorUri = context.ErrorUri
}
}; };
await _dispatcher.DispatchAsync(notification); await _dispatcher.DispatchAsync(notification);

34
src/OpenIddict.Validation.Owin/OpenIddictValidationOwinHandlers.cs

@ -325,18 +325,36 @@ namespace OpenIddict.Validation.Owin
} }
var properties = context.Transaction.GetProperty<AuthenticationProperties>(typeof(AuthenticationProperties).FullName!); var properties = context.Transaction.GetProperty<AuthenticationProperties>(typeof(AuthenticationProperties).FullName!);
if (properties is not null) if (properties is null)
{ {
context.Response.Error = GetProperty(properties, Properties.Error); return default;
context.Response.ErrorDescription = GetProperty(properties, Properties.ErrorDescription);
context.Response.ErrorUri = GetProperty(properties, Properties.ErrorUri);
context.Response.Scope = GetProperty(properties, Properties.Scope);
} }
return default; if (properties.Dictionary.TryGetValue(Properties.Error, out string? error) &&
!string.IsNullOrEmpty(error))
{
context.Parameters[Parameters.Error] = error;
}
if (properties.Dictionary.TryGetValue(Properties.ErrorDescription, out string? description) &&
!string.IsNullOrEmpty(description))
{
context.Parameters[Parameters.ErrorDescription] = description;
}
static string? GetProperty(AuthenticationProperties properties, string name) if (properties.Dictionary.TryGetValue(Properties.ErrorUri, out string? uri) &&
=> properties.Dictionary.TryGetValue(name, out string? value) ? value : null; !string.IsNullOrEmpty(uri))
{
context.Parameters[Parameters.ErrorUri] = uri;
}
if (properties.Dictionary.TryGetValue(Properties.Scope, out string? scope) &&
!string.IsNullOrEmpty(scope))
{
context.Parameters[Parameters.Scope] = scope;
}
return default;
} }
} }

26
src/OpenIddict.Validation/OpenIddictValidationEvents.cs

@ -5,6 +5,7 @@
*/ */
using System; using System;
using System.Collections.Generic;
using System.ComponentModel; using System.ComponentModel;
using System.Security.Claims; using System.Security.Claims;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
@ -213,6 +214,26 @@ namespace OpenIddict.Validation
get => Transaction.Response!; get => Transaction.Response!;
set => Transaction.Response = value; set => Transaction.Response = value;
} }
/// <summary>
/// Gets or sets the error returned to the caller.
/// </summary>
public string? Error { get; set; }
/// <summary>
/// Gets or sets the error description returned to the caller.
/// </summary>
public string? ErrorDescription { get; set; }
/// <summary>
/// Gets or sets the error URL returned to the caller.
/// </summary>
public string? ErrorUri { get; set; }
/// <summary>
/// Gets the additional parameters returned to the caller.
/// </summary>
public Dictionary<string, OpenIddictParameter> Parameters { get; } = new(StringComparer.Ordinal);
} }
/// <summary> /// <summary>
@ -294,6 +315,11 @@ namespace OpenIddict.Validation
get => Transaction.Response!; get => Transaction.Response!;
set => Transaction.Response = value; set => Transaction.Response = value;
} }
/// <summary>
/// Gets the additional parameters returned to caller.
/// </summary>
public Dictionary<string, OpenIddictParameter> Parameters { get; } = new(StringComparer.Ordinal);
} }
} }
} }

39
src/OpenIddict.Validation/OpenIddictValidationHandlers.cs

@ -220,6 +220,45 @@ namespace OpenIddict.Validation
} }
} }
/// <summary>
/// Contains the logic responsible of attaching the appropriate parameters to the error response.
/// </summary>
public class AttachErrorParameters : IOpenIddictValidationHandler<ProcessErrorContext>
{
/// <summary>
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictValidationHandlerDescriptor Descriptor { get; }
= OpenIddictValidationHandlerDescriptor.CreateBuilder<ProcessErrorContext>()
.UseSingletonHandler<AttachErrorParameters>()
.SetOrder(int.MinValue + 100_000)
.SetType(OpenIddictValidationHandlerType.BuiltIn)
.Build();
/// <inheritdoc/>
public ValueTask HandleAsync(ProcessErrorContext context)
{
if (context is null)
{
throw new ArgumentNullException(nameof(context));
}
context.Response.Error = context.Error;
context.Response.ErrorDescription = context.ErrorDescription;
context.Response.ErrorUri = context.ErrorUri;
if (context.Parameters.Count > 0)
{
foreach (var parameter in context.Parameters)
{
context.Response.SetParameter(parameter.Key, parameter.Value);
}
}
return default;
}
}
/// <summary> /// <summary>
/// Contains the logic responsible of extracting potential errors from the response. /// Contains the logic responsible of extracting potential errors from the response.
/// </summary> /// </summary>

Loading…
Cancel
Save