Dynamic ACL Binding Technical Reference

Available Dynamic ACL Types

Some of the previously described access modes have a corresponding dynamic ACL type associated with them. Because dynamic ACLs are for data-dependent access, they have more restrictive applicability:

Type Mode Implies Supported Resources
owner Write data insert, update, delete, select table, column, reference
insert Insert data reference
update Modify data table, column, reference
delete Delete data table, column
select View data table, column

Table and column-level dynamic ACLs are only applicable to access requests against existing database content. Insertion of new rows can only be granted by a static policy. However, reference-level dynamic ACLs can grant or deny the ability to specify specific foreign keys even during row insertion.

Dynamic data rights do not imply model access. Model access must be determined in a data-independent manner in order to even pose an access request which might be granted by dynamic access rights.

Dynamic ACL Binding Representation

The data-dependent ACL bindings are encoded in an "acl_bindings" sub-resource of the governed resource. This is a hash-map keyed by ACL binding name. For example, a table resource has a canonical representation as in the following example:

{
  "schema_name": "My Schema",
  "table_name": "My Table",
  "kind": "table",
  "comment": "The purpose of My Table is...",
  "annotations": ...,
  "column_definitions": ...,
  "keys": ...,
  "foreign_keys": ...,
  "acls": {
    "write": ["some/curator/URI"]
  },
  "acl_bindings": {
    "My Binding": {
      "types": ["owner"],
      "projection": "Managed By",
      "projection_type": "acl",
      "scope_acl": ["registered-users-group"]
    }
  }
}

This example has an explicitly set, data-independent curator group who can modify all rows in the table, while other data-independent ACLs are inherited from the enclosing schema. A dynamic ACL binding called My Row Owners specifies that an ACL stored in the Managed By column of the table grants owner dynamic access type for individual rows. The representation uses an array for the type so that multiple access modes can be more easily configured without having to repeat the same projection many times. This binding has a scoping ACL such that only members of the registered-users-group can acquire these row-level rights.

Inheritence and False Binding

As a convenience, columns effectively inherit the ACL bindings of their table. A column whose "acl_bindings" document is empty will permit all operations that the table would allow for each row. To grant fewer writes, the column-level "acl_bindings" MUST override the named bindings inherited from the table.

  • Replacement: the column MAY provide a different binding document under the same binding name.
  • Suppression: the column MAY provide a literal false value instead of a binding document.

Projection Document

The "projection" field of the ACL binding is a document representing a parsed abstract syntax tree for an attribute query fragment. The general form of the ACL document is an array of path elements:

  • [ element ,, column ]

This corresponds to the serialized query fragment element/.../column to project ACL content from an implicit base entity context using the ERMrest /attribute/base API. The final column MUST be a string literal naming a column in the effective entity-path context. Each anterior element MAY use one of the following sub-document structures:

  • { "context": leftalias , direction : fkeyname , "alias": rightalias }
    • Links a new table instance to the existing path via inner join
    • The left-hand path context is the table instance named by leftalias or the immediately preceding path context if leftalias is null or absent.
      • The alias "base" is implicitly bound to the base table to which this ACL is bound.
    • The joining condition is determined by the named foreign key constraint fkeyname where one end is tied to the left-hand path context and the other to the newly added table instance.
    • The direction of the joining condition is "inbound" or "outbound" and MUST be specified.
    • The rightalias string literal is bound to the new table instance unless it is null or absent.
      • The alias "base" is reserved and cannot be bound as a rightalias.
  • { "and": [ filter ,], "negate": negate }
    • A logical conjunction of multiple filter clauses is applied to the query to constrain matching rows.
    • The logical result is negated only if negate is true.
    • Each filter clause may be a terminal filter element, conjunction, or disjunction.
  • { "or": [ filter ,], "negate": negate }
    • A logical disjunction of multiple filter clauses is applied to the query to constrain matching rows.
    • The logical result is negated only if negate is true.
    • Each filter clause may be a terminal filter element, conjunction, or disjunction.
  • { "filter": [ leftalias , column ], "operand": value , "operator": operator , "negate": negate }
    • An individual filter element is applied to the query or individual filter clauses participate in a conjunction or disjunction.
    • The filter constrains a named column in the table named by leftalias or the current path context if leftalias is null.
    • The operator specifies the constraint operator via one of the valid operator names in the ERMrest REST API.
    • The value specifies the constant operand for a binary constraint operator.
    • The logical result of the constraint is negated only if negate is true.

Many fields may be omitted from the above structures to allow concise projection documents:

  • Many null or absent values have a default semantics defined:
    • leftalias is omitted to get a default path-based entity context
    • rightalias is omitted if no alias binding is required
    • negate is omitted for normal (non-negated) logical decisions
    • operator is omitted for regular "=" equality comparisons
    • value is omitted when the unary "::null::" operator is used
  • A few fields are required to be present with a non-null value
    • direction and fkeyname MUST always be present in link documents.
    • filter MUST always be present in conjunction and disjunction documents.
    • column MUST always be present in filter clauses.
    • value MUST always be present with each binary operator including the default "="
  • Two syntactic short-hands are allowed for bare column names:
    • An single-element projection [ column ] MAY omit the array and specify just the string literal column.
    • An unqualified filter column [ null, column ] MAY omit the array and specify just the string literal column.

Effective ACL Projection Query

The projection document assumes that a base row query similar to /ermrest/catalog/N/attribute/Base/key=X/ will be formulated by the system, and the projection document describes the suffix necessary to turn this into an ACL projection query. E.g. in the dynamic ACL example above, the projection string "Managed%20By" names a column Managed By could be appended to a base-row URL to form a complete ACL projection query URL:

/ermrest/catalog/N/attribute/My%20Schema:My20Table/key=X/Managed%20By

For more complicated projection documents, there is a similar mechanical transformation which can produce an effective ACL projection query. The supported projection language covers a subset of all possible query URLs.

Projection Types

Zero or one rows MAY be returned as the query result. Several projected column types are supported, and more than one projection type is supported. See the following matrix:

Projected Column Type Supported "projection_type" Description
text[] acl (default) The projected array is interpreted as ACL content.
text acl (default) The projected text is interpreted as if it were an array containing the single value.
any nonnull A non-null projected value is interpreted as a true authorization decision.

The nonnull projection type is supported by all column types. The acl projection type is only supported for the projected column types shown above.

Scoping ACLs

The "scope_acl" field of each ACL binding document restricts the set of clients for whom the data-dependent privileges may be granted. If a client’s attributes do not match this scoping ACL, the effective permissions for the client are the same as if this ACL binding were absent from the system.

If "scope_acl" is omitted during binding creation, a default scoping ACL value of ["*"] is configured. This provides backwards compatibility with older policies used in earlier versions of ERMrest, where all ACL bindings were evaluated for all clients.