diff --git a/apps/services/auth/admin-api/src/app/v2/scopes/test/me-scopes.spec.ts b/apps/services/auth/admin-api/src/app/v2/scopes/test/me-scopes.spec.ts index d85cc5ba1808..89618911bb21 100644 --- a/apps/services/auth/admin-api/src/app/v2/scopes/test/me-scopes.spec.ts +++ b/apps/services/auth/admin-api/src/app/v2/scopes/test/me-scopes.spec.ts @@ -12,6 +12,7 @@ import { ApiScopeDelegationType, AdminPatchScopeDto, ApiScope, + SUPER_USER_DELEGATION_TYPES, } from '@island.is/auth-api-lib' import { FixtureFactory } from '@island.is/services/auth/testing' import { @@ -127,6 +128,10 @@ const createTestData = async ({ AuthDelegationType.LegalGuardian, AuthDelegationProvider.NationalRegistry, ], + [ + AuthDelegationType.LegalRepresentative, + AuthDelegationProvider.DistrictCommissionersRegistry, + ], ].map(async ([delegationType, provider]) => fixtureFactory.createDelegationType({ id: delegationType, @@ -374,6 +379,8 @@ interface PatchTestCase { allowExplicitDelegationGrant?: boolean grantToPersonalRepresentatives?: boolean isAccessControlled?: boolean + addedDelegationTypes?: AuthDelegationType[] + removedDelegationTypes?: AuthDelegationType[] } expected: { status: number @@ -513,6 +520,44 @@ const patchTestCases: Record = { }, } +const expected403Response = { + status: 403, + body: { + title: 'Forbidden', + status: 403, + detail: 'User does not have access to update admin controlled fields', + type: 'https://httpstatuses.org/403', + }, +} + +SUPER_USER_DELEGATION_TYPES.map((delegationType) => { + const delegationTypeName = AuthDelegationType[delegationType] + + patchTestCases[ + `should return a forbidden exception when adding super user delegation type: ${delegationTypeName}` + ] = { + user: currentUser, + tenantId: TENANT_ID, + scopeName: mockedPatchApiScope.name, + input: { + addedDelegationTypes: [delegationType], + }, + expected: expected403Response, + } + + patchTestCases[ + `should return a forbidden exception when removing super user delegation type: ${delegationTypeName}` + ] = { + user: currentUser, + tenantId: TENANT_ID, + scopeName: mockedPatchApiScope.name, + input: { + removedDelegationTypes: [delegationType], + }, + expected: expected403Response, + } +}) + describe('MeScopesController', () => { describe('with auth', () => { // GET: /v2/me/tenants/:tenantId/scopes @@ -761,7 +806,7 @@ describe('MeScopesController', () => { }) }) - describe('PATCH: /v2/me/tenants/:tenantId/scopes/:scopeName', () => { + describe('PATCH: /v2/me/tenants/:tenantId/scopes/:scopeName as super user', () => { let app: TestApp let server: request.SuperTest let apiScopeDelegationTypeModel: typeof ApiScopeDelegationType @@ -831,6 +876,7 @@ describe('MeScopesController', () => { AuthDelegationType.LegalGuardian, AuthDelegationType.ProcurationHolder, AuthDelegationType.PersonalRepresentative, + AuthDelegationType.LegalRepresentative, ], }, expected: { @@ -845,6 +891,7 @@ describe('MeScopesController', () => { AuthDelegationType.LegalGuardian, AuthDelegationType.ProcurationHolder, AuthDelegationType.PersonalRepresentative, + AuthDelegationType.LegalRepresentative, ], }, }) @@ -858,6 +905,7 @@ describe('MeScopesController', () => { AuthDelegationType.LegalGuardian, AuthDelegationType.ProcurationHolder, AuthDelegationType.PersonalRepresentative, + AuthDelegationType.LegalRepresentative, ], }, expected: { @@ -872,6 +920,7 @@ describe('MeScopesController', () => { AuthDelegationType.LegalGuardian, AuthDelegationType.ProcurationHolder, AuthDelegationType.PersonalRepresentative, + AuthDelegationType.LegalRepresentative, ], }, }) @@ -883,6 +932,7 @@ describe('MeScopesController', () => { AuthDelegationType.LegalGuardian, AuthDelegationType.ProcurationHolder, AuthDelegationType.PersonalRepresentative, + AuthDelegationType.LegalRepresentative, ], }, expected: { @@ -949,7 +999,7 @@ describe('MeScopesController', () => { }) }) - describe('POST: /v2/me/tenants/:tenantId/scopes', () => { + describe('POST: /v2/me/tenants/:tenantId/scopes as super user', () => { let app: TestApp let server: request.SuperTest let apiScopeDelegationTypeModel: typeof ApiScopeDelegationType @@ -1035,7 +1085,7 @@ describe('MeScopesController', () => { }) }) - describe('POST: /v2/me/tenants/:tenantId/scopes', () => { + describe('POST: /v2/me/tenants/:tenantId/scopes as normal user', () => { let app: TestApp let server: request.SuperTest let apiScopeDelegationTypeModel: typeof ApiScopeDelegationType diff --git a/libs/auth-api-lib/src/lib/clients/admin/admin-clients.service.ts b/libs/auth-api-lib/src/lib/clients/admin/admin-clients.service.ts index 9717417d72a8..443a1071149a 100644 --- a/libs/auth-api-lib/src/lib/clients/admin/admin-clients.service.ts +++ b/libs/auth-api-lib/src/lib/clients/admin/admin-clients.service.ts @@ -668,12 +668,11 @@ export class AdminClientsService { ...(input.addedDelegationTypes ?? []), ] - if ( - !isSuperUser && - allDelegationTypes.some((delegationType) => - SUPER_USER_DELEGATION_TYPES.includes(delegationType), - ) - ) { + const hasSuperUserDelegationType = allDelegationTypes.some( + (delegationType) => SUPER_USER_DELEGATION_TYPES.includes(delegationType), + ) + + if (!isSuperUser && hasSuperUserDelegationType) { return false } diff --git a/libs/auth-api-lib/src/lib/resources/admin/admin-scope.service.ts b/libs/auth-api-lib/src/lib/resources/admin/admin-scope.service.ts index 0a4a5892d2ee..4230c0f391a5 100644 --- a/libs/auth-api-lib/src/lib/resources/admin/admin-scope.service.ts +++ b/libs/auth-api-lib/src/lib/resources/admin/admin-scope.service.ts @@ -27,7 +27,10 @@ import { User } from '@island.is/auth-nest-tools' import { AdminPortalScope } from '@island.is/auth/scopes' import { AuthDelegationType } from '@island.is/shared/types' import { ApiScopeDelegationType } from '../models/api-scope-delegation-type.model' -import { delegationTypeSuperUserFilter } from '../utils/filters' +import { + delegationTypeSuperUserFilter, + SUPER_USER_DELEGATION_TYPES, +} from '../utils/filters' /** * This is a service that is used to access the admin scopes @@ -409,14 +412,11 @@ export class AdminScopeService { ...(input.removedDelegationTypes ?? []), ] - const isPersonalRepresentativeUpdate = allDelegationTypes.some( - (delegationType) => - delegationType.startsWith( - `${AuthDelegationType.PersonalRepresentative}:`, - ), + const hasSuperUserDelegationType = allDelegationTypes.some( + (delegationType) => SUPER_USER_DELEGATION_TYPES.includes(delegationType), ) - if (isPersonalRepresentativeUpdate && !isSuperUser) { + if (!isSuperUser && hasSuperUserDelegationType) { return false } diff --git a/libs/auth-api-lib/src/lib/resources/admin/dto/admin-patch-scope.dto.ts b/libs/auth-api-lib/src/lib/resources/admin/dto/admin-patch-scope.dto.ts index 374e31f454b2..11d4df948a9d 100644 --- a/libs/auth-api-lib/src/lib/resources/admin/dto/admin-patch-scope.dto.ts +++ b/libs/auth-api-lib/src/lib/resources/admin/dto/admin-patch-scope.dto.ts @@ -3,6 +3,7 @@ import { IsArray, IsBoolean, IsOptional, ValidateNested } from 'class-validator' import { Type } from 'class-transformer' import { TranslatedValueDto } from '../../../translation/dto/translated-value.dto' +import { AuthDelegationType } from '@island.is/shared/types' export class AdminPatchScopeDto { @ApiPropertyOptional({ @@ -95,7 +96,7 @@ export class AdminPatchScopeDto { type: [String], example: ['Custom'], }) - addedDelegationTypes?: string[] + addedDelegationTypes?: AuthDelegationType[] @IsArray() @IsOptional() @@ -103,7 +104,7 @@ export class AdminPatchScopeDto { type: [String], example: ['Custom'], }) - removedDelegationTypes?: string[] + removedDelegationTypes?: AuthDelegationType[] } /**