diff --git a/libs/auth-api-lib/src/lib/delegations/delegation-scope.service.ts b/libs/auth-api-lib/src/lib/delegations/delegation-scope.service.ts index bb74ed0a4d6e..701fa0785810 100644 --- a/libs/auth-api-lib/src/lib/delegations/delegation-scope.service.ts +++ b/libs/auth-api-lib/src/lib/delegations/delegation-scope.service.ts @@ -27,8 +27,10 @@ import { DelegationDelegationType } from './models/delegation-delegation-type.mo import { DelegationScope } from './models/delegation-scope.model' import { DelegationTypeModel } from './models/delegation-type.model' import { Delegation } from './models/delegation.model' +import { ApiScopeInfo } from './delegations-incoming.service' import type { User } from '@island.is/auth-nest-tools' +import filterByCustomScopeRule from './utils/filterByScopeCustomScopeRule' @Injectable() export class DelegationScopeService { @@ -222,7 +224,18 @@ export class DelegationScopeService { }, ], }) - .then((apiScopes) => apiScopes.map((apiScope) => apiScope.name)) + .then((apiScopes) => + apiScopes + .filter((scope) => + // Remove scopes that are not allowed for the delegation type + filterByCustomScopeRule( + scope, + [AuthDelegationType.GeneralMandate], + this.delegationConfig.customScopeRules, + ), + ) + .map((apiScope) => apiScope.name), + ) } private async findAllNationalRegistryScopes(): Promise { diff --git a/libs/auth-api-lib/src/lib/delegations/delegations-incoming-custom.service.ts b/libs/auth-api-lib/src/lib/delegations/delegations-incoming-custom.service.ts index e11e509095bd..2eac4bf93fe7 100644 --- a/libs/auth-api-lib/src/lib/delegations/delegations-incoming-custom.service.ts +++ b/libs/auth-api-lib/src/lib/delegations/delegations-incoming-custom.service.ts @@ -26,6 +26,7 @@ import { Delegation } from './models/delegation.model' import { NationalRegistryV3FeatureService } from './national-registry-v3-feature.service' import { DelegationValidity } from './types/delegationValidity' import { getScopeValidityWhereClause } from './utils/scopes' +import filterByCustomScopeRule from './utils/filterByScopeCustomScopeRule' type FindAllValidIncomingOptions = { nationalId: string @@ -182,20 +183,6 @@ export class DelegationsIncomingCustomService { }) } - private filterByCustomScopeRule(scope: ApiScopeInfo) { - const foundCSR = this.delegationConfig.customScopeRules.find( - (csr) => csr.scopeName === scope.name, - ) - - if (!foundCSR) { - return true - } - - return foundCSR.onlyForDelegationType.includes( - AuthDelegationType.GeneralMandate, - ) - } - /** * Finds all companies that have a general mandate for the user. * @param user @@ -233,7 +220,11 @@ export class DelegationsIncomingCustomService { const customApiScopes = clientAllowedApiScopes.filter( (s) => !s.isAccessControlled && - this.filterByCustomScopeRule(s) && + filterByCustomScopeRule( + s, + [AuthDelegationType.GeneralMandate], + this.delegationConfig.customScopeRules, + ) && s.supportedDelegationTypes?.some((dt) => supportedDelegationTypes.includes( dt.delegationType as AuthDelegationType, diff --git a/libs/auth-api-lib/src/lib/delegations/utils/filterByScopeCustomScopeRule.ts b/libs/auth-api-lib/src/lib/delegations/utils/filterByScopeCustomScopeRule.ts new file mode 100644 index 000000000000..87fbd1d7adff --- /dev/null +++ b/libs/auth-api-lib/src/lib/delegations/utils/filterByScopeCustomScopeRule.ts @@ -0,0 +1,21 @@ +import { AuthDelegationType } from '@island.is/shared/types' +import { ApiScopeInfo } from '../delegations-incoming.service' + +export default function filterByCustomScopeRule( + scope: ApiScopeInfo, + filterOutForDelegationType: AuthDelegationType[], + customScopeRules: { + scopeName: string + onlyForDelegationType: string[] + }[], +): boolean { + const foundCSR = customScopeRules.find((csr) => csr.scopeName === scope.name) + + if (!foundCSR) { + return true + } + + return foundCSR.onlyForDelegationType.some((type) => + filterOutForDelegationType.includes(type as AuthDelegationType), + ) +} diff --git a/libs/auth-api-lib/src/lib/resources/delegation-resources.service.ts b/libs/auth-api-lib/src/lib/resources/delegation-resources.service.ts index 3f5b80d434dd..7de2870f58bd 100644 --- a/libs/auth-api-lib/src/lib/resources/delegation-resources.service.ts +++ b/libs/auth-api-lib/src/lib/resources/delegation-resources.service.ts @@ -25,6 +25,7 @@ import { mapToScopeTree } from './utils/scope-tree.mapper' import type { Attributes, WhereOptions } from 'sequelize' import type { ConfigType } from '@island.is/nest/config' +import { ApiScopeDelegationType } from './models/api-scope-delegation-type.model' type DelegationConfigType = ConfigType type ScopeRule = DelegationConfigType['customScopeRules'] extends Array< @@ -42,6 +43,8 @@ export class DelegationResourcesService { private domainModel: typeof Domain, @InjectModel(DelegationScope) private delegationScopeModel: typeof DelegationScope, + @InjectModel(ApiScopeDelegationType) + private apiScopeDelegationTypeModel: typeof ApiScopeDelegationType, private resourceTranslationService: ResourceTranslationService, @Inject(DelegationConfig.KEY) private delegationConfig: ConfigType, @@ -304,20 +307,37 @@ export class DelegationResourcesService { } private async delegationTypeFilter(user: User, prefix?: string) { - if (!user.delegationType || !user.actor) { + if (!user.delegationType) { return [] } // We currently only support access control for company (delegation) actors. // Actors for individuals should not have the scope required to reach this // point, but we assert it just to be safe. + // EDIT: This is no longer true, as we now support LegalRepresentative delegations for individuals. if (!isCompany(user.nationalId)) { - throw new ForbiddenException( - 'Actors for individuals should not be able to manage delegations.', - ) + if ( + !user.delegationType.includes(AuthDelegationType.LegalRepresentative) + ) { + throw new ForbiddenException( + 'Actors for individuals should not be able to manage delegations.', + ) + } } const delegationOr: Array> = [] + if (user.delegationType.includes(AuthDelegationType.LegalRepresentative)) { + const scopes = await this.apiScopeDelegationTypeModel.findAll({ + attributes: ['apiScopeName'], + where: { + delegationType: AuthDelegationType.LegalRepresentative, + }, + }) + + delegationOr.push({ + [col(prefix, 'name')]: scopes.map((scope) => scope.apiScopeName), + }) + } if (user.delegationType.includes(AuthDelegationType.ProcurationHolder)) { delegationOr.push({ [col(prefix, 'grantToProcuringHolders')]: true }) } diff --git a/libs/auth-api-lib/src/lib/resources/resources.module.ts b/libs/auth-api-lib/src/lib/resources/resources.module.ts index c7198b3ecef4..541380575a33 100644 --- a/libs/auth-api-lib/src/lib/resources/resources.module.ts +++ b/libs/auth-api-lib/src/lib/resources/resources.module.ts @@ -26,6 +26,7 @@ import { ResourceTranslationService } from './resource-translation.service' import { ResourcesService } from './resources.service' import { ScopeService } from './scope.service' import { TenantsService } from './tenants.service' +import { ApiScopeDelegationType } from './models/api-scope-delegation-type.model' @Module({ imports: [ @@ -39,6 +40,7 @@ import { TenantsService } from './tenants.service' ApiScopeUser, ApiScopeUserAccess, ApiResourceScope, + ApiScopeDelegationType, IdentityResourceUserClaim, ApiScopeUserClaim, ApiResourceUserClaim,