Versatile OpenID Connect stack for ASP.NET Core and Microsoft.Owin (compatible with ASP.NET 4.6.1)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

136 lines
5.8 KiB

/*
* 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.Text;
using System.Threading.Tasks;
using JetBrains.Annotations;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using static OpenIddict.Server.OpenIddictServerEvents;
namespace OpenIddict.Server
{
public class OpenIddictServerProvider : IOpenIddictServerProvider
{
private readonly ILogger<OpenIddictServerProvider> _logger;
private readonly IOptionsMonitor<OpenIddictServerOptions> _options;
private readonly IServiceProvider _provider;
/// <summary>
/// Creates a new instance of the <see cref="OpenIddictServerProvider"/> class.
/// </summary>
public OpenIddictServerProvider(
[NotNull] ILogger<OpenIddictServerProvider> logger,
[NotNull] IOptionsMonitor<OpenIddictServerOptions> options,
[NotNull] IServiceProvider provider)
{
_logger = logger;
_options = options;
_provider = provider;
}
public ValueTask<OpenIddictServerTransaction> CreateTransactionAsync()
=> new ValueTask<OpenIddictServerTransaction>(new OpenIddictServerTransaction
{
Issuer = _options.CurrentValue.Issuer,
Logger = _logger,
Options = _options.CurrentValue
});
public async ValueTask DispatchAsync<TContext>([NotNull] TContext context) where TContext : BaseContext
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
await foreach (var handler in GetHandlersAsync())
{
await handler.HandleAsync(context);
switch (context)
{
case BaseRequestContext notification when notification.IsRequestHandled:
_logger.LogDebug("The request was handled in user code.");
return;
case BaseRequestContext notification when notification.IsRequestSkipped:
_logger.LogDebug("The default request handling was skipped from user code.");
return;
case BaseValidatingContext notification when notification.IsRejected:
_logger.LogDebug("The request was rejected in user code.");
return;
case BaseValidatingTicketContext notification when notification.IsHandled:
_logger.LogDebug("Authentication was handled in user code.");
return;
default: continue;
}
}
async IAsyncEnumerable<IOpenIddictServerHandler<TContext>> GetHandlersAsync()
{
var descriptors = new List<OpenIddictServerHandlerDescriptor>(
capacity: _options.CurrentValue.CustomHandlers.Count +
_options.CurrentValue.DefaultHandlers.Count);
descriptors.AddRange(_options.CurrentValue.CustomHandlers);
descriptors.AddRange(_options.CurrentValue.DefaultHandlers);
descriptors.Sort((left, right) => left.Order.CompareTo(right.Order));
for (var index = 0; index < descriptors.Count; index++)
{
var descriptor = descriptors[index];
if (descriptor.ContextType != typeof(TContext) || !await IsActiveAsync(descriptor))
{
continue;
}
var handler = descriptor.ServiceDescriptor.ImplementationInstance != null ?
descriptor.ServiceDescriptor.ImplementationInstance as IOpenIddictServerHandler<TContext> :
_provider.GetService(descriptor.ServiceDescriptor.ServiceType) as IOpenIddictServerHandler<TContext>;
if (handler == null)
{
throw new InvalidOperationException(new StringBuilder()
.AppendLine($"The event handler of type '{descriptor.ServiceDescriptor.ServiceType}' couldn't be resolved.")
.AppendLine("This may indicate that it was not properly registered in the dependency injection container.")
.Append("To register an event handler, use 'services.AddOpenIddict().AddServer().AddEventHandler()'.")
.ToString());
}
yield return handler;
}
}
async ValueTask<bool> IsActiveAsync(OpenIddictServerHandlerDescriptor descriptor)
{
for (var index = 0; index < descriptor.FilterTypes.Length; index++)
{
if (!(_provider.GetService(descriptor.FilterTypes[index]) is IOpenIddictServerHandlerFilter<TContext> filter))
{
throw new InvalidOperationException(new StringBuilder()
.AppendLine($"The event handler filter of type '{descriptor.FilterTypes[index]}' couldn't be resolved.")
.AppendLine("This may indicate that it was not properly registered in the dependency injection container.")
.ToString());
}
if (!await filter.IsActiveAsync(context))
{
return false;
}
}
return true;
}
}
}
}