Tests voor client api and service

This commit is contained in:
eelke 2026-02-22 09:27:48 +01:00
parent cd2ec646fd
commit 3d73a9914c
12 changed files with 267 additions and 30 deletions

View file

@ -1,14 +1,14 @@
using FluentResults;
using IdentityShroud.Api.Mappers;
using IdentityShroud.Core.Contracts;
using IdentityShroud.Core.Messages.Realm;
using IdentityShroud.Core.Model;
using IdentityShroud.Core.Services;
using Microsoft.AspNetCore.Http.HttpResults;
using Microsoft.AspNetCore.Mvc;
namespace IdentityShroud.Api;
public record ClientCreateReponse(int Id, string ClientId);
/// <summary>
@ -34,13 +34,18 @@ public static class ClientApi
.WithName(ClientGetRouteName);
}
private static Task ClientGet(HttpContext context)
private static Ok<ClientRepresentation> ClientGet(
Guid realmId,
int clientId,
HttpContext context)
{
throw new NotImplementedException();
Client client = (Client)context.Items["ClientEntity"]!;
return TypedResults.Ok(new ClientMapper().ToDto(client));
}
private static async Task<Results<CreatedAtRoute<ClientCreateReponse>, InternalServerError>>
ClientCreate(
Guid realmId,
ClientCreateRequest request,
[FromServices] IClientService service,
HttpContext context,
@ -64,6 +69,5 @@ public static class ClientApi
["realmId"] = realm.Id,
["clientId"] = client.Id,
});
throw new NotImplementedException();
}
}

View file

@ -0,0 +1,16 @@
namespace IdentityShroud.Api;
public record ClientRepresentation
{
public int Id { get; set; }
public Guid RealmId { get; set; }
public required string ClientId { get; set; }
public string? Name { get; set; }
public string? Description { get; set; }
public string? SignatureAlgorithm { get; set; }
public bool AllowClientCredentialsFlow { get; set; } = false;
public required DateTime CreatedAt { get; set; }
}

View file

@ -7,8 +7,9 @@ public class ClientIdValidationFilter(IClientService clientService) : IEndpointF
{
public async ValueTask<object?> InvokeAsync(EndpointFilterInvocationContext context, EndpointFilterDelegate next)
{
Guid realmId = context.Arguments.OfType<Guid>().First();
int id = context.Arguments.OfType<int>().First();
Client? client = await clientService.FindById(id, context.HttpContext.RequestAborted);
Client? client = await clientService.FindById(realmId, id, context.HttpContext.RequestAborted);
if (client is null)
{
return Results.NotFound();

View file

@ -0,0 +1,11 @@
using IdentityShroud.Core.Model;
using Riok.Mapperly.Abstractions;
namespace IdentityShroud.Api.Mappers;
[Mapper]
public partial class ClientMapper
{
[MapperIgnoreSource(nameof(Client.Secrets))]
public partial ClientRepresentation ToDto(Client client);
}

View file

@ -0,0 +1,22 @@
using FluentValidation;
using IdentityShroud.Core.Contracts;
namespace IdentityShroud.Api;
public class ClientCreateRequestValidator : AbstractValidator<ClientCreateRequest>
{
// most of standard ascii minus the control characters and space
private const string ClientIdPattern = "^[\x21-\x7E]+";
private string[] AllowedAlgorithms = [ "RS256", "ES256" ];
public ClientCreateRequestValidator()
{
RuleFor(e => e.ClientId).NotEmpty().MaximumLength(40).Matches(ClientIdPattern);
RuleFor(e => e.Name).MaximumLength(80);
RuleFor(e => e.Description).MaximumLength(2048);
RuleFor(e => e.SignatureAlgorithm)
.Must(v => v is null || AllowedAlgorithms.Contains(v))
.WithMessage($"SignatureAlgorithm must be one of {string.Join(", ", AllowedAlgorithms)} or null");
}
}