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

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

@ -46,18 +46,17 @@ namespace OpenIddict.Server.AspNetCore
/*
* Challenge processing:
*/
AttachHostChallengeError.Descriptor,
AttachHostParameters<ProcessChallengeContext>.Descriptor,
ResolveHostChallengeParameters.Descriptor,
/*
* Sign-in processing:
*/
AttachHostParameters<ProcessSignInContext>.Descriptor,
ResolveHostSignInParameters.Descriptor,
/*
* Sign-out processing:
*/
AttachHostParameters<ProcessSignOutContext>.Descriptor)
ResolveHostSignOutParameters.Descriptor)
.AddRange(Authentication.DefaultHandlers)
.AddRange(Device.DefaultHandlers)
.AddRange(Discovery.DefaultHandlers)
@ -296,10 +295,11 @@ namespace OpenIddict.Server.AspNetCore
}
/// <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.
/// </summary>
public class AttachHostChallengeError : IOpenIddictServerHandler<ProcessChallengeContext>
public class ResolveHostChallengeParameters : IOpenIddictServerHandler<ProcessChallengeContext>
{
/// <summary>
/// Gets the default descriptor definition assigned to this handler.
@ -307,8 +307,8 @@ namespace OpenIddict.Server.AspNetCore
public static OpenIddictServerHandlerDescriptor Descriptor { get; }
= OpenIddictServerHandlerDescriptor.CreateBuilder<ProcessChallengeContext>()
.AddFilter<RequireHttpRequest>()
.UseSingletonHandler<AttachHostChallengeError>()
.SetOrder(AttachDefaultChallengeError.Descriptor.Order - 1_000)
.UseSingletonHandler<ResolveHostChallengeParameters>()
.SetOrder(AttachDefaultChallengeError.Descriptor.Order - 500)
.SetType(OpenIddictServerHandlerType.BuiltIn)
.Build();
@ -321,12 +321,49 @@ namespace OpenIddict.Server.AspNetCore
}
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.Response.ErrorDescription = properties.GetString(Properties.ErrorDescription);
context.Response.ErrorUri = properties.GetString(Properties.ErrorUri);
context.Response.Scope = properties.GetString(Properties.Scope);
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;
@ -334,31 +371,82 @@ namespace OpenIddict.Server.AspNetCore
}
/// <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.
/// </summary>
public class AttachHostParameters<TContext> : IOpenIddictServerHandler<TContext> where TContext : BaseContext
public class ResolveHostSignInParameters : IOpenIddictServerHandler<ProcessSignInContext>
{
/// <summary>
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictServerHandlerDescriptor Descriptor { get; }
= OpenIddictServerHandlerDescriptor.CreateBuilder<TContext>()
= OpenIddictServerHandlerDescriptor.CreateBuilder<ProcessSignInContext>()
.AddFilter<RequireHttpRequest>()
.UseSingletonHandler<AttachHostParameters<TContext>>()
.SetOrder(int.MaxValue - 150_000)
.UseSingletonHandler<ResolveHostSignInParameters>()
.SetOrder(AttachSignInParameters.Descriptor.Order - 500)
.SetType(OpenIddictServerHandlerType.BuiltIn)
.Build();
/// <inheritdoc/>
public ValueTask HandleAsync(TContext context)
public ValueTask HandleAsync(ProcessSignInContext context)
{
if (context is null)
{
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!);
if (properties is null)
@ -368,8 +456,7 @@ namespace OpenIddict.Server.AspNetCore
foreach (var parameter in properties.Parameters)
{
// Note: AddParameter() is used to ensure existing parameters are not overriden.
context.Transaction.Response.AddParameter(parameter.Key, parameter.Value switch
context.Parameters[parameter.Key] = parameter.Value switch
{
OpenIddictParameter value => value,
JsonElement value => new OpenIddictParameter(value),
@ -380,7 +467,7 @@ namespace OpenIddict.Server.AspNetCore
string[] value => new OpenIddictParameter(value),
_ => throw new InvalidOperationException(SR.GetResourceString(SR.ID0115))
});
};
}
return default;

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

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

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

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

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

@ -44,7 +44,7 @@ namespace OpenIddict.Server.Owin
/*
* Challenge processing:
*/
AttachHostChallengeError.Descriptor)
ResolveHostChallengeParameters.Descriptor)
.AddRange(Authentication.DefaultHandlers)
.AddRange(Device.DefaultHandlers)
.AddRange(Discovery.DefaultHandlers)
@ -285,10 +285,11 @@ namespace OpenIddict.Server.Owin
}
/// <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.
/// </summary>
public class AttachHostChallengeError : IOpenIddictServerHandler<ProcessChallengeContext>
public class ResolveHostChallengeParameters : IOpenIddictServerHandler<ProcessChallengeContext>
{
/// <summary>
/// Gets the default descriptor definition assigned to this handler.
@ -296,8 +297,8 @@ namespace OpenIddict.Server.Owin
public static OpenIddictServerHandlerDescriptor Descriptor { get; }
= OpenIddictServerHandlerDescriptor.CreateBuilder<ProcessChallengeContext>()
.AddFilter<RequireOwinRequest>()
.UseSingletonHandler<AttachHostChallengeError>()
.SetOrder(AttachDefaultChallengeError.Descriptor.Order - 1_000)
.UseSingletonHandler<ResolveHostChallengeParameters>()
.SetOrder(AttachChallengeParameters.Descriptor.Order - 500)
.SetType(OpenIddictServerHandlerType.BuiltIn)
.Build();
@ -310,18 +311,36 @@ namespace OpenIddict.Server.Owin
}
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);
context.Response.ErrorDescription = GetProperty(properties, Properties.ErrorDescription);
context.Response.ErrorUri = GetProperty(properties, Properties.ErrorUri);
context.Response.Scope = GetProperty(properties, Properties.Scope);
return default;
}
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)
=> properties.Dictionary.TryGetValue(name, out string? value) ? value : null;
if (properties.Dictionary.TryGetValue(Properties.ErrorUri, out string? uri) &&
!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!;
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>
@ -490,6 +510,11 @@ namespace OpenIddict.Server
get => Transaction.Response!;
set => Transaction.Response = value;
}
/// <summary>
/// Gets the additional parameters returned to caller.
/// </summary>
public Dictionary<string, OpenIddictParameter> Parameters { get; } = new(StringComparer.Ordinal);
}
/// <summary>
@ -524,7 +549,7 @@ namespace OpenIddict.Server
}
/// <summary>
/// Gets the additional parameters returned to the client application.
/// Gets the additional parameters returned to caller.
/// </summary>
public Dictionary<string, OpenIddictParameter> Parameters { get; } = new(StringComparer.Ordinal);
@ -735,7 +760,7 @@ namespace OpenIddict.Server
}
/// <summary>
/// Gets the additional parameters returned to the client application.
/// Gets the additional parameters returned to caller.
/// </summary>
public Dictionary<string, OpenIddictParameter> Parameters { get; } = new(StringComparer.Ordinal);
}

141
src/OpenIddict.Server/OpenIddictServerHandlers.cs

@ -49,6 +49,7 @@ namespace OpenIddict.Server
AttachDefaultChallengeError.Descriptor,
RejectDeviceCodeEntry.Descriptor,
RejectUserCodeEntry.Descriptor,
AttachChallengeParameters.Descriptor,
/*
* Sign-in processing:
@ -88,7 +89,12 @@ namespace OpenIddict.Server
* Sign-out processing:
*/
ValidateSignOutDemand.Descriptor,
AttachSignOutParameters.Descriptor)
AttachSignOutParameters.Descriptor,
/*
* Error processing:
*/
AttachErrorParameters.Descriptor)
.AddRange(Authentication.DefaultHandlers)
.AddRange(Device.DefaultHandlers)
@ -918,8 +924,8 @@ namespace OpenIddict.Server
}
if (context.EndpointType is not (OpenIddictServerEndpointType.Authorization or
OpenIddictServerEndpointType.Token or
OpenIddictServerEndpointType.Userinfo or
OpenIddictServerEndpointType.Token or
OpenIddictServerEndpointType.Userinfo or
OpenIddictServerEndpointType.Verification))
{
throw new InvalidOperationException(SR.GetResourceString(SR.ID0006));
@ -952,38 +958,47 @@ namespace OpenIddict.Server
throw new ArgumentNullException(nameof(context));
}
context.Response.Error ??= context.EndpointType switch
if (!context.Parameters.ContainsKey(Parameters.Error))
{
OpenIddictServerEndpointType.Authorization or OpenIddictServerEndpointType.Verification
=> Errors.AccessDenied,
context.Parameters[Parameters.Error] = context.EndpointType switch
{
OpenIddictServerEndpointType.Authorization or OpenIddictServerEndpointType.Verification
=> Errors.AccessDenied,
OpenIddictServerEndpointType.Token => Errors.InvalidGrant,
OpenIddictServerEndpointType.Userinfo => Errors.InsufficientAccess,
OpenIddictServerEndpointType.Token => Errors.InvalidGrant,
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
=> SR.GetResourceString(SR.ID2015),
context.Parameters[Parameters.ErrorDescription] = context.EndpointType switch
{
OpenIddictServerEndpointType.Authorization or OpenIddictServerEndpointType.Verification
=> SR.GetResourceString(SR.ID2015),
OpenIddictServerEndpointType.Token => SR.GetResourceString(SR.ID2024),
OpenIddictServerEndpointType.Userinfo => SR.GetResourceString(SR.ID2025),
OpenIddictServerEndpointType.Token => SR.GetResourceString(SR.ID2024),
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
=> SR.FormatID8000(SR.ID2015),
context.Parameters[Parameters.ErrorUri] = context.EndpointType switch
{
OpenIddictServerEndpointType.Authorization or OpenIddictServerEndpointType.Verification
=> SR.FormatID8000(SR.ID2015),
OpenIddictServerEndpointType.Token => SR.FormatID8000(SR.ID2024),
OpenIddictServerEndpointType.Userinfo => SR.FormatID8000(SR.ID2025),
OpenIddictServerEndpointType.Token => SR.FormatID8000(SR.ID2024),
OpenIddictServerEndpointType.Userinfo => SR.FormatID8000(SR.ID2025),
_ => throw new InvalidOperationException(SR.GetResourceString(SR.ID0006))
};
_ => throw new InvalidOperationException(SR.GetResourceString(SR.ID0006))
};
}
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>
/// Contains the logic responsible of ensuring that the sign-in demand
/// 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
OpenIddictServerEndpointType.Device or
OpenIddictServerEndpointType.Token or
OpenIddictServerEndpointType.Device or
OpenIddictServerEndpointType.Token or
OpenIddictServerEndpointType.Verification))
{
throw new InvalidOperationException(SR.GetResourceString(SR.ID0010));
@ -3045,5 +3095,44 @@ namespace OpenIddict.Server
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)
{
Response = new OpenIddictResponse
{
Error = context.Error ?? Errors.InvalidRequest,
ErrorDescription = context.ErrorDescription,
ErrorUri = context.ErrorUri
}
Error = context.Error ?? Errors.InvalidRequest,
ErrorDescription = context.ErrorDescription,
ErrorUri = context.ErrorUri,
Response = new OpenIddictResponse()
};
await _dispatcher.DispatchAsync(notification);
@ -225,12 +223,10 @@ namespace OpenIddict.Validation.AspNetCore
{
var notification = new ProcessErrorContext(transaction)
{
Response = new OpenIddictResponse
{
Error = context.Error ?? Errors.InvalidRequest,
ErrorDescription = context.ErrorDescription,
ErrorUri = context.ErrorUri
}
Error = context.Error ?? Errors.InvalidRequest,
ErrorDescription = context.ErrorDescription,
ErrorUri = context.ErrorUri,
Response = new OpenIddictResponse()
};
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.Primitives;
using Microsoft.Net.Http.Headers;
using OpenIddict.Abstractions;
using static OpenIddict.Abstractions.OpenIddictConstants;
using static OpenIddict.Validation.AspNetCore.OpenIddictValidationAspNetCoreHandlerFilters;
using static OpenIddict.Validation.OpenIddictValidationEvents;
@ -325,12 +326,49 @@ namespace OpenIddict.Validation.AspNetCore
}
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);
context.Response.ErrorDescription = properties.GetString(Properties.ErrorDescription);
context.Response.ErrorUri = properties.GetString(Properties.ErrorUri);
context.Response.Scope = properties.GetString(Properties.Scope);
return default;
}
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;

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

@ -91,12 +91,10 @@ namespace OpenIddict.Validation.Owin
{
var notification = new ProcessErrorContext(transaction)
{
Response = new OpenIddictResponse
{
Error = context.Error ?? Errors.InvalidRequest,
ErrorDescription = context.ErrorDescription,
ErrorUri = context.ErrorUri
}
Error = context.Error ?? Errors.InvalidRequest,
ErrorDescription = context.ErrorDescription,
ErrorUri = context.ErrorUri,
Response = new OpenIddictResponse()
};
await _dispatcher.DispatchAsync(notification);
@ -237,12 +235,10 @@ namespace OpenIddict.Validation.Owin
{
var notification = new ProcessErrorContext(transaction)
{
Response = new OpenIddictResponse
{
Error = context.Error ?? Errors.InvalidRequest,
ErrorDescription = context.ErrorDescription,
ErrorUri = context.ErrorUri
}
Error = context.Error ?? Errors.InvalidRequest,
ErrorDescription = context.ErrorDescription,
ErrorUri = context.ErrorUri,
Response = new OpenIddictResponse()
};
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!);
if (properties is not null)
if (properties is null)
{
context.Response.Error = GetProperty(properties, Properties.Error);
context.Response.ErrorDescription = GetProperty(properties, Properties.ErrorDescription);
context.Response.ErrorUri = GetProperty(properties, Properties.ErrorUri);
context.Response.Scope = GetProperty(properties, Properties.Scope);
return default;
}
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)
=> properties.Dictionary.TryGetValue(name, out string? value) ? value : null;
if (properties.Dictionary.TryGetValue(Properties.ErrorUri, out string? uri) &&
!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.Collections.Generic;
using System.ComponentModel;
using System.Security.Claims;
using Microsoft.Extensions.Logging;
@ -213,6 +214,26 @@ namespace OpenIddict.Validation
get => Transaction.Response!;
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>
@ -294,6 +315,11 @@ namespace OpenIddict.Validation
get => Transaction.Response!;
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>
/// Contains the logic responsible of extracting potential errors from the response.
/// </summary>

Loading…
Cancel
Save