Overview
To implement access policies, it has often been necessary to set up intermediate groups, include/exclude, requirement groups, and allow/deny manual groups. Grouper has features to help in this area including: rules, hooks, templates, move/copy, import/export, and GSH scripts.
The ABAC with scripted groups feature is designed to offer increased efficiency in implementing access policies. It's important for the common groups and policy language to be well documented and people to be properly trained.
JEXL loaded groups
In Grouper 2.6.6 there is a first pass at JEXL loaded groups. It is basic and can be built on. Note: this is subject to change as we see a working solution and discuss the optimal path forward.
For more info, see the February 2022 blog on Attribute Based Access Control with Grouper. |
Expression language (JEXL) scripts facilitate implementing the part of ABAC that defines who is included in a policy based on attributes of those users. Other parts of ABAC such as resource attributes or environment attributes can be taken into consideration with Grouper permissions or by the service which has protected resources.
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 subjects (or in future groups as members)
Why do we need this feature?
Note in Grouper v2.6.6 you need to wait an hour after changing a script, or run the JEXL script loader full job. In the future we will have an incremental and run the full nightly. Note: there is one full daemon that handles all of the JEXL script ABAC groups. You do not add this, it is built-in
The script can only be written by people who can READ groups in the script and UPDATE the owner group. Since this is actually a JEXL script (not a JEXL expression), so you could have multiple lines, variables, conditionals, etc
In an entity script, the variable 'entity' is an instance of class: edu.internet2.middleware.grouper.abac.GrouperAbacEntity
You can use entity.memberOf('full:group:id:path') exactly like that to see if user is in a group or not.
Expression | Description | |
---|---|---|
| Three part intersection. Full time staff in MFA | |
| Example policy That means users who are not in globalLockout and not in vpnManualLockout | |
| Exclusive OR This is VPN users not in MFA and MFA users not in VPN: |
There are some trade-offs with performance and resources. This is the current implementation. It is optimized to reduce run-time. It does use a lot of memory, though that was a consideration.
Allow common reference groups to have user friendly labels
e.g. employee instead of ref:employee |
e.g.
FROM Member of employee, and member of app:jiraAdminsManualTO ${entity.memberOf(‘ref:employee’) && entity.memberOf(‘app:jiraAdminsManual’)} |
e.g.
FROM Has affiliation attribute with name of staff and dept of english, but not a member of lockout TO entity.hasAttribute('affiliation', 'name==staff && dept==english') && entity.notMemberOf('ref:lockout') |
Setup your entity data fields and use that data in JEXL scripts. This data can come from LDAP or SQL
Gail Lift: Michigan is starting to see situations where this approach would be REALLY useful. We are also interested in near real time / changelog.
We have struggled to build widely usable reference groups, because each unit has their own special needs: "Regular staff, but only in these jobcodes" and "Regular staff, but only in those jobcodes". Because a person can have multiple jobs, or multiple student programs, simple group math is not enough. If Mary has 2 jobs, {"dept":"English","jobcode":"12345"} and {"dept":"History","jobcode":"67890"}, intersecting a dept ref group with a jobcode ref group will not work as desired.
We are hoping the the new approach with Entity Attribute Resolver Groups will help with these needs. But we are concerned about how to get all the needed data into the my_people_affiliation table. (you could feed from arbitrary LDAP/SQL/WS sources)
We have affiliation data for employees, emeritus, Ann Arbor students, Dearborn students, Flint students, alumni, and Sponsored Affiliates (guests). Class enrollment data will be added later. Each affiliations has its own set of attributes that need to be available for group construction. A couple of typical samples, seen as we store them in LDAP in an almost-JSON format:
umichAAAcadProgram: {acadCareer=GBA}:{acadProg=00018}:{acadPlan=0010MAC}:{campus=A}:{progStatus=AC}:{admitTerm=2410}:{admitTermBegDt=2022-08-29}:{expGradTerm=}:{degrChkoutStat=}:{acadCareerDescr=Graduate Business Admin}:{acadPlanDegree=MAC}:{acadPlanDescr=Accounting MAcc}:{acadPlanField=0010}:{acadPlanFieldDescr=}:{acadPlanType=MAJ}:{acadPlanTypeDescr=Major}:{acadGroup=BA}:{acadGroupDescr=Ross School of Business}:{acadProgDescr=Accounting MAcc}
umichHR: {jobCategory=Faculty}:{campus=UM_ANN-ARBOR}:{deptId=304000}:{deptGroup=MEDICAL_SCHOOL}:{deptDescription=MM Orthopaedic Surgery}:{deptGroupDescription=Medical School}:{deptVPArea=EXEC_VP_MED_AFF}:{jobcode=201000}:{jobFamily=10}:{emplStatus=A}:{regTemp=R}:{supervisorId=12345678}:{tenureStatus=TEN}:{jobIndicator=P}For a single my_people_affiliation table, having a column for each distinct keyword would require about 70 columns. In any given row, most columns would have a null value. At the other extreme, we could use a single column for the affiliation data, so the columns would be employee_id, affiliation_name, affiliation_value. At this extreme, most queries would require substring matching. Would a structure between these make sense? Is a separate table for each affiliation better? (Dont worry about a table with all data)
Feed the expression through this simple program
Output
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
Expression 3: primaryAffiliation is faculty or staff and dept is physics or math
|
To confirm a policy is correct, a long form translation of the policy can be displayed along with group names and group counts (future state)
This is a complicated topic since it is parsing a programming language.
As a first pass we could have the overall group and lines from all component groups with count and the exact policy isnt there. This would apply for any unparsable policies once we have better visualization.
In a future pass, if the script follows certain standards and is "parsable" (allow-deny where parens and multiples could be involved), then I could picture a visualization for that. Note: either the visualization will be slow, or lots of data will be cached, or it will be stale from the last full sync. This is because JEXLs cannot be transformed into queries with counts, it needs the data in memory to allow JEXL to do its thing.
We need to get a list of sample policies people want to use so we can make sure we are going in the right direction.
A nightly full sync will occur. The incremental sync should stop. Make sure all the loaded groups are up to date.
An incremental change log consumer can
Allow attributes to be loaded on groups. and scripts could have a slightly different syntax. e.g.
group.hasAttribute['campus', 'main'] && group.hasAttribute['course'] |
Maybe there is an option to control what the result is. Or if it is even possible.
(group.hasAttribute['campus', 'main'] && group.hasAttribute['course']) && !entity.hasAttribute['lockout'] |
Point in time on attributes that support it
entity.hasHadAttribute('dept', '234', '2w') |
or
entity.hasOrHadAttribute('dept', '234', '2w') |
Have a config that allows point in time on the whole policy. i.e. only point in time in past, or include current members. This would be only going forward?
Allow institution specific policy examples on the policy editor page. Can only see the example if can see certain attributes/groups
Allow the institution to construct inputs and use GSH to make policy templates. Can only see if the template if can see certain attributes/groups. Perhaps could be a type of GSH template?
See Also
Access Management Features Overview