44 changed files with 801 additions and 453 deletions
@ -0,0 +1,14 @@ |
|||||
|
<Project Sdk="Microsoft.NET.Sdk"> |
||||
|
|
||||
|
<Import Project="..\..\build\common.props" /> |
||||
|
|
||||
|
<PropertyGroup> |
||||
|
<TargetFramework>netstandard1.3</TargetFramework> |
||||
|
<IsPackable>false</IsPackable> |
||||
|
</PropertyGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<PackageReference Include="System.Reflection.TypeExtensions" Version="$(TypeExtensionsVersion)" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
</Project> |
||||
@ -0,0 +1,26 @@ |
|||||
|
/* |
||||
|
* 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.Threading; |
||||
|
using System.Threading.Tasks; |
||||
|
using JetBrains.Annotations; |
||||
|
|
||||
|
namespace OpenIddict.Server |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Dispatches events by invoking the corresponding handlers.
|
||||
|
/// </summary>
|
||||
|
public interface IOpenIddictServerEventService |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Publishes a new event.
|
||||
|
/// </summary>
|
||||
|
/// <typeparam name="TEvent">The type of the event to publish.</typeparam>
|
||||
|
/// <param name="notification">The event to publish.</param>
|
||||
|
/// <returns>A <see cref="Task"/> that can be used to monitor the asynchronous operation.</returns>
|
||||
|
Task PublishAsync<TEvent>([NotNull] TEvent notification) where TEvent : class, IOpenIddictServerEvent; |
||||
|
} |
||||
|
} |
||||
@ -1,164 +0,0 @@ |
|||||
/* |
|
||||
* 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; |
|
||||
using System.Threading; |
|
||||
using System.Threading.Tasks; |
|
||||
using AspNet.Security.OpenIdConnect.Primitives; |
|
||||
using JetBrains.Annotations; |
|
||||
using Microsoft.AspNetCore.Authentication; |
|
||||
using Microsoft.Extensions.DependencyInjection; |
|
||||
using static OpenIddict.Server.OpenIddictServerEvents; |
|
||||
|
|
||||
namespace OpenIddict.Server.Internal |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Dispatches events by invoking the corresponding notification handlers.
|
|
||||
/// Note: this API supports the OpenIddict infrastructure and is not intended to be used
|
|
||||
/// directly from your code. This API may change or be removed in future minor releases.
|
|
||||
/// </summary>
|
|
||||
public class OpenIddictServerEventService |
|
||||
{ |
|
||||
private readonly IServiceProvider _provider; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Creates a new instance of the <see cref="OpenIddictServerEventService"/> class.
|
|
||||
/// Note: this API supports the OpenIddict infrastructure and is not intended to be used
|
|
||||
/// directly from your code. This API may change or be removed in future minor releases.
|
|
||||
/// </summary>
|
|
||||
public OpenIddictServerEventService([NotNull] IServiceProvider provider) |
|
||||
{ |
|
||||
_provider = provider; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Publishes a new event.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TEvent">The type of the event to publish.</typeparam>
|
|
||||
/// <param name="notification">The event to publish.</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>
|
|
||||
public async Task PublishAsync<TEvent>([NotNull] TEvent notification, CancellationToken cancellationToken = default) |
|
||||
where TEvent : class, IOpenIddictServerEvent |
|
||||
{ |
|
||||
if (notification == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(notification)); |
|
||||
} |
|
||||
|
|
||||
foreach (var handler in _provider.GetServices<IOpenIddictServerEventHandler<TEvent>>()) |
|
||||
{ |
|
||||
cancellationToken.ThrowIfCancellationRequested(); |
|
||||
|
|
||||
await handler.HandleAsync(notification, cancellationToken); |
|
||||
|
|
||||
// Note: the following logic determines whether next handlers should be invoked
|
|
||||
// depending on whether the underlying event context was substantially updated.
|
|
||||
switch (notification) |
|
||||
{ |
|
||||
case MatchEndpoint value when value.Context.State != EventResultState.Continue: return; |
|
||||
case MatchEndpoint value when value.Context.IsAuthorizationEndpoint || |
|
||||
value.Context.IsConfigurationEndpoint || |
|
||||
value.Context.IsCryptographyEndpoint || |
|
||||
value.Context.IsIntrospectionEndpoint || |
|
||||
value.Context.IsLogoutEndpoint || |
|
||||
value.Context.IsRevocationEndpoint || |
|
||||
value.Context.IsTokenEndpoint || |
|
||||
value.Context.IsUserinfoEndpoint: return; |
|
||||
|
|
||||
case ExtractAuthorizationRequest value when value.Context.State != EventResultState.Continue: return; |
|
||||
case ExtractConfigurationRequest value when value.Context.State != EventResultState.Continue: return; |
|
||||
case ExtractCryptographyRequest value when value.Context.State != EventResultState.Continue: return; |
|
||||
case ExtractIntrospectionRequest value when value.Context.State != EventResultState.Continue: return; |
|
||||
case ExtractLogoutRequest value when value.Context.State != EventResultState.Continue: return; |
|
||||
case ExtractRevocationRequest value when value.Context.State != EventResultState.Continue: return; |
|
||||
case ExtractTokenRequest value when value.Context.State != EventResultState.Continue: return; |
|
||||
case ExtractUserinfoRequest value when value.Context.State != EventResultState.Continue: return; |
|
||||
|
|
||||
case ValidateAuthorizationRequest value when value.Context.State != EventResultState.Continue: return; |
|
||||
case ValidateConfigurationRequest value when value.Context.State != EventResultState.Continue: return; |
|
||||
case ValidateCryptographyRequest value when value.Context.State != EventResultState.Continue: return; |
|
||||
case ValidateIntrospectionRequest value when value.Context.State != EventResultState.Continue: return; |
|
||||
case ValidateLogoutRequest value when value.Context.State != EventResultState.Continue: return; |
|
||||
case ValidateRevocationRequest value when value.Context.State != EventResultState.Continue: return; |
|
||||
case ValidateTokenRequest value when value.Context.State != EventResultState.Continue: return; |
|
||||
case ValidateUserinfoRequest value when value.Context.State != EventResultState.Continue: return; |
|
||||
|
|
||||
case ValidateAuthorizationRequest value when value.Context.IsRejected: return; |
|
||||
case ValidateConfigurationRequest value when value.Context.IsRejected: return; |
|
||||
case ValidateCryptographyRequest value when value.Context.IsRejected: return; |
|
||||
case ValidateIntrospectionRequest value when value.Context.IsRejected: return; |
|
||||
case ValidateLogoutRequest value when value.Context.IsRejected: return; |
|
||||
case ValidateRevocationRequest value when value.Context.IsRejected: return; |
|
||||
case ValidateTokenRequest value when value.Context.IsRejected: return; |
|
||||
case ValidateUserinfoRequest value when value.Context.IsRejected: return; |
|
||||
|
|
||||
case ValidateIntrospectionRequest value when value.Context.IsSkipped: return; |
|
||||
case ValidateRevocationRequest value when value.Context.IsSkipped: return; |
|
||||
case ValidateTokenRequest value when value.Context.IsSkipped: return; |
|
||||
|
|
||||
case HandleAuthorizationRequest value when value.Context.State != EventResultState.Continue: return; |
|
||||
case HandleConfigurationRequest value when value.Context.State != EventResultState.Continue: return; |
|
||||
case HandleCryptographyRequest value when value.Context.State != EventResultState.Continue: return; |
|
||||
case HandleIntrospectionRequest value when value.Context.State != EventResultState.Continue: return; |
|
||||
case HandleLogoutRequest value when value.Context.State != EventResultState.Continue: return; |
|
||||
case HandleRevocationRequest value when value.Context.State != EventResultState.Continue: return; |
|
||||
case HandleTokenRequest value when value.Context.State != EventResultState.Continue: return; |
|
||||
case HandleUserinfoRequest value when value.Context.State != EventResultState.Continue: return; |
|
||||
|
|
||||
case HandleAuthorizationRequest value when value.Context.Ticket != null: return; |
|
||||
|
|
||||
case HandleTokenRequest value when value.Context.Ticket != null && |
|
||||
!value.Context.Request.IsAuthorizationCodeGrantType() && |
|
||||
!value.Context.Request.IsRefreshTokenGrantType(): return; |
|
||||
|
|
||||
case HandleTokenRequest value when value.Context.Ticket == null && |
|
||||
(value.Context.Request.IsAuthorizationCodeGrantType() || |
|
||||
value.Context.Request.IsRefreshTokenGrantType()): return; |
|
||||
|
|
||||
case HandleAuthorizationRequest value when value.Context.Ticket != null: return; |
|
||||
|
|
||||
case ProcessChallengeResponse value when value.Context.State != EventResultState.Continue: return; |
|
||||
case ProcessSigninResponse value when value.Context.State != EventResultState.Continue: return; |
|
||||
case ProcessSignoutResponse value when value.Context.State != EventResultState.Continue: return; |
|
||||
|
|
||||
case ProcessChallengeResponse value when value.Context.IsRejected: return; |
|
||||
case ProcessSigninResponse value when value.Context.IsRejected: return; |
|
||||
case ProcessSignoutResponse value when value.Context.IsRejected: return; |
|
||||
|
|
||||
case ApplyAuthorizationResponse value when value.Context.State != EventResultState.Continue: return; |
|
||||
case ApplyConfigurationResponse value when value.Context.State != EventResultState.Continue: return; |
|
||||
case ApplyCryptographyResponse value when value.Context.State != EventResultState.Continue: return; |
|
||||
case ApplyIntrospectionResponse value when value.Context.State != EventResultState.Continue: return; |
|
||||
case ApplyLogoutResponse value when value.Context.State != EventResultState.Continue: return; |
|
||||
case ApplyRevocationResponse value when value.Context.State != EventResultState.Continue: return; |
|
||||
case ApplyTokenResponse value when value.Context.State != EventResultState.Continue: return; |
|
||||
case ApplyUserinfoResponse value when value.Context.State != EventResultState.Continue: return; |
|
||||
|
|
||||
case DeserializeAuthorizationCode value when value.Context.State != EventResultState.Continue: return; |
|
||||
case DeserializeAccessToken value when value.Context.State != EventResultState.Continue: return; |
|
||||
case DeserializeIdentityToken value when value.Context.State != EventResultState.Continue: return; |
|
||||
case DeserializeRefreshToken value when value.Context.State != EventResultState.Continue: return; |
|
||||
|
|
||||
case DeserializeAuthorizationCode value when value.Context.Ticket != null: return; |
|
||||
case DeserializeAccessToken value when value.Context.Ticket != null: return; |
|
||||
case DeserializeIdentityToken value when value.Context.Ticket != null: return; |
|
||||
case DeserializeRefreshToken value when value.Context.Ticket != null: return; |
|
||||
|
|
||||
case SerializeAuthorizationCode value when value.Context.State != EventResultState.Continue: return; |
|
||||
case SerializeAccessToken value when value.Context.State != EventResultState.Continue: return; |
|
||||
case SerializeIdentityToken value when value.Context.State != EventResultState.Continue: return; |
|
||||
case SerializeRefreshToken value when value.Context.State != EventResultState.Continue: return; |
|
||||
|
|
||||
case SerializeAuthorizationCode value when !string.IsNullOrEmpty(value.Context.AuthorizationCode): return; |
|
||||
case SerializeAccessToken value when !string.IsNullOrEmpty(value.Context.AccessToken): return; |
|
||||
case SerializeIdentityToken value when !string.IsNullOrEmpty(value.Context.IdentityToken): return; |
|
||||
case SerializeRefreshToken value when !string.IsNullOrEmpty(value.Context.RefreshToken): return; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -0,0 +1,52 @@ |
|||||
|
/* |
||||
|
* 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; |
||||
|
using System.Threading.Tasks; |
||||
|
using JetBrains.Annotations; |
||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
|
||||
|
namespace OpenIddict.Server |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Dispatches events by invoking the corresponding notification handlers.
|
||||
|
/// </summary>
|
||||
|
public class OpenIddictServerEventService : IOpenIddictServerEventService |
||||
|
{ |
||||
|
private readonly IServiceProvider _provider; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Creates a new instance of the <see cref="OpenIddictServerEventService"/> class.
|
||||
|
/// </summary>
|
||||
|
public OpenIddictServerEventService([NotNull] IServiceProvider provider) |
||||
|
=> _provider = provider; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Publishes a new event.
|
||||
|
/// </summary>
|
||||
|
/// <typeparam name="TEvent">The type of the event to publish.</typeparam>
|
||||
|
/// <param name="notification">The event to publish.</param>
|
||||
|
/// <returns>A <see cref="Task"/> that can be used to monitor the asynchronous operation.</returns>
|
||||
|
public async Task PublishAsync<TEvent>([NotNull] TEvent notification) where TEvent : class, IOpenIddictServerEvent |
||||
|
{ |
||||
|
if (notification == null) |
||||
|
{ |
||||
|
throw new ArgumentNullException(nameof(notification)); |
||||
|
} |
||||
|
|
||||
|
foreach (var handler in _provider.GetServices<IOpenIddictServerEventHandler<TEvent>>()) |
||||
|
{ |
||||
|
switch (await handler.HandleAsync(notification)) |
||||
|
{ |
||||
|
case OpenIddictServerEventState.Unhandled: continue; |
||||
|
case OpenIddictServerEventState.Handled: return; |
||||
|
|
||||
|
default: throw new InvalidOperationException("The specified event state is not valid."); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,33 @@ |
|||||
|
/* |
||||
|
* 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. |
||||
|
*/ |
||||
|
|
||||
|
namespace OpenIddict.Server |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Represents the state of an event triggered by the OpenIddict
|
||||
|
/// server components and processed by user-defined handlers.
|
||||
|
/// </summary>
|
||||
|
public enum OpenIddictServerEventState |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Marks the event as unhandled, allowing the event service to invoke the
|
||||
|
/// other event handlers registered in the dependency injection container.
|
||||
|
/// Using this value is recommended for event handlers that don't produce
|
||||
|
/// an immediate response (i.e that don't call context.HandleResponse(),
|
||||
|
/// context.SkipToNextMiddleware(), context.Validate() or context.Reject()).
|
||||
|
/// </summary>
|
||||
|
Unhandled = 0, |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Marks the event as fully handled, preventing the event service from invoking
|
||||
|
/// other event handlers registered in the dependency injection container.
|
||||
|
/// Using this value is recommended for event handlers that produce an
|
||||
|
/// immediate response (i.e that call context.SkipToNextMiddleware(),
|
||||
|
/// context.HandleResponse(), context.Validate() or context.Reject()).
|
||||
|
/// </summary>
|
||||
|
Handled = 1 |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,25 @@ |
|||||
|
/* |
||||
|
* 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.Threading.Tasks; |
||||
|
using JetBrains.Annotations; |
||||
|
|
||||
|
namespace OpenIddict.Validation |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Dispatches events by invoking the corresponding handlers.
|
||||
|
/// </summary>
|
||||
|
public interface IOpenIddictValidationEventService |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Publishes a new event.
|
||||
|
/// </summary>
|
||||
|
/// <typeparam name="TEvent">The type of the event to publish.</typeparam>
|
||||
|
/// <param name="notification">The event to publish.</param>
|
||||
|
/// <returns>A <see cref="Task"/> that can be used to monitor the asynchronous operation.</returns>
|
||||
|
Task PublishAsync<TEvent>([NotNull] TEvent notification) where TEvent : class, IOpenIddictValidationEvent; |
||||
|
} |
||||
|
} |
||||
@ -1,77 +0,0 @@ |
|||||
/* |
|
||||
* 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; |
|
||||
using System.Threading; |
|
||||
using System.Threading.Tasks; |
|
||||
using JetBrains.Annotations; |
|
||||
using Microsoft.AspNetCore.Authentication; |
|
||||
using Microsoft.Extensions.DependencyInjection; |
|
||||
|
|
||||
namespace OpenIddict.Validation.Internal |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Dispatches events by invoking the corresponding notification handlers.
|
|
||||
/// Note: this API supports the OpenIddict infrastructure and is not intended to be used
|
|
||||
/// directly from your code. This API may change or be removed in future minor releases.
|
|
||||
/// </summary>
|
|
||||
public class OpenIddictValidationEventService |
|
||||
{ |
|
||||
private readonly IServiceProvider _provider; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Creates a new instance of the <see cref="OpenIddictValidationEventService"/> class.
|
|
||||
/// Note: this API supports the OpenIddict infrastructure and is not intended to be used
|
|
||||
/// directly from your code. This API may change or be removed in future minor releases.
|
|
||||
/// </summary>
|
|
||||
public OpenIddictValidationEventService([NotNull] IServiceProvider provider) |
|
||||
{ |
|
||||
_provider = provider; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Publishes a new event.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TEvent">The type of the event to publish.</typeparam>
|
|
||||
/// <param name="notification">The event to publish.</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>
|
|
||||
public async Task PublishAsync<TEvent>([NotNull] TEvent notification, CancellationToken cancellationToken = default) |
|
||||
where TEvent : class, IOpenIddictValidationEvent |
|
||||
{ |
|
||||
if (notification == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(notification)); |
|
||||
} |
|
||||
|
|
||||
foreach (var handler in _provider.GetServices<IOpenIddictValidationEventHandler<TEvent>>()) |
|
||||
{ |
|
||||
cancellationToken.ThrowIfCancellationRequested(); |
|
||||
|
|
||||
await handler.HandleAsync(notification, cancellationToken); |
|
||||
|
|
||||
// Note: the following logic determines whether next handlers should be invoked
|
|
||||
// depending on whether the underlying event context was substantially updated.
|
|
||||
switch (notification) |
|
||||
{ |
|
||||
case OpenIddictValidationEvents.ApplyChallenge value when value.Context.State != EventResultState.Continue: return; |
|
||||
|
|
||||
case OpenIddictValidationEvents.CreateTicket value when value.Context.State != EventResultState.Continue: return; |
|
||||
case OpenIddictValidationEvents.CreateTicket value when value.Context.Ticket == null: return; |
|
||||
|
|
||||
case OpenIddictValidationEvents.DecryptToken value when value.Context.State != EventResultState.Continue: return; |
|
||||
case OpenIddictValidationEvents.DecryptToken value when value.Context.Ticket != null: return; |
|
||||
|
|
||||
case OpenIddictValidationEvents.RetrieveToken value when value.Context.State != EventResultState.Continue: return; |
|
||||
case OpenIddictValidationEvents.RetrieveToken value when value.Context.Ticket != null: return; |
|
||||
|
|
||||
case OpenIddictValidationEvents.ValidateToken value when value.Context.State != EventResultState.Continue: return; |
|
||||
case OpenIddictValidationEvents.ValidateToken value when value.Context.Ticket == null: return; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -0,0 +1,52 @@ |
|||||
|
/* |
||||
|
* 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; |
||||
|
using System.Threading.Tasks; |
||||
|
using JetBrains.Annotations; |
||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
|
||||
|
namespace OpenIddict.Validation |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Dispatches events by invoking the corresponding notification handlers.
|
||||
|
/// </summary>
|
||||
|
public class OpenIddictValidationEventService : IOpenIddictValidationEventService |
||||
|
{ |
||||
|
private readonly IServiceProvider _provider; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Creates a new instance of the <see cref="OpenIddictValidationEventService"/> class.
|
||||
|
/// </summary>
|
||||
|
public OpenIddictValidationEventService([NotNull] IServiceProvider provider) |
||||
|
=> _provider = provider; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Publishes a new event.
|
||||
|
/// </summary>
|
||||
|
/// <typeparam name="TEvent">The type of the event to publish.</typeparam>
|
||||
|
/// <param name="notification">The event to publish.</param>
|
||||
|
/// <returns>A <see cref="Task"/> that can be used to monitor the asynchronous operation.</returns>
|
||||
|
public async Task PublishAsync<TEvent>([NotNull] TEvent notification) where TEvent : class, IOpenIddictValidationEvent |
||||
|
{ |
||||
|
if (notification == null) |
||||
|
{ |
||||
|
throw new ArgumentNullException(nameof(notification)); |
||||
|
} |
||||
|
|
||||
|
foreach (var handler in _provider.GetServices<IOpenIddictValidationEventHandler<TEvent>>()) |
||||
|
{ |
||||
|
switch (await handler.HandleAsync(notification)) |
||||
|
{ |
||||
|
case OpenIddictValidationEventState.Unhandled: continue; |
||||
|
case OpenIddictValidationEventState.Handled: return; |
||||
|
|
||||
|
default: throw new InvalidOperationException("The specified event state is not valid."); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,33 @@ |
|||||
|
/* |
||||
|
* 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. |
||||
|
*/ |
||||
|
|
||||
|
namespace OpenIddict.Validation |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Represents the state of an event triggered by the OpenIddict
|
||||
|
/// validation components and processed by user-defined handlers.
|
||||
|
/// </summary>
|
||||
|
public enum OpenIddictValidationEventState |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Marks the event as unhandled, allowing the event service to invoke the
|
||||
|
/// other event handlers registered in the dependency injection container.
|
||||
|
/// Using this value is recommended for event handlers that don't produce
|
||||
|
/// an immediate response (i.e that don't call context.HandleResponse(),
|
||||
|
/// context.Fail(), context.NoResult() or context.Success()).
|
||||
|
/// </summary>
|
||||
|
Unhandled = 0, |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Marks the event as fully handled, preventing the event service from invoking
|
||||
|
/// other event handlers registered in the dependency injection container.
|
||||
|
/// Using this value is recommended for event handlers that produce an
|
||||
|
/// immediate response (i.e that call context.HandleResponse(),
|
||||
|
/// context.Fail(), context.NoResult() or context.Success()).
|
||||
|
/// </summary>
|
||||
|
Handled = 1 |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,60 @@ |
|||||
|
/* |
||||
|
* 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; |
||||
|
using System.Threading.Tasks; |
||||
|
using Xunit; |
||||
|
|
||||
|
namespace OpenIddict.Server.Tests |
||||
|
{ |
||||
|
public class OpenIddictServerEventHandlerTests |
||||
|
{ |
||||
|
[Fact] |
||||
|
public void Constructor_ThrowsAnExceptionForNullHandler() |
||||
|
{ |
||||
|
// Arrange, act and assert
|
||||
|
var exception = Assert.Throws<ArgumentNullException>(() |
||||
|
=> new OpenIddictServerEventHandler<Event>(handler: null)); |
||||
|
|
||||
|
Assert.Equal("handler", exception.ParamName); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task HandleAsync_ThrowsAnExceptionForNullNotification() |
||||
|
{ |
||||
|
// Arrange
|
||||
|
var handler = new OpenIddictServerEventHandler<Event>( |
||||
|
notification => Task.FromResult(OpenIddictServerEventState.Handled)); |
||||
|
|
||||
|
// Act and assert
|
||||
|
var exception = await Assert.ThrowsAsync<ArgumentNullException>(() |
||||
|
=> handler.HandleAsync(notification: null)); |
||||
|
|
||||
|
Assert.Equal("notification", exception.ParamName); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task HandleAsync_InvokesInlineHandler() |
||||
|
{ |
||||
|
// Arrange
|
||||
|
var marker = false; |
||||
|
var handler = new OpenIddictServerEventHandler<Event>( |
||||
|
notification => |
||||
|
{ |
||||
|
marker = true; |
||||
|
return Task.FromResult(OpenIddictServerEventState.Handled); |
||||
|
}); |
||||
|
|
||||
|
// Act
|
||||
|
await handler.HandleAsync(new Event()); |
||||
|
|
||||
|
// Assert
|
||||
|
Assert.True(marker); |
||||
|
} |
||||
|
|
||||
|
public class Event : IOpenIddictServerEvent { } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,92 @@ |
|||||
|
/* |
||||
|
* 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; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Threading.Tasks; |
||||
|
using Moq; |
||||
|
using Xunit; |
||||
|
|
||||
|
namespace OpenIddict.Server.Tests |
||||
|
{ |
||||
|
public class OpenIddictServerEventServiceTests |
||||
|
{ |
||||
|
[Fact] |
||||
|
public async Task PublishAsync_ThrowsAnExceptionForNullNotification() |
||||
|
{ |
||||
|
// Arrange
|
||||
|
var provider = Mock.Of<IServiceProvider>(); |
||||
|
var service = new OpenIddictServerEventService(provider); |
||||
|
|
||||
|
// Act and assert
|
||||
|
var exception = await Assert.ThrowsAsync<ArgumentNullException>(() |
||||
|
=> service.PublishAsync<Event>(notification: null)); |
||||
|
|
||||
|
Assert.Equal("notification", exception.ParamName); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task PublishAsync_InvokesHandlers() |
||||
|
{ |
||||
|
// Arrange
|
||||
|
var handlers = new List<IOpenIddictServerEventHandler<Event>> |
||||
|
{ |
||||
|
Mock.Of<IOpenIddictServerEventHandler<Event>>(), |
||||
|
Mock.Of<IOpenIddictServerEventHandler<Event>>() |
||||
|
}; |
||||
|
|
||||
|
var provider = new Mock<IServiceProvider>(); |
||||
|
provider.Setup(mock => mock.GetService(typeof(IEnumerable<IOpenIddictServerEventHandler<Event>>))) |
||||
|
.Returns(handlers); |
||||
|
|
||||
|
var service = new OpenIddictServerEventService(provider.Object); |
||||
|
|
||||
|
var notification = new Event(); |
||||
|
|
||||
|
// Act
|
||||
|
await service.PublishAsync(notification); |
||||
|
|
||||
|
// Assert
|
||||
|
Mock.Get(handlers[0]).Verify(mock => mock.HandleAsync(notification), Times.Once()); |
||||
|
Mock.Get(handlers[1]).Verify(mock => mock.HandleAsync(notification), Times.Once()); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task PublishAsync_StopsInvokingHandlersWhenHandledIsReturned() |
||||
|
{ |
||||
|
// Arrange
|
||||
|
var handlers = new List<IOpenIddictServerEventHandler<Event>> |
||||
|
{ |
||||
|
Mock.Of<IOpenIddictServerEventHandler<Event>>( |
||||
|
mock => mock.HandleAsync(It.IsAny<Event>()) == Task.FromResult(OpenIddictServerEventState.Unhandled)), |
||||
|
Mock.Of<IOpenIddictServerEventHandler<Event>>( |
||||
|
mock => mock.HandleAsync(It.IsAny<Event>()) == Task.FromResult(OpenIddictServerEventState.Unhandled)), |
||||
|
Mock.Of<IOpenIddictServerEventHandler<Event>>( |
||||
|
mock => mock.HandleAsync(It.IsAny<Event>()) == Task.FromResult(OpenIddictServerEventState.Handled)), |
||||
|
Mock.Of<IOpenIddictServerEventHandler<Event>>() |
||||
|
}; |
||||
|
|
||||
|
var provider = new Mock<IServiceProvider>(); |
||||
|
provider.Setup(mock => mock.GetService(typeof(IEnumerable<IOpenIddictServerEventHandler<Event>>))) |
||||
|
.Returns(handlers); |
||||
|
|
||||
|
var service = new OpenIddictServerEventService(provider.Object); |
||||
|
|
||||
|
var notification = new Event(); |
||||
|
|
||||
|
// Act
|
||||
|
await service.PublishAsync(notification); |
||||
|
|
||||
|
// Assert
|
||||
|
Mock.Get(handlers[0]).Verify(mock => mock.HandleAsync(notification), Times.Once()); |
||||
|
Mock.Get(handlers[1]).Verify(mock => mock.HandleAsync(notification), Times.Once()); |
||||
|
Mock.Get(handlers[2]).Verify(mock => mock.HandleAsync(notification), Times.Once()); |
||||
|
Mock.Get(handlers[3]).Verify(mock => mock.HandleAsync(notification), Times.Never()); |
||||
|
} |
||||
|
|
||||
|
public class Event : IOpenIddictServerEvent { } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,60 @@ |
|||||
|
/* |
||||
|
* 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; |
||||
|
using System.Threading.Tasks; |
||||
|
using Xunit; |
||||
|
|
||||
|
namespace OpenIddict.Validation.Tests |
||||
|
{ |
||||
|
public class OpenIddictValidationEventHandlerTests |
||||
|
{ |
||||
|
[Fact] |
||||
|
public void Constructor_ThrowsAnExceptionForNullHandler() |
||||
|
{ |
||||
|
// Arrange, act and assert
|
||||
|
var exception = Assert.Throws<ArgumentNullException>(() |
||||
|
=> new OpenIddictValidationEventHandler<Event>(handler: null)); |
||||
|
|
||||
|
Assert.Equal("handler", exception.ParamName); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task HandleAsync_ThrowsAnExceptionForNullNotification() |
||||
|
{ |
||||
|
// Arrange
|
||||
|
var handler = new OpenIddictValidationEventHandler<Event>( |
||||
|
notification => Task.FromResult(OpenIddictValidationEventState.Handled)); |
||||
|
|
||||
|
// Act and assert
|
||||
|
var exception = await Assert.ThrowsAsync<ArgumentNullException>(() |
||||
|
=> handler.HandleAsync(notification: null)); |
||||
|
|
||||
|
Assert.Equal("notification", exception.ParamName); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task HandleAsync_InvokesInlineHandler() |
||||
|
{ |
||||
|
// Arrange
|
||||
|
var marker = false; |
||||
|
var handler = new OpenIddictValidationEventHandler<Event>( |
||||
|
notification => |
||||
|
{ |
||||
|
marker = true; |
||||
|
return Task.FromResult(OpenIddictValidationEventState.Handled); |
||||
|
}); |
||||
|
|
||||
|
// Act
|
||||
|
await handler.HandleAsync(new Event()); |
||||
|
|
||||
|
// Assert
|
||||
|
Assert.True(marker); |
||||
|
} |
||||
|
|
||||
|
public class Event : IOpenIddictValidationEvent { } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,92 @@ |
|||||
|
/* |
||||
|
* 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; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Threading.Tasks; |
||||
|
using Moq; |
||||
|
using Xunit; |
||||
|
|
||||
|
namespace OpenIddict.Validation.Tests |
||||
|
{ |
||||
|
public class OpenIddictValidationEventServiceTests |
||||
|
{ |
||||
|
[Fact] |
||||
|
public async Task PublishAsync_ThrowsAnExceptionForNullNotification() |
||||
|
{ |
||||
|
// Arrange
|
||||
|
var provider = Mock.Of<IServiceProvider>(); |
||||
|
var service = new OpenIddictValidationEventService(provider); |
||||
|
|
||||
|
// Act and assert
|
||||
|
var exception = await Assert.ThrowsAsync<ArgumentNullException>(() |
||||
|
=> service.PublishAsync<Event>(notification: null)); |
||||
|
|
||||
|
Assert.Equal("notification", exception.ParamName); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task PublishAsync_InvokesHandlers() |
||||
|
{ |
||||
|
// Arrange
|
||||
|
var handlers = new List<IOpenIddictValidationEventHandler<Event>> |
||||
|
{ |
||||
|
Mock.Of<IOpenIddictValidationEventHandler<Event>>(), |
||||
|
Mock.Of<IOpenIddictValidationEventHandler<Event>>() |
||||
|
}; |
||||
|
|
||||
|
var provider = new Mock<IServiceProvider>(); |
||||
|
provider.Setup(mock => mock.GetService(typeof(IEnumerable<IOpenIddictValidationEventHandler<Event>>))) |
||||
|
.Returns(handlers); |
||||
|
|
||||
|
var service = new OpenIddictValidationEventService(provider.Object); |
||||
|
|
||||
|
var notification = new Event(); |
||||
|
|
||||
|
// Act
|
||||
|
await service.PublishAsync(notification); |
||||
|
|
||||
|
// Assert
|
||||
|
Mock.Get(handlers[0]).Verify(mock => mock.HandleAsync(notification), Times.Once()); |
||||
|
Mock.Get(handlers[1]).Verify(mock => mock.HandleAsync(notification), Times.Once()); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task PublishAsync_StopsInvokingHandlersWhenHandledIsReturned() |
||||
|
{ |
||||
|
// Arrange
|
||||
|
var handlers = new List<IOpenIddictValidationEventHandler<Event>> |
||||
|
{ |
||||
|
Mock.Of<IOpenIddictValidationEventHandler<Event>>( |
||||
|
mock => mock.HandleAsync(It.IsAny<Event>()) == Task.FromResult(OpenIddictValidationEventState.Unhandled)), |
||||
|
Mock.Of<IOpenIddictValidationEventHandler<Event>>( |
||||
|
mock => mock.HandleAsync(It.IsAny<Event>()) == Task.FromResult(OpenIddictValidationEventState.Unhandled)), |
||||
|
Mock.Of<IOpenIddictValidationEventHandler<Event>>( |
||||
|
mock => mock.HandleAsync(It.IsAny<Event>()) == Task.FromResult(OpenIddictValidationEventState.Handled)), |
||||
|
Mock.Of<IOpenIddictValidationEventHandler<Event>>() |
||||
|
}; |
||||
|
|
||||
|
var provider = new Mock<IServiceProvider>(); |
||||
|
provider.Setup(mock => mock.GetService(typeof(IEnumerable<IOpenIddictValidationEventHandler<Event>>))) |
||||
|
.Returns(handlers); |
||||
|
|
||||
|
var service = new OpenIddictValidationEventService(provider.Object); |
||||
|
|
||||
|
var notification = new Event(); |
||||
|
|
||||
|
// Act
|
||||
|
await service.PublishAsync(notification); |
||||
|
|
||||
|
// Assert
|
||||
|
Mock.Get(handlers[0]).Verify(mock => mock.HandleAsync(notification), Times.Once()); |
||||
|
Mock.Get(handlers[1]).Verify(mock => mock.HandleAsync(notification), Times.Once()); |
||||
|
Mock.Get(handlers[2]).Verify(mock => mock.HandleAsync(notification), Times.Once()); |
||||
|
Mock.Get(handlers[3]).Verify(mock => mock.HandleAsync(notification), Times.Never()); |
||||
|
} |
||||
|
|
||||
|
public class Event : IOpenIddictValidationEvent { } |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue