* Initial stab at how this could look * Authorization PoC wip * Add connection manager * Add DI to its own class * Use enum instead of string * Use groups * Refactor group management into its own service * Update a users groups when it's saved * Add saved events * Wire up deleted notifications * Ensure update date and create date is the same * Cleanup * Minor cleanup * Remove unusued usings * Move route to constant * Add docstrings to server event router * Fix and suppress warnings * Refactor to authorizer pattern * Update EventType * Remove unused enums * Add trashed events * Notify current user that they've been updated * Add broadcast We don't need it, but seems like a thing that a server event router should be able to do. * Add ServerEventRouterTests * Add ServerEventUserManagerTests * Use TimeProvider * Remove principal null check * Don't assign event type * Minor cleanup * Rename AuthorizedEventSources * Change permission for relations * Exctract event authorization into its own service * Add some tests * Update name * Add forgotten file * Rmember to add to DI
125 lines
6.0 KiB
C#
125 lines
6.0 KiB
C#
using System.Security.Claims;
|
|
using Microsoft.AspNetCore.SignalR;
|
|
using Moq;
|
|
using NUnit.Framework;
|
|
using Umbraco.Cms.Api.Management.ServerEvents;
|
|
using Umbraco.Cms.Core;
|
|
using Umbraco.Cms.Core.ServerEvents;
|
|
|
|
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Cms.Api.Management.ServerEvents;
|
|
|
|
[TestFixture]
|
|
public class ServerEventUserManagerTests
|
|
{
|
|
[Test]
|
|
public async Task AssignsUserToEventSourceGroup()
|
|
{
|
|
var userKey = Guid.NewGuid();
|
|
var user = CreateFakeUser(userKey);
|
|
var authorizationService = CreateServeEventAuthorizationService(new FakeAuthorizer(["source"]));
|
|
var mocks = CreateHubContextMocks();
|
|
|
|
// Add a connection to the user
|
|
var connection = "connection1";
|
|
var connectionManager = new UserConnectionManager();
|
|
connectionManager.AddConnection(userKey, connection);
|
|
|
|
var sut = new ServerEventUserManager(connectionManager, authorizationService, mocks.HubContextMock.Object);
|
|
await sut.AssignToGroupsAsync(user, connection);
|
|
|
|
// Ensure AddToGroupAsync was called once, and only once with the expected parameters.
|
|
mocks.GroupManagerMock.Verify(x => x.AddToGroupAsync(connection, "source", It.IsAny<CancellationToken>()), Times.Once);
|
|
mocks.GroupManagerMock.Verify(x => x.AddToGroupAsync(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<CancellationToken>()), Times.Once);
|
|
}
|
|
|
|
[Test]
|
|
public async Task DoesNotAssignUserToEventSourceGroupWhenUnauthorized()
|
|
{
|
|
var userKey = Guid.NewGuid();
|
|
var user = CreateFakeUser(userKey);
|
|
var authorizationService = CreateServeEventAuthorizationService(new FakeAuthorizer(["source"], (_, _) => false));
|
|
var mocks = CreateHubContextMocks();
|
|
|
|
// Add a connection to the user
|
|
var connection = "connection1";
|
|
var connectionManager = new UserConnectionManager();
|
|
connectionManager.AddConnection(userKey, connection);
|
|
|
|
var sut = new ServerEventUserManager(connectionManager, authorizationService, mocks.HubContextMock.Object);
|
|
await sut.AssignToGroupsAsync(user, connection);
|
|
|
|
// Ensure AddToGroupAsync was never called.
|
|
mocks.GroupManagerMock.Verify(x => x.AddToGroupAsync(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<CancellationToken>()), Times.Never);
|
|
}
|
|
|
|
[Test]
|
|
public async Task RefreshGroupsAsyncRefreshesUserGroups()
|
|
{
|
|
var userKey = Guid.NewGuid();
|
|
var user = CreateFakeUser(userKey);
|
|
var allowedSource = "allowedSource";
|
|
var disallowedSource = "NotAllowed";
|
|
var authorizationService = CreateServeEventAuthorizationService(new FakeAuthorizer([allowedSource]), new FakeAuthorizer([disallowedSource], (_, _) => false));
|
|
var mocks = CreateHubContextMocks();
|
|
|
|
// Add a connection to the user
|
|
var connection = "connection1";
|
|
var connectionManager = new UserConnectionManager();
|
|
connectionManager.AddConnection(userKey, connection);
|
|
|
|
var sut = new ServerEventUserManager(connectionManager, authorizationService, mocks.HubContextMock.Object);
|
|
await sut.RefreshGroupsAsync(user);
|
|
|
|
// Ensure AddToGroupAsync was called once, and only once with the expected parameters.
|
|
mocks.GroupManagerMock.Verify(x => x.AddToGroupAsync(connection, allowedSource, It.IsAny<CancellationToken>()), Times.Once);
|
|
mocks.GroupManagerMock.Verify(x => x.AddToGroupAsync(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<CancellationToken>()), Times.Once);
|
|
|
|
// Ensure RemoveToGroup was called for the disallowed source, and only the disallowed source.
|
|
mocks.GroupManagerMock.Verify(x => x.RemoveFromGroupAsync(connection, disallowedSource, It.IsAny<CancellationToken>()), Times.Once());
|
|
mocks.GroupManagerMock.Verify(x => x.RemoveFromGroupAsync(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<CancellationToken>()), Times.Once());
|
|
}
|
|
|
|
[Test]
|
|
public async Task RefreshUserGroupsDoesNothingIfNoConnections()
|
|
{
|
|
var userKey = Guid.NewGuid();
|
|
var user = CreateFakeUser(userKey);
|
|
var authorizationService = CreateServeEventAuthorizationService(new FakeAuthorizer(["source"]), new FakeAuthorizer(["disallowedSource"], (_, _) => false)) ?? throw new ArgumentNullException("CreateServeEventAuthorizationService(new FakeAuthorizer([\"source\"]), new FakeAuthorizer([\"disallowedSource\"], (_, _) => false))");
|
|
var mocks = CreateHubContextMocks();
|
|
|
|
var connectionManager = new UserConnectionManager();
|
|
|
|
var sut = new ServerEventUserManager(connectionManager, authorizationService, mocks.HubContextMock.Object);
|
|
await sut.RefreshGroupsAsync(user);
|
|
|
|
// Ensure AddToGroupAsync was never called.
|
|
mocks.GroupManagerMock.Verify(x => x.AddToGroupAsync(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<CancellationToken>()), Times.Never);
|
|
}
|
|
|
|
private ClaimsPrincipal CreateFakeUser(Guid key) =>
|
|
new(new ClaimsIdentity([
|
|
|
|
// This is the claim that's used to store the ID
|
|
new Claim(Constants.Security.OpenIdDictSubClaimType, key.ToString())
|
|
]));
|
|
|
|
private IServerEventAuthorizationService CreateServeEventAuthorizationService(params IEnumerable<IEventSourceAuthorizer> authorizers)
|
|
=> new ServerEventAuthorizationService(new EventSourceAuthorizerCollection(() => authorizers));
|
|
|
|
private (Mock<IServerEventHub> HubMock, Mock<IHubClients<IServerEventHub>> HubClientsMock, Mock<IGroupManager> GroupManagerMock, Mock<IHubContext<ServerEventHub, IServerEventHub>> HubContextMock) CreateHubContextMocks()
|
|
{
|
|
var hubMock = new Mock<IServerEventHub>();
|
|
|
|
var hubClients = new Mock<IHubClients<IServerEventHub>>();
|
|
hubClients.Setup(x => x.All).Returns(hubMock.Object);
|
|
|
|
var groupManagerMock = new Mock<IGroupManager>();
|
|
|
|
var hubContext = new Mock<IHubContext<ServerEventHub, IServerEventHub>>();
|
|
hubContext.Setup(x => x.Clients).Returns(hubClients.Object);
|
|
hubContext.Setup(x => x.Groups).Returns(groupManagerMock.Object);
|
|
return (hubMock, hubClients, groupManagerMock, hubContext);
|
|
}
|
|
|
|
}
|