|
|
|
@ -7,6 +7,7 @@ |
|
|
|
using System.Collections.Immutable; |
|
|
|
using System.ComponentModel; |
|
|
|
using System.Diagnostics; |
|
|
|
using System.Globalization; |
|
|
|
using System.Text; |
|
|
|
using System.Text.Encodings.Web; |
|
|
|
using System.Text.Json; |
|
|
|
@ -32,7 +33,18 @@ public static partial class OpenIddictServerOwinHandlers |
|
|
|
/* |
|
|
|
* Challenge processing: |
|
|
|
*/ |
|
|
|
AttachHostChallengeError.Descriptor) |
|
|
|
AttachHostChallengeError.Descriptor, |
|
|
|
ResolveHostChallengeParameters.Descriptor, |
|
|
|
|
|
|
|
/* |
|
|
|
* Sign-in processing: |
|
|
|
*/ |
|
|
|
ResolveHostSignInParameters.Descriptor, |
|
|
|
|
|
|
|
/* |
|
|
|
* Sign-out processing: |
|
|
|
*/ |
|
|
|
ResolveHostSignOutParameters.Descriptor) |
|
|
|
.AddRange(Authentication.DefaultHandlers) |
|
|
|
.AddRange(Device.DefaultHandlers) |
|
|
|
.AddRange(Discovery.DefaultHandlers) |
|
|
|
@ -304,6 +316,228 @@ public static partial class OpenIddictServerOwinHandlers |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Contains the logic responsible for 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 ResolveHostChallengeParameters : IOpenIddictServerHandler<ProcessChallengeContext> |
|
|
|
{ |
|
|
|
/// <summary>
|
|
|
|
/// Gets the default descriptor definition assigned to this handler.
|
|
|
|
/// </summary>
|
|
|
|
public static OpenIddictServerHandlerDescriptor Descriptor { get; } |
|
|
|
= OpenIddictServerHandlerDescriptor.CreateBuilder<ProcessChallengeContext>() |
|
|
|
.AddFilter<RequireOwinRequest>() |
|
|
|
.UseSingletonHandler<ResolveHostChallengeParameters>() |
|
|
|
.SetOrder(AttachChallengeParameters.Descriptor.Order - 500) |
|
|
|
.SetType(OpenIddictServerHandlerType.BuiltIn) |
|
|
|
.Build(); |
|
|
|
|
|
|
|
/// <inheritdoc/>
|
|
|
|
public ValueTask HandleAsync(ProcessChallengeContext context) |
|
|
|
{ |
|
|
|
if (context is null) |
|
|
|
{ |
|
|
|
throw new ArgumentNullException(nameof(context)); |
|
|
|
} |
|
|
|
|
|
|
|
var properties = context.Transaction.GetProperty<AuthenticationProperties>(typeof(AuthenticationProperties).FullName!); |
|
|
|
if (properties is null) |
|
|
|
{ |
|
|
|
return default; |
|
|
|
} |
|
|
|
|
|
|
|
// Note: unlike ASP.NET Core, Owin's AuthenticationProperties doesn't offer a strongly-typed
|
|
|
|
// dictionary that allows flowing parameters while preserving their original types. To allow
|
|
|
|
// returning custom parameters, the OWIN host allows using AuthenticationProperties.Dictionary
|
|
|
|
// but requires suffixing the properties that are meant to be used as parameters using a special
|
|
|
|
// suffix that indicates that the property is public and determines its actual representation.
|
|
|
|
foreach (var property in properties.Dictionary) |
|
|
|
{ |
|
|
|
var (name, value) = property.Key switch |
|
|
|
{ |
|
|
|
// If the property ends with #string, represent it as a string parameter.
|
|
|
|
string key when key.EndsWith(PropertyTypes.String, StringComparison.OrdinalIgnoreCase) => ( |
|
|
|
Name: key.Substring(0, key.Length - PropertyTypes.String.Length), |
|
|
|
Value: new OpenIddictParameter(property.Value)), |
|
|
|
|
|
|
|
// If the property ends with #boolean, return it as a boolean parameter.
|
|
|
|
string key when key.EndsWith(PropertyTypes.Boolean, StringComparison.OrdinalIgnoreCase) => ( |
|
|
|
Name: key.Substring(0, key.Length - PropertyTypes.Boolean.Length), |
|
|
|
Value: new OpenIddictParameter(bool.Parse(property.Value))), |
|
|
|
|
|
|
|
// If the property ends with #integer, return it as an integer parameter.
|
|
|
|
string key when key.EndsWith(PropertyTypes.Integer, StringComparison.OrdinalIgnoreCase) => ( |
|
|
|
Name: key.Substring(0, key.Length - PropertyTypes.Integer.Length), |
|
|
|
Value: new OpenIddictParameter(long.Parse(property.Value, CultureInfo.InvariantCulture))), |
|
|
|
|
|
|
|
// If the property ends with #json, return it as a JSON parameter.
|
|
|
|
string key when key.EndsWith(PropertyTypes.Json, StringComparison.OrdinalIgnoreCase) => ( |
|
|
|
Name: key.Substring(0, key.Length - PropertyTypes.Json.Length), |
|
|
|
Value: new OpenIddictParameter(JsonSerializer.Deserialize<JsonElement>(property.Value))), |
|
|
|
|
|
|
|
_ => default |
|
|
|
}; |
|
|
|
|
|
|
|
if (!string.IsNullOrEmpty(name)) |
|
|
|
{ |
|
|
|
context.Parameters[name] = value; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return default; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Contains the logic responsible for 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 ResolveHostSignInParameters : IOpenIddictServerHandler<ProcessSignInContext> |
|
|
|
{ |
|
|
|
/// <summary>
|
|
|
|
/// Gets the default descriptor definition assigned to this handler.
|
|
|
|
/// </summary>
|
|
|
|
public static OpenIddictServerHandlerDescriptor Descriptor { get; } |
|
|
|
= OpenIddictServerHandlerDescriptor.CreateBuilder<ProcessSignInContext>() |
|
|
|
.AddFilter<RequireOwinRequest>() |
|
|
|
.UseSingletonHandler<ResolveHostSignInParameters>() |
|
|
|
.SetOrder(AttachSignInParameters.Descriptor.Order - 500) |
|
|
|
.SetType(OpenIddictServerHandlerType.BuiltIn) |
|
|
|
.Build(); |
|
|
|
|
|
|
|
/// <inheritdoc/>
|
|
|
|
public ValueTask HandleAsync(ProcessSignInContext context) |
|
|
|
{ |
|
|
|
if (context is null) |
|
|
|
{ |
|
|
|
throw new ArgumentNullException(nameof(context)); |
|
|
|
} |
|
|
|
|
|
|
|
var properties = context.Transaction.GetProperty<AuthenticationProperties>(typeof(AuthenticationProperties).FullName!); |
|
|
|
if (properties is null) |
|
|
|
{ |
|
|
|
return default; |
|
|
|
} |
|
|
|
|
|
|
|
// Note: unlike ASP.NET Core, Owin's AuthenticationProperties doesn't offer a strongly-typed
|
|
|
|
// dictionary that allows flowing parameters while preserving their original types. To allow
|
|
|
|
// returning custom parameters, the OWIN host allows using AuthenticationProperties.Dictionary
|
|
|
|
// but requires suffixing the properties that are meant to be used as parameters using a special
|
|
|
|
// suffix that indicates that the property is public and determines its actual representation.
|
|
|
|
foreach (var property in properties.Dictionary) |
|
|
|
{ |
|
|
|
var (name, value) = property.Key switch |
|
|
|
{ |
|
|
|
// If the property ends with #string, represent it as a string parameter.
|
|
|
|
string key when key.EndsWith(PropertyTypes.String, StringComparison.OrdinalIgnoreCase) => ( |
|
|
|
Name: key.Substring(0, key.Length - PropertyTypes.String.Length), |
|
|
|
Value: new OpenIddictParameter(property.Value)), |
|
|
|
|
|
|
|
// If the property ends with #boolean, return it as a boolean parameter.
|
|
|
|
string key when key.EndsWith(PropertyTypes.Boolean, StringComparison.OrdinalIgnoreCase) => ( |
|
|
|
Name: key.Substring(0, key.Length - PropertyTypes.Boolean.Length), |
|
|
|
Value: new OpenIddictParameter(bool.Parse(property.Value))), |
|
|
|
|
|
|
|
// If the property ends with #integer, return it as an integer parameter.
|
|
|
|
string key when key.EndsWith(PropertyTypes.Integer, StringComparison.OrdinalIgnoreCase) => ( |
|
|
|
Name: key.Substring(0, key.Length - PropertyTypes.Integer.Length), |
|
|
|
Value: new OpenIddictParameter(long.Parse(property.Value, CultureInfo.InvariantCulture))), |
|
|
|
|
|
|
|
// If the property ends with #json, return it as a JSON parameter.
|
|
|
|
string key when key.EndsWith(PropertyTypes.Json, StringComparison.OrdinalIgnoreCase) => ( |
|
|
|
Name: key.Substring(0, key.Length - PropertyTypes.Json.Length), |
|
|
|
Value: new OpenIddictParameter(JsonSerializer.Deserialize<JsonElement>(property.Value))), |
|
|
|
|
|
|
|
_ => default |
|
|
|
}; |
|
|
|
|
|
|
|
if (!string.IsNullOrEmpty(name)) |
|
|
|
{ |
|
|
|
context.Parameters[name] = value; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return default; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Contains the logic responsible for resolving the additional sign-out parameters stored in the
|
|
|
|
/// OWIN 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 OWIN.
|
|
|
|
/// </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<RequireOwinRequest>() |
|
|
|
.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) |
|
|
|
{ |
|
|
|
return default; |
|
|
|
} |
|
|
|
|
|
|
|
// Note: unlike ASP.NET Core, Owin's AuthenticationProperties doesn't offer a strongly-typed
|
|
|
|
// dictionary that allows flowing parameters while preserving their original types. To allow
|
|
|
|
// returning custom parameters, the OWIN host allows using AuthenticationProperties.Dictionary
|
|
|
|
// but requires suffixing the properties that are meant to be used as parameters using a special
|
|
|
|
// suffix that indicates that the property is public and determines its actual representation.
|
|
|
|
foreach (var property in properties.Dictionary) |
|
|
|
{ |
|
|
|
var (name, value) = property.Key switch |
|
|
|
{ |
|
|
|
// If the property ends with #string, represent it as a string parameter.
|
|
|
|
string key when key.EndsWith(PropertyTypes.String, StringComparison.OrdinalIgnoreCase) => ( |
|
|
|
Name: key.Substring(0, key.Length - PropertyTypes.String.Length), |
|
|
|
Value: new OpenIddictParameter(property.Value)), |
|
|
|
|
|
|
|
// If the property ends with #boolean, return it as a boolean parameter.
|
|
|
|
string key when key.EndsWith(PropertyTypes.Boolean, StringComparison.OrdinalIgnoreCase) => ( |
|
|
|
Name: key.Substring(0, key.Length - PropertyTypes.Boolean.Length), |
|
|
|
Value: new OpenIddictParameter(bool.Parse(property.Value))), |
|
|
|
|
|
|
|
// If the property ends with #integer, return it as an integer parameter.
|
|
|
|
string key when key.EndsWith(PropertyTypes.Integer, StringComparison.OrdinalIgnoreCase) => ( |
|
|
|
Name: key.Substring(0, key.Length - PropertyTypes.Integer.Length), |
|
|
|
Value: new OpenIddictParameter(long.Parse(property.Value, CultureInfo.InvariantCulture))), |
|
|
|
|
|
|
|
// If the property ends with #json, return it as a JSON parameter.
|
|
|
|
string key when key.EndsWith(PropertyTypes.Json, StringComparison.OrdinalIgnoreCase) => ( |
|
|
|
Name: key.Substring(0, key.Length - PropertyTypes.Json.Length), |
|
|
|
Value: new OpenIddictParameter(JsonSerializer.Deserialize<JsonElement>(property.Value))), |
|
|
|
|
|
|
|
_ => default |
|
|
|
}; |
|
|
|
|
|
|
|
if (!string.IsNullOrEmpty(name)) |
|
|
|
{ |
|
|
|
context.Parameters[name] = value; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return default; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Contains the logic responsible for extracting OpenID Connect requests from GET HTTP requests.
|
|
|
|
/// Note: this handler is not used when the OpenID Connect request is not initially handled by OWIN.
|
|
|
|
|