// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Microsoft.AspNetCore.Authorization
{
///
/// Represents a collection of authorization requirements and the scheme or
/// schemes they are evaluated against, all of which must succeed
/// for authorization to succeed.
///
public class AuthorizationPolicy
{
///
/// Creates a new instance of .
///
///
/// The list of s which must succeed for
/// this policy to be successful.
///
///
/// The authentication schemes the are evaluated against.
///
public AuthorizationPolicy(IEnumerable requirements, IEnumerable authenticationSchemes)
{
if (requirements == null)
{
throw new ArgumentNullException(nameof(requirements));
}
if (authenticationSchemes == null)
{
throw new ArgumentNullException(nameof(authenticationSchemes));
}
if (requirements.Count() == 0)
{
throw new InvalidOperationException(Resources.Exception_AuthorizationPolicyEmpty);
}
Requirements = new List(requirements).AsReadOnly();
AuthenticationSchemes = new List(authenticationSchemes).AsReadOnly();
}
///
/// Gets a readonly list of s which must succeed for
/// this policy to be successful.
///
public IReadOnlyList Requirements { get; }
///
/// Gets a readonly list of the authentication schemes the
/// are evaluated against.
///
public IReadOnlyList AuthenticationSchemes { get; }
///
/// Combines the specified into a single policy.
///
/// The authorization policies to combine.
///
/// A new which represents the combination of the
/// specified .
///
public static AuthorizationPolicy Combine(params AuthorizationPolicy[] policies)
{
if (policies == null)
{
throw new ArgumentNullException(nameof(policies));
}
return Combine((IEnumerable)policies);
}
///
/// Combines the specified into a single policy.
///
/// The authorization policies to combine.
///
/// A new which represents the combination of the
/// specified .
///
public static AuthorizationPolicy Combine(IEnumerable policies)
{
if (policies == null)
{
throw new ArgumentNullException(nameof(policies));
}
var builder = new AuthorizationPolicyBuilder();
foreach (var policy in policies)
{
builder.Combine(policy);
}
return builder.Build();
}
///
/// Combines the provided by the specified
/// .
///
/// A which provides the policies to combine.
/// A collection of authorization data used to apply authorization to a resource.
///
/// A new which represents the combination of the
/// authorization policies provided by the specified .
///
public static async Task CombineAsync(IAuthorizationPolicyProvider policyProvider, IEnumerable authorizeData)
{
if (policyProvider == null)
{
throw new ArgumentNullException(nameof(policyProvider));
}
if (authorizeData == null)
{
throw new ArgumentNullException(nameof(authorizeData));
}
var policyBuilder = new AuthorizationPolicyBuilder();
var any = false;
foreach (var authorizeDatum in authorizeData)
{
any = true;
var useDefaultPolicy = true;
if (!string.IsNullOrWhiteSpace(authorizeDatum.Policy))
{
var policy = await policyProvider.GetPolicyAsync(authorizeDatum.Policy);
if (policy == null)
{
throw new InvalidOperationException(Resources.FormatException_AuthorizationPolicyNotFound(authorizeDatum.Policy));
}
policyBuilder.Combine(policy);
useDefaultPolicy = false;
}
var rolesSplit = authorizeDatum.Roles?.Split(',');
if (rolesSplit != null && rolesSplit.Any())
{
var trimmedRolesSplit = rolesSplit.Where(r => !string.IsNullOrWhiteSpace(r)).Select(r => r.Trim());
policyBuilder.RequireRole(trimmedRolesSplit);
useDefaultPolicy = false;
}
var authTypesSplit = authorizeDatum.AuthenticationSchemes?.Split(',');
if (authTypesSplit != null && authTypesSplit.Any())
{
foreach (var authType in authTypesSplit)
{
if (!string.IsNullOrWhiteSpace(authType))
{
policyBuilder.AuthenticationSchemes.Add(authType.Trim());
}
}
}
if (useDefaultPolicy)
{
policyBuilder.Combine(await policyProvider.GetDefaultPolicyAsync());
}
}
return any ? policyBuilder.Build() : null;
}
}
}