Fix merge and consolidate ClaimsIdentityExtensions into one file.
This commit is contained in:
@@ -2,8 +2,11 @@
|
||||
// See LICENSE for more details.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Security.Claims;
|
||||
using System.Security.Principal;
|
||||
using Umbraco.Cms.Core;
|
||||
|
||||
namespace Umbraco.Extensions
|
||||
{
|
||||
@@ -72,5 +75,203 @@ namespace Umbraco.Extensions
|
||||
|
||||
return identity.FindFirst(claimType)?.Value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the required claim types for a back office identity
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This does not include the role claim type or allowed apps type since that is a collection and in theory could be empty
|
||||
/// </remarks>
|
||||
public static IEnumerable<string> RequiredBackOfficeClaimTypes => new[]
|
||||
{
|
||||
ClaimTypes.NameIdentifier, //id
|
||||
ClaimTypes.Name, //username
|
||||
ClaimTypes.GivenName,
|
||||
// Constants.Security.StartContentNodeIdClaimType, These seem to be able to be null...
|
||||
// Constants.Security.StartMediaNodeIdClaimType,
|
||||
ClaimTypes.Locality,
|
||||
Constants.Security.SecurityStampClaimType
|
||||
};
|
||||
|
||||
public const string Issuer = Constants.Security.BackOfficeAuthenticationType;
|
||||
|
||||
/// <summary>
|
||||
/// Verify that a ClaimsIdentity has all the required claim types
|
||||
/// </summary>
|
||||
/// <param name="identity"></param>
|
||||
/// <param name="verifiedIdentity">Verified identity wrapped in a ClaimsIdentity with BackOfficeAuthentication type</param>
|
||||
/// <returns>True if ClaimsIdentity</returns>
|
||||
public static bool VerifyBackOfficeIdentity(this ClaimsIdentity identity, out ClaimsIdentity verifiedIdentity)
|
||||
{
|
||||
// Validate that all required claims exist
|
||||
foreach (var claimType in RequiredBackOfficeClaimTypes)
|
||||
{
|
||||
if (identity.HasClaim(x => x.Type == claimType) == false ||
|
||||
identity.HasClaim(x => x.Type == claimType && x.Value.IsNullOrWhiteSpace()))
|
||||
{
|
||||
verifiedIdentity = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
verifiedIdentity = new ClaimsIdentity(identity.Claims, Constants.Security.BackOfficeAuthenticationType);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add the required claims to be a BackOffice ClaimsIdentity
|
||||
/// </summary>
|
||||
/// <param name="identity">this</param>
|
||||
/// <param name="userId">The users Id</param>
|
||||
/// <param name="username">Username</param>
|
||||
/// <param name="realName">Real name</param>
|
||||
/// <param name="startContentNodes">Start content nodes</param>
|
||||
/// <param name="startMediaNodes">Start media nodes</param>
|
||||
/// <param name="culture">The locality of the user</param>
|
||||
/// <param name="securityStamp">Security stamp</param>
|
||||
/// <param name="allowedApps">Allowed apps</param>
|
||||
/// <param name="roles">Roles</param>
|
||||
public static void AddRequiredClaims(this ClaimsIdentity identity, string userId, string username,
|
||||
string realName, IEnumerable<int> startContentNodes, IEnumerable<int> startMediaNodes, string culture,
|
||||
string securityStamp, IEnumerable<string> allowedApps, IEnumerable<string> roles)
|
||||
{
|
||||
//This is the id that 'identity' uses to check for the user id
|
||||
if (identity.HasClaim(x => x.Type == ClaimTypes.NameIdentifier) == false)
|
||||
{
|
||||
identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, userId, ClaimValueTypes.String,
|
||||
Issuer, Issuer, identity));
|
||||
}
|
||||
|
||||
if (identity.HasClaim(x => x.Type == ClaimTypes.Name) == false)
|
||||
{
|
||||
identity.AddClaim(new Claim(ClaimTypes.Name, username, ClaimValueTypes.String, Issuer, Issuer, identity));
|
||||
}
|
||||
|
||||
if (identity.HasClaim(x => x.Type == ClaimTypes.GivenName) == false)
|
||||
{
|
||||
identity.AddClaim(new Claim(ClaimTypes.GivenName, realName, ClaimValueTypes.String, Issuer, Issuer, identity));
|
||||
}
|
||||
|
||||
if (identity.HasClaim(x => x.Type == Constants.Security.StartContentNodeIdClaimType) == false &&
|
||||
startContentNodes != null)
|
||||
{
|
||||
foreach (var startContentNode in startContentNodes)
|
||||
{
|
||||
identity.AddClaim(new Claim(Constants.Security.StartContentNodeIdClaimType, startContentNode.ToInvariantString(), ClaimValueTypes.Integer32, Issuer, Issuer, identity));
|
||||
}
|
||||
}
|
||||
|
||||
if (identity.HasClaim(x => x.Type == Constants.Security.StartMediaNodeIdClaimType) == false &&
|
||||
startMediaNodes != null)
|
||||
{
|
||||
foreach (var startMediaNode in startMediaNodes)
|
||||
{
|
||||
identity.AddClaim(new Claim(Constants.Security.StartMediaNodeIdClaimType, startMediaNode.ToInvariantString(), ClaimValueTypes.Integer32, Issuer, Issuer, identity));
|
||||
}
|
||||
}
|
||||
|
||||
if (identity.HasClaim(x => x.Type == ClaimTypes.Locality) == false)
|
||||
{
|
||||
identity.AddClaim(new Claim(ClaimTypes.Locality, culture, ClaimValueTypes.String, Issuer, Issuer, identity));
|
||||
}
|
||||
|
||||
// The security stamp claim is also required
|
||||
if (identity.HasClaim(x => x.Type == Constants.Security.SecurityStampClaimType) == false)
|
||||
{
|
||||
identity.AddClaim(new Claim(Constants.Security.SecurityStampClaimType, securityStamp, ClaimValueTypes.String, Issuer, Issuer, identity));
|
||||
}
|
||||
|
||||
// Add each app as a separate claim
|
||||
if (identity.HasClaim(x => x.Type == Constants.Security.AllowedApplicationsClaimType) == false &&
|
||||
allowedApps != null)
|
||||
{
|
||||
foreach (var application in allowedApps)
|
||||
{
|
||||
identity.AddClaim(new Claim(Constants.Security.AllowedApplicationsClaimType, application, ClaimValueTypes.String, Issuer, Issuer, identity));
|
||||
}
|
||||
}
|
||||
|
||||
// Claims are added by the ClaimsIdentityFactory because our UserStore supports roles, however this identity might
|
||||
// not be made with that factory if it was created with a different ticket so perform the check
|
||||
if (identity.HasClaim(x => x.Type == ClaimsIdentity.DefaultRoleClaimType) == false && roles != null)
|
||||
{
|
||||
// Manually add them
|
||||
foreach (var roleName in roles)
|
||||
{
|
||||
identity.AddClaim(new Claim(identity.RoleClaimType, roleName, ClaimValueTypes.String, Issuer, Issuer, identity));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the start content nodes from a ClaimsIdentity
|
||||
/// </summary>
|
||||
/// <param name="identity"></param>
|
||||
/// <returns>Array of start content nodes</returns>
|
||||
public static int[] GetStartContentNodes(this ClaimsIdentity identity) =>
|
||||
identity.FindAll(x => x.Type == Constants.Security.StartContentNodeIdClaimType)
|
||||
.Select(node => int.TryParse(node.Value, out var i) ? i : default)
|
||||
.Where(x => x != default).ToArray();
|
||||
|
||||
/// <summary>
|
||||
/// Get the start media nodes from a ClaimsIdentity
|
||||
/// </summary>
|
||||
/// <param name="identity"></param>
|
||||
/// <returns>Array of start media nodes</returns>
|
||||
public static int[] GetStartMediaNodes(this ClaimsIdentity identity) =>
|
||||
identity.FindAll(x => x.Type == Constants.Security.StartMediaNodeIdClaimType)
|
||||
.Select(node => int.TryParse(node.Value, out var i) ? i : default)
|
||||
.Where(x => x != default).ToArray();
|
||||
|
||||
/// <summary>
|
||||
/// Get the allowed applications from a ClaimsIdentity
|
||||
/// </summary>
|
||||
/// <param name="identity"></param>
|
||||
/// <returns></returns>
|
||||
public static string[] GetAllowedApplications(this ClaimsIdentity identity) => identity
|
||||
.FindAll(x => x.Type == Constants.Security.AllowedApplicationsClaimType).Select(app => app.Value).ToArray();
|
||||
|
||||
/// <summary>
|
||||
/// Get the user ID from a ClaimsIdentity
|
||||
/// </summary>
|
||||
/// <param name="identity"></param>
|
||||
/// <returns>User ID as integer</returns>
|
||||
public static int GetId(this ClaimsIdentity identity) => int.Parse(identity.FindFirstValue(ClaimTypes.NameIdentifier));
|
||||
|
||||
/// <summary>
|
||||
/// Get the real name belonging to the user from a ClaimsIdentity
|
||||
/// </summary>
|
||||
/// <param name="identity"></param>
|
||||
/// <returns>Real name of the user</returns>
|
||||
public static string GetRealName(this ClaimsIdentity identity) => identity.FindFirstValue(ClaimTypes.GivenName);
|
||||
|
||||
/// <summary>
|
||||
/// Get the username of the user from a ClaimsIdentity
|
||||
/// </summary>
|
||||
/// <param name="identity"></param>
|
||||
/// <returns>Username of the user</returns>
|
||||
public static string GetUsername(this ClaimsIdentity identity) => identity.FindFirstValue(ClaimTypes.Name);
|
||||
|
||||
/// <summary>
|
||||
/// Get the culture string from a ClaimsIdentity
|
||||
/// </summary>
|
||||
/// <param name="identity"></param>
|
||||
/// <returns>Culture string</returns>
|
||||
public static string GetCultureString(this ClaimsIdentity identity) => identity.FindFirstValue(ClaimTypes.Locality);
|
||||
|
||||
/// <summary>
|
||||
/// Get the security stamp from a ClaimsIdentity
|
||||
/// </summary>
|
||||
/// <param name="identity"></param>
|
||||
/// <returns>Security stamp</returns>
|
||||
public static string GetSecurityStamp(this ClaimsIdentity identity) => identity.FindFirstValue(Constants.Security.SecurityStampClaimType);
|
||||
|
||||
/// <summary>
|
||||
/// Get the roles assigned to a user from a ClaimsIdentity
|
||||
/// </summary>
|
||||
/// <param name="identity"></param>
|
||||
/// <returns>Array of roles</returns>
|
||||
public static string[] GetRoles(this ClaimsIdentity identity) => identity
|
||||
.FindAll(x => x.Type == ClaimsIdentity.DefaultRoleClaimType).Select(role => role.Value).ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,153 +0,0 @@
|
||||
// Copyright (c) Umbraco.
|
||||
// See LICENSE for more details.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Security.Claims;
|
||||
using Umbraco.Core;
|
||||
|
||||
namespace Umbraco.Extensions
|
||||
{
|
||||
public static class ClaimsIdentityExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns the required claim types for a back office identity
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This does not include the role claim type or allowed apps type since that is a collection and in theory could be empty
|
||||
/// </remarks>
|
||||
public static IEnumerable<string> RequiredBackOfficeClaimTypes => new[]
|
||||
{
|
||||
ClaimTypes.NameIdentifier, //id
|
||||
ClaimTypes.Name, //username
|
||||
ClaimTypes.GivenName,
|
||||
// Constants.Security.StartContentNodeIdClaimType, These seem to be able to be null...
|
||||
// Constants.Security.StartMediaNodeIdClaimType,
|
||||
ClaimTypes.Locality,
|
||||
Constants.Security.SecurityStampClaimType
|
||||
};
|
||||
|
||||
public const string Issuer = Constants.Security.BackOfficeAuthenticationType;
|
||||
|
||||
/// <summary>
|
||||
/// Verify that a ClaimsIdentity has all the required claim types
|
||||
/// </summary>
|
||||
/// <param name="identity"></param>
|
||||
/// <param name="verifiedIdentity">Verified identity wrapped in a ClaimsIdentity with BackOfficeAuthentication type</param>
|
||||
/// <returns>True if ClaimsIdentity</returns>
|
||||
public static bool VerifyBackOfficeIdentity(this ClaimsIdentity identity, out ClaimsIdentity verifiedIdentity)
|
||||
{
|
||||
// Validate that all required claims exist
|
||||
foreach (var claimType in RequiredBackOfficeClaimTypes)
|
||||
{
|
||||
if (identity.HasClaim(x => x.Type == claimType) == false ||
|
||||
identity.HasClaim(x => x.Type == claimType && x.Value.IsNullOrWhiteSpace()))
|
||||
{
|
||||
verifiedIdentity = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
verifiedIdentity = new ClaimsIdentity(identity.Claims, Constants.Security.BackOfficeAuthenticationType);
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void AddRequiredClaims(this ClaimsIdentity identity, string userId, string username,
|
||||
string realName, IEnumerable<int> startContentNodes, IEnumerable<int> startMediaNodes, string culture,
|
||||
string securityStamp, IEnumerable<string> allowedApps, IEnumerable<string> roles)
|
||||
{
|
||||
//This is the id that 'identity' uses to check for the user id
|
||||
if (identity.HasClaim(x => x.Type == ClaimTypes.NameIdentifier) == false)
|
||||
{
|
||||
identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, userId, ClaimValueTypes.String,
|
||||
Issuer, Issuer, identity));
|
||||
}
|
||||
|
||||
if (identity.HasClaim(x => x.Type == ClaimTypes.Name) == false)
|
||||
{
|
||||
identity.AddClaim(new Claim(ClaimTypes.Name, username, ClaimValueTypes.String, Issuer, Issuer, identity));
|
||||
}
|
||||
|
||||
if (identity.HasClaim(x => x.Type == ClaimTypes.GivenName) == false)
|
||||
{
|
||||
identity.AddClaim(new Claim(ClaimTypes.GivenName, realName, ClaimValueTypes.String, Issuer, Issuer, identity));
|
||||
}
|
||||
|
||||
if (identity.HasClaim(x => x.Type == Constants.Security.StartContentNodeIdClaimType) == false &&
|
||||
startContentNodes != null)
|
||||
{
|
||||
foreach (var startContentNode in startContentNodes)
|
||||
{
|
||||
identity.AddClaim(new Claim(Constants.Security.StartContentNodeIdClaimType, startContentNode.ToInvariantString(), ClaimValueTypes.Integer32, Issuer, Issuer, identity));
|
||||
}
|
||||
}
|
||||
|
||||
if (identity.HasClaim(x => x.Type == Constants.Security.StartMediaNodeIdClaimType) == false &&
|
||||
startMediaNodes != null)
|
||||
{
|
||||
foreach (var startMediaNode in startMediaNodes)
|
||||
{
|
||||
identity.AddClaim(new Claim(Constants.Security.StartMediaNodeIdClaimType, startMediaNode.ToInvariantString(), ClaimValueTypes.Integer32, Issuer, Issuer, identity));
|
||||
}
|
||||
}
|
||||
|
||||
if (identity.HasClaim(x => x.Type == ClaimTypes.Locality) == false)
|
||||
{
|
||||
identity.AddClaim(new Claim(ClaimTypes.Locality, culture, ClaimValueTypes.String, Issuer, Issuer, identity));
|
||||
}
|
||||
|
||||
// The security stamp claim is also required
|
||||
if (identity.HasClaim(x => x.Type == Constants.Security.SecurityStampClaimType) == false)
|
||||
{
|
||||
identity.AddClaim(new Claim(Constants.Security.SecurityStampClaimType, securityStamp, ClaimValueTypes.String, Issuer, Issuer, identity));
|
||||
}
|
||||
|
||||
// Add each app as a separate claim
|
||||
if (identity.HasClaim(x => x.Type == Constants.Security.AllowedApplicationsClaimType) == false &&
|
||||
allowedApps != null)
|
||||
{
|
||||
foreach (var application in allowedApps)
|
||||
{
|
||||
identity.AddClaim(new Claim(Constants.Security.AllowedApplicationsClaimType, application, ClaimValueTypes.String, Issuer, Issuer, identity));
|
||||
}
|
||||
}
|
||||
|
||||
// Claims are added by the ClaimsIdentityFactory because our UserStore supports roles, however this identity might
|
||||
// not be made with that factory if it was created with a different ticket so perform the check
|
||||
if (identity.HasClaim(x => x.Type == ClaimsIdentity.DefaultRoleClaimType) == false && roles != null)
|
||||
{
|
||||
// Manually add them
|
||||
foreach (var roleName in roles)
|
||||
{
|
||||
identity.AddClaim(new Claim(identity.RoleClaimType, roleName, ClaimValueTypes.String, Issuer, Issuer, identity));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static int[] GetStartContentNodes(this ClaimsIdentity identity) =>
|
||||
identity.FindAll(x => x.Type == Constants.Security.StartContentNodeIdClaimType)
|
||||
.Select(node => int.TryParse(node.Value, out var i) ? i : default)
|
||||
.Where(x => x != default).ToArray();
|
||||
|
||||
public static int[] GetStartMediaNodes(this ClaimsIdentity identity) =>
|
||||
identity.FindAll(x => x.Type == Constants.Security.StartMediaNodeIdClaimType)
|
||||
.Select(node => int.TryParse(node.Value, out var i) ? i : default)
|
||||
.Where(x => x != default).ToArray();
|
||||
|
||||
public static string[] GetAllowedApplications(this ClaimsIdentity identity) => identity
|
||||
.FindAll(x => x.Type == Constants.Security.AllowedApplicationsClaimType).Select(app => app.Value).ToArray();
|
||||
|
||||
public static int GetId(this ClaimsIdentity identity) => int.Parse(identity.FindFirstValue(ClaimTypes.NameIdentifier));
|
||||
|
||||
public static string GetRealName(this ClaimsIdentity identity) => identity.FindFirstValue(ClaimTypes.GivenName);
|
||||
|
||||
public static string GetUsername(this ClaimsIdentity identity) => identity.FindFirstValue(ClaimTypes.Name);
|
||||
|
||||
public static string GetCultureString(this ClaimsIdentity identity) => identity.FindFirstValue(ClaimTypes.Locality);
|
||||
|
||||
public static string GetSecurityStamp(this ClaimsIdentity identity) => identity.FindFirstValue(Constants.Security.SecurityStampClaimType);
|
||||
|
||||
public static string[] GetRoles(this ClaimsIdentity identity) => identity
|
||||
.FindAll(x => x.Type == ClaimsIdentity.DefaultRoleClaimType).Select(role => role.Value).ToArray();
|
||||
}
|
||||
}
|
||||
@@ -11,9 +11,9 @@ using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Microsoft.Net.Http.Headers;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Web.BackOffice.Security;
|
||||
using Umbraco.Extensions;
|
||||
using Umbraco.Web.BackOffice.Security;
|
||||
|
||||
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Web.BackOffice.Security
|
||||
{
|
||||
|
||||
@@ -32,7 +32,7 @@ namespace Umbraco.Tests.TestHelpers.ControllerTesting
|
||||
|
||||
var identity = new ClaimsIdentity();
|
||||
identity.AddRequiredClaims(
|
||||
Core.Constants.Security.SuperUserIdAsString,
|
||||
Cms.Core.Constants.Security.SuperUserIdAsString,
|
||||
"admin",
|
||||
"Admin",
|
||||
new[] { -1 },
|
||||
|
||||
@@ -5,7 +5,6 @@ using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Authentication.Cookies;
|
||||
using Microsoft.AspNetCore.DataProtection;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Umbraco.Cms.Core;
|
||||
@@ -13,12 +12,9 @@ using Umbraco.Cms.Core.Configuration.Models;
|
||||
using Umbraco.Cms.Core.Hosting;
|
||||
using Umbraco.Cms.Core.Net;
|
||||
using Umbraco.Cms.Core.Routing;
|
||||
using Umbraco.Cms.Core.Security;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Core.Web;
|
||||
using Umbraco.Extensions;
|
||||
using Umbraco.Net;
|
||||
using Umbraco.Web.Common.Security;
|
||||
using ClaimsIdentityExtensions = Umbraco.Extensions.ClaimsIdentityExtensions;
|
||||
using Constants = Umbraco.Cms.Core.Constants;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user