Permissions
Every call runs as the user who logged in. What that user may not see is silently left out of searches and listings, reading it usually fails with "Not found." or "Access denied.", and an object created without an ACL ends up invisible even to its creator: always send an ACL when you create objects. The server checks two kinds of rights:
vault-level rights what the user may do in the vault at all
(LogIn response: session_data.access_rights.vault_access)
create_objects, see_all_objects, see_deleted_objects, undelete_objects,
destroy_objects, change_metadata_structure, manage_workflows, ...
object permissions what the user may do with one object version
(the version's AccessControlList)
read, edit, delete, change permissions
Value list items, object types, classes and property definitions carry ACLs of their own (the
acl fields of ValueList, ObjectClass
and PropertyDef), with the caller's resulting rights in fields such
as ObjectClass.current_user_permissions.
Object ACLs
An AccessControlList has:
custom_component(AccessControlListComponent): either a reference to a named ACL (has_named_acltrue andnamed_acl_id) or explicit entries inpermissions, each an AccessControlEntry with a subject (a user, a user group, or a pseudo-user such as "the user in the object's Owner property") and the permissions granted.restrictive_componentsandadditive_components: automatic permissions, which an object gets through lookup values to items that pass their permissions on (seePropertyDef.enable_automatic_permissions).checked_out_to_user: the user who has the object checked out and therefore extra rights to it while the check-out lasts.
Named ACLs are reusable, named permission sets. List them with
GetNamedACLs, with include_builtin true and
types set to the NACLType values you want as bits (1 for normal
named ACLs); types 0 returns nothing. The built-in named ACLs include -1 "Full control for all
internal users" and -20 "Only for me". The Sample Vault adds its own, such as 1 "Visible to
company management only".
Give new objects an ACL
AddObjectWithFiles and
AddObject do not compute a default ACL from the
class or object type. An unset acl creates an object with an empty ACL: no entries, so
once the object is checked in, only users with the vault-level right to see all objects (vault
administrators, for example) can read it, not even its creator. In the Sample Vault, a
normal user who created a document without an ACL could no longer read it after checking it in:
AddObject answered with latest_visible false, and the created_object that
AddObjectWithFiles returned had no title or properties.
Send a named ACL reference instead; the server fills in its entries:
acl { custom_component { has_named_acl: true named_acl_id: -1 } }
The document created this way stored group 1 (All internal users) with full control, and its
creator could read it. A reference alone works for named ACLs that do not depend on the current
user. For "Only for me" (-20), a reference alone leaves the object without permissions: send the
named ACL's full acl_for_objects from GetNamedACLs instead, which names the user.
To have the server recalculate an existing object's ACL from its property
values, call SetProperties with
acl_mode ACLENFORCING_MODE_RESET_TO_DEFAULT
(ACLEnforcingMode); in the Sample Vault that also produced
named ACL -1.
Reading permissions
| Question | Call |
|---|---|
| What may I do in this vault? | session_data.access_rights in the LogIn response |
| What is the ACL of this object version? | GetSecurity |
| Who can do what with this object version? | GetEffectivePermissions |
| Would an ACL give me some access? | CheckAccess |
| Change an object's ACL | ChangeSecurity |
| Value list item permissions | GetValueListItemsWithPermissions with include_permissions |
GetEffectivePermissions lists every user who has access, one
EffectivePermissions per user ID with can_user_see,
can_user_edit, can_user_delete and can_user_change_permissions; a normal user can call it.
What "access denied" looks like
A caller who lacks rights sees one of three outcomes:
- Silence. Searches and listings leave out what the caller may not see. In the Sample Vault the same class search returned 0 contracts to a normal user and 13 to an administrator. An object history the caller may not read comes back empty.
- "Not found." Reading an object the caller cannot see at all, such as an object checked out to another user and never checked in, or a deleted object, fails like a missing object.
- "Access denied." Acting on something the caller can identify but lacks rights for.
Errors arrive with gRPC status UNKNOWN; the status details hold the message. The trailer
mfiles-error-serialized-bin holds an RPCErrorInfoArray
whose error_code values identify the error (int32, so 0x800407E4 reads as -2147219484). An
access denial includes 0x800407E4, usually with a second code for the reason:
| Case (seen in the Sample Vault) | Message | Reason code |
|---|---|---|
| No access to the object version | "Access denied. You do not have sufficient access rights to the object." | 0x800400AA |
| Missing vault-level right (an admin service, undelete, destroy) | "Access denied. You do not have the access rights required by this operation." | 0x800400A9 |
| Workflow state transition not allowed | 'Access denied. The state transition "..." is not allowed.' | 0x800400C3 |
| Object or version not visible, or not existing | "Not found." | 0x8004000B (no 0x800407E4) |
The messages contain a line break after "Access denied." An expired or invalid session is the
exception: it arrives as gRPC status UNAUTHENTICATED (see
Authentication and sessions).
Treat access denied as final for the current user and request: retrying the same call does not help. Errors shows how to decode the error trailer and lists the other common codes.