diff --git a/sandbox/OpenIddict.Sandbox.AspNet.Client/Controllers/AuthenticationController.cs b/sandbox/OpenIddict.Sandbox.AspNet.Client/Controllers/AuthenticationController.cs
index bdd0d2ae..10f72d17 100644
--- a/sandbox/OpenIddict.Sandbox.AspNet.Client/Controllers/AuthenticationController.cs
+++ b/sandbox/OpenIddict.Sandbox.AspNet.Client/Controllers/AuthenticationController.cs
@@ -15,7 +15,7 @@ namespace OpenIddict.Sandbox.AspNet.Client.Controllers
{
public class AuthenticationController : Controller
{
- [HttpGet, Route("~/login")]
+ [HttpPost, Route("~/login"), ValidateAntiForgeryToken]
public ActionResult LogIn(string provider, string returnUrl)
{
var context = HttpContext.GetOwinContext();
diff --git a/sandbox/OpenIddict.Sandbox.AspNet.Client/Views/Home/Index.cshtml b/sandbox/OpenIddict.Sandbox.AspNet.Client/Views/Home/Index.cshtml
index d996692f..2115a85a 100644
--- a/sandbox/OpenIddict.Sandbox.AspNet.Client/Views/Home/Index.cshtml
+++ b/sandbox/OpenIddict.Sandbox.AspNet.Client/Views/Home/Index.cshtml
@@ -31,6 +31,8 @@
}
@@ -38,15 +40,31 @@
else
{
Welcome, anonymous
- @Html.ActionLink("Sign in using the local OIDC server", "Login", "Authentication",
- new { provider = "Local" }, new { @class = "btn btn-lg btn-success" })
- @Html.ActionLink("Sign in using the local OIDC server (using GitHub delegation)", "Login", "Authentication",
- new { provider = "Local+GitHub" }, new { @class = "btn btn-lg btn-success" })
- @Html.ActionLink("Sign in using GitHub", "Login", "Authentication",
- new { provider = "GitHub" }, new { @class = "btn btn-lg btn-success" })
- @Html.ActionLink("Sign in using Google", "Login", "Authentication",
- new { provider = "Google" }, new { @class = "btn btn-lg btn-success" })
- @Html.ActionLink("Sign in using Twitter", "Login", "Authentication",
- new { provider = "Twitter" }, new { @class = "btn btn-lg btn-success" })
+
+
}
\ No newline at end of file
diff --git a/sandbox/OpenIddict.Sandbox.AspNetCore.Client/Controllers/AuthenticationController.cs b/sandbox/OpenIddict.Sandbox.AspNetCore.Client/Controllers/AuthenticationController.cs
index 6ce2bc4b..7e33c2ba 100644
--- a/sandbox/OpenIddict.Sandbox.AspNetCore.Client/Controllers/AuthenticationController.cs
+++ b/sandbox/OpenIddict.Sandbox.AspNetCore.Client/Controllers/AuthenticationController.cs
@@ -10,7 +10,7 @@ namespace OpenIddict.Sandbox.AspNetCore.Client.Controllers;
public class AuthenticationController : Controller
{
- [HttpGet("~/login")]
+ [HttpPost("~/login"), ValidateAntiForgeryToken]
public ActionResult LogIn(string provider, string returnUrl)
{
// Note: OpenIddict always validates the specified provider name when handling the challenge operation,
@@ -41,7 +41,10 @@ public class AuthenticationController : Controller
// Only allow local return URLs to prevent open redirect attacks.
RedirectUri = Url.IsLocalUrl(returnUrl) ? returnUrl : "/",
- Parameters = { [Parameters.IdentityProvider] = "GitHub" }
+ Parameters =
+ {
+ [Parameters.IdentityProvider] = "GitHub"
+ }
};
// Ask the OpenIddict client middleware to redirect the user agent to the identity provider.
@@ -146,7 +149,7 @@ public class AuthenticationController : Controller
// Such identities cannot be used as-is to build an authentication cookie in ASP.NET Core (as the
// antiforgery stack requires at least a name claim to bind CSRF cookies to the user's identity) but
// the access/refresh tokens can be retrieved using result.Properties.GetTokens() to make API calls.
- if (result.Principal.Identity is not ClaimsIdentity { IsAuthenticated: true })
+ if (result.Principal is not ClaimsPrincipal { Identity.IsAuthenticated: true })
{
throw new InvalidOperationException("The external authorization data cannot be used for authentication.");
}
diff --git a/sandbox/OpenIddict.Sandbox.AspNetCore.Client/Views/Home/Index.cshtml b/sandbox/OpenIddict.Sandbox.AspNetCore.Client/Views/Home/Index.cshtml
index d5393c95..4c97a1d7 100644
--- a/sandbox/OpenIddict.Sandbox.AspNetCore.Client/Views/Home/Index.cshtml
+++ b/sandbox/OpenIddict.Sandbox.AspNetCore.Client/Views/Home/Index.cshtml
@@ -33,17 +33,33 @@
else
{
Welcome, anonymous
- Sign in using the local OIDC server
- Sign in using the local OIDC server (using GitHub delegation)
- Sign in using GitHub
- Sign in using Google
- Sign in using Reddit
- Sign in using Twitter
+
+
}
\ No newline at end of file
diff --git a/sandbox/OpenIddict.Sandbox.AspNetCore.Server/Controllers/AuthenticationController.cs b/sandbox/OpenIddict.Sandbox.AspNetCore.Server/Controllers/AuthenticationController.cs
index 21d4ef21..419185cb 100644
--- a/sandbox/OpenIddict.Sandbox.AspNetCore.Server/Controllers/AuthenticationController.cs
+++ b/sandbox/OpenIddict.Sandbox.AspNetCore.Server/Controllers/AuthenticationController.cs
@@ -45,7 +45,7 @@ public class AuthenticationController : Controller
// Such identities cannot be used as-is to build an authentication cookie in ASP.NET Core (as the
// antiforgery stack requires at least a name claim to bind CSRF cookies to the user's identity) but
// the access/refresh tokens can be retrieved using result.Properties.GetTokens() to make API calls.
- if (result.Principal.Identity is not ClaimsIdentity { IsAuthenticated: true })
+ if (result.Principal is not ClaimsPrincipal { Identity.IsAuthenticated: true })
{
throw new InvalidOperationException("The external authorization data cannot be used for authentication.");
}
diff --git a/src/OpenIddict.Client.AspNetCore/OpenIddictClientAspNetCoreHandlers.cs b/src/OpenIddict.Client.AspNetCore/OpenIddictClientAspNetCoreHandlers.cs
index 5d0a410c..9729d3ee 100644
--- a/src/OpenIddict.Client.AspNetCore/OpenIddictClientAspNetCoreHandlers.cs
+++ b/src/OpenIddict.Client.AspNetCore/OpenIddictClientAspNetCoreHandlers.cs
@@ -42,13 +42,13 @@ public static partial class OpenIddictClientAspNetCoreHandlers
/*
* Challenge processing:
*/
- ResolveHostChallengeParameters.Descriptor,
+ ResolveHostChallengeProperties.Descriptor,
GenerateLoginCorrelationCookie.Descriptor,
/*
* Sign-out processing:
*/
- ResolveHostSignOutParameters.Descriptor,
+ ResolveHostSignOutProperties.Descriptor,
GenerateLogoutCorrelationCookie.Descriptor)
.AddRange(Authentication.DefaultHandlers)
.AddRange(Session.DefaultHandlers);
@@ -414,11 +414,11 @@ public static partial class OpenIddictClientAspNetCoreHandlers
}
///
- /// Contains the logic responsible for resolving the additional challenge parameters stored in the ASP.NET
- /// Core authentication properties specified by the application that triggered the challenge operation.
+ /// Contains the logic responsible for resolving the context-specific properties and parameters stored in the
+ /// ASP.NET Core authentication properties specified by the application that triggered the challenge operation.
/// Note: this handler is not used when the OpenID Connect request is not initially handled by ASP.NET Core.
///
- public class ResolveHostChallengeParameters : IOpenIddictClientHandler
+ public class ResolveHostChallengeProperties : IOpenIddictClientHandler
{
///
/// Gets the default descriptor definition assigned to this handler.
@@ -426,7 +426,7 @@ public static partial class OpenIddictClientAspNetCoreHandlers
public static OpenIddictClientHandlerDescriptor Descriptor { get; }
= OpenIddictClientHandlerDescriptor.CreateBuilder()
.AddFilter()
- .UseSingletonHandler()
+ .UseSingletonHandler()
.SetOrder(ValidateChallengeDemand.Descriptor.Order - 500)
.SetType(OpenIddictClientHandlerType.BuiltIn)
.Build();
@@ -439,76 +439,74 @@ public static partial class OpenIddictClientAspNetCoreHandlers
throw new ArgumentNullException(nameof(context));
}
- Debug.Assert(context.Principal is { Identity: ClaimsIdentity }, SR.GetResourceString(SR.ID4006));
-
var properties = context.Transaction.GetProperty(typeof(AuthenticationProperties).FullName!);
- if (properties is null)
- {
- return default;
- }
-
- // If an issuer was explicitly set, update the challenge context to use it.
- if (properties.Items.TryGetValue(Properties.Issuer, out string? issuer) && !string.IsNullOrEmpty(issuer))
+ if (properties is { Items.Count: > 0 })
{
- // Ensure the issuer set by the application is a valid absolute URI.
- if (!Uri.TryCreate(issuer, UriKind.Absolute, out Uri? uri) || !uri.IsWellFormedOriginalString())
+ // If an issuer was explicitly set, update the challenge context to use it.
+ if (properties.Items.TryGetValue(Properties.Issuer, out string? issuer) && !string.IsNullOrEmpty(issuer))
{
- throw new InvalidOperationException(SR.GetResourceString(SR.ID0306));
- }
+ // Ensure the issuer set by the application is a valid absolute URI.
+ if (!Uri.TryCreate(issuer, UriKind.Absolute, out Uri? uri) || !uri.IsWellFormedOriginalString())
+ {
+ throw new InvalidOperationException(SR.GetResourceString(SR.ID0306));
+ }
- context.Issuer = uri;
- }
+ context.Issuer = uri;
+ }
- // If a provider name was explicitly set, update the challenge context to use it.
- if (properties.Items.TryGetValue(Properties.ProviderName, out string? provider) &&
- !string.IsNullOrEmpty(provider))
- {
- context.ProviderName = provider;
- }
+ // If a provider name was explicitly set, update the challenge context to use it.
+ if (properties.Items.TryGetValue(Properties.ProviderName, out string? provider) &&
+ !string.IsNullOrEmpty(provider))
+ {
+ context.ProviderName = provider;
+ }
- // If a return URL was specified, use it as the target_link_uri claim.
- if (!string.IsNullOrEmpty(properties.RedirectUri))
- {
- context.TargetLinkUri = properties.RedirectUri;
- }
+ // If a return URL was specified, use it as the target_link_uri claim.
+ if (!string.IsNullOrEmpty(properties.RedirectUri))
+ {
+ context.TargetLinkUri = properties.RedirectUri;
+ }
- // If an identity token hint was specified, attach it to the context.
- if (properties.Items.TryGetValue(Properties.IdentityTokenHint, out string? token) &&
- !string.IsNullOrEmpty(token))
- {
- context.IdentityTokenHint = token;
- }
+ // If an identity token hint was specified, attach it to the context.
+ if (properties.Items.TryGetValue(Properties.IdentityTokenHint, out string? token) &&
+ !string.IsNullOrEmpty(token))
+ {
+ context.IdentityTokenHint = token;
+ }
- // If a login hint was specified, attach it to the context.
- if (properties.Items.TryGetValue(Properties.LoginHint, out string? hint) &&
- !string.IsNullOrEmpty(hint))
- {
- context.LoginHint = hint;
- }
+ // If a login hint was specified, attach it to the context.
+ if (properties.Items.TryGetValue(Properties.LoginHint, out string? hint) &&
+ !string.IsNullOrEmpty(hint))
+ {
+ context.LoginHint = hint;
+ }
- // Preserve the host properties in the principal.
- if (properties.Items.Count is not 0)
- {
- context.Principal.SetClaim(Claims.Private.HostProperties, properties.Items);
+ foreach (var property in properties.Items)
+ {
+ context.Properties[property.Key] = property.Value;
+ }
}
- foreach (var parameter in properties.Parameters)
+ if (properties is { Parameters.Count: > 0 })
{
- context.Parameters[parameter.Key] = parameter.Value switch
+ foreach (var parameter in properties.Parameters)
{
- 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),
+ 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),
#if SUPPORTS_JSON_NODES
- JsonNode value => new OpenIddictParameter(value),
+ JsonNode value => new OpenIddictParameter(value),
#endif
- _ => throw new InvalidOperationException(SR.GetResourceString(SR.ID0115))
- };
+ _ => throw new InvalidOperationException(SR.GetResourceString(SR.ID0115))
+ };
+ }
}
return default;
@@ -590,11 +588,11 @@ public static partial class OpenIddictClientAspNetCoreHandlers
}
///
- /// Contains the logic responsible for resolving the additional sign-out parameters stored in the ASP.NET
- /// Core authentication properties specified by the application that triggered the sign-out operation.
+ /// Contains the logic responsible for resolving the context-specific properties and 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.
///
- public class ResolveHostSignOutParameters : IOpenIddictClientHandler
+ public class ResolveHostSignOutProperties : IOpenIddictClientHandler
{
///
/// Gets the default descriptor definition assigned to this handler.
@@ -602,7 +600,7 @@ public static partial class OpenIddictClientAspNetCoreHandlers
public static OpenIddictClientHandlerDescriptor Descriptor { get; }
= OpenIddictClientHandlerDescriptor.CreateBuilder()
.AddFilter()
- .UseSingletonHandler()
+ .UseSingletonHandler()
.SetOrder(ValidateSignOutDemand.Descriptor.Order - 500)
.SetType(OpenIddictClientHandlerType.BuiltIn)
.Build();
@@ -615,76 +613,74 @@ public static partial class OpenIddictClientAspNetCoreHandlers
throw new ArgumentNullException(nameof(context));
}
- Debug.Assert(context.Principal is { Identity: ClaimsIdentity }, SR.GetResourceString(SR.ID4006));
-
var properties = context.Transaction.GetProperty(typeof(AuthenticationProperties).FullName!);
- if (properties is null)
- {
- return default;
- }
-
- // If an issuer was explicitly set, update the sign-out context to use it.
- if (properties.Items.TryGetValue(Properties.Issuer, out string? issuer) && !string.IsNullOrEmpty(issuer))
+ if (properties is { Items.Count: > 0 })
{
- // Ensure the issuer set by the application is a valid absolute URI.
- if (!Uri.TryCreate(issuer, UriKind.Absolute, out Uri? uri) || !uri.IsWellFormedOriginalString())
+ // If an issuer was explicitly set, update the sign-out context to use it.
+ if (properties.Items.TryGetValue(Properties.Issuer, out string? issuer) && !string.IsNullOrEmpty(issuer))
{
- throw new InvalidOperationException(SR.GetResourceString(SR.ID0306));
- }
+ // Ensure the issuer set by the application is a valid absolute URI.
+ if (!Uri.TryCreate(issuer, UriKind.Absolute, out Uri? uri) || !uri.IsWellFormedOriginalString())
+ {
+ throw new InvalidOperationException(SR.GetResourceString(SR.ID0306));
+ }
- context.Issuer = uri;
- }
+ context.Issuer = uri;
+ }
- // If a provider name was explicitly set, update the sign-out context to use it.
- if (properties.Items.TryGetValue(Properties.ProviderName, out string? provider) &&
- !string.IsNullOrEmpty(provider))
- {
- context.ProviderName = provider;
- }
+ // If a provider name was explicitly set, update the sign-out context to use it.
+ if (properties.Items.TryGetValue(Properties.ProviderName, out string? provider) &&
+ !string.IsNullOrEmpty(provider))
+ {
+ context.ProviderName = provider;
+ }
- // If a return URL was specified, use it as the target_link_uri claim.
- if (!string.IsNullOrEmpty(properties.RedirectUri))
- {
- context.TargetLinkUri = properties.RedirectUri;
- }
+ // If a return URL was specified, use it as the target_link_uri claim.
+ if (!string.IsNullOrEmpty(properties.RedirectUri))
+ {
+ context.TargetLinkUri = properties.RedirectUri;
+ }
- // If an identity token hint was specified, attach it to the context.
- if (properties.Items.TryGetValue(Properties.IdentityTokenHint, out string? token) &&
- !string.IsNullOrEmpty(token))
- {
- context.IdentityTokenHint = token;
- }
+ // If an identity token hint was specified, attach it to the context.
+ if (properties.Items.TryGetValue(Properties.IdentityTokenHint, out string? token) &&
+ !string.IsNullOrEmpty(token))
+ {
+ context.IdentityTokenHint = token;
+ }
- // If a login hint was specified, attach it to the context.
- if (properties.Items.TryGetValue(Properties.LoginHint, out string? hint) &&
- !string.IsNullOrEmpty(hint))
- {
- context.LoginHint = hint;
- }
+ // If a login hint was specified, attach it to the context.
+ if (properties.Items.TryGetValue(Properties.LoginHint, out string? hint) &&
+ !string.IsNullOrEmpty(hint))
+ {
+ context.LoginHint = hint;
+ }
- // Preserve the host properties in the principal.
- if (properties.Items.Count is not 0)
- {
- context.Principal.SetClaim(Claims.Private.HostProperties, properties.Items);
+ foreach (var property in properties.Items)
+ {
+ context.Properties[property.Key] = property.Value;
+ }
}
- foreach (var parameter in properties.Parameters)
+ if (properties is { Parameters.Count: > 0 })
{
- context.Parameters[parameter.Key] = parameter.Value switch
+ foreach (var parameter in properties.Parameters)
{
- 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),
+ 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),
#if SUPPORTS_JSON_NODES
- JsonNode value => new OpenIddictParameter(value),
+ JsonNode value => new OpenIddictParameter(value),
#endif
- _ => throw new InvalidOperationException(SR.GetResourceString(SR.ID0115))
- };
+ _ => throw new InvalidOperationException(SR.GetResourceString(SR.ID0115))
+ };
+ }
}
return default;
diff --git a/src/OpenIddict.Client.Owin/OpenIddictClientOwinHandlers.cs b/src/OpenIddict.Client.Owin/OpenIddictClientOwinHandlers.cs
index 16c8e197..4ece2246 100644
--- a/src/OpenIddict.Client.Owin/OpenIddictClientOwinHandlers.cs
+++ b/src/OpenIddict.Client.Owin/OpenIddictClientOwinHandlers.cs
@@ -38,13 +38,13 @@ public static partial class OpenIddictClientOwinHandlers
/*
* Challenge processing:
*/
- ResolveHostChallengeParameters.Descriptor,
+ ResolveHostChallengeProperties.Descriptor,
GenerateLoginCorrelationCookie.Descriptor,
/*
* Sign-out processing:
*/
- ResolveHostSignOutParameters.Descriptor,
+ ResolveHostSignOutProperties.Descriptor,
GenerateLogoutCorrelationCookie.Descriptor)
.AddRange(Authentication.DefaultHandlers)
.AddRange(Session.DefaultHandlers);
@@ -319,7 +319,7 @@ public static partial class OpenIddictClientOwinHandlers
///
/// Contains the logic responsible for comparing the current request URL to the expected URL stored in the state token.
- /// 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 OWIN.
///
public class ValidateEndpointUri : IOpenIddictClientHandler
{
@@ -425,11 +425,11 @@ public static partial class OpenIddictClientOwinHandlers
}
///
- /// Contains the logic responsible for resolving the additional challenge parameters stored in the ASP.NET
- /// Core authentication properties specified by the application that triggered the challenge operation.
+ /// Contains the logic responsible for resolving the context-specific properties and parameters stored in the
+ /// OWIN authentication properties specified by the application that triggered the challenge operation.
/// Note: this handler is not used when the OpenID Connect request is not initially handled by OWIN.
///
- public class ResolveHostChallengeParameters : IOpenIddictClientHandler
+ public class ResolveHostChallengeProperties : IOpenIddictClientHandler
{
///
/// Gets the default descriptor definition assigned to this handler.
@@ -437,7 +437,7 @@ public static partial class OpenIddictClientOwinHandlers
public static OpenIddictClientHandlerDescriptor Descriptor { get; }
= OpenIddictClientHandlerDescriptor.CreateBuilder()
.AddFilter()
- .UseSingletonHandler()
+ .UseSingletonHandler()
.SetOrder(ValidateChallengeDemand.Descriptor.Order - 500)
.SetType(OpenIddictClientHandlerType.BuiltIn)
.Build();
@@ -450,10 +450,8 @@ public static partial class OpenIddictClientOwinHandlers
throw new ArgumentNullException(nameof(context));
}
- Debug.Assert(context.Principal is { Identity: ClaimsIdentity }, SR.GetResourceString(SR.ID4006));
-
var properties = context.Transaction.GetProperty(typeof(AuthenticationProperties).FullName!);
- if (properties is null)
+ if (properties is not { Dictionary.Count: > 0 })
{
return default;
}
@@ -497,13 +495,7 @@ public static partial class OpenIddictClientOwinHandlers
context.LoginHint = hint;
}
- // Preserve the host properties in the principal.
- if (properties.Dictionary.Count is not 0)
- {
- context.Principal.SetClaim(Claims.Private.HostProperties, properties.Dictionary);
- }
-
- // Note: unlike ASP.NET Core, Owin's AuthenticationProperties doesn't offer a strongly-typed
+ // 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
@@ -539,6 +531,11 @@ public static partial class OpenIddictClientOwinHandlers
{
context.Parameters[name] = value;
}
+
+ else
+ {
+ context.Properties[property.Key] = property.Value;
+ }
}
return default;
@@ -628,11 +625,11 @@ public static partial class OpenIddictClientOwinHandlers
}
///
- /// Contains the logic responsible for resolving the additional sign-out parameters stored in the ASP.NET
- /// Core authentication properties specified by the application that triggered the sign-out operation.
+ /// Contains the logic responsible for resolving the context-specific properties and 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.
///
- public class ResolveHostSignOutParameters : IOpenIddictClientHandler
+ public class ResolveHostSignOutProperties : IOpenIddictClientHandler
{
///
/// Gets the default descriptor definition assigned to this handler.
@@ -640,7 +637,7 @@ public static partial class OpenIddictClientOwinHandlers
public static OpenIddictClientHandlerDescriptor Descriptor { get; }
= OpenIddictClientHandlerDescriptor.CreateBuilder()
.AddFilter()
- .UseSingletonHandler()
+ .UseSingletonHandler()
.SetOrder(ValidateSignOutDemand.Descriptor.Order - 500)
.SetType(OpenIddictClientHandlerType.BuiltIn)
.Build();
@@ -653,10 +650,8 @@ public static partial class OpenIddictClientOwinHandlers
throw new ArgumentNullException(nameof(context));
}
- Debug.Assert(context.Principal is { Identity: ClaimsIdentity }, SR.GetResourceString(SR.ID4006));
-
var properties = context.Transaction.GetProperty(typeof(AuthenticationProperties).FullName!);
- if (properties is null)
+ if (properties is not { Dictionary.Count: > 0 })
{
return default;
}
@@ -700,13 +695,7 @@ public static partial class OpenIddictClientOwinHandlers
context.LoginHint = hint;
}
- // Preserve the host properties in the principal.
- if (properties.Dictionary.Count is not 0)
- {
- context.Principal.SetClaim(Claims.Private.HostProperties, properties.Dictionary);
- }
-
- // Note: unlike ASP.NET Core, Owin's AuthenticationProperties doesn't offer a strongly-typed
+ // 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
@@ -742,6 +731,11 @@ public static partial class OpenIddictClientOwinHandlers
{
context.Parameters[name] = value;
}
+
+ else
+ {
+ context.Properties[property.Key] = property.Value;
+ }
}
return default;
diff --git a/src/OpenIddict.Client/OpenIddictClientEvents.cs b/src/OpenIddict.Client/OpenIddictClientEvents.cs
index ed7cdba2..2e7672d9 100644
--- a/src/OpenIddict.Client/OpenIddictClientEvents.cs
+++ b/src/OpenIddict.Client/OpenIddictClientEvents.cs
@@ -693,6 +693,11 @@ public static partial class OpenIddictClientEvents
set => Transaction.Response = value;
}
+ ///
+ /// Gets the user-defined authentication properties, if available.
+ ///
+ public Dictionary Properties { get; } = new(StringComparer.Ordinal);
+
///
/// Gets or sets the name of the provider that will be
/// used to resolve the issuer identity, if applicable.
@@ -700,7 +705,7 @@ public static partial class OpenIddictClientEvents
public string? ProviderName { get; set; }
///
- /// Gets the additional parameters returned to caller.
+ /// Gets the additional parameters returned to the caller.
///
public Dictionary Parameters { get; } = new(StringComparer.Ordinal);
@@ -843,6 +848,11 @@ public static partial class OpenIddictClientEvents
set => Transaction.Response = value;
}
+ ///
+ /// Gets the user-defined authentication properties, if available.
+ ///
+ public Dictionary Properties { get; } = new(StringComparer.Ordinal);
+
///
/// Gets or sets the name of the provider that will be
/// used to resolve the issuer identity, if applicable.
@@ -884,7 +894,7 @@ public static partial class OpenIddictClientEvents
public string? RequestForgeryProtection { get; set; }
///
- /// Gets the additional parameters returned to caller.
+ /// Gets the additional parameters returned to the caller.
///
public Dictionary Parameters { get; } = new(StringComparer.Ordinal);
diff --git a/src/OpenIddict.Client/OpenIddictClientHandlers.cs b/src/OpenIddict.Client/OpenIddictClientHandlers.cs
index 2c1f01c5..ecb8ccde 100644
--- a/src/OpenIddict.Client/OpenIddictClientHandlers.cs
+++ b/src/OpenIddict.Client/OpenIddictClientHandlers.cs
@@ -94,6 +94,7 @@ public static partial class OpenIddictClientHandlers
ResolveClientRegistrationFromChallengeContext.Descriptor,
AttachGrantType.Descriptor,
EvaluateGeneratedChallengeTokens.Descriptor,
+ AttachChallengeHostProperties.Descriptor,
AttachResponseType.Descriptor,
AttachResponseMode.Descriptor,
AttachClientId.Descriptor,
@@ -116,6 +117,7 @@ public static partial class OpenIddictClientHandlers
AttachOptionalClientId.Descriptor,
AttachPostLogoutRedirectUri.Descriptor,
EvaluateGeneratedLogoutTokens.Descriptor,
+ AttachSignOutHostProperties.Descriptor,
AttachLogoutRequestForgeryProtection.Descriptor,
PrepareLogoutStateTokenPrincipal.Descriptor,
GenerateLogoutStateToken.Descriptor,
@@ -3567,6 +3569,37 @@ public static partial class OpenIddictClientHandlers
}
}
+ ///
+ /// Contains the logic responsible for attaching the user-defined properties to the authentication principal.
+ ///
+ public class AttachChallengeHostProperties : IOpenIddictClientHandler
+ {
+ ///
+ /// Gets the default descriptor definition assigned to this handler.
+ ///
+ public static OpenIddictClientHandlerDescriptor Descriptor { get; }
+ = OpenIddictClientHandlerDescriptor.CreateBuilder()
+ .UseSingletonHandler()
+ .SetOrder(EvaluateGeneratedChallengeTokens.Descriptor.Order + 1_000)
+ .SetType(OpenIddictClientHandlerType.BuiltIn)
+ .Build();
+
+ ///
+ public ValueTask HandleAsync(ProcessChallengeContext context)
+ {
+ if (context is null)
+ {
+ throw new ArgumentNullException(nameof(context));
+ }
+
+ Debug.Assert(context.Principal is { Identity: ClaimsIdentity }, SR.GetResourceString(SR.ID4006));
+
+ context.Principal.SetClaim(Claims.Private.HostProperties, context.Properties);
+
+ return default;
+ }
+ }
+
///
/// Contains the logic responsible for attaching the response type to the challenge request.
///
@@ -3579,7 +3612,7 @@ public static partial class OpenIddictClientHandlers
= OpenIddictClientHandlerDescriptor.CreateBuilder()
.AddFilter()
.UseSingletonHandler()
- .SetOrder(EvaluateGeneratedChallengeTokens.Descriptor.Order + 1_000)
+ .SetOrder(AttachChallengeHostProperties.Descriptor.Order + 1_000)
.Build();
///
@@ -4646,6 +4679,37 @@ public static partial class OpenIddictClientHandlers
}
}
+ ///
+ /// Contains the logic responsible for attaching the user-defined properties to the authentication principal.
+ ///
+ public class AttachSignOutHostProperties : IOpenIddictClientHandler
+ {
+ ///
+ /// Gets the default descriptor definition assigned to this handler.
+ ///
+ public static OpenIddictClientHandlerDescriptor Descriptor { get; }
+ = OpenIddictClientHandlerDescriptor.CreateBuilder()
+ .UseSingletonHandler()
+ .SetOrder(EvaluateGeneratedLogoutTokens.Descriptor.Order + 1_000)
+ .SetType(OpenIddictClientHandlerType.BuiltIn)
+ .Build();
+
+ ///
+ public ValueTask HandleAsync(ProcessSignOutContext context)
+ {
+ if (context is null)
+ {
+ throw new ArgumentNullException(nameof(context));
+ }
+
+ Debug.Assert(context.Principal is { Identity: ClaimsIdentity }, SR.GetResourceString(SR.ID4006));
+
+ context.Principal.SetClaim(Claims.Private.HostProperties, context.Properties);
+
+ return default;
+ }
+ }
+
///
/// Contains the logic responsible for attaching a request forgery protection to the authorization request.
///
@@ -4657,7 +4721,7 @@ public static partial class OpenIddictClientHandlers
public static OpenIddictClientHandlerDescriptor Descriptor { get; }
= OpenIddictClientHandlerDescriptor.CreateBuilder()
.UseSingletonHandler()
- .SetOrder(EvaluateGeneratedLogoutTokens.Descriptor.Order + 1_000)
+ .SetOrder(AttachSignOutHostProperties.Descriptor.Order + 1_000)
.Build();
///
diff --git a/src/OpenIddict.Server.AspNetCore/OpenIddictServerAspNetCoreHandlers.cs b/src/OpenIddict.Server.AspNetCore/OpenIddictServerAspNetCoreHandlers.cs
index e258ac1b..6a62dd43 100644
--- a/src/OpenIddict.Server.AspNetCore/OpenIddictServerAspNetCoreHandlers.cs
+++ b/src/OpenIddict.Server.AspNetCore/OpenIddictServerAspNetCoreHandlers.cs
@@ -7,7 +7,6 @@
using System.Collections.Immutable;
using System.ComponentModel;
using System.Diagnostics;
-using System.Security.Claims;
using System.Text;
using System.Text.Encodings.Web;
using System.Text.Json;
@@ -38,18 +37,18 @@ public static partial class OpenIddictServerAspNetCoreHandlers
/*
* Challenge processing:
*/
+ ResolveHostChallengeProperties.Descriptor,
AttachHostChallengeError.Descriptor,
- ResolveHostChallengeParameters.Descriptor,
/*
* Sign-in processing:
*/
- ResolveHostSignInParameters.Descriptor,
+ ResolveHostSignInProperties.Descriptor,
/*
* Sign-out processing:
*/
- ResolveHostSignOutParameters.Descriptor)
+ ResolveHostSignOutProperties.Descriptor)
.AddRange(Authentication.DefaultHandlers)
.AddRange(Device.DefaultHandlers)
.AddRange(Discovery.DefaultHandlers)
@@ -279,10 +278,11 @@ public static partial class OpenIddictServerAspNetCoreHandlers
}
///
- /// Contains the logic responsible for attaching the error details using the ASP.NET Core authentication properties.
+ /// Contains the logic responsible for resolving the context-specific properties and parameters stored in the
+ /// ASP.NET Core authentication properties specified by the application that triggered the challenge operation.
/// Note: this handler is not used when the OpenID Connect request is not initially handled by ASP.NET Core.
///
- public class AttachHostChallengeError : IOpenIddictServerHandler
+ public class ResolveHostChallengeProperties : IOpenIddictServerHandler
{
///
/// Gets the default descriptor definition assigned to this handler.
@@ -290,8 +290,8 @@ public static partial class OpenIddictServerAspNetCoreHandlers
public static OpenIddictServerHandlerDescriptor Descriptor { get; }
= OpenIddictServerHandlerDescriptor.CreateBuilder()
.AddFilter()
- .UseSingletonHandler()
- .SetOrder(AttachDefaultChallengeError.Descriptor.Order - 500)
+ .UseSingletonHandler()
+ .SetOrder(ValidateChallengeDemand.Descriptor.Order - 500)
.SetType(OpenIddictServerHandlerType.BuiltIn)
.Build();
@@ -304,12 +304,34 @@ public static partial class OpenIddictServerAspNetCoreHandlers
}
var properties = context.Transaction.GetProperty(typeof(AuthenticationProperties).FullName!);
- if (properties is not null)
+ if (properties is { Items.Count: > 0 })
{
- 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);
+ foreach (var property in properties.Items)
+ {
+ context.Properties[property.Key] = property.Value;
+ }
+ }
+
+ if (properties is { Parameters.Count: > 0 })
+ {
+ 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),
+
+#if SUPPORTS_JSON_NODES
+ JsonNode value => new OpenIddictParameter(value),
+#endif
+ _ => throw new InvalidOperationException(SR.GetResourceString(SR.ID0115))
+ };
+ }
}
return default;
@@ -317,11 +339,10 @@ public static partial class OpenIddictServerAspNetCoreHandlers
}
///
- /// Contains the logic responsible for resolving the additional challenge parameters stored in the ASP.NET
- /// Core authentication properties specified by the application that triggered the sign-in operation.
+ /// Contains the logic responsible for attaching the error details using the ASP.NET Core authentication properties.
/// Note: this handler is not used when the OpenID Connect request is not initially handled by ASP.NET Core.
///
- public class ResolveHostChallengeParameters : IOpenIddictServerHandler
+ public class AttachHostChallengeError : IOpenIddictServerHandler
{
///
/// Gets the default descriptor definition assigned to this handler.
@@ -329,8 +350,8 @@ public static partial class OpenIddictServerAspNetCoreHandlers
public static OpenIddictServerHandlerDescriptor Descriptor { get; }
= OpenIddictServerHandlerDescriptor.CreateBuilder()
.AddFilter()
- .UseSingletonHandler()
- .SetOrder(AttachCustomChallengeParameters.Descriptor.Order - 500)
+ .UseSingletonHandler()
+ .SetOrder(AttachDefaultChallengeError.Descriptor.Order - 500)
.SetType(OpenIddictServerHandlerType.BuiltIn)
.Build();
@@ -343,28 +364,12 @@ public static partial class OpenIddictServerAspNetCoreHandlers
}
var properties = context.Transaction.GetProperty(typeof(AuthenticationProperties).FullName!);
- if (properties is null)
- {
- return default;
- }
-
- foreach (var parameter in properties.Parameters)
+ if (properties is not null)
{
- 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),
-
-#if SUPPORTS_JSON_NODES
- JsonNode value => new OpenIddictParameter(value),
-#endif
- _ => throw new InvalidOperationException(SR.GetResourceString(SR.ID0115))
- };
+ 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;
@@ -372,11 +377,11 @@ public static partial class OpenIddictServerAspNetCoreHandlers
}
///
- /// Contains the logic responsible for resolving the additional sign-in parameters stored in the ASP.NET
- /// Core authentication properties specified by the application that triggered the sign-in operation.
+ /// Contains the logic responsible for resolving the context-specific properties and 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.
///
- public class ResolveHostSignInParameters : IOpenIddictServerHandler
+ public class ResolveHostSignInProperties : IOpenIddictServerHandler
{
///
/// Gets the default descriptor definition assigned to this handler.
@@ -384,8 +389,8 @@ public static partial class OpenIddictServerAspNetCoreHandlers
public static OpenIddictServerHandlerDescriptor Descriptor { get; }
= OpenIddictServerHandlerDescriptor.CreateBuilder()
.AddFilter()
- .UseSingletonHandler()
- .SetOrder(AttachCustomSignInParameters.Descriptor.Order - 500)
+ .UseSingletonHandler()
+ .SetOrder(ValidateSignInDemand.Descriptor.Order - 500)
.SetType(OpenIddictServerHandlerType.BuiltIn)
.Build();
@@ -397,37 +402,35 @@ public static partial class OpenIddictServerAspNetCoreHandlers
throw new ArgumentNullException(nameof(context));
}
- Debug.Assert(context.Principal is { Identity: ClaimsIdentity }, SR.GetResourceString(SR.ID4006));
-
var properties = context.Transaction.GetProperty(typeof(AuthenticationProperties).FullName!);
- if (properties is null)
+ if (properties is { Items.Count: > 0 })
{
- return default;
- }
-
- // Preserve the host properties in the principal.
- if (properties.Items.Count is not 0)
- {
- context.Principal.SetClaim(Claims.Private.HostProperties, properties.Items);
+ foreach (var property in properties.Items)
+ {
+ context.Properties[property.Key] = property.Value;
+ }
}
- foreach (var parameter in properties.Parameters)
+ if (properties is { Parameters.Count: > 0 })
{
- context.Parameters[parameter.Key] = parameter.Value switch
+ foreach (var parameter in properties.Parameters)
{
- 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),
+ 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),
#if SUPPORTS_JSON_NODES
- JsonNode value => new OpenIddictParameter(value),
+ JsonNode value => new OpenIddictParameter(value),
#endif
- _ => throw new InvalidOperationException(SR.GetResourceString(SR.ID0115))
- };
+ _ => throw new InvalidOperationException(SR.GetResourceString(SR.ID0115))
+ };
+ }
}
return default;
@@ -435,11 +438,11 @@ public static partial class OpenIddictServerAspNetCoreHandlers
}
///
- /// Contains the logic responsible for resolving the additional sign-out parameters stored in the ASP.NET
- /// Core authentication properties specified by the application that triggered the sign-out operation.
+ /// Contains the logic responsible for resolving the context-specific properties and 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.
///
- public class ResolveHostSignOutParameters : IOpenIddictServerHandler
+ public class ResolveHostSignOutProperties : IOpenIddictServerHandler
{
///
/// Gets the default descriptor definition assigned to this handler.
@@ -447,8 +450,8 @@ public static partial class OpenIddictServerAspNetCoreHandlers
public static OpenIddictServerHandlerDescriptor Descriptor { get; }
= OpenIddictServerHandlerDescriptor.CreateBuilder()
.AddFilter()
- .UseSingletonHandler()
- .SetOrder(AttachCustomSignOutParameters.Descriptor.Order - 500)
+ .UseSingletonHandler()
+ .SetOrder(ValidateSignOutDemand.Descriptor.Order - 500)
.SetType(OpenIddictServerHandlerType.BuiltIn)
.Build();
@@ -461,28 +464,34 @@ public static partial class OpenIddictServerAspNetCoreHandlers
}
var properties = context.Transaction.GetProperty(typeof(AuthenticationProperties).FullName!);
- if (properties is null)
+ if (properties is { Items.Count: > 0 })
{
- return default;
+ foreach (var property in properties.Items)
+ {
+ context.Properties[property.Key] = property.Value;
+ }
}
- foreach (var parameter in properties.Parameters)
+ if (properties is { Parameters.Count: > 0 })
{
- context.Parameters[parameter.Key] = parameter.Value switch
+ foreach (var parameter in properties.Parameters)
{
- 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),
+ 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),
#if SUPPORTS_JSON_NODES
- JsonNode value => new OpenIddictParameter(value),
+ JsonNode value => new OpenIddictParameter(value),
#endif
- _ => throw new InvalidOperationException(SR.GetResourceString(SR.ID0115))
- };
+ _ => throw new InvalidOperationException(SR.GetResourceString(SR.ID0115))
+ };
+ }
}
return default;
diff --git a/src/OpenIddict.Server.Owin/OpenIddictServerOwinHandlers.cs b/src/OpenIddict.Server.Owin/OpenIddictServerOwinHandlers.cs
index c10ce5f2..56b046e0 100644
--- a/src/OpenIddict.Server.Owin/OpenIddictServerOwinHandlers.cs
+++ b/src/OpenIddict.Server.Owin/OpenIddictServerOwinHandlers.cs
@@ -8,7 +8,6 @@ using System.Collections.Immutable;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
-using System.Security.Claims;
using System.Text;
using System.Text.Encodings.Web;
using System.Text.Json;
@@ -34,18 +33,18 @@ public static partial class OpenIddictServerOwinHandlers
/*
* Challenge processing:
*/
+ ResolveHostChallengeProperties.Descriptor,
AttachHostChallengeError.Descriptor,
- ResolveHostChallengeParameters.Descriptor,
/*
* Sign-in processing:
*/
- ResolveHostSignInParameters.Descriptor,
+ ResolveHostSignInProperties.Descriptor,
/*
* Sign-out processing:
*/
- ResolveHostSignOutParameters.Descriptor)
+ ResolveHostSignOutProperties.Descriptor)
.AddRange(Authentication.DefaultHandlers)
.AddRange(Device.DefaultHandlers)
.AddRange(Discovery.DefaultHandlers)
@@ -277,52 +276,11 @@ public static partial class OpenIddictServerOwinHandlers
}
///
- /// Contains the logic responsible for attaching the error details using the OWIN authentication properties.
- /// Note: this handler is not used when the OpenID Connect request is not initially handled by OWIN.
- ///
- public class AttachHostChallengeError : IOpenIddictServerHandler
- {
- ///
- /// Gets the default descriptor definition assigned to this handler.
- ///
- public static OpenIddictServerHandlerDescriptor Descriptor { get; }
- = OpenIddictServerHandlerDescriptor.CreateBuilder()
- .AddFilter()
- .UseSingletonHandler()
- .SetOrder(AttachDefaultChallengeError.Descriptor.Order - 500)
- .SetType(OpenIddictServerHandlerType.BuiltIn)
- .Build();
-
- ///
- public ValueTask HandleAsync(ProcessChallengeContext context)
- {
- if (context is null)
- {
- throw new ArgumentNullException(nameof(context));
- }
-
- var properties = context.Transaction.GetProperty(typeof(AuthenticationProperties).FullName!);
- if (properties is not 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;
-
- static string? GetProperty(AuthenticationProperties properties, string name)
- => properties.Dictionary.TryGetValue(name, out string? value) ? value : null;
- }
- }
-
- ///
- /// Contains the logic responsible for resolving the additional challenge parameters stored in the
- /// OWIN authentication properties specified by the application that triggered the sign-in operation.
+ /// Contains the logic responsible for resolving the context-specific properties and parameters stored in the
+ /// OWIN authentication properties specified by the application that triggered the challenge operation.
/// Note: this handler is not used when the OpenID Connect request is not initially handled by OWIN.
///
- public class ResolveHostChallengeParameters : IOpenIddictServerHandler
+ public class ResolveHostChallengeProperties : IOpenIddictServerHandler
{
///
/// Gets the default descriptor definition assigned to this handler.
@@ -330,8 +288,8 @@ public static partial class OpenIddictServerOwinHandlers
public static OpenIddictServerHandlerDescriptor Descriptor { get; }
= OpenIddictServerHandlerDescriptor.CreateBuilder()
.AddFilter()
- .UseSingletonHandler()
- .SetOrder(AttachCustomChallengeParameters.Descriptor.Order - 500)
+ .UseSingletonHandler()
+ .SetOrder(ValidateChallengeDemand.Descriptor.Order - 500)
.SetType(OpenIddictServerHandlerType.BuiltIn)
.Build();
@@ -344,12 +302,12 @@ public static partial class OpenIddictServerOwinHandlers
}
var properties = context.Transaction.GetProperty(typeof(AuthenticationProperties).FullName!);
- if (properties is null)
+ if (properties is not { Dictionary.Count: > 0 })
{
return default;
}
- // Note: unlike ASP.NET Core, Owin's AuthenticationProperties doesn't offer a strongly-typed
+ // 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
@@ -385,18 +343,64 @@ public static partial class OpenIddictServerOwinHandlers
{
context.Parameters[name] = value;
}
+
+ else
+ {
+ context.Properties[property.Key] = property.Value;
+ }
+ }
+
+ return default;
+ }
+ }
+
+ ///
+ /// Contains the logic responsible for attaching the error details using the OWIN authentication properties.
+ /// Note: this handler is not used when the OpenID Connect request is not initially handled by OWIN.
+ ///
+ public class AttachHostChallengeError : IOpenIddictServerHandler
+ {
+ ///
+ /// Gets the default descriptor definition assigned to this handler.
+ ///
+ public static OpenIddictServerHandlerDescriptor Descriptor { get; }
+ = OpenIddictServerHandlerDescriptor.CreateBuilder()
+ .AddFilter()
+ .UseSingletonHandler()
+ .SetOrder(AttachDefaultChallengeError.Descriptor.Order - 500)
+ .SetType(OpenIddictServerHandlerType.BuiltIn)
+ .Build();
+
+ ///
+ public ValueTask HandleAsync(ProcessChallengeContext context)
+ {
+ if (context is null)
+ {
+ throw new ArgumentNullException(nameof(context));
+ }
+
+ var properties = context.Transaction.GetProperty(typeof(AuthenticationProperties).FullName!);
+ if (properties is not 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;
+
+ static string? GetProperty(AuthenticationProperties properties, string name)
+ => properties.Dictionary.TryGetValue(name, out string? value) ? value : null;
}
}
///
- /// Contains the logic responsible for resolving the additional sign-in parameters stored in the
+ /// Contains the logic responsible for resolving the context-specific properties and 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.
///
- public class ResolveHostSignInParameters : IOpenIddictServerHandler
+ public class ResolveHostSignInProperties : IOpenIddictServerHandler
{
///
/// Gets the default descriptor definition assigned to this handler.
@@ -404,8 +408,8 @@ public static partial class OpenIddictServerOwinHandlers
public static OpenIddictServerHandlerDescriptor Descriptor { get; }
= OpenIddictServerHandlerDescriptor.CreateBuilder()
.AddFilter()
- .UseSingletonHandler()
- .SetOrder(AttachCustomSignInParameters.Descriptor.Order - 500)
+ .UseSingletonHandler()
+ .SetOrder(ValidateSignInDemand.Descriptor.Order - 500)
.SetType(OpenIddictServerHandlerType.BuiltIn)
.Build();
@@ -417,21 +421,13 @@ public static partial class OpenIddictServerOwinHandlers
throw new ArgumentNullException(nameof(context));
}
- Debug.Assert(context.Principal is { Identity: ClaimsIdentity }, SR.GetResourceString(SR.ID4006));
-
var properties = context.Transaction.GetProperty(typeof(AuthenticationProperties).FullName!);
- if (properties is null)
+ if (properties is not { Dictionary.Count: > 0 })
{
return default;
}
- // Preserve the host properties in the principal.
- if (properties.Dictionary.Count is not 0)
- {
- context.Principal.SetClaim(Claims.Private.HostProperties, properties.Dictionary);
- }
-
- // Note: unlike ASP.NET Core, Owin's AuthenticationProperties doesn't offer a strongly-typed
+ // 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
@@ -467,6 +463,11 @@ public static partial class OpenIddictServerOwinHandlers
{
context.Parameters[name] = value;
}
+
+ else
+ {
+ context.Properties[property.Key] = property.Value;
+ }
}
return default;
@@ -474,11 +475,11 @@ public static partial class OpenIddictServerOwinHandlers
}
///
- /// Contains the logic responsible for resolving the additional sign-out parameters stored in the
+ /// Contains the logic responsible for resolving the context-specific properties and 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.
///
- public class ResolveHostSignOutParameters : IOpenIddictServerHandler
+ public class ResolveHostSignOutProperties : IOpenIddictServerHandler
{
///
/// Gets the default descriptor definition assigned to this handler.
@@ -486,8 +487,8 @@ public static partial class OpenIddictServerOwinHandlers
public static OpenIddictServerHandlerDescriptor Descriptor { get; }
= OpenIddictServerHandlerDescriptor.CreateBuilder()
.AddFilter()
- .UseSingletonHandler()
- .SetOrder(AttachCustomSignOutParameters.Descriptor.Order - 500)
+ .UseSingletonHandler()
+ .SetOrder(ValidateSignOutDemand.Descriptor.Order - 500)
.SetType(OpenIddictServerHandlerType.BuiltIn)
.Build();
@@ -500,12 +501,12 @@ public static partial class OpenIddictServerOwinHandlers
}
var properties = context.Transaction.GetProperty(typeof(AuthenticationProperties).FullName!);
- if (properties is null)
+ if (properties is not { Dictionary.Count: > 0 })
{
return default;
}
- // Note: unlike ASP.NET Core, Owin's AuthenticationProperties doesn't offer a strongly-typed
+ // 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
@@ -541,6 +542,11 @@ public static partial class OpenIddictServerOwinHandlers
{
context.Parameters[name] = value;
}
+
+ else
+ {
+ context.Properties[property.Key] = property.Value;
+ }
}
return default;
diff --git a/src/OpenIddict.Server/OpenIddictServerEvents.cs b/src/OpenIddict.Server/OpenIddictServerEvents.cs
index 37c7e014..cae31091 100644
--- a/src/OpenIddict.Server/OpenIddictServerEvents.cs
+++ b/src/OpenIddict.Server/OpenIddictServerEvents.cs
@@ -565,7 +565,12 @@ public static partial class OpenIddictServerEvents
}
///
- /// Gets the additional parameters returned to caller.
+ /// Gets the user-defined authentication properties, if available.
+ ///
+ public Dictionary Properties { get; } = new(StringComparer.Ordinal);
+
+ ///
+ /// Gets the additional parameters returned to the caller.
///
public Dictionary Parameters { get; } = new(StringComparer.Ordinal);
}
@@ -602,7 +607,12 @@ public static partial class OpenIddictServerEvents
}
///
- /// Gets the additional parameters returned to caller.
+ /// Gets the user-defined authentication properties, if available.
+ ///
+ public Dictionary Properties { get; } = new(StringComparer.Ordinal);
+
+ ///
+ /// Gets the additional parameters returned to the caller.
///
public Dictionary Parameters { get; } = new(StringComparer.Ordinal);
@@ -813,7 +823,12 @@ public static partial class OpenIddictServerEvents
}
///
- /// Gets the additional parameters returned to caller.
+ /// Gets the user-defined authentication properties, if available.
+ ///
+ public Dictionary Properties { get; } = new(StringComparer.Ordinal);
+
+ ///
+ /// Gets the additional parameters returned to the caller.
///
public Dictionary Parameters { get; } = new(StringComparer.Ordinal);
}
diff --git a/src/OpenIddict.Server/OpenIddictServerHandlers.cs b/src/OpenIddict.Server/OpenIddictServerHandlers.cs
index 436142c2..dd58baa7 100644
--- a/src/OpenIddict.Server/OpenIddictServerHandlers.cs
+++ b/src/OpenIddict.Server/OpenIddictServerHandlers.cs
@@ -49,6 +49,7 @@ public static partial class OpenIddictServerHandlers
ValidateSignInDemand.Descriptor,
RedeemTokenEntry.Descriptor,
RestoreInternalClaims.Descriptor,
+ AttachHostProperties.Descriptor,
AttachDefaultScopes.Descriptor,
AttachDefaultPresenters.Descriptor,
InferResources.Descriptor,
@@ -1382,6 +1383,37 @@ public static partial class OpenIddictServerHandlers
}
}
+ ///
+ /// Contains the logic responsible for attaching the user-defined properties to the authentication principal.
+ ///
+ public class AttachHostProperties : IOpenIddictServerHandler
+ {
+ ///
+ /// Gets the default descriptor definition assigned to this handler.
+ ///
+ public static OpenIddictServerHandlerDescriptor Descriptor { get; }
+ = OpenIddictServerHandlerDescriptor.CreateBuilder()
+ .UseSingletonHandler()
+ .SetOrder(RestoreInternalClaims.Descriptor.Order + 1_000)
+ .SetType(OpenIddictServerHandlerType.BuiltIn)
+ .Build();
+
+ ///
+ public ValueTask HandleAsync(ProcessSignInContext context)
+ {
+ if (context is null)
+ {
+ throw new ArgumentNullException(nameof(context));
+ }
+
+ Debug.Assert(context.Principal is { Identity: ClaimsIdentity }, SR.GetResourceString(SR.ID4006));
+
+ context.Principal.SetClaim(Claims.Private.HostProperties, context.Properties);
+
+ return default;
+ }
+ }
+
///
/// Contains the logic responsible for attaching default scopes to the authentication principal.
///
@@ -1393,7 +1425,7 @@ public static partial class OpenIddictServerHandlers
public static OpenIddictServerHandlerDescriptor Descriptor { get; }
= OpenIddictServerHandlerDescriptor.CreateBuilder()
.UseSingletonHandler()
- .SetOrder(RestoreInternalClaims.Descriptor.Order + 1_000)
+ .SetOrder(AttachHostProperties.Descriptor.Order + 1_000)
.SetType(OpenIddictServerHandlerType.BuiltIn)
.Build();
diff --git a/src/OpenIddict.Validation.AspNetCore/OpenIddictValidationAspNetCoreHandlers.cs b/src/OpenIddict.Validation.AspNetCore/OpenIddictValidationAspNetCoreHandlers.cs
index efed4f58..bf688229 100644
--- a/src/OpenIddict.Validation.AspNetCore/OpenIddictValidationAspNetCoreHandlers.cs
+++ b/src/OpenIddict.Validation.AspNetCore/OpenIddictValidationAspNetCoreHandlers.cs
@@ -8,7 +8,6 @@ using System.Collections.Immutable;
using System.ComponentModel;
using System.Diagnostics;
using System.Text;
-using System.Text.Encodings.Web;
using System.Text.Json;
using Microsoft.AspNetCore;
using Microsoft.Extensions.Logging;
@@ -42,8 +41,8 @@ public static partial class OpenIddictValidationAspNetCoreHandlers
/*
* Challenge processing:
*/
+ ResolveHostChallengeProperties.Descriptor,
AttachHostChallengeError.Descriptor,
- ResolveHostChallengeParameters.Descriptor,
/*
* Response processing:
@@ -279,10 +278,11 @@ public static partial class OpenIddictValidationAspNetCoreHandlers
}
///
- /// Contains the logic responsible for attaching the error details using the ASP.NET Core authentication properties.
+ /// Contains the logic responsible for resolving the context-specific properties and parameters stored in the
+ /// ASP.NET Core authentication properties specified by the application that triggered the challenge operation.
/// Note: this handler is not used when the OpenID Connect request is not initially handled by ASP.NET Core.
///
- public class AttachHostChallengeError : IOpenIddictValidationHandler
+ public class ResolveHostChallengeProperties : IOpenIddictValidationHandler
{
///
/// Gets the default descriptor definition assigned to this handler.
@@ -290,8 +290,8 @@ public static partial class OpenIddictValidationAspNetCoreHandlers
public static OpenIddictValidationHandlerDescriptor Descriptor { get; }
= OpenIddictValidationHandlerDescriptor.CreateBuilder()
.AddFilter()
- .UseSingletonHandler()
- .SetOrder(AttachDefaultChallengeError.Descriptor.Order - 500)
+ .UseSingletonHandler()
+ .SetOrder(AttachHostChallengeError.Descriptor.Order - 500)
.SetType(OpenIddictValidationHandlerType.BuiltIn)
.Build();
@@ -304,12 +304,34 @@ public static partial class OpenIddictValidationAspNetCoreHandlers
}
var properties = context.Transaction.GetProperty(typeof(AuthenticationProperties).FullName!);
- if (properties is not null)
+ if (properties is { Items.Count: > 0 })
{
- 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);
+ foreach (var property in properties.Items)
+ {
+ context.Properties[property.Key] = property.Value;
+ }
+ }
+
+ if (properties is { Parameters.Count: > 0 })
+ {
+ 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),
+
+ #if SUPPORTS_JSON_NODES
+ JsonNode value => new OpenIddictParameter(value),
+ #endif
+ _ => throw new InvalidOperationException(SR.GetResourceString(SR.ID0115))
+ };
+ }
}
return default;
@@ -317,11 +339,10 @@ public static partial class OpenIddictValidationAspNetCoreHandlers
}
///
- /// Contains the logic responsible for resolving the additional sign-in parameters stored in the ASP.NET
- /// Core authentication properties specified by the application that triggered the sign-in operation.
+ /// Contains the logic responsible for attaching the error details using the ASP.NET Core authentication properties.
/// Note: this handler is not used when the OpenID Connect request is not initially handled by ASP.NET Core.
///
- public class ResolveHostChallengeParameters : IOpenIddictValidationHandler
+ public class AttachHostChallengeError : IOpenIddictValidationHandler
{
///
/// Gets the default descriptor definition assigned to this handler.
@@ -329,8 +350,8 @@ public static partial class OpenIddictValidationAspNetCoreHandlers
public static OpenIddictValidationHandlerDescriptor Descriptor { get; }
= OpenIddictValidationHandlerDescriptor.CreateBuilder()
.AddFilter()
- .UseSingletonHandler()
- .SetOrder(AttachCustomChallengeParameters.Descriptor.Order - 500)
+ .UseSingletonHandler()
+ .SetOrder(AttachDefaultChallengeError.Descriptor.Order - 500)
.SetType(OpenIddictValidationHandlerType.BuiltIn)
.Build();
@@ -343,28 +364,12 @@ public static partial class OpenIddictValidationAspNetCoreHandlers
}
var properties = context.Transaction.GetProperty(typeof(AuthenticationProperties).FullName!);
- if (properties is null)
- {
- return default;
- }
-
- foreach (var parameter in properties.Parameters)
+ if (properties is not null)
{
- 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),
-
-#if SUPPORTS_JSON_NODES
- JsonNode value => new OpenIddictParameter(value),
-#endif
- _ => throw new InvalidOperationException(SR.GetResourceString(SR.ID0115))
- };
+ 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;
diff --git a/src/OpenIddict.Validation.Owin/OpenIddictValidationOwinConstants.cs b/src/OpenIddict.Validation.Owin/OpenIddictValidationOwinConstants.cs
index 27edde10..84763f60 100644
--- a/src/OpenIddict.Validation.Owin/OpenIddictValidationOwinConstants.cs
+++ b/src/OpenIddict.Validation.Owin/OpenIddictValidationOwinConstants.cs
@@ -36,4 +36,12 @@ public static class OpenIddictValidationOwinConstants
public const string ErrorUri = ".error_uri";
public const string Scope = ".scope";
}
+
+ public static class PropertyTypes
+ {
+ public const string Boolean = "#boolean";
+ public const string Integer = "#integer";
+ public const string Json = "#json";
+ public const string String = "#string";
+ }
}
diff --git a/src/OpenIddict.Validation.Owin/OpenIddictValidationOwinHandlers.cs b/src/OpenIddict.Validation.Owin/OpenIddictValidationOwinHandlers.cs
index 671d1310..aa44e9e3 100644
--- a/src/OpenIddict.Validation.Owin/OpenIddictValidationOwinHandlers.cs
+++ b/src/OpenIddict.Validation.Owin/OpenIddictValidationOwinHandlers.cs
@@ -7,7 +7,9 @@
using System.Collections.Immutable;
using System.ComponentModel;
using System.Diagnostics;
+using System.Globalization;
using System.Text;
+using System.Text.Json;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Owin;
@@ -35,6 +37,7 @@ public static partial class OpenIddictValidationOwinHandlers
/*
* Challenge processing:
*/
+ ResolveHostChallengeProperties.Descriptor,
AttachHostChallengeError.Descriptor,
/*
@@ -276,6 +279,85 @@ public static partial class OpenIddictValidationOwinHandlers
}
}
+ ///
+ /// Contains the logic responsible for resolving the context-specific properties and parameters stored in the
+ /// OWIN authentication properties specified by the application that triggered the challenge operation.
+ /// Note: this handler is not used when the OpenID Connect request is not initially handled by OWIN.
+ ///
+ public class ResolveHostChallengeProperties : IOpenIddictValidationHandler
+ {
+ ///
+ /// Gets the default descriptor definition assigned to this handler.
+ ///
+ public static OpenIddictValidationHandlerDescriptor Descriptor { get; }
+ = OpenIddictValidationHandlerDescriptor.CreateBuilder()
+ .AddFilter()
+ .UseSingletonHandler()
+ .SetOrder(AttachHostChallengeError.Descriptor.Order - 500)
+ .SetType(OpenIddictValidationHandlerType.BuiltIn)
+ .Build();
+
+ ///
+ public ValueTask HandleAsync(ProcessChallengeContext context)
+ {
+ if (context is null)
+ {
+ throw new ArgumentNullException(nameof(context));
+ }
+
+ var properties = context.Transaction.GetProperty(typeof(AuthenticationProperties).FullName!);
+ if (properties is not { Dictionary.Count: > 0 })
+ {
+ 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(property.Value))),
+
+ _ => default
+ };
+
+ if (!string.IsNullOrEmpty(name))
+ {
+ context.Parameters[name] = value;
+ }
+
+ else
+ {
+ context.Properties[property.Key] = property.Value;
+ }
+ }
+
+ return default;
+ }
+ }
+
///
/// Contains the logic responsible for attaching the error details using the OWIN authentication properties.
/// Note: this handler is not used when the OpenID Connect request is not initially handled by OWIN.
diff --git a/src/OpenIddict.Validation/OpenIddictValidationEvents.cs b/src/OpenIddict.Validation/OpenIddictValidationEvents.cs
index d03044fd..3d3bc40d 100644
--- a/src/OpenIddict.Validation/OpenIddictValidationEvents.cs
+++ b/src/OpenIddict.Validation/OpenIddictValidationEvents.cs
@@ -331,7 +331,12 @@ public static partial class OpenIddictValidationEvents
}
///
- /// Gets the additional parameters returned to caller.
+ /// Gets the user-defined authentication properties, if available.
+ ///
+ public Dictionary Properties { get; } = new(StringComparer.Ordinal);
+
+ ///
+ /// Gets the additional parameters returned to the caller.
///
public Dictionary Parameters { get; } = new(StringComparer.Ordinal);
}
diff --git a/test/OpenIddict.Server.AspNetCore.IntegrationTests/OpenIddictServerAspNetCoreIntegrationTests.cs b/test/OpenIddict.Server.AspNetCore.IntegrationTests/OpenIddictServerAspNetCoreIntegrationTests.cs
index cbbf0910..0f80c943 100644
--- a/test/OpenIddict.Server.AspNetCore.IntegrationTests/OpenIddictServerAspNetCoreIntegrationTests.cs
+++ b/test/OpenIddict.Server.AspNetCore.IntegrationTests/OpenIddictServerAspNetCoreIntegrationTests.cs
@@ -136,6 +136,48 @@ public partial class OpenIddictServerAspNetCoreIntegrationTests : OpenIddictServ
Assert.Equal(new DateTimeOffset(2120, 01, 01, 00, 00, 00, TimeSpan.Zero), properties.ExpiresUtc);
}
+ [Fact]
+ public async Task ProcessChallenge_ImportsAuthenticationProperties()
+ {
+ // Arrange
+ await using var server = await CreateServerAsync(options =>
+ {
+ options.EnableDegradedMode();
+ options.SetTokenEndpointUris("/challenge/custom");
+
+ options.AddEventHandler(builder =>
+ builder.UseInlineHandler(context =>
+ {
+ context.SkipRequest();
+
+ return default;
+ }));
+
+ options.AddEventHandler(builder =>
+ builder.UseInlineHandler(context =>
+ {
+ Assert.Equal("value", context.Properties["custom_property"]);
+
+ return default;
+ }));
+ });
+
+ await using var client = await server.CreateClientAsync();
+
+ // Act
+ var response = await client.PostAsync("/challenge/custom", new OpenIddictRequest
+ {
+ GrantType = GrantTypes.Password,
+ Username = "johndoe",
+ Password = "A3ddj3w"
+ });
+
+ // Assert
+ Assert.NotEmpty(response.Error);
+ Assert.NotEmpty(response.ErrorDescription);
+ Assert.NotEmpty(response.ErrorUri);
+ }
+
[Fact]
public async Task ProcessChallenge_ReturnsParametersFromAuthenticationProperties()
{
@@ -734,6 +776,46 @@ public partial class OpenIddictServerAspNetCoreIntegrationTests : OpenIddictServ
Assert.Equal("Bob le Magnifique", (string?) response["name"]);
}
+ [Fact]
+ public async Task ProcessSignIn_ImportsAuthenticationProperties()
+ {
+ // Arrange
+ await using var server = await CreateServerAsync(options =>
+ {
+ options.EnableDegradedMode();
+ options.SetTokenEndpointUris("/signin/custom");
+
+ options.AddEventHandler(builder =>
+ builder.UseInlineHandler(context =>
+ {
+ context.SkipRequest();
+
+ return default;
+ }));
+
+ options.AddEventHandler(builder =>
+ builder.UseInlineHandler(context =>
+ {
+ Assert.Equal("value", context.Properties["custom_property"]);
+
+ return default;
+ }));
+ });
+
+ await using var client = await server.CreateClientAsync();
+
+ // Act
+ var response = await client.PostAsync("/signin/custom", new OpenIddictRequest
+ {
+ GrantType = GrantTypes.Password,
+ Username = "johndoe",
+ Password = "A3ddj3w"
+ });
+
+ // Assert
+ Assert.NotEmpty(response.AccessToken);
+ }
+
[Fact]
public async Task ProcessSignIn_ReturnsParametersFromAuthenticationProperties()
{
@@ -782,6 +864,45 @@ public partial class OpenIddictServerAspNetCoreIntegrationTests : OpenIddictServ
#endif
}
+ [Fact]
+ public async Task ProcessSignOut_ImportsAuthenticationProperties()
+ {
+ // Arrange
+ await using var server = await CreateServerAsync(options =>
+ {
+ options.EnableDegradedMode();
+ options.SetLogoutEndpointUris("/signout/custom");
+
+ options.AddEventHandler(builder =>
+ builder.UseInlineHandler(context =>
+ {
+ context.SkipRequest();
+
+ return default;
+ }));
+
+ options.AddEventHandler(builder =>
+ builder.UseInlineHandler(context =>
+ {
+ Assert.Equal("value", context.Properties["custom_property"]);
+
+ return default;
+ }));
+ });
+
+ await using var client = await server.CreateClientAsync();
+
+ // Act
+ var response = await client.PostAsync("/signout/custom", new OpenIddictRequest
+ {
+ PostLogoutRedirectUri = "http://www.fabrikam.com/path",
+ State = "af0ifjsldkj"
+ });
+
+ // Assert
+ Assert.NotEmpty(response.State);
+ }
+
[Fact]
public async Task ProcessSignOut_ReturnsParametersFromAuthenticationProperties()
{
@@ -904,7 +1025,10 @@ public partial class OpenIddictServerAspNetCoreIntegrationTests : OpenIddictServ
var principal = new ClaimsPrincipal(identity);
var properties = new AuthenticationProperties(
- items: new Dictionary(),
+ items: new Dictionary
+ {
+ ["custom_property"] = "value"
+ },
parameters: new Dictionary
{
["boolean_parameter"] = true,
@@ -931,7 +1055,10 @@ public partial class OpenIddictServerAspNetCoreIntegrationTests : OpenIddictServ
else if (context.Request.Path == "/signout/custom")
{
var properties = new AuthenticationProperties(
- items: new Dictionary(),
+ items: new Dictionary
+ {
+ ["custom_property"] = "value"
+ },
parameters: new Dictionary
{
["boolean_parameter"] = true,
@@ -956,7 +1083,9 @@ public partial class OpenIddictServerAspNetCoreIntegrationTests : OpenIddictServ
{
[OpenIddictServerAspNetCoreConstants.Properties.Error] = "custom_error",
[OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] = "custom_error_description",
- [OpenIddictServerAspNetCoreConstants.Properties.ErrorUri] = "custom_error_uri"
+ [OpenIddictServerAspNetCoreConstants.Properties.ErrorUri] = "custom_error_uri",
+
+ ["custom_property"] = "value"
},
parameters: new Dictionary
{
diff --git a/test/OpenIddict.Server.Owin.IntegrationTests/OpenIddictServerOwinIntegrationTests.cs b/test/OpenIddict.Server.Owin.IntegrationTests/OpenIddictServerOwinIntegrationTests.cs
index d6bc21fc..18599e14 100644
--- a/test/OpenIddict.Server.Owin.IntegrationTests/OpenIddictServerOwinIntegrationTests.cs
+++ b/test/OpenIddict.Server.Owin.IntegrationTests/OpenIddictServerOwinIntegrationTests.cs
@@ -130,6 +130,48 @@ public partial class OpenIddictServerOwinIntegrationTests : OpenIddictServerInte
Assert.Equal(new DateTimeOffset(2120, 01, 01, 00, 00, 00, TimeSpan.Zero), properties.ExpiresUtc);
}
+ [Fact]
+ public async Task ProcessChallenge_ImportsAuthenticationProperties()
+ {
+ // Arrange
+ await using var server = await CreateServerAsync(options =>
+ {
+ options.EnableDegradedMode();
+ options.SetTokenEndpointUris("/challenge/custom");
+
+ options.AddEventHandler(builder =>
+ builder.UseInlineHandler(context =>
+ {
+ context.SkipRequest();
+
+ return default;
+ }));
+
+ options.AddEventHandler(builder =>
+ builder.UseInlineHandler(context =>
+ {
+ Assert.Equal("value", context.Properties["custom_property"]);
+
+ return default;
+ }));
+ });
+
+ await using var client = await server.CreateClientAsync();
+
+ // Act
+ var response = await client.PostAsync("/challenge/custom", new OpenIddictRequest
+ {
+ GrantType = GrantTypes.Password,
+ Username = "johndoe",
+ Password = "A3ddj3w"
+ });
+
+ // Assert
+ Assert.NotEmpty(response.Error);
+ Assert.NotEmpty(response.ErrorDescription);
+ Assert.NotEmpty(response.ErrorUri);
+ }
+
[Fact]
public async Task ProcessChallenge_ReturnsParametersFromAuthenticationProperties()
{
@@ -719,6 +761,46 @@ public partial class OpenIddictServerOwinIntegrationTests : OpenIddictServerInte
Assert.Equal("Bob le Magnifique", (string?) response["name"]);
}
+ [Fact]
+ public async Task ProcessSignIn_ImportsAuthenticationProperties()
+ {
+ // Arrange
+ await using var server = await CreateServerAsync(options =>
+ {
+ options.EnableDegradedMode();
+ options.SetTokenEndpointUris("/signin/custom");
+
+ options.AddEventHandler(builder =>
+ builder.UseInlineHandler(context =>
+ {
+ context.SkipRequest();
+
+ return default;
+ }));
+
+ options.AddEventHandler(builder =>
+ builder.UseInlineHandler(context =>
+ {
+ Assert.Equal("value", context.Properties["custom_property"]);
+
+ return default;
+ }));
+ });
+
+ await using var client = await server.CreateClientAsync();
+
+ // Act
+ var response = await client.PostAsync("/signin/custom", new OpenIddictRequest
+ {
+ GrantType = GrantTypes.Password,
+ Username = "johndoe",
+ Password = "A3ddj3w"
+ });
+
+ // Assert
+ Assert.NotEmpty(response.AccessToken);
+ }
+
[Fact]
public async Task ProcessSignIn_ReturnsParametersFromAuthenticationProperties()
{
@@ -758,6 +840,45 @@ public partial class OpenIddictServerOwinIntegrationTests : OpenIddictServerInte
Assert.Equal(JsonValueKind.Array, ((JsonElement) response["json_parameter"]).ValueKind);
}
+ [Fact]
+ public async Task ProcessSignOut_ImportsAuthenticationProperties()
+ {
+ // Arrange
+ await using var server = await CreateServerAsync(options =>
+ {
+ options.EnableDegradedMode();
+ options.SetLogoutEndpointUris("/signout/custom");
+
+ options.AddEventHandler(builder =>
+ builder.UseInlineHandler(context =>
+ {
+ context.SkipRequest();
+
+ return default;
+ }));
+
+ options.AddEventHandler(builder =>
+ builder.UseInlineHandler(context =>
+ {
+ Assert.Equal("value", context.Properties["custom_property"]);
+
+ return default;
+ }));
+ });
+
+ await using var client = await server.CreateClientAsync();
+
+ // Act
+ var response = await client.PostAsync("/signout/custom", new OpenIddictRequest
+ {
+ PostLogoutRedirectUri = "http://www.fabrikam.com/path",
+ State = "af0ifjsldkj"
+ });
+
+ // Assert
+ Assert.NotEmpty(response.State);
+ }
+
[Fact]
public async Task ProcessSignOut_ReturnsParametersFromAuthenticationProperties()
{
@@ -866,6 +987,8 @@ public partial class OpenIddictServerOwinIntegrationTests : OpenIddictServerInte
var properties = new AuthenticationProperties(new Dictionary
{
+ ["custom_property"] = "value",
+
["boolean_parameter#boolean"] = "true",
["integer_parameter#integer"] = "42",
["string_parameter#string"] = "Bob l'Eponge",
@@ -887,6 +1010,8 @@ public partial class OpenIddictServerOwinIntegrationTests : OpenIddictServerInte
var properties = new AuthenticationProperties(new Dictionary
{
+ ["custom_property"] = "value",
+
["boolean_parameter#boolean"] = "true",
["integer_parameter#integer"] = "42",
["string_parameter#string"] = "Bob l'Eponge"
@@ -910,6 +1035,8 @@ public partial class OpenIddictServerOwinIntegrationTests : OpenIddictServerInte
[OpenIddictServerOwinConstants.Properties.ErrorDescription] = "custom_error_description",
[OpenIddictServerOwinConstants.Properties.ErrorUri] = "custom_error_uri",
+ ["custom_property"] = "value",
+
["boolean_parameter#boolean"] = "true",
["integer_parameter#integer"] = "42",
["string_parameter#string"] = "Bob l'Eponge",