thalos-bff/tests/Thalos.Bff.Application.UnitTests/RefreshSessionHandlerTests.cs
José René White Enciso 56510de55e feat(thalos-bff): add canonical session endpoints
Why: standardize session login/refresh/logout/me behavior for web clients behind thalos security boundaries.

What: add canonical routes, cookie policy handling, grpc session calls, compatibility aliases, standardized auth errors, updated contracts, tests, and docs.

Rule: keep BFF as edge adapter over service contracts and preserve identity ownership in thalos.
2026-03-08 14:48:46 -06:00

91 lines
3.4 KiB
C#

using Thalos.Bff.Application.Adapters;
using Thalos.Bff.Application.Handlers;
using Thalos.Bff.Application.Sessions;
using Thalos.Bff.Contracts.Api;
using BuildingBlock.Identity.Contracts.Requests;
using BuildingBlock.Identity.Contracts.Responses;
namespace Thalos.Bff.Application.UnitTests;
public class RefreshSessionHandlerTests
{
[Fact]
public async Task HandleAsync_WhenCalled_MapsThroughContractAdapter()
{
var handler = new RefreshSessionHandler(new FakeThalosServiceClient(), new FakeIdentityEdgeContractAdapter());
var response = await handler.HandleAsync(new RefreshSessionApiRequest("refresh-123", "corr-123"));
Assert.Equal("token-refreshed", response.AccessToken);
Assert.Equal(1800, response.ExpiresInSeconds);
}
private sealed class FakeThalosServiceClient : IThalosServiceClient
{
public Task<SessionTokensResult> StartSessionAsync(IssueIdentityTokenRequest request, string correlationId)
{
return Task.FromResult(new SessionTokensResult(
"token-xyz",
"refresh-xyz",
1800,
request.SubjectId,
request.TenantId,
request.Provider));
}
public Task<IssueIdentityTokenResponse> IssueTokenAsync(IssueIdentityTokenRequest request)
{
return Task.FromResult(new IssueIdentityTokenResponse("token-xyz", 1800));
}
public Task<EvaluateIdentityPolicyResponse> EvaluatePolicyAsync(EvaluateIdentityPolicyRequest request)
{
return Task.FromResult(new EvaluateIdentityPolicyResponse(request.SubjectId, request.PermissionCode, true));
}
public Task<RefreshIdentitySessionResponse> RefreshSessionAsync(RefreshIdentitySessionRequest request)
{
return Task.FromResult(new RefreshIdentitySessionResponse("token-refreshed", 1800));
}
public Task<SessionTokensResult> RefreshSessionTokensAsync(RefreshIdentitySessionRequest request)
{
return Task.FromResult(new SessionTokensResult(
"token-refreshed",
request.RefreshToken,
1800,
"user-1",
"tenant-1",
request.Provider));
}
}
private sealed class FakeIdentityEdgeContractAdapter : IIdentityEdgeContractAdapter
{
public EvaluateIdentityPolicyRequest ToPolicyRequest(IssueTokenApiRequest request, string permissionCode)
{
return new EvaluateIdentityPolicyRequest(request.SubjectId, request.TenantId, permissionCode);
}
public IssueIdentityTokenRequest ToIssueTokenRequest(IssueTokenApiRequest request)
{
return new IssueIdentityTokenRequest(request.SubjectId, request.TenantId);
}
public IssueTokenApiResponse ToIssueTokenApiResponse(IssueIdentityTokenResponse response)
{
return new IssueTokenApiResponse(response.Token, response.ExpiresInSeconds);
}
public RefreshIdentitySessionRequest ToRefreshSessionRequest(RefreshSessionApiRequest request)
{
return new RefreshIdentitySessionRequest(request.RefreshToken, request.CorrelationId);
}
public RefreshSessionApiResponse ToRefreshSessionApiResponse(RefreshIdentitySessionResponse response)
{
return new RefreshSessionApiResponse(response.Token, response.ExpiresInSeconds);
}
}
}