* Run code cleanup * Start manual cleanup after dotnet format * Finish up manual pass * Fix up missed warnings * Fix after merge * Update src/Umbraco.Core/Cache/ContentTypeCacheRefresher.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/Cache/DataTypeCacheRefresher.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/Cache/DeepCloneAppCache.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/Cache/DomainCacheRefresher.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/Cache/FastDictionaryAppCacheBase.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/Cache/FastDictionaryAppCacheBase.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/Cache/FastDictionaryAppCacheBase.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/Cache/FastDictionaryAppCacheBase.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/Cache/FastDictionaryAppCacheBase.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/Cache/MacroCacheRefresher.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/Cache/MediaCacheRefresher.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/Cache/MemberCacheRefresher.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/Cache/MemberGroupCacheRefresher.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/Composing/OrderedCollectionBuilderBase.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/Configuration/Models/RequestHandlerSettings.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/Composing/SetCollectionBuilderBase.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/Composing/WeightedCollectionBuilderBase.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/ContentApps/ContentAppFactoryCollectionBuilder.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/Dashboards/DashboardCollectionBuilder.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/Extensions/StringExtensions.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/Extensions/StringExtensions.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/Extensions/StringExtensions.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/Extensions/StringExtensions.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/Extensions/StringExtensions.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/Extensions/StringExtensions.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/Extensions/StringExtensions.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/Notifications/ContentTypeRefreshedNotification.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/Notifications/ContentTypeSavedNotification.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/Notifications/ContentTypeSavingNotification.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/Notifications/DictionaryCacheRefresherNotification.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/Notifications/DataTypeCacheRefresherNotification.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/Notifications/ContentUnpublishingNotification.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/Notifications/DictionaryItemDeletingNotification.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/Notifications/DictionaryItemSavedNotification.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/Notifications/DictionaryItemSavingNotification.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/Notifications/DomainCacheRefresherNotification.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/Notifications/LanguageCacheRefresherNotification.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/Notifications/MacroCacheRefresherNotification.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/Notifications/MediaCacheRefresherNotification.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/Notifications/MediaEmptiedRecycleBinNotification.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/Notifications/MediaEmptyingRecycleBinNotification.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/Notifications/MediaMovedNotification.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/Notifications/MediaMovedToRecycleBinNotification.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/Extensions/StringExtensions.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/Extensions/StringExtensions.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/Extensions/StringExtensions.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/Extensions/StringExtensions.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/Extensions/StringExtensions.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/Extensions/StringExtensions.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/Notifications/MediaMovedToRecycleBinNotification.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/Notifications/MediaMovingNotification.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/Notifications/MediaMovingToRecycleBinNotification.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/Notifications/MediaTreeChangeNotification.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/Notifications/MediaTreeChangeNotification.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/Notifications/MediaTypeChangedNotification.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/Notifications/MediaTypeDeletingNotification.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/Notifications/MediaTypeMovedNotification.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/Notifications/MediaTypeMovingNotification.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/Notifications/MediaTypeMovingNotification.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/Notifications/MediaTypeRefreshedNotification.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/Notifications/MemberCacheRefresherNotification.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/Notifications/MemberGroupCacheRefresherNotification.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/Notifications/MemberGroupDeletingNotification.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/Notifications/MemberGroupSavedNotification.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/Notifications/MemberGroupSavingNotification.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/Notifications/MemberTypeChangedNotification.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/Notifications/MemberTypeDeletedNotification.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/Notifications/MemberTypeDeletingNotification.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/Notifications/MemberTypeMovedNotification.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/Notifications/MemberTypeMovedNotification.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/Notifications/MemberTypeMovingNotification.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/Notifications/MemberTypeMovingNotification.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/Notifications/MemberTypeRefreshedNotification.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/Notifications/MemberTypeSavingNotification.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/Extensions/StringExtensions.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/Extensions/UriExtensions.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/Notifications/MovedToRecycleBinNotification.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/Notifications/MovedToRecycleBinNotification.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/Notifications/MovingToRecycleBinNotification.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/Notifications/MovingToRecycleBinNotification.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/Notifications/PartialViewDeletingNotification.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/Extensions/UriExtensions.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/IO/PhysicalFileSystem.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/IO/PhysicalFileSystem.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/IO/ShadowWrapper.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/Logging/DisposableTimer.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/Install/InstallSteps/UpgradeStep.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/Mapping/MapDefinitionCollectionBuilder.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/Media/EmbedProviders/EmbedProvidersCollectionBuilder.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/Notifications/PartialViewSavedNotification.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/Models/ContentEditing/ContentVariationDisplay.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/Notifications/PartialViewSavingNotification.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/Notifications/PublicAccessCacheRefresherNotification.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/Notifications/PublicAccessEntryDeletedNotification.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/Notifications/PublicAccessEntryDeletingNotification.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/Notifications/PublicAccessEntryDeletingNotification.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/Notifications/PublicAccessEntrySavedNotification.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/Notifications/PublicAccessEntrySavingNotification.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/Notifications/PublicAccessEntrySavingNotification.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/Notifications/RelationTypeCacheRefresherNotification.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/Notifications/RelationTypeDeletingNotification.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/Notifications/RelationTypeSavedNotification.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/Notifications/RelationTypeSavingNotification.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/Notifications/StatefulNotification.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/Notifications/StylesheetDeletingNotification.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/Notifications/StylesheetSavingNotification.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/Models/DeepCloneHelper.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/Models/File.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/Models/PropertyGroupExtensions.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Update src/Umbraco.Core/Models/PropertyGroupExtensions.cs Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> * Fix based on review * Fix after merge Signed-off-by: Zeegaan <nge@umbraco.dk> Co-authored-by: Nikolaj Geisle <niko737@edu.ucl.dk> Co-authored-by: Mole <nikolajlauridsen@protonmail.ch> Co-authored-by: Zeegaan <nge@umbraco.dk>
396 lines
15 KiB
C#
396 lines
15 KiB
C#
// Copyright (c) Umbraco.
|
|
// See LICENSE for more details.
|
|
|
|
using System.Diagnostics.CodeAnalysis;
|
|
using System.Globalization;
|
|
using System.Security.Claims;
|
|
using System.Security.Principal;
|
|
using Umbraco.Cms.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 static T? GetUserId<T>(this IIdentity identity)
|
|
{
|
|
var strId = identity.GetUserId();
|
|
Attempt<T> converted = strId.TryConvertTo<T>();
|
|
return converted.Result ?? default;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns the user id from the <see cref="IIdentity" /> of either the claim type
|
|
/// <see cref="ClaimTypes.NameIdentifier" /> or "sub"
|
|
/// </summary>
|
|
/// <param name="identity"></param>
|
|
/// <returns>
|
|
/// The string value of the user id if found otherwise null
|
|
/// </returns>
|
|
public static string? GetUserId(this IIdentity identity)
|
|
{
|
|
if (identity == null)
|
|
{
|
|
throw new ArgumentNullException(nameof(identity));
|
|
}
|
|
|
|
string? userId = null;
|
|
if (identity is ClaimsIdentity claimsIdentity)
|
|
{
|
|
userId = claimsIdentity.FindFirstValue(ClaimTypes.NameIdentifier)
|
|
?? claimsIdentity.FindFirstValue("sub");
|
|
}
|
|
|
|
return userId;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns the user name from the <see cref="IIdentity" /> of either the claim type <see cref="ClaimTypes.Name" /> or
|
|
/// "preferred_username"
|
|
/// </summary>
|
|
/// <param name="identity"></param>
|
|
/// <returns>
|
|
/// The string value of the user name if found otherwise null
|
|
/// </returns>
|
|
public static string? GetUserName(this IIdentity identity)
|
|
{
|
|
if (identity == null)
|
|
{
|
|
throw new ArgumentNullException(nameof(identity));
|
|
}
|
|
|
|
string? username = null;
|
|
if (identity is ClaimsIdentity claimsIdentity)
|
|
{
|
|
username = claimsIdentity.FindFirstValue(ClaimTypes.Name)
|
|
?? claimsIdentity.FindFirstValue("preferred_username");
|
|
}
|
|
|
|
return username;
|
|
}
|
|
|
|
public static string? GetEmail(this IIdentity identity)
|
|
{
|
|
if (identity == null)
|
|
{
|
|
throw new ArgumentNullException(nameof(identity));
|
|
}
|
|
|
|
string? email = null;
|
|
if (identity is ClaimsIdentity claimsIdentity)
|
|
{
|
|
email = claimsIdentity.FindFirstValue(ClaimTypes.Email);
|
|
}
|
|
|
|
return email;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns the first claim value found in the <see cref="ClaimsIdentity" /> for the given claimType
|
|
/// </summary>
|
|
/// <param name="identity"></param>
|
|
/// <param name="claimType"></param>
|
|
/// <returns>
|
|
/// The string value of the claim if found otherwise null
|
|
/// </returns>
|
|
public static string? FindFirstValue(this ClaimsIdentity identity, string claimType)
|
|
{
|
|
if (identity == null)
|
|
{
|
|
throw new ArgumentNullException(nameof(identity));
|
|
}
|
|
|
|
return identity.FindFirst(claimType)?.Value;
|
|
}
|
|
|
|
/// <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,
|
|
[MaybeNullWhen(false)] out ClaimsIdentity verifiedIdentity)
|
|
{
|
|
if (identity is null)
|
|
{
|
|
verifiedIdentity = null;
|
|
return false;
|
|
}
|
|
|
|
// 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 = identity.AuthenticationType == Constants.Security.BackOfficeAuthenticationType
|
|
? identity
|
|
: 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,
|
|
Constants.Security.BackOfficeAuthenticationType,
|
|
Constants.Security.BackOfficeAuthenticationType,
|
|
identity));
|
|
}
|
|
|
|
if (identity.HasClaim(x => x.Type == ClaimTypes.Name) == false)
|
|
{
|
|
identity.AddClaim(new Claim(
|
|
ClaimTypes.Name,
|
|
username,
|
|
ClaimValueTypes.String,
|
|
Constants.Security.BackOfficeAuthenticationType,
|
|
Constants.Security.BackOfficeAuthenticationType,
|
|
identity));
|
|
}
|
|
|
|
if (identity.HasClaim(x => x.Type == ClaimTypes.GivenName) == false)
|
|
{
|
|
identity.AddClaim(new Claim(
|
|
ClaimTypes.GivenName,
|
|
realName,
|
|
ClaimValueTypes.String,
|
|
Constants.Security.BackOfficeAuthenticationType,
|
|
Constants.Security.BackOfficeAuthenticationType,
|
|
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,
|
|
Constants.Security.BackOfficeAuthenticationType,
|
|
Constants.Security.BackOfficeAuthenticationType,
|
|
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,
|
|
Constants.Security.BackOfficeAuthenticationType,
|
|
Constants.Security.BackOfficeAuthenticationType,
|
|
identity));
|
|
}
|
|
}
|
|
|
|
if (identity.HasClaim(x => x.Type == ClaimTypes.Locality) == false)
|
|
{
|
|
identity.AddClaim(new Claim(
|
|
ClaimTypes.Locality,
|
|
culture,
|
|
ClaimValueTypes.String,
|
|
Constants.Security.BackOfficeAuthenticationType,
|
|
Constants.Security.BackOfficeAuthenticationType,
|
|
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,
|
|
Constants.Security.BackOfficeAuthenticationType,
|
|
Constants.Security.BackOfficeAuthenticationType,
|
|
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,
|
|
Constants.Security.BackOfficeAuthenticationType,
|
|
Constants.Security.BackOfficeAuthenticationType,
|
|
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,
|
|
Constants.Security.BackOfficeAuthenticationType,
|
|
Constants.Security.BackOfficeAuthenticationType,
|
|
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, NumberStyles.Integer, CultureInfo.InvariantCulture, 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, NumberStyles.Integer, CultureInfo.InvariantCulture, 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)
|
|
{
|
|
var firstValue = identity.FindFirstValue(ClaimTypes.NameIdentifier);
|
|
if (firstValue is not null)
|
|
{
|
|
return int.Parse(firstValue, CultureInfo.InvariantCulture);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/// <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();
|
|
|
|
/// <summary>
|
|
/// Adds or updates and existing claim.
|
|
/// </summary>
|
|
public static void AddOrUpdateClaim(this ClaimsIdentity identity, Claim? claim)
|
|
{
|
|
if (identity == null)
|
|
{
|
|
throw new ArgumentNullException(nameof(identity));
|
|
}
|
|
|
|
if (claim is not null)
|
|
{
|
|
Claim? existingClaim = identity.Claims.FirstOrDefault(x => x.Type == claim.Type);
|
|
identity.TryRemoveClaim(existingClaim);
|
|
|
|
identity.AddClaim(claim);
|
|
}
|
|
}
|
|
}
|