Renamed and added initial member role store methods, and initial unit tests

This commit is contained in:
Emma Garland
2021-03-03 17:33:57 +00:00
parent 7ff96d3ed3
commit c9229880da
4 changed files with 415 additions and 60 deletions

View File

@@ -1,57 +0,0 @@
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.Scoping;
using Umbraco.Cms.Core.Services;
namespace Umbraco.Cms.Core.Security
{
/// <summary>
/// A custom user store that uses Umbraco member data
/// </summary>
public class MemberRolesUserStore : RoleStoreBase<IdentityRole<string>, string, IdentityUserRole<string>, IdentityRoleClaim<string>>
{
private readonly IMemberService _memberService;
private readonly IMemberGroupService _memberGroupService;
private readonly IScopeProvider _scopeProvider;
public MemberRolesUserStore(IMemberService memberService, IMemberGroupService memberGroupService, IScopeProvider scopeProvider, IdentityErrorDescriber describer)
: base(describer)
{
_memberService = memberService ?? throw new ArgumentNullException(nameof(memberService));
_memberGroupService = memberGroupService ?? throw new ArgumentNullException(nameof(memberGroupService));
_scopeProvider = scopeProvider ?? throw new ArgumentNullException(nameof(scopeProvider));
}
/// <inheritdoc />
public override IQueryable<IdentityRole<string>> Roles { get; }
/// <inheritdoc />
public override Task<IdentityResult> CreateAsync(IdentityRole<string> role, CancellationToken cancellationToken = new CancellationToken()) => throw new System.NotImplementedException();
/// <inheritdoc />
public override Task<IdentityResult> UpdateAsync(IdentityRole<string> role, CancellationToken cancellationToken = new CancellationToken()) => throw new System.NotImplementedException();
/// <inheritdoc />
public override Task<IdentityResult> DeleteAsync(IdentityRole<string> role, CancellationToken cancellationToken = new CancellationToken()) => throw new System.NotImplementedException();
/// <inheritdoc />
public override Task<IdentityRole<string>> FindByIdAsync(string id, CancellationToken cancellationToken = new CancellationToken()) => throw new System.NotImplementedException();
/// <inheritdoc />
public override Task<IdentityRole<string>> FindByNameAsync(string normalizedName, CancellationToken cancellationToken = new CancellationToken()) => throw new System.NotImplementedException();
/// <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();
}
}

View File

@@ -0,0 +1,193 @@
using System;
using System.Collections;
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.Scoping;
using Umbraco.Cms.Core.Services;
namespace Umbraco.Cms.Core.Security
{
/// <summary>
/// A custom user store that uses Umbraco member data
/// </summary>
public class MembersRoleStore : RoleStoreBase<IdentityRole<string>, string, IdentityUserRole<string>, IdentityRoleClaim<string>>
{
private readonly IMemberService _memberService;
private readonly IMemberGroupService _memberGroupService;
private readonly IScopeProvider _scopeProvider;
public MembersRoleStore(IMemberService memberService, IMemberGroupService memberGroupService, IScopeProvider scopeProvider, IdentityErrorDescriber describer)
: base(describer)
{
_memberService = memberService ?? throw new ArgumentNullException(nameof(memberService));
_memberGroupService = memberGroupService ?? throw new ArgumentNullException(nameof(memberGroupService));
_scopeProvider = scopeProvider ?? throw new ArgumentNullException(nameof(scopeProvider));
}
/// <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))
{
return new Task<IdentityResult>(() => IdentityResult.Failed());
}
IMemberGroup memberGroup = _memberGroupService.GetById(roleId);
if (memberGroup != null)
{
if (MapToMemberGroup(role, memberGroup))
{
_memberGroupService.Save(memberGroup);
}
}
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))
{
return new Task<IdentityResult>(() => IdentityResult.Failed());
}
IMemberGroup memberGroup = _memberGroupService.GetById(roleId);
if (memberGroup != null)
{
_memberGroupService.Delete(memberGroup);
}
else
{
//TODO: throw exception when not found, or return failure?
return Task.FromResult(IdentityResult.Failed());
}
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));
}
/// <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;
}
}
}

View File

@@ -74,8 +74,5 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Infrastructure.Security
Assert.IsTrue(identityResult.Succeeded);
Assert.IsTrue(!identityResult.Errors.Any());
}
//GetPasswordHashAsync
//GetUserIdAsync
}
}

View File

@@ -0,0 +1,222 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Identity;
using Moq;
using NUnit.Framework;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Scoping;
using Umbraco.Cms.Core.Security;
using Umbraco.Cms.Core.Services;
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Infrastructure.Security
{
[TestFixture]
public class MemberRoleStoreTests
{
private Mock<IMemberService> _mockMemberService;
private Mock<IMemberGroupService> _mockMemberGroupService;
public MembersRoleStore CreateSut()
{
_mockMemberService = new Mock<IMemberService>();
_mockMemberGroupService = new Mock<IMemberGroupService>();
return new MembersRoleStore(
_mockMemberService.Object,
_mockMemberGroupService.Object,
new Mock<IScopeProvider>().Object,
new IdentityErrorDescriber());
}
[Test]
public void GivenICreateAMemberRole_AndTheGroupIsNull_ThenIShouldGetAFailedResultAsync()
{
// arrange
MembersRoleStore sut = CreateSut();
CancellationToken fakeCancellationToken = new CancellationToken() { };
// act
Action actual = () => sut.CreateAsync(null, fakeCancellationToken);
// assert
Assert.That(actual, Throws.ArgumentNullException);
}
[Test]
public async Task GivenICreateAMemberRole_AndTheGroupIsPopulatedCorrectly_ThenIShouldGetASuccessResultAsync()
{
// arrange
MembersRoleStore sut = CreateSut();
var fakeRole = new IdentityRole<string>()
{
Id = "777",
Name = "testname"
};
var fakeCancellationToken = new CancellationToken() { };
IMemberGroup mockMemberGroup = Mock.Of<IMemberGroup>(m =>
m.Name == "fakeGroupName" && m.CreatorId == 77);
bool raiseEvents = false;
_mockMemberGroupService.Setup(x => x.Save(mockMemberGroup, raiseEvents));
// act
IdentityResult identityResult = await sut.CreateAsync(fakeRole, fakeCancellationToken);
// assert
Assert.IsTrue(identityResult.Succeeded);
Assert.IsTrue(!identityResult.Errors.Any());
_mockMemberGroupService.Verify(x => x.Save(It.IsAny<MemberGroup>(), It.IsAny<bool>()));
}
[Test]
public async Task GivenIUpdateAMemberRole_AndTheGroupExists_ThenIShouldGetASuccessResultAsync()
{
// arrange
MembersRoleStore sut = CreateSut();
var fakeRole = new IdentityRole<string>()
{
Id = "777",
Name = "testname"
};
var fakeCancellationToken = new CancellationToken() { };
IMemberGroup mockMemberGroup = Mock.Of<IMemberGroup>(m =>
m.Name == "fakeGroupName" && m.CreatorId == 77);
bool raiseEvents = false;
_mockMemberGroupService.Setup(x => x.GetById(777)).Returns(mockMemberGroup);
_mockMemberGroupService.Setup(x => x.Save(mockMemberGroup, raiseEvents));
// act
IdentityResult identityResult = await sut.UpdateAsync(fakeRole, fakeCancellationToken);
// assert
Assert.IsTrue(identityResult.Succeeded);
Assert.IsTrue(!identityResult.Errors.Any());
_mockMemberGroupService.Verify(x => x.Save(mockMemberGroup, false));
_mockMemberGroupService.Verify(x => x.GetById(777));
}
[Test]
public async Task GivenIUpdateAMemberRole_AndTheGroupDoesntExist_ThenIShouldGetAFailureResultAsync()
{
// arrange
MembersRoleStore sut = CreateSut();
var fakeRole = new IdentityRole<string>()
{
Id = "777",
Name = "testname"
};
var fakeCancellationToken = new CancellationToken() { };
IMemberGroup mockMemberGroup = Mock.Of<IMemberGroup>(m =>
m.Name == "fakeGroupName" && m.CreatorId == 77);
bool raiseEvents = false;
// act
IdentityResult identityResult = await sut.UpdateAsync(fakeRole, fakeCancellationToken);
// assert
Assert.IsTrue(identityResult.Succeeded == false);
Assert.IsTrue(identityResult.Errors.Any());
_mockMemberGroupService.Verify(x => x.GetById(777));
}
[Test]
public async Task GivenIDeleteAMemberRole_AndItExists_ThenTheMemberGroupShouldBeDeleted_AndIShouldGetASuccessResultAsync()
{
// arrange
MembersRoleStore sut = CreateSut();
var fakeRole = new IdentityRole<string>()
{
Id = "777",
Name = "testname"
};
var fakeCancellationToken = new CancellationToken() { };
IMemberGroup mockMemberGroup = Mock.Of<IMemberGroup>(m =>
m.Name == "fakeGroupName" && m.CreatorId == 77);
_mockMemberGroupService.Setup(x => x.GetById(777)).Returns(mockMemberGroup);
// act
IdentityResult identityResult = await sut.DeleteAsync(fakeRole, fakeCancellationToken);
// assert
Assert.IsTrue(identityResult.Succeeded);
Assert.IsTrue(!identityResult.Errors.Any());
_mockMemberGroupService.Verify(x => x.GetById(777));
_mockMemberGroupService.Verify(x => x.Delete(mockMemberGroup));
}
[Test]
public async Task GivenIDeleteAMemberRole_AndItDoesntExist_ThenTheMemberGroupShouldBeDeleted_AndIShouldGetASuccessResultAsync()
{
// arrange
MembersRoleStore sut = CreateSut();
var fakeRole = new IdentityRole<string>()
{
Id = "777",
Name = "testname"
};
var fakeCancellationToken = new CancellationToken() { };
IMemberGroup mockMemberGroup = Mock.Of<IMemberGroup>(m =>
m.Name == "fakeGroupName" && m.CreatorId == 77);
// act
IdentityResult identityResult = await sut.DeleteAsync(fakeRole, fakeCancellationToken);
// assert
Assert.IsTrue(identityResult.Succeeded == false);
Assert.IsTrue(identityResult.Errors.Any());
_mockMemberGroupService.Verify(x => x.GetById(777));
_mockMemberGroupService.Verify(x => x.Delete(mockMemberGroup));
}
[Test]
public async Task GivenIGetAllMemberRoles_ThenIShouldGetAllMemberGroups_AndASuccessResultAsync()
{
// arrange
MembersRoleStore sut = CreateSut();
var fakeRole = new IdentityRole<string>()
{
Id = "777",
Name = "testname"
};
IEnumerable<IdentityRole<string>> expected = new List<IdentityRole<string>>()
{
new IdentityRole("fakeGroupName")
{
Id = "77"
}
};
IMemberGroup mockMemberGroup = Mock.Of<IMemberGroup>(m =>
m.Name == "fakeGroupName" && m.CreatorId == 77);
IEnumerable<IMemberGroup> fakeMemberGroups = new List<IMemberGroup>()
{
mockMemberGroup
};
_mockMemberGroupService.Setup(x => x.GetAll()).Returns(fakeMemberGroups);
// act
IQueryable<IdentityRole<string>> actual = sut.Roles;
// assert
Assert.AreEqual(expected.AsQueryable(), actual);
_mockMemberGroupService.Verify(x => x.GetAll());
}
}
}