test(bff): /behandel/werkbak needs a medewerker token with the behandelaar role (refs #13)

Red — the medewerker JWT scheme, the behandelaar policy, and the werkbak endpoint
do not exist yet (endpoint 404s).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-15 11:03:36 +02:00
parent 69db103e0e
commit 08515b9bba
4 changed files with 87 additions and 0 deletions

View File

@@ -0,0 +1,57 @@
using System.Net;
using System.Net.Http.Headers;
using System.Net.Http.Json;
using Bff.Api;
namespace Bff.Tests;
/// <summary>
/// The behandel werkbak endpoint (S-12c): reached only with a medewerker-realm token that carries the
/// <c>behandelaar</c> role. A missing token is 401; an authenticated medewerker without the role is
/// 403; a behandelaar gets the werkbak (staff view, incl. bsn).
/// </summary>
public class BehandelEndpointTests
{
private static HttpRequestMessage Werkbak(string? bearer)
{
var request = new HttpRequestMessage(HttpMethod.Get, "/behandel/werkbak");
if (bearer is not null)
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", bearer);
return request;
}
[Fact]
public async Task Rejects_the_werkbak_without_a_token()
{
using var factory = new BffFactory();
var response = await factory.CreateClient().SendAsync(Werkbak(bearer: null));
Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode);
}
[Fact]
public async Task Rejects_a_medewerker_without_the_behandelaar_role()
{
using var factory = new BffFactory();
var response = await factory.CreateClient().SendAsync(Werkbak(TestTokens.Medewerker("teamlead")));
Assert.Equal(HttpStatusCode.Forbidden, response.StatusCode);
}
[Fact]
public async Task Serves_the_werkbak_to_a_behandelaar()
{
using var factory = new BffFactory();
factory.Domain.Werkbak.Add(new WerkbakItem("reg-1", "123456782", "InBehandeling"));
var response = await factory.CreateClient().SendAsync(Werkbak(TestTokens.Medewerker("behandelaar")));
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
var items = await response.Content.ReadFromJsonAsync<List<WerkbakItem>>();
var item = Assert.Single(items!);
Assert.Equal("reg-1", item.RegistrationId);
Assert.Equal("123456782", item.Bsn);
}
}

View File

@@ -60,12 +60,16 @@ internal sealed class FakeDomainClient : IDomainClient
{
public string? SubmittedBsn { get; private set; }
public SubmitAccepted Result { get; set; } = new("reg-123", "Ingediend");
public List<WerkbakItem> Werkbak { get; } = [];
public Task<SubmitAccepted> SubmitRegistrationAsync(string bsn, CancellationToken ct = default)
{
SubmittedBsn = bsn;
return Task.FromResult(Result);
}
public Task<IReadOnlyList<WerkbakItem>> GetWerkbakAsync(CancellationToken ct = default)
=> Task.FromResult<IReadOnlyList<WerkbakItem>>(Werkbak);
}
/// <summary>Serves a configurable set of projection rows.</summary>

View File

@@ -17,6 +17,22 @@ internal static class TestTokens
new SymmetricSecurityKey(Encoding.UTF8.GetBytes("a-different-signing-key-256-bits-long-indeed-yes!")),
expired: false);
/// <summary>A medewerker-realm token carrying the given realm roles under <c>realm_access.roles</c>
/// (Keycloak's shape), signed with the valid test key. Used to exercise behandel authorization.</summary>
public static string Medewerker(params string[] roles)
{
var handler = new JsonWebTokenHandler();
return handler.CreateToken(new SecurityTokenDescriptor
{
Claims = new Dictionary<string, object>
{
["realm_access"] = new Dictionary<string, object> { ["roles"] = roles },
},
Expires = DateTime.UtcNow.AddMinutes(30),
SigningCredentials = new SigningCredentials(BffFactory.TestSigningKey, SecurityAlgorithms.HmacSha256),
});
}
private static string Create(string bsn, SymmetricSecurityKey key, bool expired)
{
var handler = new JsonWebTokenHandler();