From 7ea4d6a30f7c9c7728105159a98d3af765c0fb99 Mon Sep 17 00:00:00 2001 From: Richard Garcia Date: Fri, 13 Mar 2026 01:09:28 -0300 Subject: [PATCH 01/14] feature(#6): this commit introduces the injection of the permissions namespace policy service --- .../Extensions/ApplicationServicesExtension.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Source/HttpsRichardy.Federation.Infrastructure.IoC/Extensions/ApplicationServicesExtension.cs b/Source/HttpsRichardy.Federation.Infrastructure.IoC/Extensions/ApplicationServicesExtension.cs index ba097ba..108da15 100644 --- a/Source/HttpsRichardy.Federation.Infrastructure.IoC/Extensions/ApplicationServicesExtension.cs +++ b/Source/HttpsRichardy.Federation.Infrastructure.IoC/Extensions/ApplicationServicesExtension.cs @@ -9,7 +9,9 @@ public static void AddServices(this IServiceCollection services) services.AddTransient(); services.AddTransient(); services.AddTransient(); + services.AddTransient(); + services.AddTransient(); services.AddTransient(); services.AddTransient(); From 3100f956641488a07b6eca2fcc52b57f84745ef1 Mon Sep 17 00:00:00 2001 From: Richard Garcia Date: Fri, 13 Mar 2026 01:10:29 -0300 Subject: [PATCH 02/14] feature(#6): this commit introduces new 409 responses when attempting to create a reserved permission --- .../Controllers/PermissionsController.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Source/HttpsRichardy.Federation.WebApi/Controllers/PermissionsController.cs b/Source/HttpsRichardy.Federation.WebApi/Controllers/PermissionsController.cs index 38ca261..9e54dec 100644 --- a/Source/HttpsRichardy.Federation.WebApi/Controllers/PermissionsController.cs +++ b/Source/HttpsRichardy.Federation.WebApi/Controllers/PermissionsController.cs @@ -35,6 +35,9 @@ public async Task CreatePermissionAsync([FromBody] PermissionCrea { IsFailure: true } when result.Error == PermissionErrors.PermissionAlreadyExists => StatusCode(StatusCodes.Status409Conflict, result.Error), + + { IsFailure: true } when result.Error == PermissionErrors.PermissionNameIsReserved => + StatusCode(StatusCodes.Status409Conflict, result.Error), }; } @@ -52,6 +55,9 @@ public async Task UpdatePermissionAsync([FromRoute] string id, [F { IsFailure: true } when result.Error == PermissionErrors.PermissionDoesNotExist => StatusCode(StatusCodes.Status404NotFound, result.Error), + + { IsFailure: true } when result.Error == PermissionErrors.PermissionNameIsReserved => + StatusCode(StatusCodes.Status409Conflict, result.Error), }; } From a4dd64e531d56cdc1f84f7866f1c0a9ba3441efc Mon Sep 17 00:00:00 2001 From: Richard Garcia Date: Fri, 13 Mar 2026 01:10:57 -0300 Subject: [PATCH 03/14] feature(#6): this commit introduces the new 409 response into the convention when there is an attempt to create a reserved permission --- .../Conventions/PermissionsConventions.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Source/HttpsRichardy.Federation.WebApi/Conventions/PermissionsConventions.cs b/Source/HttpsRichardy.Federation.WebApi/Conventions/PermissionsConventions.cs index 90fe560..3649ad7 100644 --- a/Source/HttpsRichardy.Federation.WebApi/Conventions/PermissionsConventions.cs +++ b/Source/HttpsRichardy.Federation.WebApi/Conventions/PermissionsConventions.cs @@ -16,6 +16,7 @@ public static void CreatePermissionAsync(PermissionCreationScheme request, Cance [ApiConventionNameMatch(ApiConventionNameMatchBehavior.Prefix)] [ProducesResponseType(typeof(PermissionDetailsScheme), StatusCodes.Status200OK)] [ProducesResponseType(typeof(Error), StatusCodes.Status404NotFound)] + [ProducesResponseType(typeof(Error), StatusCodes.Status409Conflict)] public static void UpdatePermissionAsync(string id, PermissionUpdateScheme request, CancellationToken cancellation) { } [ApiConventionNameMatch(ApiConventionNameMatchBehavior.Prefix)] From 734269d5e275d43db0831b359dfb70702919333d Mon Sep 17 00:00:00 2001 From: Richard Garcia Date: Fri, 13 Mar 2026 01:11:45 -0300 Subject: [PATCH 04/14] feature(#6): this commit introduces new tests to the test suite to ensure that reserved permissions cannot be created --- .../Endpoints/PermissionEndpointTests.cs | 115 ++++++++++++++++++ 1 file changed, 115 insertions(+) diff --git a/Tests/Integration/Endpoints/PermissionEndpointTests.cs b/Tests/Integration/Endpoints/PermissionEndpointTests.cs index 21cb0b0..e923db6 100644 --- a/Tests/Integration/Endpoints/PermissionEndpointTests.cs +++ b/Tests/Integration/Endpoints/PermissionEndpointTests.cs @@ -112,6 +112,76 @@ public async Task WhenPostPermissionsWithDuplicateName_ShouldReturnConflict() Assert.Equal(PermissionErrors.PermissionAlreadyExists, error); } + [Fact(DisplayName = "[e2e] - when POST /permissions in a non-master realm with reserved system name should return 409 #ERROR-7B1E2")] + public async Task WhenPostPermissionsWithReservedSystemNameInNonMasterRealm_ShouldReturnConflict() + { + /* arrange: authenticate in master realm */ + var masterClient = factory.HttpClient.WithRealmHeader("master"); + var masterCredentials = new AuthenticationCredentials + { + Username = "federation.testing.user", + Password = "federation.testing.password" + }; + + var masterAuthenticationResponse = await masterClient.PostAsJsonAsync("api/v1/identity/authenticate", masterCredentials); + var masterAuthenticationResult = await masterAuthenticationResponse.Content.ReadFromJsonAsync(); + + Assert.NotNull(masterAuthenticationResult); + Assert.NotEmpty(masterAuthenticationResult.AccessToken); + + masterClient.WithAuthorization(masterAuthenticationResult.AccessToken); + + /* arrange: create a new realm */ + var realmPayload = _fixture.Build() + .With(realm => realm.Name, $"test-realm-{Guid.NewGuid()}") + .Create(); + + var realmResponse = await masterClient.PostAsJsonAsync("api/v1/realms", realmPayload); + var realm = await realmResponse.Content.ReadFromJsonAsync(); + + Assert.NotNull(realm); + Assert.Equal(HttpStatusCode.Created, realmResponse.StatusCode); + + /* arrange: authenticate realm via OAuth 2.0 client_credentials */ + var oauthCredentials = new Dictionary + { + { "grant_type", "client_credentials" }, + { "client_id", realm.ClientId }, + { "client_secret", realm.ClientSecret } + }; + + var oauthContent = new FormUrlEncodedContent(oauthCredentials); + var connectClient = factory.HttpClient; + + var oauthResponse = await connectClient.PostAsync("api/v1/protocol/open-id/connect/token", oauthContent); + var oauthResult = await oauthResponse.Content.ReadFromJsonAsync(); + + Assert.Equal(HttpStatusCode.OK, oauthResponse.StatusCode); + + Assert.NotNull(oauthResult); + Assert.NotEmpty(oauthResult.AccessToken); + + var realmClient = factory.HttpClient.WithRealmHeader(realm.Name); + + realmClient.WithAuthorization(oauthResult.AccessToken); + + /* act: attempt to create a permission using a reserved system name */ + var payload = _fixture.Build() + .With(permission => permission.Name, Permissions.ViewRealms) + .Create(); + + var response = await realmClient.PostAsJsonAsync("api/v1/permissions", payload); + + /* assert: response should be 409 Conflict */ + Assert.Equal(HttpStatusCode.Conflict, response.StatusCode); + + var error = await response.Content.ReadFromJsonAsync(); + + Assert.NotNull(error); + Assert.Equal(HttpStatusCode.Conflict, response.StatusCode); + Assert.Equal(PermissionErrors.PermissionNameIsReserved, error); + } + [Fact(DisplayName = "[e2e] - when PUT /permissions/{id} with valid data should update permission successfully")] public async Task WhenPutPermissionsWithValidData_ShouldUpdatePermissionSuccessfully() { @@ -160,6 +230,51 @@ public async Task WhenPutPermissionsWithValidData_ShouldUpdatePermissionSuccessf Assert.Equal(updatePayload.Name, updatedPermission.Name); } + [Fact(DisplayName = "[e2e] - when PUT /permissions/{id} with reserved system name should return 409 #ERROR-7B1E2")] + public async Task WhenPutPermissionsWithReservedSystemName_ShouldReturnConflict() + { + /* arrange: authenticate user and get access token */ + var httpClient = factory.HttpClient.WithRealmHeader("master"); + var credentials = new AuthenticationCredentials + { + Username = "federation.testing.user", + Password = "federation.testing.password" + }; + + var authenticationResponse = await httpClient.PostAsJsonAsync("api/v1/identity/authenticate", credentials); + var authenticationResult = await authenticationResponse.Content.ReadFromJsonAsync(); + + Assert.NotNull(authenticationResult); + Assert.NotEmpty(authenticationResult.AccessToken); + + httpClient.WithAuthorization(authenticationResult.AccessToken); + + /* arrange: create a custom permission */ + var createPayload = _fixture.Build() + .With(permission => permission.Name, $"test.permission.{Guid.NewGuid()}") + .Create(); + + var createResponse = await httpClient.PostAsJsonAsync("api/v1/permissions", createPayload); + var permission = await createResponse.Content.ReadFromJsonAsync(); + + Assert.NotNull(permission); + Assert.Equal(HttpStatusCode.Created, createResponse.StatusCode); + + /* act: attempt to rename it to a reserved system permission */ + var updatePayload = _fixture.Build() + .With(update => update.Name, Permissions.ViewRealms) + .Create(); + + var response = await httpClient.PutAsJsonAsync($"api/v1/permissions/{permission.Id}", updatePayload); + var error = await response.Content.ReadFromJsonAsync(); + + /* assert: response should be 409 Conflict */ + Assert.NotNull(error); + + Assert.Equal(HttpStatusCode.Conflict, response.StatusCode); + Assert.Equal(PermissionErrors.PermissionNameIsReserved, error); + } + [Fact(DisplayName = "[e2e] - when PUT /permissions/{id} with non-existent permission should return 404 #ERROR-93697")] public async Task WhenPutPermissionsWithNonExistentPermission_ShouldReturnNotFound() { From a00b7679b6319aaa91bac2f0185b63a83a3b73b6 Mon Sep 17 00:00:00 2001 From: Richard Garcia Date: Fri, 13 Mar 2026 01:12:17 -0300 Subject: [PATCH 05/14] feature(#6): this commit simplifies the creation of reserved permissions in the bootstrapper --- .../Extensions/BootstrapperExtension.cs | 33 ++++--------------- 1 file changed, 6 insertions(+), 27 deletions(-) diff --git a/Source/HttpsRichardy.Federation.WebApi/Extensions/BootstrapperExtension.cs b/Source/HttpsRichardy.Federation.WebApi/Extensions/BootstrapperExtension.cs index 21d02e3..25297a5 100644 --- a/Source/HttpsRichardy.Federation.WebApi/Extensions/BootstrapperExtension.cs +++ b/Source/HttpsRichardy.Federation.WebApi/Extensions/BootstrapperExtension.cs @@ -33,33 +33,12 @@ public static async Task UseBootstrapperAsync(this IApplicationBuilder builder) } defaultRealm.SecretHash = await passwordHasher.HashPasswordAsync(realmCredentials.ClientId + defaultRealm.Name); - defaultRealm.Permissions = [ - new() { Id = Identifier.Generate(), Name = Permissions.CreateGroup, RealmId = defaultRealm.Id }, - new() { Id = Identifier.Generate(), Name = Permissions.DeleteGroup, RealmId = defaultRealm.Id }, - new() { Id = Identifier.Generate(), Name = Permissions.ViewGroups, RealmId = defaultRealm.Id }, - new() { Id = Identifier.Generate(), Name = Permissions.EditGroup, RealmId = defaultRealm.Id }, - - new() { Id = Identifier.Generate(), Name = Permissions.DeleteUser, RealmId = defaultRealm.Id }, - new() { Id = Identifier.Generate(), Name = Permissions.EditUser, RealmId = defaultRealm.Id }, - new() { Id = Identifier.Generate(), Name = Permissions.ViewUsers, RealmId = defaultRealm.Id }, - - new() { Id = Identifier.Generate(), Name = Permissions.CreateRealm, RealmId = defaultRealm.Id }, - new() { Id = Identifier.Generate(), Name = Permissions.DeleteRealm, RealmId = defaultRealm.Id }, - new() { Id = Identifier.Generate(), Name = Permissions.EditRealm, RealmId = defaultRealm.Id }, - new() { Id = Identifier.Generate(), Name = Permissions.ViewRealms, RealmId = defaultRealm.Id }, - - new() { Id = Identifier.Generate(), Name = Permissions.CreatePermission, RealmId = defaultRealm.Id }, - new() { Id = Identifier.Generate(), Name = Permissions.AssignPermissions, RealmId = defaultRealm.Id }, - new() { Id = Identifier.Generate(), Name = Permissions.RevokePermissions, RealmId = defaultRealm.Id }, - new() { Id = Identifier.Generate(), Name = Permissions.ViewPermissions, RealmId = defaultRealm.Id }, - new() { Id = Identifier.Generate(), Name = Permissions.EditPermission, RealmId = defaultRealm.Id }, - new() { Id = Identifier.Generate(), Name = Permissions.DeletePermission, RealmId = defaultRealm.Id }, - - new() { Id = Identifier.Generate(), Name = Permissions.CreateScope, RealmId = defaultRealm.Id }, - new() { Id = Identifier.Generate(), Name = Permissions.EditScope, RealmId = defaultRealm.Id }, - new() { Id = Identifier.Generate(), Name = Permissions.DeleteScope, RealmId = defaultRealm.Id }, - new() { Id = Identifier.Generate(), Name = Permissions.ViewScopes, RealmId = defaultRealm.Id }, - ]; + defaultRealm.Permissions = [.. RealmPermissions.SystemPermissions.Select(permissionName => new Permission + { + Id = Identifier.Generate(), + Name = permissionName, + RealmId = defaultRealm.Id + })]; var scopes = new List { From a4b387ef53f67781fdee514513e4bbf8872113aa Mon Sep 17 00:00:00 2001 From: Richard Garcia Date: Fri, 13 Mar 2026 01:12:47 -0300 Subject: [PATCH 06/14] feature(#6): this commit defines the contract for the permission namespace policy service --- .../Policies/IPermissionNamespacePolicy.cs | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 Source/HttpsRichardy.Federation.Domain/Policies/IPermissionNamespacePolicy.cs diff --git a/Source/HttpsRichardy.Federation.Domain/Policies/IPermissionNamespacePolicy.cs b/Source/HttpsRichardy.Federation.Domain/Policies/IPermissionNamespacePolicy.cs new file mode 100644 index 0000000..356e1f4 --- /dev/null +++ b/Source/HttpsRichardy.Federation.Domain/Policies/IPermissionNamespacePolicy.cs @@ -0,0 +1,20 @@ +namespace HttpsRichardy.Federation.Domain.Policies; + +// defines a policy responsible for protecting the system permission namespace +// from unauthorized usage by realms + +// certain permissions are reserved by the federation system and represent +// privileged administrative capabilities (e.g. managing realms or federation resources) + +// this policy ensures that realms cannot create or manipulate permissions +// whose identifiers belong to the reserved system namespace, preventing +// privilege escalation through permission name collision + +public interface IPermissionNamespacePolicy +{ + public Task EnsurePermissionIsAllowedAsync( + Realm realm, + Permission permission, + CancellationToken cancellation = default + ); +} From 52f26dbfc043ec5f905f8e949f32c28cf432374a Mon Sep 17 00:00:00 2001 From: Richard Garcia Date: Fri, 13 Mar 2026 01:13:23 -0300 Subject: [PATCH 07/14] feature(#6): this commit defines the new error representing the error of attempting to create a reserved permission --- .../Errors/PermissionErrors.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Source/HttpsRichardy.Federation.Domain/Errors/PermissionErrors.cs b/Source/HttpsRichardy.Federation.Domain/Errors/PermissionErrors.cs index 04083dc..d43db90 100644 --- a/Source/HttpsRichardy.Federation.Domain/Errors/PermissionErrors.cs +++ b/Source/HttpsRichardy.Federation.Domain/Errors/PermissionErrors.cs @@ -7,6 +7,11 @@ public static class PermissionErrors Description: "The permission with the specified name already exists." ); + public static readonly Error PermissionNameIsReserved = new( + Code: "#ERROR-7B1E2", + Description: "The permission name is reserved by the system." + ); + public static readonly Error PermissionDoesNotExist = new( Code: "#ERROR-93697", Description: "The specified permission does not exist." From 2b7749b35f42883df1ba757cbe91c98c6689313b Mon Sep 17 00:00:00 2001 From: Richard Garcia Date: Fri, 13 Mar 2026 01:14:30 -0300 Subject: [PATCH 08/14] feature(#6): this commit introduces security policy restrictions/checks so that reserved permissions cannot be created, preventing privilege escalation. --- .../Handlers/Permission/PermissionCreationHandler.cs | 11 +++++++++-- .../Handlers/Permission/PermissionUpdateHandler.cs | 10 ++++++++-- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/Source/HttpsRichardy.Federation.Application/Handlers/Permission/PermissionCreationHandler.cs b/Source/HttpsRichardy.Federation.Application/Handlers/Permission/PermissionCreationHandler.cs index b04fbd2..8a26dbb 100644 --- a/Source/HttpsRichardy.Federation.Application/Handlers/Permission/PermissionCreationHandler.cs +++ b/Source/HttpsRichardy.Federation.Application/Handlers/Permission/PermissionCreationHandler.cs @@ -1,11 +1,18 @@ namespace HttpsRichardy.Federation.Application.Handlers.Permission; -public sealed class PermissionCreationHandler(IPermissionCollection collection, IRealmProvider realmProvider) : +public sealed class PermissionCreationHandler(IPermissionCollection collection, IPermissionNamespacePolicy policy, IRealmProvider realmProvider) : IDispatchHandler> { public async Task> HandleAsync(PermissionCreationScheme parameters, CancellationToken cancellation = default) { var realm = realmProvider.GetCurrentRealm(); + var result = await policy.EnsurePermissionIsAllowedAsync(realm, new() { Name = parameters.Name }, cancellation); + + if (result.IsFailure) + { + return Result.Failure(PermissionErrors.PermissionNameIsReserved); + } + var filters = PermissionFilters.WithSpecifications() .WithName(parameters.Name) .Build(); @@ -23,4 +30,4 @@ public async Task> HandleAsync(PermissionCreatio return Result.Success(PermissionMapper.AsResponse(createdPermission)); } -} \ No newline at end of file +} diff --git a/Source/HttpsRichardy.Federation.Application/Handlers/Permission/PermissionUpdateHandler.cs b/Source/HttpsRichardy.Federation.Application/Handlers/Permission/PermissionUpdateHandler.cs index 89a6af9..cea626e 100644 --- a/Source/HttpsRichardy.Federation.Application/Handlers/Permission/PermissionUpdateHandler.cs +++ b/Source/HttpsRichardy.Federation.Application/Handlers/Permission/PermissionUpdateHandler.cs @@ -1,6 +1,6 @@ namespace HttpsRichardy.Federation.Application.Handlers.Permission; -public sealed class PermissionUpdateHandler(IPermissionCollection collection, IRealmProvider realmProvider) : +public sealed class PermissionUpdateHandler(IPermissionCollection collection, IPermissionNamespacePolicy policy, IRealmProvider realmProvider) : IDispatchHandler> { public async Task> HandleAsync(PermissionUpdateScheme parameters, CancellationToken cancellation = default) @@ -18,10 +18,16 @@ public async Task> HandleAsync(PermissionUpdateS return Result.Failure(PermissionErrors.PermissionDoesNotExist); } + var result = await policy.EnsurePermissionIsAllowedAsync(realm, new() { Name = parameters.Name }, cancellation); + if (result.IsFailure) + { + return Result.Failure(PermissionErrors.PermissionNameIsReserved); + } + permission = PermissionMapper.AsPermission(parameters, permission, realm); var updatedPermission = await collection.UpdateAsync(permission, cancellation: cancellation); return Result.Success(PermissionMapper.AsResponse(updatedPermission)); } -} \ No newline at end of file +} From 94f58a62d6c53664c27992f1191177e1d723ac80 Mon Sep 17 00:00:00 2001 From: Richard Garcia Date: Fri, 13 Mar 2026 01:15:11 -0300 Subject: [PATCH 09/14] feature(#6): this commit renames the static constant class --- .../Handlers/Realm/RealmCreationHandler.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/HttpsRichardy.Federation.Application/Handlers/Realm/RealmCreationHandler.cs b/Source/HttpsRichardy.Federation.Application/Handlers/Realm/RealmCreationHandler.cs index d8467ba..263e4f0 100644 --- a/Source/HttpsRichardy.Federation.Application/Handlers/Realm/RealmCreationHandler.cs +++ b/Source/HttpsRichardy.Federation.Application/Handlers/Realm/RealmCreationHandler.cs @@ -31,7 +31,7 @@ public async Task> HandleAsync( var defaultRealm = matchingRealms.FirstOrDefault()!; realm.Permissions = defaultRealm.Permissions - .Where(permission => DefaultRealmPermissions.InitialPermissions.Contains(permission.Name)) + .Where(permission => RealmPermissions.InitialPermissions.Contains(permission.Name)) .ToList(); await collection.InsertAsync(realm, cancellation: cancellation); From 84c8a7680f4d95e5bcfe57444b76e333427b81e8 Mon Sep 17 00:00:00 2001 From: Richard Garcia Date: Fri, 13 Mar 2026 01:15:52 -0300 Subject: [PATCH 10/14] feature(#6): this commit introduces the implementation of the permissions namespace policy service --- .../Policies/PermissionNamespacePolicy.cs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 Source/HttpsRichardy.Federation.Application/Policies/PermissionNamespacePolicy.cs diff --git a/Source/HttpsRichardy.Federation.Application/Policies/PermissionNamespacePolicy.cs b/Source/HttpsRichardy.Federation.Application/Policies/PermissionNamespacePolicy.cs new file mode 100644 index 0000000..c5b617b --- /dev/null +++ b/Source/HttpsRichardy.Federation.Application/Policies/PermissionNamespacePolicy.cs @@ -0,0 +1,15 @@ +namespace HttpsRichardy.Federation.Application.Policies; + +public sealed class PermissionNamespacePolicy : IPermissionNamespacePolicy +{ + public async Task EnsurePermissionIsAllowedAsync( + Realm realm, Permission permission, CancellationToken cancellation = default) + { + var isReserved = RealmPermissions.SystemPermissions + .Contains(permission.Name); + + return isReserved + ? Result.Failure(PermissionErrors.PermissionNameIsReserved) + : Result.Success(); + } +} From 32aa29de7948148c4621228f448818afb8eb6d94 Mon Sep 17 00:00:00 2001 From: Richard Garcia Date: Fri, 13 Mar 2026 01:16:19 -0300 Subject: [PATCH 11/14] feature(#6): this commit removes unnecessary global usage directive --- Source/HttpsRichardy.Federation.Application/Usings.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/Source/HttpsRichardy.Federation.Application/Usings.cs b/Source/HttpsRichardy.Federation.Application/Usings.cs index 3647bab..154c608 100644 --- a/Source/HttpsRichardy.Federation.Application/Usings.cs +++ b/Source/HttpsRichardy.Federation.Application/Usings.cs @@ -30,7 +30,6 @@ global using HttpsRichardy.Federation.Application.Providers; global using HttpsRichardy.Federation.Application.Mappers; global using HttpsRichardy.Federation.Application.Utilities; -global using HttpsRichardy.Federation.Application.Handlers.Authorization; global using FluentValidation; global using HttpsRichardy.Dispatcher.Contracts; From a087c3f84096c5ce35b745cba349ce658a78b8e0 Mon Sep 17 00:00:00 2001 From: Richard Garcia Date: Fri, 13 Mar 2026 01:16:58 -0300 Subject: [PATCH 12/14] feature(#6): this commit renames the file and adds hash set for reserved permissions --- .../Constants/DefaultRealmPermissions.cs | 28 --------- .../Constants/RealmPermissions.cs | 57 +++++++++++++++++++ 2 files changed, 57 insertions(+), 28 deletions(-) delete mode 100644 Source/HttpsRichardy.Federation.Common/Constants/DefaultRealmPermissions.cs create mode 100644 Source/HttpsRichardy.Federation.Common/Constants/RealmPermissions.cs diff --git a/Source/HttpsRichardy.Federation.Common/Constants/DefaultRealmPermissions.cs b/Source/HttpsRichardy.Federation.Common/Constants/DefaultRealmPermissions.cs deleted file mode 100644 index ff59119..0000000 --- a/Source/HttpsRichardy.Federation.Common/Constants/DefaultRealmPermissions.cs +++ /dev/null @@ -1,28 +0,0 @@ -namespace HttpsRichardy.Federation.Common.Constants; - -public static class DefaultRealmPermissions -{ - public static readonly string[] InitialPermissions = - [ - Permissions.CreateGroup, - Permissions.DeleteGroup, - Permissions.ViewGroups, - Permissions.EditGroup, - - Permissions.DeleteUser, - Permissions.EditUser, - Permissions.ViewUsers, - - Permissions.CreatePermission, - Permissions.AssignPermissions, - Permissions.RevokePermissions, - Permissions.ViewPermissions, - Permissions.EditPermission, - Permissions.DeletePermission, - - Permissions.CreateScope, - Permissions.EditScope, - Permissions.DeleteGroup, - Permissions.ViewScopes - ]; -} diff --git a/Source/HttpsRichardy.Federation.Common/Constants/RealmPermissions.cs b/Source/HttpsRichardy.Federation.Common/Constants/RealmPermissions.cs new file mode 100644 index 0000000..d99beb3 --- /dev/null +++ b/Source/HttpsRichardy.Federation.Common/Constants/RealmPermissions.cs @@ -0,0 +1,57 @@ +namespace HttpsRichardy.Federation.Common.Constants; + +public static class RealmPermissions +{ + public static readonly HashSet InitialPermissions = + [ + Permissions.CreateGroup, + Permissions.DeleteGroup, + Permissions.ViewGroups, + Permissions.EditGroup, + + Permissions.DeleteUser, + Permissions.EditUser, + Permissions.ViewUsers, + + Permissions.CreatePermission, + Permissions.AssignPermissions, + Permissions.RevokePermissions, + Permissions.ViewPermissions, + Permissions.EditPermission, + Permissions.DeletePermission, + + Permissions.CreateScope, + Permissions.EditScope, + Permissions.DeleteGroup, + Permissions.ViewScopes + ]; + + public static readonly HashSet SystemPermissions = + [ + Permissions.CreateGroup, + Permissions.DeleteGroup, + Permissions.EditGroup, + Permissions.ViewGroups, + + Permissions.DeleteUser, + Permissions.EditUser, + Permissions.ViewUsers, + + Permissions.CreatePermission, + Permissions.AssignPermissions, + Permissions.RevokePermissions, + Permissions.ViewPermissions, + Permissions.EditPermission, + Permissions.DeletePermission, + + Permissions.CreateRealm, + Permissions.DeleteRealm, + Permissions.EditRealm, + Permissions.ViewRealms, + + Permissions.CreateScope, + Permissions.EditScope, + Permissions.DeleteScope, + Permissions.ViewScopes + ]; +} From e60544bb3d5e3cb892b28c92feb5852b1fa07d7c Mon Sep 17 00:00:00 2001 From: Richard Garcia Date: Fri, 13 Mar 2026 01:17:39 -0300 Subject: [PATCH 13/14] =?UTF-8?q?feature(#6):=20this=20commit=20introduces?= =?UTF-8?q?=20global=20usage=20reference=20to=20the=20=E2=80=9Ccommon.cons?= =?UTF-8?q?tants=E2=80=9D=20namespace?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Tests/Usings.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Tests/Usings.cs b/Tests/Usings.cs index bc3f51e..7be8b25 100644 --- a/Tests/Usings.cs +++ b/Tests/Usings.cs @@ -17,6 +17,7 @@ global using HttpsRichardy.Federation.Domain.Aggregates; global using HttpsRichardy.Federation.Domain.Filtering; global using HttpsRichardy.Federation.Domain.Collections; +global using HttpsRichardy.Federation.Common.Constants; global using HttpsRichardy.Federation.Application.Services; global using HttpsRichardy.Federation.Application.Providers; From 191a89dad3c8c0438b41e40f974866f7955568e9 Mon Sep 17 00:00:00 2001 From: Richard Garcia Date: Fri, 13 Mar 2026 01:18:17 -0300 Subject: [PATCH 14/14] feature(#6): this commit fixes non-deterministic behaviors when running tests, correctly cleaning up resources --- Tests/Integration/Fixtures/MongoDatabaseFixture.cs | 5 +++-- Tests/Integration/Fixtures/WebApplicationFixture.cs | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Tests/Integration/Fixtures/MongoDatabaseFixture.cs b/Tests/Integration/Fixtures/MongoDatabaseFixture.cs index 9d61b9d..1d0f4dd 100644 --- a/Tests/Integration/Fixtures/MongoDatabaseFixture.cs +++ b/Tests/Integration/Fixtures/MongoDatabaseFixture.cs @@ -40,8 +40,9 @@ public async Task InitializeAsync() public async Task CleanDatabaseAsync() { - var cursor = await Database.ListCollectionNamesAsync(); - var collections = await cursor.ToListAsync(); + var collections = await Database + .ListCollectionNames() + .ToListAsync(); foreach (var collectionName in collections) { diff --git a/Tests/Integration/Fixtures/WebApplicationFixture.cs b/Tests/Integration/Fixtures/WebApplicationFixture.cs index 5cc1ec3..da5faaf 100644 --- a/Tests/Integration/Fixtures/WebApplicationFixture.cs +++ b/Tests/Integration/Fixtures/WebApplicationFixture.cs @@ -17,6 +17,7 @@ public WebApplicationFixture() public async Task InitializeAsync() { await _databaseFixture.InitializeAsync(); + await _databaseFixture.CleanDatabaseAsync(); Environment.SetEnvironmentVariable("Settings__Administration__Username", "federation.testing.user"); Environment.SetEnvironmentVariable("Settings__Administration__Password", "federation.testing.password"); @@ -122,7 +123,6 @@ public async Task DisposeAsync() HttpClient.Dispose(); await _factory.DisposeAsync(); - await _databaseFixture.CleanDatabaseAsync(); await _databaseFixture.DisposeAsync(); } }