2020-12-03 20:30:35 +11:00
using System ;
2020-04-02 08:08:09 +01:00
using System.Linq ;
using System.Security.Claims ;
using System.Threading.Tasks ;
using Microsoft.AspNetCore.Identity ;
using Microsoft.Extensions.Options ;
2020-12-03 23:49:32 +11:00
using Umbraco.Core.Security ;
2020-04-02 08:08:09 +01:00
2020-12-04 02:21:21 +11:00
namespace Umbraco.Core.Security
2020-04-02 08:08:09 +01:00
{
2020-12-03 20:30:35 +11:00
/// <summary>
/// A <see cref="UserClaimsPrincipalFactory{TUser}" for the back office/>
/// </summary>
public class BackOfficeClaimsPrincipalFactory : UserClaimsPrincipalFactory < BackOfficeIdentityUser >
2020-04-02 08:08:09 +01:00
{
2020-12-03 20:30:35 +11:00
/// <summary>
/// Initializes a new instance of the <see cref="BackOfficeClaimsPrincipalFactory"/> class.
/// </summary>
/// <param name="userManager">The user manager</param>
/// <param name="optionsAccessor">The <see cref="BackOfficeIdentityOptions"/></param>
public BackOfficeClaimsPrincipalFactory ( UserManager < BackOfficeIdentityUser > userManager , IOptions < BackOfficeIdentityOptions > optionsAccessor )
2020-04-02 08:08:09 +01:00
: base ( userManager , optionsAccessor )
{
}
2020-12-03 20:30:35 +11:00
/// <inheritdoc />
/// <remarks>
/// Returns a custom <see cref="UmbracoBackOfficeIdentity"/> and allows flowing claims from the external identity
/// </remarks>
public override async Task < ClaimsPrincipal > CreateAsync ( BackOfficeIdentityUser user )
2020-04-02 08:08:09 +01:00
{
2020-12-03 20:30:35 +11:00
if ( user = = null )
{
throw new ArgumentNullException ( nameof ( user ) ) ;
}
2020-04-04 19:58:09 +01:00
2020-12-03 20:30:35 +11:00
ClaimsIdentity baseIdentity = await base . GenerateClaimsAsync ( user ) ;
2020-04-04 19:58:09 +01:00
2020-10-23 10:10:02 +11:00
// now we can flow any custom claims that the actual user has currently assigned which could be done in the OnExternalLogin callback
2020-12-04 12:54:31 +11:00
foreach ( IdentityUserClaim < string > claim in user . Claims )
{
baseIdentity . AddClaim ( new Claim ( claim . ClaimType , claim . ClaimValue ) ) ;
}
2020-10-23 10:10:02 +11:00
2020-12-03 20:30:35 +11:00
// TODO: We want to remove UmbracoBackOfficeIdentity and only rely on ClaimsIdentity, once
// that is done then we'll create a ClaimsIdentity with all of the requirements here instead
2020-04-02 08:08:09 +01:00
var umbracoIdentity = new UmbracoBackOfficeIdentity (
2020-04-04 12:36:04 +01:00
baseIdentity ,
2020-04-02 08:08:09 +01:00
user . Id ,
user . UserName ,
user . Name ,
user . CalculatedContentStartNodeIds ,
user . CalculatedMediaStartNodeIds ,
user . Culture ,
user . SecurityStamp ,
user . AllowedSections ,
user . Roles . Select ( x = > x . RoleId ) . ToArray ( ) ) ;
return new ClaimsPrincipal ( umbracoIdentity ) ;
}
2020-06-03 18:10:35 +10:00
2020-12-03 20:30:35 +11:00
/// <inheritdoc />
protected override async Task < ClaimsIdentity > GenerateClaimsAsync ( BackOfficeIdentityUser user )
2020-06-03 18:10:35 +10:00
{
// TODO: Have a look at the base implementation https://github.com/dotnet/aspnetcore/blob/master/src/Identity/Extensions.Core/src/UserClaimsPrincipalFactory.cs#L79
// since it's setting an authentication type that is probably not what we want.
// also, this is the method that we should be returning our UmbracoBackOfficeIdentity from , not the method above,
// the method above just returns a principal that wraps the identity and we dont use a custom principal,
// see https://github.com/dotnet/aspnetcore/blob/master/src/Identity/Extensions.Core/src/UserClaimsPrincipalFactory.cs#L66
2020-12-03 20:30:35 +11:00
ClaimsIdentity identity = await base . GenerateClaimsAsync ( user ) ;
2020-06-03 18:10:35 +10:00
return identity ;
}
2020-04-02 08:08:09 +01:00
}
}