SGL Reference
NOTE 1: SGL can be rendered in various styles. The definitions given here in the reference section just use the recommended JSON rendering, for conciseness and simplicity. With the documentation on renderings, you should be able to interpolate into ProtoBuf, MsgPack, CBOR, human-friendly text, or another style if that is of interest.
Rules
A rule is an object in the form:
{
"grant": privileges, // An array of strings
"when": condition // A condition object
}
Rule.grant
Contains a set of strings that name privileges meaningful in your problem domain. For more on semantics, see Privileges below.
Rule.when
Contains a condition.
Rule.id
This field is optional and often omitted – hence it is not shown in the example above. If present, it is a string that provides a convenient identifier to reference the rule. It is not used by SGL processing.
Privileges
You make up privilege names. They should be short tokens without leading,
trailing, or internal whitespace, and without punctuation characters
that could cause problems for parsers. Unicode is supported (using NFKC
form is strongly recommended to
guarantee deterministic comparison). However, snake_case
ASCII is
the best choice if practical, for maximum interoperability. Privileges
are compared case-sensitive. Order doesn’t matter, and duplicates are
removed.
Principal
Principals are objects that contain whatever properties are evaluated when determining whether a condition has been met. Two properties of a principal are predefined; custom ones can be added.
Principal.id
Contains a string that uniquely identifies the principal. This might be
an employee UUID, a customer email address, or a first name. In the
context of decentralized identity
or self-sovereign identity,
which provided foundational SGL use cases, making the ID a DID is a good idea. The id
field is
optional and, when present, is used to
match against a condition with id.
Principal.roles
A set of strings that name roles belonging to this principal. These are matched against a condition with role.
Role names have the same rules about format and comparison as privilege names.
Condition
A condition defines the circumstances that must exist before someone can exercise the privileges listed in a rule.
There are 4 variants of condition. The variants cannot be combined (e.g.,
mixing “id” with “roles” or “any” or “all”), although they can be
implemented with a single structure that assigns null
to unused fields.
Condition with id
This variant requires that the principal seeking a privilege possess a specific identifier:
{"id": "Fred"}
Normally, conditions like this test for an id
that equals the
specified value. However, other operators can be used instead. This
allows tests such as >
, !=
, and like
(regex). Conditions that
evaluate custom scalar properties work the same way.
See Custom Properties for more details.
Condition with roles
This variant requires the specified value to be in the roles
set
belonging to one or more of the principals seeking a privilege:
{"n": 3, "roles": "friend"}
The n
field is optional. If omitted, "n": 1
is assumed.
Conditions that evaluate custom array/set properties work the same way. See Custom Properties for more details.
Condition with any
This variant provides boolean OR features. It requires a match against any of the conditions nested in its array:
{"any": [
{"roles": "grandparent"},
{"roles": "sibling"}
]}
Conditions with any
can also have an n
field. If present, it specifies
that n
subconditions must be satisfied from among all the alternatives
(instead of the default, 1). Note that this is NOT requiring n
matching principals from the group. This condition says that out of
the list of 3 subconditions, any 2 must be satisfied, NOT that any of the
3 listed roles must match twice:
{"any": [
{"roles": "employee"},
{"roles": "investor"},
{"roles": "customer"}
], "n": 2}
In this situation, n
can be a number larger than the number of elements
in the any
array of condition. For example, if the above rule were
changed so n
equaled 5, the semantics would be that 5 times a match
would have to be found for one of the 3 listed subconditions. (The behavior
here is affected by the disjoint
parameter to the
satisfies()
API.)
Condition with all
This provides boolean AND features. It requires a match against all of the conditions nested in its array:
{"any": [
{"roles": "employee"},
{"roles": "customer"},
{"id": "8675309"}
]}
See the note about disjoint
for advanced usage.
API
satisfies()
Python:
def satisfies(group, condition, disjoint=True) -> bool
Tells whether a group satisfies the condition embodied in a rule.
See Reference for an explanation of disjoint
.
Here, group
is one or more principals–the set about
which we want to check privileges. Taking advantage of python’s loose
typing, group
can be an array of Principal
, or a single Principal
,
or a dict
built from Principal
-compatible JSON. A Principal
identifies an entity with an id
or a set of roles
that the entity
holds, or both. So a valid group
arg might be:
[ {"id": "Bob", "roles": ["employee", "friend"]} ]
or maybe:
Principal( id="Sally", roles=["CEO"] )
disjoint
controls whether the subset of the group that satisfies each part of a condition tree must be disjoint (non-overlapping). Normally, you wantdisjoint
to be true. For example, if your condition include a requirement that 2 people with theemployee
privilege and 2 with theinvestor
privilege cooperate to exercise a privilege likeboard_vote_of_no_confidence
, you don’t want 2 employees who are also investors to satisfy both condition; you want 4 people at a minimum. Settingdisjoint
toFalse
allows the overlap.