// Copyright Epic Games, Inc. All Rights Reserved.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Authorization.Infrastructure;
namespace Jupiter
{
///
/// An implementation of that combines multiple
/// requirements such that if any of those inner requirements are met, this requirement is met.
/// This only supports requirements that handle themselves, i.e. implement both
/// and the corresponding .
///
public class AnyRequirement : AuthorizationHandler, IAuthorizationRequirement
{
public AnyRequirement(params IAuthorizationRequirement[] innerRequirements)
{
InnerRequirements = innerRequirements ?? throw new ArgumentNullException(nameof(innerRequirements));
}
public IEnumerable InnerRequirements { get; }
protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, AnyRequirement requirement)
{
foreach (IAuthorizationRequirement innerRequirement in requirement.InnerRequirements)
{
// This only supports requirements that "handle themselves".
IAuthorizationHandler? handler = innerRequirement as IAuthorizationHandler;
if (handler != null)
{
AuthorizationHandlerContext innerContext = new AuthorizationHandlerContext(new[] { innerRequirement }, context.User, context.Resource);
await handler.HandleAsync(innerContext);
if (innerContext.HasSucceeded)
{
context.Succeed(this);
break;
}
}
}
}
public override string ToString()
{
string components = string.Join(',', InnerRequirements.Select(r => r.ToString()));
return $"Any({components})";
}
}
///
/// A helper class to build an instance of .
///
public class AnyRequirementBuilder
{
private readonly List _innerRequirements = new List();
private readonly AuthorizationPolicyBuilder _policyBuilder;
public AnyRequirementBuilder(AuthorizationPolicyBuilder policyBuilder)
{
_policyBuilder = policyBuilder;
}
public AnyRequirementBuilder AddRequirement(IAuthorizationRequirement requirement)
{
_innerRequirements.Add(requirement);
return this;
}
public AuthorizationPolicyBuilder AddAny()
{
AnyRequirement anyRequirement = new AnyRequirement(_innerRequirements.ToArray());
return _policyBuilder.AddRequirements(anyRequirement);
}
}
///
/// Helpful extensions related to
///
public static class AnyRequirementExtensions
{
///
/// Starts a building context to add requirements that will be combined as an
/// and added to the policy builder when is called later.
///
///
///
public static AnyRequirementBuilder BeginAnyContext(this AuthorizationPolicyBuilder policyBuilder)
{
return new AnyRequirementBuilder(policyBuilder);
}
public static AnyRequirementBuilder IncludeClaim(this AnyRequirementBuilder builder, string claimType, params string[] allowedValues)
{
return builder.AddRequirement(new ClaimsAuthorizationRequirement(claimType, allowedValues));
}
public static AnyRequirementBuilder IncludeClaim(this AnyRequirementBuilder builder, string claimType)
{
return builder.AddRequirement(new ClaimsAuthorizationRequirement(claimType, allowedValues: null));
}
public static AnyRequirementBuilder IncludeRole(this AnyRequirementBuilder builder, params string[] roles)
{
return builder.AddRequirement(new RolesAuthorizationRequirement(roles));
}
}
}