Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
117 commits
Select commit Hold shift + click to select a range
ee0f5f6
feature(#20): this commit introduces client aggregate with properties…
https-richardy Apr 8, 2026
f60a4ba
refactor(#20): remove unused client id and secret hash properties fro…
https-richardy Apr 8, 2026
3487e55
fix(#20): this commit introduces missing global using directive for S…
https-richardy Apr 8, 2026
db0209a
feature(#20): this commit introduces client filters and client filter…
https-richardy Apr 8, 2026
e12a8cc
feature(#20): this commit introduces client collection interface for …
https-richardy Apr 8, 2026
50f2385
feature(#20): this commit introduces clients constant to collections …
https-richardy Apr 8, 2026
68a61d2
refactor(#20): remove unused ClientId constant from Realm and its ref…
https-richardy Apr 8, 2026
1f82b07
feature(#20): this commit introduces client constants for client mana…
https-richardy Apr 8, 2026
45c476c
feature(#20): introduces realm id property to client class for enhanc…
https-richardy Apr 8, 2026
15ed3b6
feature(#20): this commit introduces realm id property to client filt…
https-richardy Apr 8, 2026
372cedd
feature(#20): this commit introduces client filters stage class for c…
https-richardy Apr 8, 2026
441d909
feature(#20): introduce client collection class for managing client d…
https-richardy Apr 8, 2026
183ff01
feature(#20): this commit introduces client collection registration f…
https-richardy Apr 8, 2026
95dc386
feature(#20): introduce client indexes for enhanced database indexing…
https-richardy Apr 8, 2026
6d861ce
feature(#20): remove redundant realm filtering tests for client id an…
https-richardy Apr 8, 2026
456bda1
feature(#20): this commit introduces client persistence tests to veri…
https-richardy Apr 8, 2026
5e7d2fe
refactor(#20): replace realm parameter with client in security token …
https-richardy Apr 8, 2026
41688a6
feature(#20): refactor handler to use client collection instead of re…
https-richardy Apr 8, 2026
12d5330
refactor(#20): simplify methods by removing clientId and secretHash p…
https-richardy Apr 8, 2026
0e17733
feature(#20): this commit updates the method to use client instead o…
https-richardy Apr 8, 2026
7b4d031
feature(#20): this commit introduces client permissions to permission…
https-richardy Apr 8, 2026
98dbd27
feature(#20): this commit introduces missing global using for domain.…
https-richardy Apr 8, 2026
5f3836a
feature(#20): this commit introduces client support in bootstrapper e…
https-richardy Apr 8, 2026
462cf09
feature(#20): this commit introduces default client to realm and set …
https-richardy Apr 8, 2026
4f6d720
feature(#20): this commit updates handler to use client collection in…
https-richardy Apr 8, 2026
ccdd777
feature(#20): introduces client creation scheme and its validator for…
https-richardy Apr 8, 2026
56d469d
feature(#20): introduces missing global using for client payloads and…
https-richardy Apr 8, 2026
aa03e39
feature(#20): introduces client creation scheme validator to validati…
https-richardy Apr 8, 2026
63d2f33
refactor(#20): simplify realm creation by removing unnecessary parame…
https-richardy Apr 8, 2026
c1a4abf
feature(#20): this commit introduces the “client id” property for pub…
https-richardy Apr 9, 2026
063f04e
feature(#20): this commit introduces the "client id" query parameter …
https-richardy Apr 9, 2026
1d6efdd
feature(#20): )this commit introduces the "client id" property to the…
https-richardy Apr 9, 2026
acb4f3c
feature(#20): this commit introduces the "client id" query parameter …
https-richardy Apr 9, 2026
2c70a95
feature(#20): this commit introduces new unique and composite query i…
https-richardy Apr 9, 2026
d522246
feature(#20): this commit introduces a new mapper dedicated to the cl…
https-richardy Apr 9, 2026
839f47e
feature(#20): this commit introduces a new handler responsible for cr…
https-richardy Apr 9, 2026
a51e1ad
feature(#20): this commit adds a forgotten global usage directive to …
https-richardy Apr 9, 2026
6f133a9
fix(#20): this commit fixes the breaking changes in the interface, al…
https-richardy Apr 10, 2026
d8710b8
feature(#20): this commit introduces a new controller responsible for…
https-richardy Apr 10, 2026
e2c7e86
feature(#20): it includes the client scheme class in the payloads nam…
https-richardy Apr 14, 2026
88691fd
feature(#20): this commit introduces the record class representing th…
https-richardy Apr 14, 2026
e444a45
feature(#20): this commit introduces a new method in the client mappe…
https-richardy Apr 14, 2026
e628a61
feature(#20): this commit introduces a new handler for filtering and …
https-richardy Apr 14, 2026
5184208
feature(#20): this commit introduces a new endpoint for obtaining cli…
https-richardy Apr 14, 2026
5591394
feature(#20): this commit includes annotation in the clients controll…
https-richardy Apr 15, 2026
e236dc4
feature(#20): this commit includes the static class `clients conventi…
https-richardy Apr 15, 2026
36af1b1
feature(#20): this commit includes the filter using `FilterDefinition…
https-richardy Apr 15, 2026
cbff935
feature(#20): this commit introduces a handler to process the list of…
https-richardy Apr 15, 2026
9e52e71
feature(#20): this commit introduces the static readonly error 'clien…
https-richardy Apr 15, 2026
8e2e179
feature(#20): includes the GET route /{id}/permissions in the clients…
https-richardy Apr 15, 2026
937bce0
feature(#20): this commit introduces a scheme and its validator.
https-richardy Apr 15, 2026
c4db240
feature(#20): implements a handler to update clients, including searc…
https-richardy Apr 15, 2026
6a19ee4
feature(#20): this commit introduces the mapper for mapping an update…
https-richardy Apr 15, 2026
354d0e2
feature(#20): this commit introduces the PUT endpoint for updating cl…
https-richardy Apr 15, 2026
cc837c6
feature(#20): this commit introduces scheme and its validator for man…
https-richardy Apr 16, 2026
5cd2bd8
feature(#20): implement client handler for managing client permissions
https-richardy Apr 16, 2026
3ee4be3
feature(#20): this commit introduces error for client already having …
https-richardy Apr 16, 2026
f808fcf
feature(#20): this commit introduces validator for assigning client p…
https-richardy Apr 16, 2026
26765bb
feature(#20): this commit introduces endpoint and conventions for ass…
https-richardy Apr 16, 2026
9d824a8
feature(#20): this commit introduces endpoint and conventions for rev…
https-richardy Apr 16, 2026
a951bf5
feature(#20): this commit introduces handler and scheme for revoking …
https-richardy Apr 16, 2026
9961118
feature(#20): this commit error for permission not assigned to client
https-richardy Apr 16, 2026
dd7c827
feature(#20): this commit introduces endpoint and conventions for del…
https-richardy Apr 16, 2026
a892d6c
feature(#20): this commit introduces handler and scheme for client de…
https-richardy Apr 16, 2026
7c2b5d0
feature(#20): update client credentials generation to use clientName …
https-richardy Apr 16, 2026
3bee2eb
feature(#20): this commit introduces error for client already exists
https-richardy Apr 16, 2026
62a86af
feature(#20): this commit introduces conflict response for existing c…
https-richardy Apr 16, 2026
edbf843
feature(#20): this commit introduces client existence check during cr…
https-richardy Apr 16, 2026
03e51ac
feature(#20): this commit introduces conflict response for existing c…
https-richardy Apr 16, 2026
2a77132
feature(#20): this commit introduces client name check during update …
https-richardy Apr 16, 2026
cf68875
refactor(#20): this commit removes "with realm id" method and update …
https-richardy Apr 16, 2026
32a852a
feature(#20): this commit updates client credentials grant handler to…
https-richardy Apr 16, 2026
2f67013
feature(#20): this commit update client credentials generation to use…
https-richardy Apr 16, 2026
ba2f910
feature(#20): this commit introduces missing global using directives …
https-richardy Apr 16, 2026
b71a1a4
feature(#20): this commit fixes hash secret comparasion
https-richardy Apr 17, 2026
c0f5a6b
feature(#20): rewrite the tests to explicitly create and authenticate…
https-richardy Apr 17, 2026
9204baf
fix(#20): this commit fixes the test logic, which previously treated …
https-richardy Apr 17, 2026
6abffed
feature(#20): this commit fixes the logic of the validation test wher…
https-richardy Apr 17, 2026
43ee72a
feature(#20): this commit removes client-id references from realms an…
https-richardy Apr 17, 2026
60bc136
feature(#20): this commit fixes the authorization logic to support cl…
https-richardy Apr 17, 2026
a7557a4
feature(#20): this commit introduces persistence tests to verify that…
https-richardy Apr 17, 2026
9944bff
feature(#20): includes a suite of end-to-end tests covering paginated…
https-richardy Apr 17, 2026
94ff943
feature(#20): this commit renames the argument variable in the lambda…
https-richardy Apr 17, 2026
206b5ff
feature(#20): this commit adds integration tests for deleting a client
https-richardy Apr 17, 2026
77e9ecd
feature(#20): this commit adds integration tests to check for a 404 r…
https-richardy Apr 17, 2026
90a771d
feature(#20): this commit adds integration tests for the endpoint tha…
https-richardy Apr 17, 2026
dc6096c
feature(#20): this commit adds integration tests for the permission r…
https-richardy Apr 17, 2026
3235572
feature(#20): this commit restores the return of the client model aft…
https-richardy Apr 17, 2026
dc40a59
feature(#20): this commit updates the API convention to include a sam…
https-richardy Apr 17, 2026
95b72e0
feature(#20): this commit updates the client creation endpoint to ret…
https-richardy Apr 17, 2026
442f746
chore(#20): this commit removes unnecessary and irrelevant comments i…
https-richardy Apr 17, 2026
d679784
refactor(#20): this commit removes client-id and client-secret from r…
https-richardy Apr 18, 2026
2653bbc
refactor(#20): this commit removes client-id property from realm fetc…
https-richardy Apr 18, 2026
10943d3
refactor(#20): this commit removes unnecessary pragma warning directi…
https-richardy Apr 18, 2026
92cfbe7
feature(#20): enhance realm and client creation logic in bootstrapper…
https-richardy Apr 18, 2026
3fada7f
feature(#20): this commit introduces support for assigning audiences …
https-richardy Apr 20, 2026
af8b5fe
feature(#20): this commit introduces a new POST action that allows yo…
https-richardy Apr 20, 2026
93831fc
feature(#20): this commit introduces an API convention to improve the…
https-richardy Apr 20, 2026
0bfa659
feature(#20): this commit introduces end-to-end tests for POST /clien…
https-richardy Apr 20, 2026
fdf3911
feature(#20): this commit renames the test client
https-richardy Apr 20, 2026
226a04d
feature(#20): this commit introduces support for multiple audiences
https-richardy Apr 20, 2026
49b0c92
feature(#20): this commit introduces end-to-end tests for a client's …
https-richardy Apr 20, 2026
7e7b4f6
feature(#20): this commit introduces a handler to revoke a client's a…
https-richardy Apr 20, 2026
f59abdf
feature(#20): this commit introduces an audience association schema v…
https-richardy Apr 20, 2026
0c1f7eb
feature(#20): this commit introduces a new error class related to cli…
https-richardy Apr 20, 2026
ec6459e
feature(#20): this commit introduces an endpoint to revoke a client's…
https-richardy Apr 20, 2026
32a2335
feature(#20): this commit removes error handling for “InvalidAudience…
https-richardy Apr 20, 2026
0b901ca
feature(#20): this commit updates listener tests to use simple names
https-richardy Apr 20, 2026
d684d6a
chore(#20): this commit removes temporary debug variables
https-richardy Apr 20, 2026
8ceda53
feature(#20): this commit removes unnecessary reading of the response…
https-richardy Apr 20, 2026
7c043ec
feature(#20): this commit updates global usings to support
https-richardy Apr 21, 2026
e850ca8
feature(#20): support for multiple audiences in JWT authentication wi…
https-richardy Apr 21, 2026
7c82ffa
feature(#20): this commit introduces new routes in ocelot.json for cl…
https-richardy Apr 21, 2026
c64bbd7
feature(#20): this commit introduces support for multiple audiences i…
https-richardy Apr 21, 2026
49e5a1f
fix: correct docker pull command URL in README.md
https-richardy Apr 21, 2026
0575156
feature(#20): this commit updates README to reflect the new version 4…
https-richardy Apr 21, 2026
96cd3b4
feature(#20)!: this commit updates commit message patterns for versio…
https-richardy Apr 21, 2026
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
@@ -1,16 +1,16 @@
namespace HttpsRichardy.Federation.Application.Handlers.Authorization;

public sealed class AuthorizationHandler(IRealmCollection realmCollection, IRedirectUriPolicy redirectUriPolicy) :
public sealed class AuthorizationHandler(IClientCollection clientCollection, IRedirectUriPolicy redirectUriPolicy) :
IDispatchHandler<AuthorizationParameters, Result<AuthorizationScheme>>
{
public async Task<Result<AuthorizationScheme>> HandleAsync(
AuthorizationParameters parameters, CancellationToken cancellation = default)
{
var filters = new RealmFiltersBuilder()
.WithClientId(parameters.ClientId)
var filters = ClientFilters.WithSpecifications()
.WithIdentifier(parameters.ClientId)
.Build();

var clients = await realmCollection.GetRealmsAsync(filters, cancellation);
var clients = await clientCollection.GetClientsAsync(filters, cancellation);
var client = clients.FirstOrDefault();

if (client is null)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,30 +1,30 @@
namespace HttpsRichardy.Federation.Application.Handlers.Authorization;

public sealed class ClientCredentialsGrantHandler(IRealmCollection realmCollection, ISecurityTokenService tokenService) :
public sealed class ClientCredentialsGrantHandler(IClientCollection clientCollection, ISecurityTokenService tokenService) :
IAuthorizationFlowHandler
{
public Grant Grant => Grant.ClientCredentials;

public async Task<Result<ClientAuthenticationResult>> HandleAsync(ClientAuthenticationCredentials parameters, CancellationToken cancellation = default)
{
var filters = new RealmFiltersBuilder()
var filters = ClientFilters.WithSpecifications()
.WithClientId(parameters.ClientId)
.Build();

var realms = await realmCollection.GetRealmsAsync(filters, cancellation: cancellation);
var realm = realms.FirstOrDefault();
var clients = await clientCollection.GetClientsAsync(filters, cancellation: cancellation);
var client = clients.FirstOrDefault();

if (realm is null)
if (client is null)
{
return Result<ClientAuthenticationResult>.Failure(AuthenticationErrors.ClientNotFound);
}

if (parameters.ClientSecret != realm.SecretHash)
if (parameters.ClientSecret != client.Secret)
{
return Result<ClientAuthenticationResult>.Failure(AuthenticationErrors.InvalidClientCredentials);
}

var tokenResult = await tokenService.GenerateAccessTokenAsync(realm, cancellation);
var tokenResult = await tokenService.GenerateAccessTokenAsync(client, cancellation);
if (tokenResult.IsFailure)
{
return Result<ClientAuthenticationResult>.Failure(tokenResult.Error);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
namespace HttpsRichardy.Federation.Application.Handlers.Client;

public sealed class AssignAudienceClientHandler(IClientCollection clientCollection) :
IDispatchHandler<AssignClientAudienceScheme, Result<IReadOnlyCollection<string>>>
{
public async Task<Result<IReadOnlyCollection<string>>> HandleAsync(
AssignClientAudienceScheme parameters, CancellationToken cancellation = default)
{
var filters = ClientFilters.WithSpecifications()
.WithIdentifier(parameters.Id)
.Build();

var clients = await clientCollection.GetClientsAsync(filters, cancellation);
var client = clients.FirstOrDefault();

if (client is null)
{
return Result<IReadOnlyCollection<string>>.Failure(ClientErrors.ClientDoesNotExist);
}

var audience = new Audience(parameters.Value);
if (client.Audiences.Any(current => current.Value == audience.Value))
{
return Result<IReadOnlyCollection<string>>.Failure(ClientErrors.ClientAlreadyHasAudience);
}

client.Audiences.Add(audience);

await clientCollection.UpdateAsync(client, cancellation);

return Result<IReadOnlyCollection<string>>.Success([.. client.Audiences.Select(current => current.Value)]);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
namespace HttpsRichardy.Federation.Application.Handlers.Client;

public sealed class AssignPermissionClientHandler(IClientCollection clientCollection, IPermissionCollection permissionCollection) :
IDispatchHandler<AssignClientPermissionScheme, Result<IReadOnlyCollection<PermissionDetailsScheme>>>
{
public async Task<Result<IReadOnlyCollection<PermissionDetailsScheme>>> HandleAsync(
AssignClientPermissionScheme parameters, CancellationToken cancellation = default)
{
var clientFilters = ClientFilters.WithSpecifications()
.WithIdentifier(parameters.Id)
.Build();

var permissionFilters = PermissionFilters.WithSpecifications()
.WithName(parameters.PermissionName.ToLower())
.Build();

var clients = await clientCollection.GetClientsAsync(clientFilters, cancellation: cancellation);
var client = clients.FirstOrDefault();

if (client is null)
{
return Result<IReadOnlyCollection<PermissionDetailsScheme>>.Failure(ClientErrors.ClientDoesNotExist);
}

var permissions = await permissionCollection.GetPermissionsAsync(permissionFilters, cancellation: cancellation);
var existingPermission = permissions.FirstOrDefault();

if (existingPermission is null)
{
return Result<IReadOnlyCollection<PermissionDetailsScheme>>.Failure(PermissionErrors.PermissionDoesNotExist);
}

if (client.Permissions.Any(permission => permission.Name == existingPermission.Name))
{
return Result<IReadOnlyCollection<PermissionDetailsScheme>>.Failure(ClientErrors.ClientAlreadyHasPermission);
}

client.Permissions.Add(existingPermission);

await clientCollection.UpdateAsync(client, cancellation: cancellation);

return Result<IReadOnlyCollection<PermissionDetailsScheme>>.Success(PermissionMapper.AsResponse(client.Permissions));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
namespace HttpsRichardy.Federation.Application.Handlers.Client;

public sealed class ClientCreationHandler(IClientCredentialsGenerator credentialsGenerator, IRealmProvider realmProvider, IClientCollection clientCollection) :
IDispatchHandler<ClientCreationScheme, Result<ClientScheme>>
{
public async Task<Result<ClientScheme>> HandleAsync(ClientCreationScheme parameters, CancellationToken cancellation = default)
{
var filters = ClientFilters.WithSpecifications()
.WithName(parameters.Name)
.Build();

var clients = await clientCollection.GetClientsAsync(filters, cancellation: cancellation);
var existingClient = clients.FirstOrDefault();

if (existingClient is not null)
{
return Result<ClientScheme>.Failure(ClientErrors.ClientAlreadyExists);
}

var realm = realmProvider.GetCurrentRealm();
var credentials = await credentialsGenerator.GenerateAsync(parameters.Name, cancellation);

var client = parameters.AsClient(credentials, realm);

await clientCollection.InsertAsync(client, cancellation: cancellation);

return Result<ClientScheme>.Success(client.AsResponse());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
namespace HttpsRichardy.Federation.Application.Handlers.Client;

public sealed class ClientDeletionHandler(IClientCollection collection) : IDispatchHandler<ClientDeletionScheme, Result>
{
public async Task<Result> HandleAsync(ClientDeletionScheme parameters, CancellationToken cancellation = default)
{
var filters = ClientFilters.WithSpecifications()
.WithIdentifier(parameters.Id)
.Build();

var clients = await collection.GetClientsAsync(filters, cancellation: cancellation);
var client = clients.FirstOrDefault();

if (client is null)
{
return Result.Failure(ClientErrors.ClientDoesNotExist);
}

await collection.DeleteAsync(client, cancellation: cancellation);

return Result.Success();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
namespace HttpsRichardy.Federation.Application.Handlers.Client;

public sealed class ClientUpdateHandler(IClientCollection collection) :
IDispatchHandler<ClientUpdateScheme, Result<ClientScheme>>
{
public async Task<Result<ClientScheme>> HandleAsync(
ClientUpdateScheme parameters, CancellationToken cancellation = default)
{
var filters = ClientFilters.WithSpecifications()
.WithIdentifier(parameters.Id)
.Build();

var clients = await collection.GetClientsAsync(filters, cancellation: cancellation);
var client = clients.FirstOrDefault();

if (client is null)
{
return Result<ClientScheme>.Failure(ClientErrors.ClientDoesNotExist);
}

var nameFilter = ClientFilters.WithSpecifications()
.WithName(parameters.Name)
.Build();

var clientsWithSameName = await collection.GetClientsAsync(nameFilter, cancellation: cancellation);
var existingClient = clientsWithSameName.FirstOrDefault(existing => existing.Id != parameters.Id);

if (existingClient is not null)
{
return Result<ClientScheme>.Failure(ClientErrors.ClientAlreadyExists);
}

client = ClientMapper.AsClient(parameters, client);

var updatedClient = await collection.UpdateAsync(client, cancellation: cancellation);

return Result<ClientScheme>.Success(ClientMapper.AsResponse(updatedClient));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
namespace HttpsRichardy.Federation.Application.Handlers.Client;

public sealed class FetchClientsHandler(IClientCollection clientCollection) :
IDispatchHandler<ClientsFetchParameters, Result<Pagination<ClientScheme>>>
{
public async Task<Result<Pagination<ClientScheme>>> HandleAsync(
ClientsFetchParameters parameters, CancellationToken cancellation = default)
{
var filters = ClientFilters.WithSpecifications()
.WithName(parameters.Name)
.WithClientId(parameters.ClientId)
.WithSort(parameters.Sort)
.WithPagination(parameters.Pagination)
.Build();

var clients = await clientCollection.GetClientsAsync(filters, cancellation);
var totalClients = await clientCollection.CountClientsAsync(filters, cancellation);

var pagination = new Pagination<ClientScheme>
{
Items = [.. clients.Select(client => ClientMapper.AsResponse(client))],
Total = (int)totalClients,
PageNumber = parameters.Pagination?.PageNumber ?? 1,
PageSize = parameters.Pagination?.PageSize ?? 20,
};

return Result<Pagination<ClientScheme>>.Success(pagination);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
namespace HttpsRichardy.Federation.Application.Handlers.Client;

public sealed class ListClientAssignedPermissionsHandler(IClientCollection collection) :
IDispatchHandler<ListClientAssignedPermissionsParameters, Result<IReadOnlyCollection<PermissionDetailsScheme>>>
{
public async Task<Result<IReadOnlyCollection<PermissionDetailsScheme>>> HandleAsync(
ListClientAssignedPermissionsParameters parameters, CancellationToken cancellation = default)
{
var filters = ClientFilters.WithSpecifications()
.WithIdentifier(parameters.Id)
.Build();

var clients = await collection.GetClientsAsync(filters, cancellation);
var client = clients.FirstOrDefault();

return client is not null
? Result<IReadOnlyCollection<PermissionDetailsScheme>>.Success(PermissionMapper.AsResponse(client.Permissions))
: Result<IReadOnlyCollection<PermissionDetailsScheme>>.Failure(ClientErrors.ClientDoesNotExist);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
namespace HttpsRichardy.Federation.Application.Handlers.Client;

public sealed class RevokeAudienceFromClientHandler(IClientCollection clientCollection) :
IDispatchHandler<RevokeClientAudienceScheme, Result<IReadOnlyCollection<string>>>
{
public async Task<Result<IReadOnlyCollection<string>>> HandleAsync(
RevokeClientAudienceScheme parameters, CancellationToken cancellation = default)
{
var filters = ClientFilters.WithSpecifications()
.WithIdentifier(parameters.Id)
.Build();

var clients = await clientCollection.GetClientsAsync(filters, cancellation);
var client = clients.FirstOrDefault();

if (client is null)
{
return Result<IReadOnlyCollection<string>>.Failure(ClientErrors.ClientDoesNotExist);
}

var audienceToRemove = client.Audiences.FirstOrDefault(current => current.Value == parameters.Audience);
if (audienceToRemove is null)
{
return Result<IReadOnlyCollection<string>>.Failure(ClientErrors.AudienceNotAssigned);
}

client.Audiences.Remove(audienceToRemove);

await clientCollection.UpdateAsync(client, cancellation);

return Result<IReadOnlyCollection<string>>.Success([.. client.Audiences.Select(current => current.Value)]);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
namespace HttpsRichardy.Federation.Application.Handlers.Client;

public sealed class RevokeClientPermissionHandler(IClientCollection clientCollection, IPermissionCollection permissionCollection) :
IDispatchHandler<RevokeClientPermissionScheme, Result>
{
public async Task<Result> HandleAsync(RevokeClientPermissionScheme parameters, CancellationToken cancellation = default)
{
var permissionFilters = PermissionFilters.WithSpecifications()
.WithIdentifier(parameters.PermissionId)
.Build();

var clientFilters = ClientFilters.WithSpecifications()
.WithIdentifier(parameters.Id)
.Build();

var clients = await clientCollection.GetClientsAsync(clientFilters, cancellation);
var client = clients.FirstOrDefault();

var permissions = await permissionCollection.GetPermissionsAsync(permissionFilters, cancellation);
var permission = permissions.FirstOrDefault();

if (client is null)
{
return Result.Failure(ClientErrors.ClientDoesNotExist);
}

if (permission is null)
{
return Result.Failure(PermissionErrors.PermissionDoesNotExist);
}

var permissionToRemove = client.Permissions.FirstOrDefault(where => where.Id == permission.Id);
if (permissionToRemove is null)
{
return Result.Failure(ClientErrors.PermissionNotAssigned);
}

client.Permissions.Remove(permissionToRemove);

await clientCollection.UpdateAsync(client, cancellation);

return Result.Success();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,7 @@ public async Task<Result<RealmDetailsScheme>> HandleAsync(
}

var credentials = await credentialsGenerator.GenerateAsync(parameters.Name, cancellation: cancellation);
var realm = RealmMapper.AsRealm(
realm: parameters,
clientId: credentials.ClientId,
secretHash: credentials.ClientSecret
);
var realm = RealmMapper.AsRealm(parameters);

var masterFilters = RealmFilters.WithSpecifications()
.WithName("master")
Expand Down
Loading
Loading