43 changed files with 788 additions and 452 deletions
@ -0,0 +1,10 @@ |
|||
<Project Sdk="Microsoft.NET.Sdk"> |
|||
|
|||
<Import Project="..\..\build\common.props" /> |
|||
|
|||
<PropertyGroup> |
|||
<TargetFramework>netstandard2.0</TargetFramework> |
|||
<IsPackable>false</IsPackable> |
|||
</PropertyGroup> |
|||
|
|||
</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,163 +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.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.Result != null: 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.Result != null: return; |
|||
case ExtractConfigurationRequest value when value.Context.Result != null: return; |
|||
case ExtractCryptographyRequest value when value.Context.Result != null: return; |
|||
case ExtractIntrospectionRequest value when value.Context.Result != null: return; |
|||
case ExtractLogoutRequest value when value.Context.Result != null: return; |
|||
case ExtractRevocationRequest value when value.Context.Result != null: return; |
|||
case ExtractTokenRequest value when value.Context.Result != null: return; |
|||
case ExtractUserinfoRequest value when value.Context.Result != null: return; |
|||
|
|||
case ValidateAuthorizationRequest value when value.Context.Result != null: return; |
|||
case ValidateConfigurationRequest value when value.Context.Result != null: return; |
|||
case ValidateCryptographyRequest value when value.Context.Result != null: return; |
|||
case ValidateIntrospectionRequest value when value.Context.Result != null: return; |
|||
case ValidateLogoutRequest value when value.Context.Result != null: return; |
|||
case ValidateRevocationRequest value when value.Context.Result != null: return; |
|||
case ValidateTokenRequest value when value.Context.Result != null: return; |
|||
case ValidateUserinfoRequest value when value.Context.Result != null: 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.Result != null: return; |
|||
case HandleConfigurationRequest value when value.Context.Result != null: return; |
|||
case HandleCryptographyRequest value when value.Context.Result != null: return; |
|||
case HandleIntrospectionRequest value when value.Context.Result != null: return; |
|||
case HandleLogoutRequest value when value.Context.Result != null: return; |
|||
case HandleRevocationRequest value when value.Context.Result != null: return; |
|||
case HandleTokenRequest value when value.Context.Result != null: return; |
|||
case HandleUserinfoRequest value when value.Context.Result != null: 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.Result != null: return; |
|||
case ProcessSigninResponse value when value.Context.Result != null: return; |
|||
case ProcessSignoutResponse value when value.Context.Result != null: 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.Result != null: return; |
|||
case ApplyConfigurationResponse value when value.Context.Result != null: return; |
|||
case ApplyCryptographyResponse value when value.Context.Result != null: return; |
|||
case ApplyIntrospectionResponse value when value.Context.Result != null: return; |
|||
case ApplyLogoutResponse value when value.Context.Result != null: return; |
|||
case ApplyRevocationResponse value when value.Context.Result != null: return; |
|||
case ApplyTokenResponse value when value.Context.Result != null: return; |
|||
case ApplyUserinfoResponse value when value.Context.Result != null: return; |
|||
|
|||
case DeserializeAuthorizationCode value when value.Context.IsHandled: return; |
|||
case DeserializeAccessToken value when value.Context.IsHandled: return; |
|||
case DeserializeIdentityToken value when value.Context.IsHandled: return; |
|||
case DeserializeRefreshToken value when value.Context.IsHandled: 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.IsHandled: return; |
|||
case SerializeAccessToken value when value.Context.IsHandled: return; |
|||
case SerializeIdentityToken value when value.Context.IsHandled: return; |
|||
case SerializeRefreshToken value when value.Context.IsHandled: 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.SkipHandler(), 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.HandleResponse(),
|
|||
/// context.SkipHandler(), 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,76 +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.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.Handled: return; |
|||
|
|||
case OpenIddictValidationEvents.CreateTicket value when value.Context.Result != null: return; |
|||
case OpenIddictValidationEvents.CreateTicket value when value.Context.Principal == null: return; |
|||
|
|||
case OpenIddictValidationEvents.DecryptToken value when value.Context.Result != null: return; |
|||
case OpenIddictValidationEvents.DecryptToken value when value.Context.Principal != null: return; |
|||
|
|||
case OpenIddictValidationEvents.RetrieveToken value when value.Context.Result != null: return; |
|||
case OpenIddictValidationEvents.RetrieveToken value when value.Context.Principal != null: return; |
|||
|
|||
case OpenIddictValidationEvents.ValidateToken value when value.Context.Result != null: return; |
|||
case OpenIddictValidationEvents.ValidateToken value when value.Context.Principal == 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