Files
Umbraco-CMS/src/Umbraco.Infrastructure/Security/MemberRoleStore.cs

194 lines
6.9 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Identity;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Services;
namespace Umbraco.Cms.Core.Security
{
/// <summary>
/// A custom user store that uses Umbraco member data
/// </summary>
public class MemberRoleStore : RoleStoreBase<IdentityRole<string>, string, IdentityUserRole<string>, IdentityRoleClaim<string>>
{
private readonly IMemberGroupService _memberGroupService;
public MemberRoleStore(IMemberGroupService memberGroupService, IdentityErrorDescriber describer)
: base(describer) => _memberGroupService = memberGroupService ?? throw new ArgumentNullException(nameof(memberGroupService));
/// <inheritdoc />
public override IQueryable<IdentityRole<string>> Roles
{
get
{
IEnumerable<IMemberGroup> memberGroups = _memberGroupService.GetAll();
var identityRoles = new List<IdentityRole<string>>();
foreach (IMemberGroup group in memberGroups)
{
IdentityRole<string> identityRole = MapFromMemberGroup(group);
identityRoles.Add(identityRole);
}
return identityRoles.AsQueryable();
}
}
/// <inheritdoc />
public override Task<IdentityResult> CreateAsync(
IdentityRole<string> role,
CancellationToken cancellationToken = new CancellationToken())
{
if (role == null)
{
throw new ArgumentNullException(nameof(role));
}
var memberGroup = new MemberGroup
{
Name = role.Name
};
_memberGroupService.Save(memberGroup);
role.Id = memberGroup.Id.ToString();
return Task.FromResult(IdentityResult.Success);
}
/// <inheritdoc />
public override Task<IdentityResult> UpdateAsync(IdentityRole<string> role,
CancellationToken cancellationToken = new CancellationToken())
{
if (role == null)
{
throw new ArgumentNullException(nameof(role));
}
if (!int.TryParse(role.Id, out int roleId))
{
//TODO: what identity error should we return in this case?
return Task.FromResult(IdentityResult.Failed(ErrorDescriber.DefaultError()));
}
IMemberGroup memberGroup = _memberGroupService.GetById(roleId);
if (memberGroup != null)
{
if (MapToMemberGroup(role, memberGroup))
{
_memberGroupService.Save(memberGroup);
}
}
else
{
//TODO: throw exception when not found, or return failure? And is this the correct message
return Task.FromResult(IdentityResult.Failed(ErrorDescriber.InvalidRoleName(role.Name)));
}
return Task.FromResult(IdentityResult.Success);
}
/// <inheritdoc />
public override Task<IdentityResult> DeleteAsync(IdentityRole<string> role,
CancellationToken cancellationToken = new CancellationToken())
{
if (role == null)
{
throw new ArgumentNullException(nameof(role));
}
if (!int.TryParse(role.Id, out int roleId))
{
//TODO: what identity error should we return in this case?
return Task.FromResult(IdentityResult.Failed(ErrorDescriber.DefaultError()));
}
IMemberGroup memberGroup = _memberGroupService.GetById(roleId);
if (memberGroup != null)
{
_memberGroupService.Delete(memberGroup);
}
else
{
//TODO: throw exception when not found, or return failure? And is this the correct message
return Task.FromResult(IdentityResult.Failed(ErrorDescriber.InvalidRoleName(role.Name)));
}
return Task.FromResult(IdentityResult.Success);
}
/// <inheritdoc />
public override Task<IdentityRole<string>> FindByIdAsync(string id,
CancellationToken cancellationToken = new CancellationToken())
{
if (!int.TryParse(id, out int roleId))
{
return null;
}
IMemberGroup memberGroup = _memberGroupService.GetById(roleId);
return Task.FromResult(memberGroup == null ? null : MapFromMemberGroup(memberGroup));
}
/// <inheritdoc />
public override Task<IdentityRole<string>> FindByNameAsync(string normalizedName,
CancellationToken cancellationToken = new CancellationToken())
{
IMemberGroup memberGroup = _memberGroupService.GetByName(normalizedName);
return Task.FromResult(memberGroup == null ? null : MapFromMemberGroup(memberGroup));
}
///TODO: are we implementing these claims methods?
/// <inheritdoc />
public override Task<IList<Claim>> GetClaimsAsync(IdentityRole<string> role, CancellationToken cancellationToken = new CancellationToken()) => throw new System.NotImplementedException();
/// <inheritdoc />
public override Task AddClaimAsync(IdentityRole<string> role, Claim claim, CancellationToken cancellationToken = new CancellationToken()) => throw new System.NotImplementedException();
/// <inheritdoc />
public override Task RemoveClaimAsync(IdentityRole<string> role, Claim claim, CancellationToken cancellationToken = new CancellationToken()) => throw new System.NotImplementedException();
/// <summary>
/// Maps a member group to an identity role
/// </summary>
/// <param name="memberGroup"></param>
/// <returns></returns>
private IdentityRole<string> MapFromMemberGroup(IMemberGroup memberGroup)
{
var result = new IdentityRole
{
Id = memberGroup.Id.ToString(),
Name = memberGroup.Name
};
return result;
}
/// <summary>
/// Map an identity role to a member group
/// </summary>
/// <param name="role"></param>
/// <param name="memberGroup"></param>
/// <returns></returns>
private bool MapToMemberGroup(IdentityRole<string> role, IMemberGroup memberGroup)
{
var anythingChanged = false;
if (!string.IsNullOrEmpty(role.Name) && memberGroup.Name != role.Name)
{
memberGroup.Name = role.Name;
anythingChanged = true;
}
return anythingChanged;
}
}
}