PublishedData Authorization Model¶
This document describes the authorization model used for published data and associated endpoints, for both the v4 endpoints (/api/v4/publisheddata) and the deprecated v3 endpoints (/api/v3/publisheddata).
Note: The ownership model described here is a temporary deviation from the SciCat authorization pattern. See Temporary ownership model below.
Actions¶
The following actions are defined for published data:
CreateReadUpdateDeleteAccessAny
Create, Read, Update and Delete are used for endpoint authorization, i.e. whether a user may call an endpoint at all. AccessAny is used for instance authorization, i.e. whether a user may act on records they do not own.
Record states¶
Every published data record carries a status field, which takes one of the following values, and which participates in authorization:
private: a draft, visible only to its creator (and admins)public: made public, but not yet registered with a DOI registrarregistered: registered with a DOI registraramended: registered and subsequently amended
Records in state public, registered or amended are readable by everyone. Only records in state private may be modified or deleted by their creator.
Permissions¶
Permissions are granted cumulatively to users based on their group association. The following permission levels are granted to users:
Unauthenticated¶
An unauthenticated user may read published data records that are in state public, registered or amended. Listing and counting endpoints are filtered accordingly, and a request for a private record is answered with 404 Not Found.
Unauthenticated users have no write access.
Authenticated¶
In addition to the permissions granted to unauthenticated users, an authenticated user may read the private records for which their username matches the record's createdBy.
An authenticated user may create published data records. They may update, register, resync and delete only records for which their username matches createdBy and whose status is private. Attempting to modify a record owned by another user is answered with 404 Not Found; attempting to modify an own record that is no longer private is answered with 400 Bad Request.
DELETE_GROUPS¶
If a user is a member of a group listed in configuration as part of DELETE_GROUPS, they are permitted to call the delete endpoint.
On the v4 endpoint, the instance-level restrictions above still apply, i.e. a non-admin may delete only their own private records. The deprecated v3 delete endpoint performs no instance-level check at all: any member of DELETE_GROUPS may delete any record in any state.
ADMIN_GROUPS¶
If a user is a member of a group listed in configuration as part of ADMIN_GROUPS, they are granted AccessAny and therefore have unrestricted read access to all published data records, regardless of status or creator, and may update, register, resync and delete records created by any user.
Admins are still subject to the lifecycle guard: records in state registered or amended cannot be updated or deleted, since they have already been handed over to a DOI registrar.
Permission Matrix¶
| Operation | Unauthenticated | Authenticated | DELETE_GROUPS |
ADMIN_GROUPS |
|---|---|---|---|---|
Create |
- | any | - | any |
Read |
published | published + own | published + own | any |
Update |
- | own private | own private | any not registered/amended |
Delete |
- | - | own private (v4) / any (v3) | any not registered/amended |
Legend:
- published: record status must be public, registered or amended
- own: record createdBy must match the user's username
- own private: record createdBy must match the user's username and status must be private
- any: unrestricted access
Implementation Notes¶
Endpoint authorization is defined in CaslAbilityFactory.publishedDataEndpointAccess and applied through the PoliciesGuard and @CheckPolicies decorators on the controllers.
Instance authorization is defined in CaslAbilityFactory.publishedDataInstanceAccess, which grants AccessAny to members of ADMIN_GROUPS only. Both controllers use this single ability to decide whether to narrow the Mongo query:
- Read endpoints (
GET /,GET /count,GET /:id) add an$orfilter that matches published records plus the caller's ownprivaterecords. The filter is combined with the client suppliedwhererather than replacing it. - Mutating endpoints (
PATCH /:id,POST /:id/register,POST /:id/resync, andDELETE /:idon v4) build a filter ondoipluscreatedByfor non-admins, so a record belonging to somebody else is simply not found, and the same filter is reused for the write itself. - The lifecycle guard on
statusis applied after the record has been fetched, and is what distinguishes a400 Bad Request(found, but not modifiable in its current state) from a404 Not Found(not visible to the caller).
Since a record's only ownership information is createdBy, there is no group-based rule to express here, and no ownerGroup/accessGroups conditions appear in the ability.
Temporary ownership model¶
Unlike datasets, samples, proposals and most other SciCat entities, the PublishedData schema does not extend OwnableClass: it has no ownerGroup and no accessGroups fields. The only ownership hint available is createdBy.
The createdBy-based rules described above were introduced as a hot fix for a security issue: on the v3 endpoints, any authenticated user could read any other user's private published data and could PATCH it, since those endpoints performed authentication but no further authorization (see PR #2886).
This is understood to be a temporary measure and knowingly deviates from the supported, group-based SciCat pattern. In particular:
- Only the exact creator of a record can act on it, whereas elsewhere in SciCat any member of the record's
ownerGroupcould. - The "four eyes" workflow, in which a colleague reviews a
privatepublished data record before it is registered, is not possible through these endpoints.
The intended long-term solution is to make PublishedData extend OwnableClass and to migrate existing records so that ownerGroup and accessGroups are populated, after which the rules above should be replaced by the standard group-based checks. This is tracked in issue #2900. The current model will be supported until that redesign is implemented.