Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -98,10 +98,18 @@ private async Task<bool> EvaluateAuthorizationAsync()
var results = new List<bool>();

if (roles.Count > 0)
results.Add(roles.Any(AuthState.IsInRole));
{
results.Add(MatchAll
? roles.All(AuthState.IsInRole)
: roles.Any(AuthState.IsInRole));
}

if (permissions.Count > 0)
results.Add(permissions.Any(AuthState.HasPermission));
{
results.Add(MatchAll
? permissions.All(AuthState.HasPermission)
: permissions.Any(AuthState.HasPermission));
}

if (!string.IsNullOrWhiteSpace(Policy))
results.Add(await EvaluatePolicyAsync());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public async Task<UAuthResult<UserRolesResponse>> GetMyRolesAsync(PageRequest? r
public async Task<UAuthResult<UserRolesResponse>> GetUserRolesAsync(UserKey userKey, PageRequest? request = null)
{
request ??= new PageRequest();
var raw = await _request.SendJsonAsync(Url($"/admin/authorization/users/{userKey}/roles/get"), request);
var raw = await _request.SendJsonAsync(Url($"/admin/authorization/users/{userKey.Value}/roles/get"), request);
return UAuthResultMapper.FromJson<UserRolesResponse>(raw);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,13 @@ public async Task<UAuthResult<PagedResult<SessionChainSummary>>> GetMyChainsAsyn

public async Task<UAuthResult<SessionChainDetail>> GetMyChainDetailAsync(SessionChainId chainId)
{
var raw = await _request.SendFormAsync(Url($"/me/sessions/chains/{chainId}"));
var raw = await _request.SendFormAsync(Url($"/me/sessions/chains/{chainId.Value}"));
return UAuthResultMapper.FromJson<SessionChainDetail>(raw);
}

public async Task<UAuthResult<RevokeResult>> RevokeMyChainAsync(SessionChainId chainId)
{
var raw = await _request.SendJsonAsync(Url($"/me/sessions/chains/{chainId}/revoke"));
var raw = await _request.SendJsonAsync(Url($"/me/sessions/chains/{chainId.Value}/revoke"));
var result = UAuthResultMapper.FromJson<RevokeResult>(raw);

if (result.Value?.CurrentChain == true)
Expand Down Expand Up @@ -73,37 +73,37 @@ public async Task<UAuthResult> RevokeAllMyChainsAsync()
public async Task<UAuthResult<PagedResult<SessionChainSummary>>> GetUserChainsAsync(UserKey userKey, PageRequest? request = null)
{
request ??= new PageRequest();
var raw = await _request.SendJsonAsync(Url($"/admin/users/{userKey}/sessions/chains"), request);
var raw = await _request.SendJsonAsync(Url($"/admin/users/{userKey.Value}/sessions/chains"), request);
return UAuthResultMapper.FromJson<PagedResult<SessionChainSummary>>(raw);
}

public async Task<UAuthResult<SessionChainDetail>> GetUserChainDetailAsync(UserKey userKey, SessionChainId chainId)
{
var raw = await _request.SendFormAsync(Url($"/admin/users/{userKey}/sessions/chains/{chainId}"));
var raw = await _request.SendFormAsync(Url($"/admin/users/{userKey.Value}/sessions/chains/{chainId.Value}"));
return UAuthResultMapper.FromJson<SessionChainDetail>(raw);
}

public async Task<UAuthResult> RevokeUserSessionAsync(UserKey userKey, AuthSessionId sessionId)
{
var raw = await _request.SendFormAsync(Url($"/admin/users/{userKey}/sessions/{sessionId}/revoke"));
var raw = await _request.SendFormAsync(Url($"/admin/users/{userKey.Value}/sessions/{sessionId.Value}/revoke"));
return UAuthResultMapper.From(raw);
}

public async Task<UAuthResult<RevokeResult>> RevokeUserChainAsync(UserKey userKey, SessionChainId chainId)
{
var raw = await _request.SendFormAsync(Url($"/admin/users/{userKey}/sessions/chains/{chainId}/revoke"));
var raw = await _request.SendFormAsync(Url($"/admin/users/{userKey.Value}/sessions/chains/{chainId.Value}/revoke"));
return UAuthResultMapper.FromJson<RevokeResult>(raw);
}

public async Task<UAuthResult> RevokeUserRootAsync(UserKey userKey)
{
var raw = await _request.SendFormAsync(Url($"/admin/users/{userKey}/sessions/revoke-root"));
var raw = await _request.SendFormAsync(Url($"/admin/users/{userKey.Value}/sessions/revoke-root"));
return UAuthResultMapper.From(raw);
}

public async Task<UAuthResult> RevokeAllUserChainsAsync(UserKey userKey)
{
var raw = await _request.SendFormAsync(Url($"/admin/users/{userKey}/sessions/revoke-all"));
var raw = await _request.SendFormAsync(Url($"/admin/users/{userKey.Value}/sessions/revoke-all"));
return UAuthResultMapper.From(raw);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -99,37 +99,37 @@ public async Task<UAuthResult<PagedResult<UserIdentifierInfo>>> GetUserAsync(Use

public async Task<UAuthResult> AddUserAsync(UserKey userKey, AddUserIdentifierRequest request)
{
var raw = await _request.SendJsonAsync(Url($"/admin/users/{userKey}/identifiers/add"), request);
var raw = await _request.SendJsonAsync(Url($"/admin/users/{userKey.Value}/identifiers/add"), request);
return UAuthResultMapper.From(raw);
}

public async Task<UAuthResult> UpdateUserAsync(UserKey userKey, UpdateUserIdentifierRequest request)
{
var raw = await _request.SendJsonAsync(Url($"/admin/users/{userKey}/identifiers/update"), request);
var raw = await _request.SendJsonAsync(Url($"/admin/users/{userKey.Value}/identifiers/update"), request);
return UAuthResultMapper.From(raw);
}

public async Task<UAuthResult> SetUserPrimaryAsync(UserKey userKey, SetPrimaryUserIdentifierRequest request)
{
var raw = await _request.SendJsonAsync(Url($"/admin/users/{userKey}/identifiers/set-primary"), request);
var raw = await _request.SendJsonAsync(Url($"/admin/users/{userKey.Value}/identifiers/set-primary"), request);
return UAuthResultMapper.From(raw);
}

public async Task<UAuthResult> UnsetUserPrimaryAsync(UserKey userKey, UnsetPrimaryUserIdentifierRequest request)
{
var raw = await _request.SendJsonAsync(Url($"/admin/users/{userKey}/identifiers/unset-primary"), request);
var raw = await _request.SendJsonAsync(Url($"/admin/users/{userKey.Value}/identifiers/unset-primary"), request);
return UAuthResultMapper.From(raw);
}

public async Task<UAuthResult> VerifyUserAsync(UserKey userKey, VerifyUserIdentifierRequest request)
{
var raw = await _request.SendJsonAsync(Url($"/admin/users/{userKey}/identifiers/verify"), request);
var raw = await _request.SendJsonAsync(Url($"/admin/users/{userKey.Value}/identifiers/verify"), request);
return UAuthResultMapper.From(raw);
}

public async Task<UAuthResult> DeleteUserAsync(UserKey userKey, DeleteUserIdentifierRequest request)
{
var raw = await _request.SendJsonAsync(Url($"/admin/users/{userKey}/identifiers/delete"), request);
var raw = await _request.SendJsonAsync(Url($"/admin/users/{userKey.Value}/identifiers/delete"), request);
return UAuthResultMapper.From(raw);
}
}
121 changes: 121 additions & 0 deletions tests/CodeBeam.UltimateAuth.Tests.Unit/Bunit/UAuthAppTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
using Bunit;
using CodeBeam.UltimateAuth.Client;
using CodeBeam.UltimateAuth.Client.Abstractions;
using CodeBeam.UltimateAuth.Client.Blazor;
using CodeBeam.UltimateAuth.Client.Infrastructure;
using CodeBeam.UltimateAuth.Tests.Unit.Helpers;
using FluentAssertions;
using Microsoft.AspNetCore.Components;
using Microsoft.Extensions.DependencyInjection;
using Moq;

namespace CodeBeam.UltimateAuth.Tests.Unit;

public class UAuthAppTests
{

private (BunitContext ctx, Mock<IUAuthStateManager> stateManager, Mock<IUAuthClientBootstrapper> bootstrapper, Mock<ISessionCoordinator> coordinator)

CreateUAuthAppTestContext(UAuthState state, bool authenticated = true)
{
var ctx = new BunitContext();

var stateManager = new Mock<IUAuthStateManager>();
stateManager.Setup(x => x.State).Returns(state);
stateManager.Setup(x => x.EnsureAsync(It.IsAny<bool>()))
.Returns(Task.CompletedTask);

var bootstrapper = new Mock<IUAuthClientBootstrapper>();
bootstrapper.Setup(x => x.EnsureStartedAsync())
.Returns(Task.CompletedTask);

var coordinator = new Mock<ISessionCoordinator>();
coordinator.Setup(x => x.StartAsync()).Returns(Task.CompletedTask);
coordinator.Setup(x => x.StopAsync()).Returns(Task.CompletedTask);

ctx.Services.AddSingleton(stateManager.Object);
ctx.Services.AddSingleton(bootstrapper.Object);
ctx.Services.AddSingleton(coordinator.Object);

var auth = ctx.AddAuthorization();
if (authenticated)
auth.SetAuthorized("test-user");
else
auth.SetNotAuthorized();

return (ctx, stateManager, bootstrapper, coordinator);
}

[Fact]
public async Task Should_Initialize_And_Bootstrap_On_First_Render()
{
var state = TestAuthState.Anonymous();
var (ctx, stateManager, bootstrapper, _) = CreateUAuthAppTestContext(state);
var cut = ctx.Render<UAuthApp>();
await cut.InvokeAsync(() => Task.CompletedTask);

bootstrapper.Verify(x => x.EnsureStartedAsync(), Times.Once);
stateManager.Verify(x => x.EnsureAsync(It.IsAny<bool>()), Times.AtLeastOnce);
}

[Fact]
public async Task Should_Start_Coordinator_When_Authenticated()
{
var state = TestAuthState.Authenticated();
var (ctx, _, _, coordinator) = CreateUAuthAppTestContext(state);
var cut = ctx.Render<UAuthApp>();
await cut.InvokeAsync(() => Task.CompletedTask);

coordinator.Verify(x => x.StartAsync(), Times.Once);
}

[Fact]
public async Task Should_Stop_Coordinator_When_State_Cleared()
{
var state = TestAuthState.Authenticated();
var (ctx, _, _, coordinator) = CreateUAuthAppTestContext(state);
var cut = ctx.Render<UAuthApp>();
state.Clear();
await cut.InvokeAsync(() => Task.CompletedTask);

coordinator.Verify(x => x.StopAsync(), Times.Once);
}

[Fact]
public async Task Should_Stop_Coordinator_On_Dispose()
{
var state = TestAuthState.Authenticated();
var (ctx, _, _, coordinator) = CreateUAuthAppTestContext(state);
var cut = ctx.Render<UAuthApp>();
await cut.Instance.DisposeAsync();

coordinator.Verify(x => x.StopAsync(), Times.Once);
}

[Fact]
public async Task Should_Call_Ensure_When_State_Is_Stale()
{
var state = TestAuthState.Authenticated();
state.MarkStale();
var (ctx, stateManager, _, _) = CreateUAuthAppTestContext(state);
var cut = ctx.Render<UAuthApp>();
await cut.InvokeAsync(() => Task.CompletedTask);

stateManager.Verify(x => x.EnsureAsync(true), Times.AtLeastOnce);
}

[Fact]
public async Task Should_Invoke_Callback_On_Reauth()
{
var state = TestAuthState.Authenticated();
var (ctx, _, _, coordinator) = CreateUAuthAppTestContext(state);
var called = false;
var cut = ctx.Render<UAuthApp>(p => p.Add(x => x.OnReauthRequired, EventCallback.Factory.Create(this, () => called = true)));

await cut.InvokeAsync(() => Task.CompletedTask);
coordinator.Raise(x => x.ReauthRequired += null);
await cut.InvokeAsync(() => Task.CompletedTask);

called.Should().BeTrue();
}
}
Loading
Loading