benchmarks/WebJobs.Script.Benchmarks/AuthUtilityBenchmarks.cs (95 lines of code) (raw):
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
using BenchmarkDotNet.Attributes;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.Azure.WebJobs.Script.WebHost.Security.Authentication;
using Microsoft.Azure.WebJobs.Script.WebHost.Security.Authorization;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
namespace Microsoft.Azure.WebJobs.Script.Benchmarks
{
public class AuthUtilityBenchmarks
{
private ClaimsPrincipal Principal;
private static List<Claim> TotallyRandomClaims { get; } = new List<Claim>()
{
new Claim(SecurityConstants.AuthLevelKeyNameClaimType, "test1"),
new Claim(SecurityConstants.AuthLevelKeyNameClaimType, "test2"),
new Claim(SecurityConstants.AuthLevelKeyNameClaimType, "test3"),
new Claim(SecurityConstants.AuthLevelClaimType, nameof(AuthorizationLevel.Function)),
new Claim(SecurityConstants.AuthLevelClaimType, nameof(AuthorizationLevel.Anonymous)),
new Claim(SecurityConstants.AuthLevelClaimType, nameof(AuthorizationLevel.User)),
new Claim(SecurityConstants.AuthLevelClaimType, nameof(AuthorizationLevel.Admin)),
new Claim(SecurityConstants.AuthLevelClaimType, nameof(AuthorizationLevel.System)),
};
[Params(null, "code")]
public string KeyName;
[Params(0, 4, 8)]
public int ClaimsCount;
[GlobalSetup]
public void Setup()
{
var identity = new ClaimsIdentity(TotallyRandomClaims.Take(ClaimsCount));
Principal = new ClaimsPrincipal(identity);
}
[Benchmark(Baseline = true)]
public bool PrincipalHasAuthLevelClaim() =>
AuthUtility.PrincipalHasAuthLevelClaim(Principal, AuthorizationLevel.Function);
[Benchmark]
public bool PrincipalHasAuthLevelClaimNoArray() =>
PrincipalHasAuthLevelClaimNoArray(Principal, AuthorizationLevel.Function);
[Benchmark]
public bool PrincipalHasAuthLevelClaimHasClaim() =>
PrincipalHasAuthLevelClaimHasClaim(Principal, AuthorizationLevel.Function);
public static bool PrincipalHasAuthLevelClaimNoArray(ClaimsPrincipal principal, AuthorizationLevel requiredLevel, string keyName = null)
{
// If the required auth level is anonymous, the requirement is met
if (requiredLevel == AuthorizationLevel.Anonymous)
{
return true;
}
// Still allocating a enumerate from Identities -> Claims
foreach (var claim in principal.Claims)
{
if (claim.Type == SecurityConstants.AuthLevelClaimType)
{
var level = claim.Value switch
{
nameof(AuthorizationLevel.Admin) => AuthorizationLevel.Admin,
nameof(AuthorizationLevel.Function) => AuthorizationLevel.Function,
nameof(AuthorizationLevel.System) => AuthorizationLevel.System,
nameof(AuthorizationLevel.User) => AuthorizationLevel.User,
_ => AuthorizationLevel.Anonymous
};
if (level == AuthorizationLevel.Admin)
{
// If we have a claim with Admin level, regardless of whether a name is required, return true.
return true;
}
if (level == requiredLevel && (keyName == null || string.Equals(principal.FindFirstValue(SecurityConstants.AuthLevelKeyNameClaimType), keyName, StringComparison.OrdinalIgnoreCase)))
{
return true;
}
}
}
return false;
}
public static bool PrincipalHasAuthLevelClaimHasClaim(ClaimsPrincipal principal, AuthorizationLevel requiredLevel, string keyName = null)
{
// If the required auth level is anonymous, the requirement is met
if (requiredLevel == AuthorizationLevel.Anonymous)
{
return true;
}
var levelString = requiredLevel switch
{
AuthorizationLevel.Admin => nameof(AuthorizationLevel.Admin),
AuthorizationLevel.Function => nameof(AuthorizationLevel.Function),
AuthorizationLevel.System => nameof(AuthorizationLevel.System),
AuthorizationLevel.User => nameof(AuthorizationLevel.User),
_ => throw new ArgumentOutOfRangeException(nameof(requiredLevel))
};
return principal.HasClaim(c => c.Type == SecurityConstants.AuthLevelClaimType
&& (c.Value == nameof(AuthorizationLevel.Admin)
|| (c.Value == levelString && (keyName == null || string.Equals(principal.FindFirstValue(SecurityConstants.AuthLevelKeyNameClaimType), keyName, StringComparison.OrdinalIgnoreCase)))
));
}
}
}