Skip to main content

Class: ACLUtils

Defined in: service-core/src/security/ACLUtils.ts:25

Common utility functions for working with AccessControlList objects and validating user permissions.

Constructors

Constructor

new ACLUtils(): ACLUtils

Returns

ACLUtils

Properties

_objectFactory?

protected optional _objectFactory?: ObjectFactory

Defined in: service-core/src/security/ACLUtils.ts:27


enabled

enabled: boolean = true

Defined in: service-core/src/security/ACLUtils.ts:30

Methods

checkRequestPerms()

checkRequestPerms(uid, user, req): Promise<boolean>

Defined in: service-core/src/security/ACLUtils.ts:106

Validates that the user has permission to perform the request operation against the URL path for the provided request. If ACLUtils has not been initialized or the acl datasource has not been configured then always returns true.

Parameters

uid

string

The uid of the access control list to verify against.

user

JWTUser | undefined

The user to validate.

req

HttpRequest

The HTTP request to check permissions for.

Returns

Promise<boolean>


findACL()

findACL(entityId, parentUids?, options?): Promise<AccessControlList | undefined>

Defined in: service-core/src/security/ACLUtils.ts:201

Retrieves the access control list with the associated identifier and populates the parent(s).

Deliberately not @Transactional and never participates in a caller's transaction: it's on the hot path for every permission check (hasPermission/checkRequestPerms), not just writes, so wrapping it would add a session open/close to every authorization check. It also has no way to safely reuse a caller's transaction context.

Parameters

entityId

string

The unique identifier of the ACL to retrieve.

parentUids?

string[] = []

The list of already found parent UIDs. This is used to break circular dependencies.

options?

Set skipCache: true to bypass the cache and always read the current database state — mirrors RepoUtils's RepoFindOptions.skipCache. The result is still written back into the cache afterward, same as a normal (non-skipped) lookup.

skipCache?

boolean

Returns

Promise<AccessControlList | undefined>


getRecord()

getRecord(acl, user): ACLRecord | null

Defined in: service-core/src/security/ACLUtils.ts:603

Retrieves the most specific record in the provided ACL associated with the provided user: an exact uid/anonymous match beats a role match, which beats a wildcard (.*/*) match — regardless of where each record sits in acl.records. Without this, a wildcard grant authored before a specific record (a natural authoring order) would silently shadow that more specific record. Only falls back to the parent ACL when nothing in this ACL's own records matches at all.

Parameters

acl

AccessControlList

The access control list that will be searched.

user

JWTUser | undefined

The user to find a record for.

Returns

ACLRecord | null

The ACL record associated with the given user if found, otherwise undefined.


hasPermission()

hasPermission(user, acl, action): Promise<boolean>

Defined in: service-core/src/security/ACLUtils.ts:158

Validates that the user has permission to perform the provided action using the given access control list.

Parameters

user

JWTUser | undefined

The user to validate permissions of.

acl

string | AccessControlList

The ACL or uid of an ACL to validate permissions against.

action

string

The action that the user desires permission for.

Returns

Promise<boolean>

true if the user has at least one of the permissions granted for the given entity, otherwise false.


populateParent()

populateParent(acl, parentUids?): Promise<void>

Defined in: service-core/src/security/ACLUtils.ts:636

Attempts to retrieve the parent access control list for the given ACL object.

Parameters

acl

AccessControlList

The access control list whose parents will be populated.

parentUids?

string[] = []

The list of already found parent UIDs. This is used to break circular dependencies.

Returns

Promise<void>


removeACL()

removeACL(uid): Promise<AccessControlList | undefined>

Defined in: service-core/src/security/ACLUtils.ts:264

Deletes the ACL with the given identifier from the database, returning the document that was actually deleted (or undefined if none existed) — captured atomically as part of the delete itself (Mongo: findOneAndDelete; SQL: a findOne immediately followed by the delete, both inside this method's own acl transaction), not a separate, earlier read. A caller using the return value as a restore snapshot (see RepoUtils.delete()/truncate()'s registerRollbackHook() usage) always gets the exact row that was removed, never a possibly-stale one raced by a concurrent legitimate write between an earlier read and this delete — and restoring it later still goes through saveACL()'s own optimistic-lock version check, so a restore attempt can't clobber a newer row that appeared after this delete either.

Runs in its own transaction scoped to the acl connection (see Transactional) rather than trying to join whatever transaction the caller is itself in — acl is frequently configured as its own, separate datastore (a documented, supported deployment shape), so a caller's session/entityManager almost never actually belongs to the same physical connection this repo does. Reusing it directly used to throw (Mongo) or silently target the wrong connection (SQL).

Parameters

uid

string

The unique identifier of the ACL to remove.

Returns

Promise<AccessControlList | undefined>


removeACLs()

removeACLs(uids): Promise<AccessControlList[]>

Defined in: service-core/src/security/ACLUtils.ts:563

Atomic removal of multiple ACLs in a single acl-scoped transaction (see @Transactional), returning whichever of them actually existed to be deleted (see removeACL()'s doc comment for why the returned documents — not a separate, earlier read — are the right thing to snapshot for a possible restore).

Deliberately sequential, not batched-concurrent: every removeACL() call below resolves to this same acl datasource, so @Transactional's merge logic joins all of them onto the one MongoDB ClientSession/SQL EntityManager this method opened. Running these with Promise.all would issue overlapping commands against one session, which drivers reject or misorder.

Parameters

uids

string[]

The unique identifiers of the ACLs to remove.

Returns

Promise<AccessControlList[]>


saveACL()

saveACL(acl, options?): Promise<AccessControlList | null>

Defined in: service-core/src/security/ACLUtils.ts:396

Stores the given access control list into the ACL database. By default, bumps the version for optimistic locking (see below) — pass preserveVersion: true to instead write acl back with its own version exactly as given, for restoring a known-good snapshot (see RepoUtils.delete()/truncate()'s registerRollbackHook() usage) rather than applying a new change on top of whatever's currently stored. A restore only ever targets a uid with nothing currently at it (that's the point — the entity-side transaction it was tied to is being rolled back, so the row it deleted should no longer exist); if something does exist there already, the restore is refused rather than silently clobbering it.

Runs in its own transaction scoped to the acl connection (see Transactional) rather than trying to join whatever transaction the caller is itself in — see removeACL's doc comment for why. Callers that need the entity-side write and this ACL save to stay consistent should register a compensating action via registerRollbackHook().

Parameters

acl

AccessControlList

The ACL to store.

options?

Set preserveVersion: true to restore acl exactly as given (see above) instead of the normal optimistic-locking update semantics.

preserveVersion?

boolean

Returns

Promise<AccessControlList | null>

Returns the ACL that was stored in the database.


saveACLs()

saveACLs(acls): Promise<void>

Defined in: service-core/src/security/ACLUtils.ts:586

Atomic save of multiple ACLs in a single acl-scoped transaction (see Transactional). Used to restore a batch of ACL snapshots — e.g. by a registerRollbackHook() compensating action — if the entity-side transaction they were removed alongside subsequently fails. Always restores each ACL's own version as given (see saveACL()'s preserveVersion option) rather than bumping it, since this is a restore, not a new change.

Deliberately sequential. See removeACLs()'s doc comment for why.

Parameters

acls

AccessControlList[]

The ACLs to store.

Returns

Promise<void>


saveDefaultACL()

saveDefaultACL(acl): Promise<AccessControlList | null>

Defined in: service-core/src/security/ACLUtils.ts:493

Stores the given default access control list into the ACL database. A default ACL is a special type of ACL that is primarily defined and maintained within the code but allows for user-specific overrides. To accomplish this, the provided ACL is split in two. A new record is automatically created with the uid of the form default_<uid> that stores the exact record as provided by code. Then a second ACL record is created with the uid being that of what is passed as the argument. This second ACL is used to store user-defined overrides. As the default_<uid> record is always overwritten with the lastest version of the code, any user-defined changes made to it are lost on service restart.

Parameters

acl

AccessControlList

Returns

Promise<AccessControlList | null>