Browse Source

Unify platform callbacks handling using a new OpenIddictClientSystemIntegrationPlatformCallback type

pull/2167/head
Kévin Chalet 1 year ago
parent
commit
84104846c6
  1. 5
      src/OpenIddict.Abstractions/OpenIddictResources.resx
  2. 5
      src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationExtensions.cs
  3. 74
      src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationHandlerFilters.cs
  4. 98
      src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationHandlers.Authentication.cs
  5. 98
      src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationHandlers.Session.cs
  6. 318
      src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationHandlers.cs
  7. 38
      src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationHelpers.cs
  8. 62
      src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationPlatformCallback.cs
  9. 118
      src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationService.cs
  10. 4
      src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationHandlers.Discovery.cs
  11. 2
      src/OpenIddict.Server/OpenIddictServerHandlers.Protection.cs

5
src/OpenIddict.Abstractions/OpenIddictResources.resx

@ -1480,7 +1480,7 @@ To apply post-logout redirection responses, create a class implementing 'IOpenId
<value>The web authentication broker is only supported on UWP and requires running Windows 10 version 1709 (Fall Creators) or higher.</value>
</data>
<data name="ID0393" xml:space="preserve">
<value>The web authentication result cannot be resolved or contains invalid data.</value>
<value>The platform callback cannot be resolved or contains invalid data.</value>
</data>
<data name="ID0394" xml:space="preserve">
<value>The issuer attached to the static configuration must be the same as the one configured in the validation options.</value>
@ -1692,6 +1692,9 @@ To apply post-logout redirection responses, create a class implementing 'IOpenId
<data name="ID0452" xml:space="preserve">
<value>Custom tabs intents are only supported on Android.</value>
</data>
<data name="ID0453" xml:space="preserve">
<value>The specified intent doesn't contain a valid data URI.</value>
</data>
<data name="ID2000" xml:space="preserve">
<value>The security token is missing.</value>
</data>

5
src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationExtensions.cs

@ -103,17 +103,18 @@ public static class OpenIddictClientSystemIntegrationExtensions
// Register the built-in filters used by the default OpenIddict client system integration event handlers.
builder.Services.TryAddSingleton<RequireASWebAuthenticationSession>();
builder.Services.TryAddSingleton<RequireASWebAuthenticationCallbackUrl>();
builder.Services.TryAddSingleton<RequireAuthenticationNonce>();
builder.Services.TryAddSingleton<RequireCustomTabsIntent>();
builder.Services.TryAddSingleton<RequireCustomTabsIntentData>();
builder.Services.TryAddSingleton<RequireEmbeddedWebServerEnabled>();
builder.Services.TryAddSingleton<RequireHttpListenerContext>();
builder.Services.TryAddSingleton<RequireInteractiveSession>();
builder.Services.TryAddSingleton<RequirePlatformCallback>();
builder.Services.TryAddSingleton<RequireProtocolActivation>();
builder.Services.TryAddSingleton<RequireSystemBrowser>();
builder.Services.TryAddSingleton<RequireWebAuthenticationBroker>();
#pragma warning disable CS0618
builder.Services.TryAddSingleton<RequireWebAuthenticationResult>();
#pragma warning restore CS0618
// Register the built-in event handlers used by the OpenIddict client system integration components.
// Note: the order used here is not important, as the actual order is set in the options.

74
src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationHandlerFilters.cs

@ -17,34 +17,6 @@ namespace OpenIddict.Client.SystemIntegration;
[EditorBrowsable(EditorBrowsableState.Advanced)]
public static class OpenIddictClientSystemIntegrationHandlerFilters
{
/// <summary>
/// Represents a filter that excludes the associated handlers if no AS web
/// authentication callback URL can be found in the transaction properties.
/// </summary>
public sealed class RequireASWebAuthenticationCallbackUrl : IOpenIddictClientHandlerFilter<BaseContext>
{
/// <inheritdoc/>
public ValueTask<bool> IsActiveAsync(BaseContext context)
{
if (context is null)
{
throw new ArgumentNullException(nameof(context));
}
#if SUPPORTS_AUTHENTICATION_SERVICES && SUPPORTS_FOUNDATION
if (IsASWebAuthenticationSessionSupported())
{
return new(ContainsASWebAuthenticationSessionResult(context.Transaction));
}
[MethodImpl(MethodImplOptions.NoInlining)]
static bool ContainsASWebAuthenticationSessionResult(OpenIddictClientTransaction transaction)
=> transaction.GetASWebAuthenticationCallbackUrl() is not null;
#endif
return new(false);
}
}
/// <summary>
/// Represents a filter that excludes the associated handlers if
/// the AS web authentication session integration was not enabled.
@ -133,33 +105,6 @@ public static class OpenIddictClientSystemIntegrationHandlerFilters
return new(false);
}
}
/// <summary>
/// Represents a filter that excludes the associated handlers if no
/// custom tabs intent data can be found in the transaction properties.
/// </summary>
public sealed class RequireCustomTabsIntentData : IOpenIddictClientHandlerFilter<BaseContext>
{
/// <inheritdoc/>
public ValueTask<bool> IsActiveAsync(BaseContext context)
{
if (context is null)
{
throw new ArgumentNullException(nameof(context));
}
#if SUPPORTS_ANDROID && SUPPORTS_ANDROIDX_BROWSER
if (IsCustomTabsIntentSupported())
{
return new(ContainsCustomTabsIntentData(context.Transaction));
}
[MethodImpl(MethodImplOptions.NoInlining)]
static bool ContainsCustomTabsIntentData(OpenIddictClientTransaction transaction)
=> transaction.GetCustomTabsIntentData() is not null;
#endif
return new(false);
}
}
/// <summary>
/// Represents a filter that excludes the associated handlers if the embedded web server was not enabled.
@ -217,6 +162,24 @@ public static class OpenIddictClientSystemIntegrationHandlerFilters
}
}
/// <summary>
/// Represents a filter that excludes the associated handlers if no
/// platform callback can be found in the transaction properties.
/// </summary>
public sealed class RequirePlatformCallback : IOpenIddictClientHandlerFilter<BaseContext>
{
/// <inheritdoc/>
public ValueTask<bool> IsActiveAsync(BaseContext context)
{
if (context is null)
{
throw new ArgumentNullException(nameof(context));
}
return new(context.Transaction.GetPlatformCallback() is not null);
}
}
/// <summary>
/// Represents a filter that excludes the associated handlers if no protocol activation was found.
/// </summary>
@ -304,6 +267,7 @@ public static class OpenIddictClientSystemIntegrationHandlerFilters
/// Represents a filter that excludes the associated handlers if no
/// web authentication operation was triggered during the transaction.
/// </summary>
[Obsolete("This filter is obsolete and will be removed in a future version.")]
public sealed class RequireWebAuthenticationResult : IOpenIddictClientHandlerFilter<BaseContext>
{
/// <inheritdoc/>

98
src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationHandlers.Authentication.cs

@ -57,9 +57,7 @@ public static partial class OpenIddictClientSystemIntegrationHandlers
*/
ExtractGetOrPostHttpListenerRequest<ExtractRedirectionRequestContext>.Descriptor,
ExtractProtocolActivationParameters<ExtractRedirectionRequestContext>.Descriptor,
ExtractASWebAuthenticationCallbackUrlData<ExtractRedirectionRequestContext>.Descriptor,
ExtractCustomTabsIntentData<ExtractRedirectionRequestContext>.Descriptor,
ExtractWebAuthenticationResultData<ExtractRedirectionRequestContext>.Descriptor,
ExtractPlatformCallbackParameters<ExtractRedirectionRequestContext>.Descriptor,
/*
* Redirection response handling:
@ -68,9 +66,7 @@ public static partial class OpenIddictClientSystemIntegrationHandlers
AttachCacheControlHeader<ApplyRedirectionResponseContext>.Descriptor,
ProcessEmptyHttpResponse.Descriptor,
ProcessProtocolActivationResponse<ApplyRedirectionResponseContext>.Descriptor,
ProcessASWebAuthenticationSessionResponse<ApplyRedirectionResponseContext>.Descriptor,
ProcessCustomTabsIntentResponse<ApplyRedirectionResponseContext>.Descriptor,
ProcessWebAuthenticationResultResponse<ApplyRedirectionResponseContext>.Descriptor
ProcessPlatformCallbackResponse<ApplyRedirectionResponseContext>.Descriptor
]);
/// <summary>
@ -123,7 +119,8 @@ public static partial class OpenIddictClientSystemIntegrationHandlers
throw new PlatformNotSupportedException(SR.GetResourceString(SR.ID0446));
}
var source = new TaskCompletionSource<NSUrl>(TaskCreationOptions.RunContinuationsAsynchronously);
var source = new TaskCompletionSource<OpenIddictClientSystemIntegrationPlatformCallback>(
TaskCreationOptions.RunContinuationsAsynchronously);
// OpenIddict represents the complete interactive authentication dance as a two-phase process:
// - The challenge, during which the user is redirected to the authorization server, either
@ -161,11 +158,11 @@ public static partial class OpenIddictClientSystemIntegrationHandlers
throw new InvalidOperationException(SR.GetResourceString(SR.ID0448));
}
NSUrl url;
OpenIddictClientSystemIntegrationPlatformCallback callback;
try
{
url = await source.Task.WaitAsync(context.CancellationToken);
callback = await source.Task.WaitAsync(context.CancellationToken);
}
// Since the result of this operation is known by the time the task signaled by ASWebAuthenticationSession
@ -195,7 +192,7 @@ public static partial class OpenIddictClientSystemIntegrationHandlers
return;
}
await _service.HandleASWebAuthenticationCallbackUrlAsync(url, context.CancellationToken);
await _service.HandlePlatformCallbackAsync(callback, context.CancellationToken);
context.HandleRequest();
return;
@ -250,7 +247,43 @@ public static partial class OpenIddictClientSystemIntegrationHandlers
{
if (url is not null)
{
source.SetResult(url);
var parameters = new Dictionary<string, OpenIddictParameter>(StringComparer.Ordinal);
if (!string.IsNullOrEmpty(url.Query))
{
foreach (var parameter in OpenIddictHelpers.ParseQuery(url.Query))
{
parameters[parameter.Key] = parameter.Value.Count switch
{
0 => default,
1 => parameter.Value[0],
_ => parameter.Value.ToArray()
};
}
}
// Note: the fragment is always processed after the query string to ensure that
// parameters extracted from the fragment are preferred to parameters extracted
// from the query string when they are present in both parts.
if (!string.IsNullOrEmpty(url.Fragment))
{
foreach (var parameter in OpenIddictHelpers.ParseFragment(url.Fragment))
{
parameters[parameter.Key] = parameter.Value.Count switch
{
0 => default,
1 => parameter.Value[0],
_ => parameter.Value.ToArray()
};
}
}
source.SetResult(new OpenIddictClientSystemIntegrationPlatformCallback(url!, parameters)
{
// Attach the raw URL to the callback properties.
Properties = { [typeof(NSUrl).FullName!] = url }
});
}
else if (error is not null)
@ -426,8 +459,47 @@ public static partial class OpenIddictClientSystemIntegrationHandlers
parameter => new StringValues((string?[]?) parameter.Value))),
callbackUri: new Uri(context.RedirectUri, UriKind.Absolute)))
{
case { ResponseStatus: WebAuthenticationStatus.Success } result:
await _service.HandleWebAuthenticationResultAsync(result, context.CancellationToken);
case { ResponseStatus: WebAuthenticationStatus.Success } result
when Uri.TryCreate(result.ResponseData, UriKind.Absolute, out Uri? uri):
var parameters = new Dictionary<string, OpenIddictParameter>(StringComparer.Ordinal);
if (!string.IsNullOrEmpty(uri.Query))
{
foreach (var parameter in OpenIddictHelpers.ParseQuery(uri.Query))
{
parameters[parameter.Key] = parameter.Value.Count switch
{
0 => default,
1 => parameter.Value[0],
_ => parameter.Value.ToArray()
};
}
}
// Note: the fragment is always processed after the query string to ensure that
// parameters extracted from the fragment are preferred to parameters extracted
// from the query string when they are present in both parts.
if (!string.IsNullOrEmpty(uri.Fragment))
{
foreach (var parameter in OpenIddictHelpers.ParseFragment(uri.Fragment))
{
parameters[parameter.Key] = parameter.Value.Count switch
{
0 => default,
1 => parameter.Value[0],
_ => parameter.Value.ToArray()
};
}
}
var callback = new OpenIddictClientSystemIntegrationPlatformCallback(uri, parameters)
{
// Attach the authentication result to the properties.
Properties = { [typeof(WebAuthenticationResult).FullName!] = result }
};
await _service.HandlePlatformCallbackAsync(callback, context.CancellationToken);
context.HandleRequest();
return;

98
src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationHandlers.Session.cs

@ -57,9 +57,7 @@ public static partial class OpenIddictClientSystemIntegrationHandlers
*/
ExtractGetOrPostHttpListenerRequest<ExtractPostLogoutRedirectionRequestContext>.Descriptor,
ExtractProtocolActivationParameters<ExtractPostLogoutRedirectionRequestContext>.Descriptor,
ExtractASWebAuthenticationCallbackUrlData<ExtractPostLogoutRedirectionRequestContext>.Descriptor,
ExtractCustomTabsIntentData<ExtractPostLogoutRedirectionRequestContext>.Descriptor,
ExtractWebAuthenticationResultData<ExtractPostLogoutRedirectionRequestContext>.Descriptor,
ExtractPlatformCallbackParameters<ExtractPostLogoutRedirectionRequestContext>.Descriptor,
/*
* Post-logout redirection response handling:
@ -68,9 +66,7 @@ public static partial class OpenIddictClientSystemIntegrationHandlers
AttachCacheControlHeader<ApplyPostLogoutRedirectionResponseContext>.Descriptor,
ProcessEmptyHttpResponse.Descriptor,
ProcessProtocolActivationResponse<ApplyPostLogoutRedirectionResponseContext>.Descriptor,
ProcessASWebAuthenticationSessionResponse<ApplyPostLogoutRedirectionResponseContext>.Descriptor,
ProcessCustomTabsIntentResponse<ApplyPostLogoutRedirectionResponseContext>.Descriptor,
ProcessWebAuthenticationResultResponse<ApplyPostLogoutRedirectionResponseContext>.Descriptor
ProcessPlatformCallbackResponse<ApplyPostLogoutRedirectionResponseContext>.Descriptor
]);
/// <summary>
@ -123,7 +119,8 @@ public static partial class OpenIddictClientSystemIntegrationHandlers
throw new PlatformNotSupportedException(SR.GetResourceString(SR.ID0446));
}
var source = new TaskCompletionSource<NSUrl>(TaskCreationOptions.RunContinuationsAsynchronously);
var source = new TaskCompletionSource<OpenIddictClientSystemIntegrationPlatformCallback>(
TaskCreationOptions.RunContinuationsAsynchronously);
// OpenIddict represents the complete interactive logout dance as a two-phase process:
// - The sign-out, during which the user is redirected to the authorization server, either
@ -161,11 +158,11 @@ public static partial class OpenIddictClientSystemIntegrationHandlers
throw new InvalidOperationException(SR.GetResourceString(SR.ID0448));
}
NSUrl url;
OpenIddictClientSystemIntegrationPlatformCallback callback;
try
{
url = await source.Task.WaitAsync(context.CancellationToken);
callback = await source.Task.WaitAsync(context.CancellationToken);
}
// Since the result of this operation is known by the time the task signaled by ASWebAuthenticationSession
@ -195,7 +192,7 @@ public static partial class OpenIddictClientSystemIntegrationHandlers
return;
}
await _service.HandleASWebAuthenticationCallbackUrlAsync(url, context.CancellationToken);
await _service.HandlePlatformCallbackAsync(callback, context.CancellationToken);
context.HandleRequest();
return;
@ -250,7 +247,43 @@ public static partial class OpenIddictClientSystemIntegrationHandlers
{
if (url is not null)
{
source.SetResult(url);
var parameters = new Dictionary<string, OpenIddictParameter>(StringComparer.Ordinal);
if (!string.IsNullOrEmpty(url.Query))
{
foreach (var parameter in OpenIddictHelpers.ParseQuery(url.Query))
{
parameters[parameter.Key] = parameter.Value.Count switch
{
0 => default,
1 => parameter.Value[0],
_ => parameter.Value.ToArray()
};
}
}
// Note: the fragment is always processed after the query string to ensure that
// parameters extracted from the fragment are preferred to parameters extracted
// from the query string when they are present in both parts.
if (!string.IsNullOrEmpty(url.Fragment))
{
foreach (var parameter in OpenIddictHelpers.ParseFragment(url.Fragment))
{
parameters[parameter.Key] = parameter.Value.Count switch
{
0 => default,
1 => parameter.Value[0],
_ => parameter.Value.ToArray()
};
}
}
source.SetResult(new OpenIddictClientSystemIntegrationPlatformCallback(url!, parameters)
{
// Attach the raw URL to the callback properties.
Properties = { [typeof(NSUrl).FullName!] = url }
});
}
else if (error is not null)
@ -426,8 +459,47 @@ public static partial class OpenIddictClientSystemIntegrationHandlers
parameter => new StringValues((string?[]?) parameter.Value))),
callbackUri: new Uri(context.PostLogoutRedirectUri, UriKind.Absolute)))
{
case { ResponseStatus: WebAuthenticationStatus.Success } result:
await _service.HandleWebAuthenticationResultAsync(result, context.CancellationToken);
case { ResponseStatus: WebAuthenticationStatus.Success } result
when Uri.TryCreate(result.ResponseData, UriKind.Absolute, out Uri? uri):
var parameters = new Dictionary<string, OpenIddictParameter>(StringComparer.Ordinal);
if (!string.IsNullOrEmpty(uri.Query))
{
foreach (var parameter in OpenIddictHelpers.ParseQuery(uri.Query))
{
parameters[parameter.Key] = parameter.Value.Count switch
{
0 => default,
1 => parameter.Value[0],
_ => parameter.Value.ToArray()
};
}
}
// Note: the fragment is always processed after the query string to ensure that
// parameters extracted from the fragment are preferred to parameters extracted
// from the query string when they are present in both parts.
if (!string.IsNullOrEmpty(uri.Fragment))
{
foreach (var parameter in OpenIddictHelpers.ParseFragment(uri.Fragment))
{
parameters[parameter.Key] = parameter.Value.Count switch
{
0 => default,
1 => parameter.Value[0],
_ => parameter.Value.ToArray()
};
}
}
var callback = new OpenIddictClientSystemIntegrationPlatformCallback(uri, parameters)
{
// Attach the authentication result to the properties.
Properties = { [typeof(WebAuthenticationResult).FullName!] = result }
};
await _service.HandlePlatformCallbackAsync(callback, context.CancellationToken);
context.HandleRequest();
return;

318
src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationHandlers.cs

@ -9,7 +9,6 @@ using System.ComponentModel;
using System.Diagnostics;
using System.Net;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security.Claims;
using System.Text;
using Microsoft.Extensions.Hosting;
@ -24,18 +23,6 @@ using static OpenIddict.Client.SystemIntegration.OpenIddictClientSystemIntegrati
using IHostApplicationLifetime = Microsoft.Extensions.Hosting.IApplicationLifetime;
#endif
#if SUPPORTS_ANDROID
using NativeUri = Android.Net.Uri;
#endif
#if SUPPORTS_FOUNDATION
using Foundation;
#endif
#if SUPPORTS_WINDOWS_RUNTIME
using Windows.Security.Authentication.Web;
#endif
namespace OpenIddict.Client.SystemIntegration;
[EditorBrowsable(EditorBrowsableState.Never)]
@ -47,9 +34,7 @@ public static partial class OpenIddictClientSystemIntegrationHandlers
*/
ResolveRequestUriFromHttpListenerRequest.Descriptor,
ResolveRequestUriFromProtocolActivation.Descriptor,
ResolveRequestUriFromASWebAuthenticationCallbackUrl.Descriptor,
ResolveRequestUriFromCustomTabsIntentData.Descriptor,
ResolveRequestUriFromWebAuthenticationResult.Descriptor,
ResolveRequestUriFromPlatformCallback.Descriptor,
InferEndpointTypeFromDynamicAddress.Descriptor,
RejectUnknownHttpRequests.Descriptor,
@ -215,26 +200,23 @@ public static partial class OpenIddictClientSystemIntegrationHandlers
}
/// <summary>
/// Contains the logic responsible for resolving the request URI from the AS web authentication session callback URL.
/// Note: this handler is not used when the OpenID Connect request is not an AS web authentication session callback URL.
/// Contains the logic responsible for resolving the request URI from the platform callback details.
/// Note: this handler is not used when the OpenID Connect request is not a platform callback.
/// </summary>
public sealed class ResolveRequestUriFromASWebAuthenticationCallbackUrl : IOpenIddictClientHandler<ProcessRequestContext>
public sealed class ResolveRequestUriFromPlatformCallback : IOpenIddictClientHandler<ProcessRequestContext>
{
/// <summary>
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictClientHandlerDescriptor Descriptor { get; }
= OpenIddictClientHandlerDescriptor.CreateBuilder<ProcessRequestContext>()
.AddFilter<RequireASWebAuthenticationCallbackUrl>()
.UseSingletonHandler<ResolveRequestUriFromASWebAuthenticationCallbackUrl>()
.AddFilter<RequirePlatformCallback>()
.UseSingletonHandler<ResolveRequestUriFromPlatformCallback>()
.SetOrder(ResolveRequestUriFromProtocolActivation.Descriptor.Order + 1_000)
.SetType(OpenIddictClientHandlerType.BuiltIn)
.Build();
/// <inheritdoc/>
[SupportedOSPlatform("ios12.0")]
[SupportedOSPlatform("maccatalyst13.1")]
[SupportedOSPlatform("macos10.15")]
public ValueTask HandleAsync(ProcessRequestContext context)
{
if (context is null)
@ -242,10 +224,9 @@ public static partial class OpenIddictClientSystemIntegrationHandlers
throw new ArgumentNullException(nameof(context));
}
#if SUPPORTS_AUTHENTICATION_SERVICES && SUPPORTS_FOUNDATION
(context.BaseUri, context.RequestUri) = context.Transaction.GetASWebAuthenticationCallbackUrl() switch
(context.BaseUri, context.RequestUri) = context.Transaction.GetPlatformCallback() switch
{
NSUrl url when Uri.TryCreate(url.AbsoluteString, UriKind.Absolute, out Uri? uri) => (
{ CallbackUri: Uri uri } => (
BaseUri: new UriBuilder(uri) { Path = null, Query = null, Fragment = null }.Uri,
RequestUri: uri),
@ -253,52 +234,6 @@ public static partial class OpenIddictClientSystemIntegrationHandlers
};
return default;
#else
throw new PlatformNotSupportedException(SR.GetResourceString(SR.ID0446));
#endif
}
}
/// <summary>
/// Contains the logic responsible for resolving the request URI from the custom tabs intent data.
/// Note: this handler is not used when the OpenID Connect request is not an custom tabs intent callback.
/// </summary>
public sealed class ResolveRequestUriFromCustomTabsIntentData : IOpenIddictClientHandler<ProcessRequestContext>
{
/// <summary>
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictClientHandlerDescriptor Descriptor { get; }
= OpenIddictClientHandlerDescriptor.CreateBuilder<ProcessRequestContext>()
.AddFilter<RequireCustomTabsIntentData>()
.UseSingletonHandler<ResolveRequestUriFromCustomTabsIntentData>()
.SetOrder(ResolveRequestUriFromASWebAuthenticationCallbackUrl.Descriptor.Order + 1_000)
.SetType(OpenIddictClientHandlerType.BuiltIn)
.Build();
/// <inheritdoc/>
[SupportedOSPlatform("android21.0")]
public ValueTask HandleAsync(ProcessRequestContext context)
{
if (context is null)
{
throw new ArgumentNullException(nameof(context));
}
#if SUPPORTS_ANDROID
(context.BaseUri, context.RequestUri) = context.Transaction.GetCustomTabsIntentData() switch
{
NativeUri url when Uri.TryCreate(url.ToString(), UriKind.Absolute, out Uri? uri) => (
BaseUri: new UriBuilder(uri) { Path = null, Query = null, Fragment = null }.Uri,
RequestUri: uri),
_ => throw new InvalidOperationException(SR.GetResourceString(SR.ID0393))
};
return default;
#else
throw new PlatformNotSupportedException(SR.GetResourceString(SR.ID0452));
#endif
}
}
@ -306,6 +241,7 @@ public static partial class OpenIddictClientSystemIntegrationHandlers
/// Contains the logic responsible for resolving the request URI from the web authentication result.
/// Note: this handler is not used when the OpenID Connect request is not a web authentication result.
/// </summary>
[Obsolete("This event handler is obsolete and will be removed in a future version.")]
public sealed class ResolveRequestUriFromWebAuthenticationResult : IOpenIddictClientHandler<ProcessRequestContext>
{
/// <summary>
@ -315,35 +251,13 @@ public static partial class OpenIddictClientSystemIntegrationHandlers
= OpenIddictClientHandlerDescriptor.CreateBuilder<ProcessRequestContext>()
.AddFilter<RequireWebAuthenticationResult>()
.UseSingletonHandler<ResolveRequestUriFromWebAuthenticationResult>()
.SetOrder(ResolveRequestUriFromCustomTabsIntentData.Descriptor.Order + 1_000)
.SetOrder(ResolveRequestUriFromPlatformCallback.Descriptor.Order + 1_000)
.SetType(OpenIddictClientHandlerType.BuiltIn)
.Build();
/// <inheritdoc/>
[SupportedOSPlatform("windows10.0.17763")]
public ValueTask HandleAsync(ProcessRequestContext context)
{
if (context is null)
{
throw new ArgumentNullException(nameof(context));
}
#if SUPPORTS_WINDOWS_RUNTIME
(context.BaseUri, context.RequestUri) = context.Transaction.GetWebAuthenticationResult() switch
{
{ ResponseStatus: WebAuthenticationStatus.Success, ResponseData: string data } when
Uri.TryCreate(data, UriKind.Absolute, out Uri? uri) => (
BaseUri: new UriBuilder(uri) { Path = null, Query = null, Fragment = null }.Uri,
RequestUri: uri),
_ => throw new InvalidOperationException(SR.GetResourceString(SR.ID0393))
};
return default;
#else
throw new PlatformNotSupportedException(SR.GetResourceString(SR.ID0392));
#endif
}
=> throw new NotSupportedException(SR.GetResourceString(SR.ID0403));
}
/// <summary>
@ -671,26 +585,23 @@ public static partial class OpenIddictClientSystemIntegrationHandlers
}
/// <summary>
/// Contains the logic responsible for extracting OpenID Connect requests from the callback URL of an AS session.
/// Note: this handler is not used when the OpenID Connect request is not an AS web authentication session callback.
/// Contains the logic responsible for extracting OpenID Connect requests from the URI of a platform callback.
/// Note: this handler is not used when the OpenID Connect request is not a platform callback.
/// </summary>
public sealed class ExtractASWebAuthenticationCallbackUrlData<TContext> : IOpenIddictClientHandler<TContext> where TContext : BaseValidatingContext
public sealed class ExtractPlatformCallbackParameters<TContext> : IOpenIddictClientHandler<TContext> where TContext : BaseValidatingContext
{
/// <summary>
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictClientHandlerDescriptor Descriptor { get; }
= OpenIddictClientHandlerDescriptor.CreateBuilder<TContext>()
.AddFilter<RequireASWebAuthenticationCallbackUrl>()
.UseSingletonHandler<ExtractASWebAuthenticationCallbackUrlData<TContext>>()
.AddFilter<RequirePlatformCallback>()
.UseSingletonHandler<ExtractPlatformCallbackParameters<TContext>>()
.SetOrder(ExtractProtocolActivationParameters<TContext>.Descriptor.Order + 1_000)
.SetType(OpenIddictClientHandlerType.BuiltIn)
.Build();
/// <inheritdoc/>
[SupportedOSPlatform("ios12.0")]
[SupportedOSPlatform("maccatalyst13.1")]
[SupportedOSPlatform("macos10.15")]
public ValueTask HandleAsync(TContext context)
{
if (context is null)
@ -698,105 +609,14 @@ public static partial class OpenIddictClientSystemIntegrationHandlers
throw new ArgumentNullException(nameof(context));
}
#if SUPPORTS_AUTHENTICATION_SERVICES && SUPPORTS_FOUNDATION
if (context.Transaction.GetASWebAuthenticationCallbackUrl()
is not NSUrl url || !Uri.TryCreate(url.AbsoluteString, UriKind.Absolute, out Uri? uri))
if (context.Transaction.GetPlatformCallback() is not OpenIddictClientSystemIntegrationPlatformCallback callback)
{
throw new InvalidOperationException(SR.GetResourceString(SR.ID0393));
}
var parameters = new Dictionary<string, StringValues>(StringComparer.Ordinal);
if (!string.IsNullOrEmpty(uri.Query))
{
foreach (var parameter in OpenIddictHelpers.ParseQuery(uri.Query))
{
parameters[parameter.Key] = parameter.Value;
}
}
// Note: the fragment is always processed after the query string to ensure that
// parameters extracted from the fragment are preferred to parameters extracted
// from the query string when they are present in both parts.
if (!string.IsNullOrEmpty(uri.Fragment))
{
foreach (var parameter in OpenIddictHelpers.ParseFragment(uri.Fragment))
{
parameters[parameter.Key] = parameter.Value;
}
}
context.Transaction.Request = new OpenIddictRequest(parameters);
context.Transaction.Request = new OpenIddictRequest(callback.Parameters);
return default;
#else
throw new PlatformNotSupportedException(SR.GetResourceString(SR.ID0446));
#endif
}
}
/// <summary>
/// Contains the logic responsible for extracting OpenID Connect requests from the callback URL of a custom tabs intent.
/// Note: this handler is not used when the OpenID Connect request is not a custom tabs intent result.
/// </summary>
public sealed class ExtractCustomTabsIntentData<TContext> : IOpenIddictClientHandler<TContext> where TContext : BaseValidatingContext
{
/// <summary>
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictClientHandlerDescriptor Descriptor { get; }
= OpenIddictClientHandlerDescriptor.CreateBuilder<TContext>()
.AddFilter<RequireCustomTabsIntentData>()
.UseSingletonHandler<ExtractCustomTabsIntentData<TContext>>()
.SetOrder(ExtractProtocolActivationParameters<TContext>.Descriptor.Order + 1_000)
.SetType(OpenIddictClientHandlerType.BuiltIn)
.Build();
/// <inheritdoc/>
[SupportedOSPlatform("android21.0")]
public ValueTask HandleAsync(TContext context)
{
if (context is null)
{
throw new ArgumentNullException(nameof(context));
}
#if SUPPORTS_ANDROID
if (context.Transaction.GetCustomTabsIntentData()
is not NativeUri url || !Uri.TryCreate(url.ToString(), UriKind.Absolute, out Uri? uri))
{
throw new InvalidOperationException(SR.GetResourceString(SR.ID0393));
}
var parameters = new Dictionary<string, StringValues>(StringComparer.Ordinal);
if (!string.IsNullOrEmpty(uri.Query))
{
foreach (var parameter in OpenIddictHelpers.ParseQuery(uri.Query))
{
parameters[parameter.Key] = parameter.Value;
}
}
// Note: the fragment is always processed after the query string to ensure that
// parameters extracted from the fragment are preferred to parameters extracted
// from the query string when they are present in both parts.
if (!string.IsNullOrEmpty(uri.Fragment))
{
foreach (var parameter in OpenIddictHelpers.ParseFragment(uri.Fragment))
{
parameters[parameter.Key] = parameter.Value;
}
}
context.Transaction.Request = new OpenIddictRequest(parameters);
return default;
#else
throw new PlatformNotSupportedException(SR.GetResourceString(SR.ID0446));
#endif
}
}
@ -805,6 +625,7 @@ public static partial class OpenIddictClientSystemIntegrationHandlers
/// requests from the response data of a web authentication result.
/// Note: this handler is not used when the OpenID Connect request is not a web authentication result.
/// </summary>
[Obsolete("This event handler is obsolete and will be removed in a future version.")]
public sealed class ExtractWebAuthenticationResultData<TContext> : IOpenIddictClientHandler<TContext> where TContext : BaseValidatingContext
{
/// <summary>
@ -814,56 +635,13 @@ public static partial class OpenIddictClientSystemIntegrationHandlers
= OpenIddictClientHandlerDescriptor.CreateBuilder<TContext>()
.AddFilter<RequireWebAuthenticationResult>()
.UseSingletonHandler<ExtractWebAuthenticationResultData<TContext>>()
.SetOrder(ExtractCustomTabsIntentData<TContext>.Descriptor.Order + 1_000)
.SetOrder(ExtractPlatformCallbackParameters<TContext>.Descriptor.Order + 1_000)
.SetType(OpenIddictClientHandlerType.BuiltIn)
.Build();
/// <inheritdoc/>
[SupportedOSPlatform("windows10.0.17763")]
public ValueTask HandleAsync(TContext context)
{
if (context is null)
{
throw new ArgumentNullException(nameof(context));
}
#if SUPPORTS_WINDOWS_RUNTIME
if (context.Transaction.GetWebAuthenticationResult()
is not { ResponseStatus: WebAuthenticationStatus.Success, ResponseData: string data } ||
!Uri.TryCreate(data, UriKind.Absolute, out Uri? uri))
{
throw new InvalidOperationException(SR.GetResourceString(SR.ID0393));
}
var parameters = new Dictionary<string, StringValues>(StringComparer.Ordinal);
if (!string.IsNullOrEmpty(uri.Query))
{
foreach (var parameter in OpenIddictHelpers.ParseQuery(uri.Query))
{
parameters[parameter.Key] = parameter.Value;
}
}
// Note: the fragment is always processed after the query string to ensure that
// parameters extracted from the fragment are preferred to parameters extracted
// from the query string when they are present in both parts.
if (!string.IsNullOrEmpty(uri.Fragment))
{
foreach (var parameter in OpenIddictHelpers.ParseFragment(uri.Fragment))
{
parameters[parameter.Key] = parameter.Value;
}
}
context.Transaction.Request = new OpenIddictRequest(parameters);
return default;
#else
throw new PlatformNotSupportedException(SR.GetResourceString(SR.ID0392));
#endif
}
=> throw new NotSupportedException(SR.GetResourceString(SR.ID0403));
}
/// <summary>
@ -2056,7 +1834,7 @@ public static partial class OpenIddictClientSystemIntegrationHandlers
// the server support response_mode=fragment, use it if the response types contain
// a value that prevents response_mode=query from being used (token/id_token).
({ Count: > 0 } client, { Count: > 0 } server) when
OpenIddictClientSystemIntegrationHelpers.IsWebAuthenticationBrokerSupported() &&
IsWebAuthenticationBrokerSupported() &&
IsAuthenticationMode(OpenIddictClientSystemIntegrationAuthenticationMode.WebAuthenticationBroker) &&
client.Contains(ResponseModes.Fragment) && server.Contains(ResponseModes.Fragment) &&
(types.Contains(ResponseTypes.IdToken) || types.Contains(ResponseTypes.Token))
@ -2067,7 +1845,7 @@ public static partial class OpenIddictClientSystemIntegrationHandlers
// assume it is supported and use it if the response types contain a value that
// prevents response_mode=query from being used (token/id_token).
({ Count: > 0 } client, { Count: 0 }) when
OpenIddictClientSystemIntegrationHelpers.IsWebAuthenticationBrokerSupported() &&
IsWebAuthenticationBrokerSupported() &&
IsAuthenticationMode(OpenIddictClientSystemIntegrationAuthenticationMode.WebAuthenticationBroker) &&
client.Contains(ResponseModes.Fragment) &&
(types.Contains(ResponseTypes.IdToken) || types.Contains(ResponseTypes.Token))
@ -2129,7 +1907,7 @@ public static partial class OpenIddictClientSystemIntegrationHandlers
// When using the web authentication broker on Windows, if both
// the client and the server support response_mode=fragment, use it.
({ Count: > 0 } client, { Count: > 0 } server) when
OpenIddictClientSystemIntegrationHelpers.IsWebAuthenticationBrokerSupported() &&
IsWebAuthenticationBrokerSupported() &&
IsAuthenticationMode(OpenIddictClientSystemIntegrationAuthenticationMode.WebAuthenticationBroker) &&
client.Contains(ResponseModes.Fragment) && server.Contains(ResponseModes.Fragment)
=> ResponseModes.Fragment,
@ -2610,43 +2388,7 @@ public static partial class OpenIddictClientSystemIntegrationHandlers
= OpenIddictClientHandlerDescriptor.CreateBuilder<TContext>()
.AddFilter<RequireProtocolActivation>()
.UseSingletonHandler<ProcessProtocolActivationResponse<TContext>>()
.SetOrder(ProcessWebAuthenticationResultResponse<TContext>.Descriptor.Order - 1_000)
.SetType(OpenIddictClientHandlerType.BuiltIn)
.Build();
/// <inheritdoc/>
public ValueTask HandleAsync(TContext context)
{
if (context is null)
{
throw new ArgumentNullException(nameof(context));
}
// For both protocol activations (initial or redirected) and web-view-like results,
// no proper response can be generated and eventually displayed to the user. In this
// case, simply stop processing the response and mark the request as fully handled.
//
// Note: this logic applies to both successful and errored responses.
context.HandleRequest();
return default;
}
}
/// <summary>
/// Contains the logic responsible for marking OpenID Connect responses returned via a custom tabs intent web as processed.
/// </summary>
public sealed class ProcessCustomTabsIntentResponse<TContext> : IOpenIddictClientHandler<TContext>
where TContext : BaseRequestContext
{
/// <summary>
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictClientHandlerDescriptor Descriptor { get; }
= OpenIddictClientHandlerDescriptor.CreateBuilder<TContext>()
.AddFilter<RequireCustomTabsIntentData>()
.UseSingletonHandler<ProcessCustomTabsIntentResponse<TContext>>()
.SetOrder(int.MaxValue)
.SetOrder(ProcessPlatformCallbackResponse<TContext>.Descriptor.Order - 1_000)
.SetType(OpenIddictClientHandlerType.BuiltIn)
.Build();
@ -2670,10 +2412,9 @@ public static partial class OpenIddictClientSystemIntegrationHandlers
}
/// <summary>
/// Contains the logic responsible for marking OpenID Connect responses
/// returned via AS web authentication callback URLs as processed.
/// Contains the logic responsible for marking OpenID Connect responses returned via a platform callback.
/// </summary>
public sealed class ProcessASWebAuthenticationSessionResponse<TContext> : IOpenIddictClientHandler<TContext>
public sealed class ProcessPlatformCallbackResponse<TContext> : IOpenIddictClientHandler<TContext>
where TContext : BaseRequestContext
{
/// <summary>
@ -2681,8 +2422,8 @@ public static partial class OpenIddictClientSystemIntegrationHandlers
/// </summary>
public static OpenIddictClientHandlerDescriptor Descriptor { get; }
= OpenIddictClientHandlerDescriptor.CreateBuilder<TContext>()
.AddFilter<RequireASWebAuthenticationCallbackUrl>()
.UseSingletonHandler<ProcessASWebAuthenticationSessionResponse<TContext>>()
.AddFilter<RequirePlatformCallback>()
.UseSingletonHandler<ProcessPlatformCallbackResponse<TContext>>()
.SetOrder(int.MaxValue)
.SetType(OpenIddictClientHandlerType.BuiltIn)
.Build();
@ -2710,6 +2451,7 @@ public static partial class OpenIddictClientSystemIntegrationHandlers
/// Contains the logic responsible for marking OpenID Connect
/// responses returned via web authentication results as processed.
/// </summary>
[Obsolete("This handler is obsolete and will be removed in a future version.")]
public sealed class ProcessWebAuthenticationResultResponse<TContext> : IOpenIddictClientHandler<TContext>
where TContext : BaseRequestContext
{

38
src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationHelpers.cs

@ -44,6 +44,14 @@ namespace OpenIddict.Client.SystemIntegration;
/// </summary>
public static class OpenIddictClientSystemIntegrationHelpers
{
/// <summary>
/// Gets the <see cref="OpenIddictClientSystemIntegrationPlatformCallback"/> associated with the current context.
/// </summary>
/// <param name="transaction">The transaction instance.</param>
/// <returns>The <see cref="OpenIddictClientSystemIntegrationPlatformCallback"/> instance or <see langword="null"/> if it couldn't be found.</returns>
public static OpenIddictClientSystemIntegrationPlatformCallback? GetPlatformCallback(this OpenIddictClientTransaction transaction)
=> transaction.GetProperty<OpenIddictClientSystemIntegrationPlatformCallback>(typeof(OpenIddictClientSystemIntegrationPlatformCallback).FullName!);
/// <summary>
/// Gets the <see cref="OpenIddictClientSystemIntegrationActivation"/> associated with the current context.
/// </summary>
@ -60,39 +68,17 @@ public static class OpenIddictClientSystemIntegrationHelpers
public static HttpListenerContext? GetHttpListenerContext(this OpenIddictClientTransaction transaction)
=> transaction.GetProperty<HttpListenerContext>(typeof(HttpListenerContext).FullName!);
#if SUPPORTS_AUTHENTICATION_SERVICES && SUPPORTS_FOUNDATION
/// <summary>
/// Gets the AS web authentication callback URL associated with the current context.
/// </summary>
/// <param name="transaction">The transaction instance.</param>
/// <returns>The <see cref="NSUrl"/> instance or <see langword="null"/> if it couldn't be found.</returns>
[SupportedOSPlatform("ios12.0")]
[SupportedOSPlatform("maccatalyst13.1")]
[SupportedOSPlatform("macos10.15")]
public static NSUrl? GetASWebAuthenticationCallbackUrl(this OpenIddictClientTransaction transaction)
=> transaction.GetProperty<NSUrl>(typeof(NSUrl).FullName!);
#endif
#if SUPPORTS_ANDROID && SUPPORTS_ANDROIDX_BROWSER
/// <summary>
/// Gets the custom tabs intent data associated with the current context.
/// </summary>
/// <param name="transaction">The transaction instance.</param>
/// <returns>The <see cref="NativeUri"/> instance or <see langword="null"/> if it couldn't be found.</returns>
[SupportedOSPlatform("android21.0")]
public static NativeUri? GetCustomTabsIntentData(this OpenIddictClientTransaction transaction)
=> transaction.GetProperty<NativeUri>(typeof(NativeUri).FullName!);
#endif
#if SUPPORTS_WINDOWS_RUNTIME
/// <summary>
/// Gets the <see cref="WebAuthenticationResult"/> associated with the current context.
/// </summary>
/// <param name="transaction">The transaction instance.</param>
/// <returns>The <see cref="HttpListenerContext"/> instance or <see langword="null"/> if it couldn't be found.</returns>
[SupportedOSPlatform("windows10.0.17763")]
[Obsolete("This extension is obsolete and will be removed in a future version."), SupportedOSPlatform("windows10.0.17763")]
public static WebAuthenticationResult? GetWebAuthenticationResult(this OpenIddictClientTransaction transaction)
=> transaction.GetProperty<WebAuthenticationResult>(typeof(WebAuthenticationResult).FullName!);
=> transaction.GetPlatformCallback() is OpenIddictClientSystemIntegrationPlatformCallback callback &&
callback.Properties.TryGetValue(typeof(WebAuthenticationResult).FullName!, out object? property) &&
property is WebAuthenticationResult result ? result : null;
#endif
/// <summary>

62
src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationPlatformCallback.cs

@ -0,0 +1,62 @@
/*
* Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
* See https://github.com/openiddict/openiddict-core for more information concerning
* the license and the contributors participating to this project.
*/
using System.Collections.Immutable;
using System.ComponentModel;
using OpenIddict.Extensions;
namespace OpenIddict.Client.SystemIntegration;
/// <summary>
/// Represents a generic platform callback.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Advanced)]
public sealed class OpenIddictClientSystemIntegrationPlatformCallback
{
/// <summary>
/// Creates a new instance of the <see cref="OpenIddictClientSystemIntegrationPlatformCallback"/> class.
/// </summary>
/// <param name="uri">The callback URI.</param>
/// <param name="parameters">The callback parameters.</param>
/// <exception cref="ArgumentNullException"><paramref name="uri"/> is <see langword="null"/>.</exception>
/// <exception cref="ArgumentNullException"><paramref name="parameters"/> is <see langword="null"/>.</exception>
public OpenIddictClientSystemIntegrationPlatformCallback(
Uri uri, IReadOnlyDictionary<string, OpenIddictParameter> parameters)
{
if (uri is null)
{
throw new ArgumentNullException(nameof(uri));
}
if (!uri.IsAbsoluteUri || OpenIddictHelpers.IsImplicitFileUri(uri))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0144), nameof(uri));
}
if (parameters is null)
{
throw new ArgumentNullException(nameof(parameters));
}
CallbackUri = uri;
Parameters = parameters.ToImmutableDictionary();
}
/// <summary>
/// Gets the callback URI.
/// </summary>
public Uri CallbackUri { get; }
/// <summary>
/// Gets the parameters attached to this instance.
/// </summary>
public ImmutableDictionary<string, OpenIddictParameter> Parameters { get; }
/// <summary>
/// Gets the additional properties attached to this instance.
/// </summary>
public Dictionary<string, object> Properties { get; } = new(StringComparer.Ordinal);
}

118
src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationService.cs

@ -7,22 +7,13 @@
using System.ComponentModel;
using System.IO.Pipes;
using System.Net;
using System.Runtime.Versioning;
using System.Security.Principal;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using OpenIddict.Extensions;
#if SUPPORTS_ANDROID
using Android.Content;
using NativeUri = Android.Net.Uri;
#endif
#if SUPPORTS_FOUNDATION
using Foundation;
#endif
#if SUPPORTS_WINDOWS_RUNTIME
using Windows.Security.Authentication.Web;
#endif
namespace OpenIddict.Client.SystemIntegration;
@ -51,18 +42,6 @@ public sealed class OpenIddictClientSystemIntegrationService
_provider = provider ?? throw new ArgumentNullException(nameof(provider));
}
/// <summary>
/// Handles the specified protocol activation.
/// </summary>
/// <param name="activation">The protocol activation details.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>A <see cref="Task"/> that can be used to monitor the asynchronous operation.</returns>
/// <exception cref="ArgumentNullException"><paramref name="activation"/> is <see langword="null"/>.</exception>
[EditorBrowsable(EditorBrowsableState.Advanced)]
public Task HandleProtocolActivationAsync(
OpenIddictClientSystemIntegrationActivation activation, CancellationToken cancellationToken = default)
=> HandleRequestAsync(activation ?? throw new ArgumentNullException(nameof(activation)), cancellationToken);
#if SUPPORTS_ANDROID && SUPPORTS_ANDROIDX_BROWSER
/// <summary>
/// Handles the specified intent.
@ -73,46 +52,93 @@ public sealed class OpenIddictClientSystemIntegrationService
/// <exception cref="ArgumentNullException"><paramref name="intent"/> is <see langword="null"/>.</exception>
[EditorBrowsable(EditorBrowsableState.Advanced)]
public Task HandleCustomTabsIntentAsync(Intent intent, CancellationToken cancellationToken = default)
=> HandleRequestAsync(intent?.Data ?? throw new ArgumentNullException(nameof(intent)), cancellationToken);
{
if (intent is null)
{
throw new ArgumentNullException(nameof(intent));
}
if (intent.Data is null)
{
throw new ArgumentException(SR.GetResourceString(SR.ID0453), nameof(intent));
}
var parameters = new Dictionary<string, OpenIddictParameter>(StringComparer.Ordinal);
if (!string.IsNullOrEmpty(intent.Data.Query))
{
foreach (var parameter in OpenIddictHelpers.ParseQuery(intent.Data.Query))
{
parameters[parameter.Key] = parameter.Value.Count switch
{
0 => default,
1 => parameter.Value[0],
_ => parameter.Value.ToArray()
};
}
}
// Note: the fragment is always processed after the query string to ensure that
// parameters extracted from the fragment are preferred to parameters extracted
// from the query string when they are present in both parts.
if (!string.IsNullOrEmpty(intent.Data.Fragment))
{
foreach (var parameter in OpenIddictHelpers.ParseFragment(intent.Data.Fragment))
{
parameters[parameter.Key] = parameter.Value.Count switch
{
0 => default,
1 => parameter.Value[0],
_ => parameter.Value.ToArray()
};
}
}
var uri = new Uri(intent.Data.ToString()!, UriKind.Absolute);
var callback = new OpenIddictClientSystemIntegrationPlatformCallback(uri, parameters)
{
// Attach the intent to the properties.
Properties = { [typeof(Intent).FullName!] = intent }
};
return HandlePlatformCallbackAsync(callback, cancellationToken);
}
#endif
/// <summary>
/// Handles the specified HTTP request.
/// Handles the specified platform callback.
/// </summary>
/// <param name="request">The HTTP request received by the embedded web server.</param>
/// <param name="callback">The platform callback details.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>A <see cref="Task"/> that can be used to monitor the asynchronous operation.</returns>
/// <exception cref="ArgumentNullException"><paramref name="request"/> is <see langword="null"/>.</exception>
internal Task HandleHttpRequestAsync(HttpListenerContext request, CancellationToken cancellationToken = default)
=> HandleRequestAsync(request ?? throw new ArgumentNullException(nameof(request)), cancellationToken);
/// <exception cref="ArgumentNullException"><paramref name="callback"/> is <see langword="null"/>.</exception>
[EditorBrowsable(EditorBrowsableState.Never)]
public Task HandlePlatformCallbackAsync(
OpenIddictClientSystemIntegrationPlatformCallback callback, CancellationToken cancellationToken = default)
=> HandleRequestAsync(callback ?? throw new ArgumentNullException(nameof(callback)), cancellationToken);
#if SUPPORTS_AUTHENTICATION_SERVICES && SUPPORTS_FOUNDATION
/// <summary>
/// Handles the specified AS web authentication session callback URL.
/// Handles the specified protocol activation.
/// </summary>
/// <param name="url">The AS web authentication session callback URL.</param>
/// <param name="activation">The protocol activation details.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>A <see cref="Task"/> that can be used to monitor the asynchronous operation.</returns>
/// <exception cref="ArgumentNullException"><paramref name="url"/> is <see langword="null"/>.</exception>
[SupportedOSPlatform("ios12.0")]
[SupportedOSPlatform("maccatalyst13.1")]
[SupportedOSPlatform("macos10.15")]
internal Task HandleASWebAuthenticationCallbackUrlAsync(NSUrl url, CancellationToken cancellationToken = default)
=> HandleRequestAsync(url, cancellationToken);
#endif
/// <exception cref="ArgumentNullException"><paramref name="activation"/> is <see langword="null"/>.</exception>
[EditorBrowsable(EditorBrowsableState.Advanced)]
public Task HandleProtocolActivationAsync(
OpenIddictClientSystemIntegrationActivation activation, CancellationToken cancellationToken = default)
=> HandleRequestAsync(activation ?? throw new ArgumentNullException(nameof(activation)), cancellationToken);
#if SUPPORTS_WINDOWS_RUNTIME
/// <summary>
/// Handles the specified web authentication result.
/// Handles the specified HTTP request.
/// </summary>
/// <param name="result">The web authentication result.</param>
/// <param name="request">The HTTP request received by the embedded web server.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>A <see cref="Task"/> that can be used to monitor the asynchronous operation.</returns>
/// <exception cref="ArgumentNullException"><paramref name="result"/> is <see langword="null"/>.</exception>
[SupportedOSPlatform("windows10.0.17763")]
internal Task HandleWebAuthenticationResultAsync(WebAuthenticationResult result, CancellationToken cancellationToken = default)
=> HandleRequestAsync(result ?? throw new ArgumentNullException(nameof(result)), cancellationToken);
#endif
/// <exception cref="ArgumentNullException"><paramref name="request"/> is <see langword="null"/>.</exception>
internal Task HandleHttpRequestAsync(HttpListenerContext request, CancellationToken cancellationToken = default)
=> HandleRequestAsync(request ?? throw new ArgumentNullException(nameof(request)), cancellationToken);
/// <summary>
/// Handles the request using the specified property.

4
src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationHandlers.Discovery.cs

@ -263,7 +263,7 @@ public static partial class OpenIddictClientWebIntegrationHandlers
/// Contains the logic responsible for amending the client authentication methods
/// supported by the device authorization endpoint for the providers that require it.
/// </summary>
[Obsolete("This class is obsolete and will be removed in a future version.", error: true)]
[Obsolete("This event handler is obsolete and will be removed in a future version.", error: true)]
public sealed class AmendDeviceAuthorizationEndpointClientAuthenticationMethods : IOpenIddictClientHandler<HandleConfigurationResponseContext>
{
/// <summary>
@ -285,7 +285,7 @@ public static partial class OpenIddictClientWebIntegrationHandlers
/// Contains the logic responsible for amending the client authentication
/// methods supported by the token endpoint for the providers that require it.
/// </summary>
[Obsolete("This class is obsolete and will be removed in a future version.", error: true)]
[Obsolete("This event handler is obsolete and will be removed in a future version.", error: true)]
public sealed class AmendTokenEndpointClientAuthenticationMethods : IOpenIddictClientHandler<HandleConfigurationResponseContext>
{
/// <summary>

2
src/OpenIddict.Server/OpenIddictServerHandlers.Protection.cs

@ -1562,7 +1562,7 @@ public static partial class OpenIddictServerHandlers
/// Contains the logic responsible for beautifying user-typed tokens.
/// Note: this handler is not used when the degraded mode is enabled.
/// </summary>
[Obsolete("This class is obsolete and will be removed in a future version.", error: true)]
[Obsolete("This event handler is obsolete and will be removed in a future version.", error: true)]
public sealed class BeautifyToken : IOpenIddictServerHandler<GenerateTokenContext>
{
/// <summary>

Loading…
Cancel
Save