We want to be able to craft policies by an expression instead of creating loaders or tons of reference groups based on cartesian products of basis/ref groups.
Individual groups can be configured to automatically have their membership managed with individual subject or other basis groups.
Tables
Two Grouper tables will be constructed
Table name | Description |
---|---|
grouper_abac_group_attributes | Rows for groups and attribute names and values |
grouper_abac_subject_attributes | Row for subjects and attribute names and values |
These tables are managed by grouper based on configuration.
Group attribute table
The group attribute values come from the attribute framework which could be automatically fed from external systems of record. For now, an OtherJob could do this on a schedule.
grouper_abac_group_attributes | |||||
Group name | Attribute name | Attribute value | Active | Next start time | Last end time |
---|---|---|---|---|---|
ref:course:term:cis123 | campus | palmer | |||
ref:course:term:cis123 | campus | southern | |||
ref:course:term:cis124 | campus | northern | |||
ref:course:term:cis124 | termStart | 8/1/2020 (note, this is actually integer seconds since 1970) | |||
ref:course:term:cis124 | termEnd | 1/1/2020 | |||
ref:course:term:cis124 | thisTerm | T |
Loading attributes to groups
This can use a similar format to the marker / name-value pair convention for attributes, or can just be attributes on groups. i.e. the marker attribute column is optional. Types will be converted (e.g. the varchar "24" will be converted to 24 if the attribute is integer based). Note: dates can be converted to the appropriate type (e.g. from date column to integer seconds from 1970)
SQL query with columns, eventually a loader job | |||||
Group name | Attribute marker name | Attribute name | Attribute value | Active | Next start time |
---|---|---|---|---|---|
ref:course:term:cis123 | etc:attribute:mySchool:course:course | etc:attribute:mySchool:course:campus | palmer | ||
ref:course:term:cis123 | etc:attribute:mySchool:course:course | etc:attribute:mySchool:course:campus | southern | ||
ref:course:term:cis124 | etc:attribute:mySchool:course:termStart | etc:attribute:mySchool:course:termStart | 8/1/2020 |
Subject attribute table
The individual attribute values are fed from basis/ref groups and the values can be transformed from the group name to something that has institutional meaning. This can happen from attribute or from text manipulation
grouper_abac_subject_attributes | ||||||
Subject id | Source id | Attribute name | Attribute value | Active | Next start time | Last end time |
---|---|---|---|---|---|---|
jsmith | person | affiliation | staff | T | ||
jsmith | person | dept | math | T | ||
jsmith | person | dept | physics | T | ||
rjohnson | person | school | engineering | F | 11/1/2020 | |
wturner | person | primaryAffiliation | faculty | T |
Expressions
The expression can only be written by people who can READ groups in the abac group/subject tables.
Boolean logic and wildcards are required
Group | Type | Expression | Description |
---|---|---|---|
org:whatever:app:somePolicy | ref/bassis groups as members | (group.campus =~ ['palmer', southern'] and termStart - 7 > sysdate and termEnd + 7 < sysdate) | Give me groups as members where campus and term match |
org:whatever2:app2:somePolicy2 | subjects as members | person.primaryAffiliation =~ ['faculty', 'staff'] and person.dept =~ ['physics', 'math'] | Subjects in a role and dept |
org:whatever3:app3:somePolicy3 | could have some groups and subjects | (group.campus =~ ['palmer', southern'] and termStart - 7 > sysdate and termEnd + 7 < sysdate) or (person.primaryAffiliation =~ ['faculty', 'staff'] and person.dept =~ ['physics', 'math']) | Take some group populations and some subjects |
Requirements for expressions
Name | Priority | Description | JSON | GraphQL | SQL | JEXL |
---|---|---|---|---|---|---|
Parsable | Required | Needs to be parsed so we can | Yes | Probably | Probably | Yes |
Library in Grouper already | Nice to have | Avoid library bloat | Yes | Soon perhaps | No (there are Java SQL parsers) | Yes |
Supports boolean logic | Required | and, or, not, etc | Clunky | Yes | Yes | Yes |
Supports grouping | Required | parens | Clunky | Yes | Yes | Yes |
Needs wildcards | Required | Some way to have wildcards for values | Yes | Yes | Yes | Not built in but we can use =^ for "like" |
Seems like JEXL is a good place to start
Expression 1: Campus not in palmer or southern, and term start more than 7 days ago
group.campus !~ ['palmer', 'southern'] and group.termStart - 7 > sysdate
Feed the expression through this simple program
public static void main(String[] args) { JexlEngine jexlEngine = new JexlEngine(); ExpressionImpl expression = (ExpressionImpl)jexlEngine.createExpression("group.campus !~ ['palmer', 'southern'] and group.termStart - 7 > sysdate"); ASTJexlScript astJexlScript = (ASTJexlScript)GrouperUtil.fieldValue(expression, "script"); printNode(astJexlScript, ""); System.out.println(expression); } public static void printNode(JexlNode jexlNode, String prefix) { System.out.println(prefix + jexlNode.getClass().getSimpleName() + (StringUtils.isBlank(jexlNode.image) ? "" : (": " + jexlNode.image))); String newPrefix = StringUtils.isBlank(prefix) ? "- " : (" " + prefix); for (int i=0;i<jexlNode.jjtGetNumChildren();i++) { printNode(jexlNode.jjtGetChild(i), newPrefix); } }
Output
ASTJexlScript - ASTAndNode - ASTNRNode - ASTReference - ASTIdentifier: group - ASTIdentifier: campus - ASTReference - ASTArrayLiteral - ASTReference - ASTStringLiteral: palmer - ASTReference - ASTStringLiteral: southern - ASTGTNode - ASTAdditiveNode - ASTReference - ASTIdentifier: group - ASTIdentifier: termStart - ASTAdditiveOperator: - - ASTNumberLiteral: 7 - ASTReference - ASTIdentifier: sysdate
Grouper can take that object model and see which group and subject attributes are related, print out a nice analysis of the policy, and know which policies are affected by real time changes
Expression 2: campus is palmer or southern, or the term is current with some overlap
group.campus =~ ['palmer', 'southern'] or (group.termStart - 7 > sysdate and group.termStart - 7 < sysdate)
Expression 3: campus is palmer or southern, or the term is current with some overlap
person.primaryAffiliation =~ ['faculty', 'staff'] and person.dept =~ ['physics', 'math']
Analyze policy
To confirm a policy is correct, a long form translation of the policy can be displayed along with group names and group counts
Full sync
A nightly full sync will occur. The incremental sync should stop. Make sure everything in the attribute tables is up to date. Make sure all the policy groups are up to date.
Incremental sync
An incremental change log consumer can
- If group attributes change, see if it affects group attributes
- See which memberships change, if these are related to subject attributes, then update the attribute tables
- If attributes change, see which policies those refer to, and incrementally adjust the membership of those groups
- Policy changes should change the population