Child pages
  • Grouper attribute based access control
Skip to end of metadata
Go to start of metadata

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.

Why do we need this feature?

  • Reduces pre-loaded rollups that might not be used
  • You don't need a loader job for each one of these groups
  • Any Grouper user could edit the policies if they can READ underlying groups.  The expressions are secure
  • The memberships of the ABAC groups are real time based on an intelligent change log consumer
  • You can have a UI to help build it and give good error messages
  • Could visualize the policies.  Perhaps could be integrated into existing visualization
  • This solved the issue of composites with any number of factors

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

GroupTypeExpressionDescription
org:whatever:app:somePolicyref/basis groups as members(group.campus =~ ['palmer', southern'] and group.termStart - 7 > sysdate and group.termEnd + 7 < sysdate)Give me groups as members where campus and term match
org:whatever2:app2:somePolicy2subjects as membersperson.primaryAffiliation =~ ['faculty', 'staff'] and person.dept =~ ['physics', 'math']Subjects in a role and dept
org:whatever3:app3:somePolicy3could have some groups and subjects

(group.campus =~ ['palmer', southern'] and group.termStart - 7 > sysdate and group.termEnd + 7 < sysdate)

or (person.primaryAffiliation =~ ['faculty', 'staff'] and person.dept =~ ['physics', 'math'])

Take some group populations and some subjects

Requirements for expressions

NamePriorityDescriptionJSONGraphQLSQLJEXL
ParsableRequired

Needs to be parsed so we can 
check security, do real-time
updates, and analyze policies

YesProbablyProbablyYes
Library in Grouper alreadyNice to haveAvoid library bloatYesSoon perhapsNo (there are
Java SQL parsers)
Yes
Supports boolean logicRequiredand, or, not, etcClunkyYesYesYes
Supports groupingRequiredparensClunkyYesYesYes
Needs wildcardsRequiredSome way to have wildcards for valuesYesYesYesNot 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

Tables

Two Grouper tables will be constructed for performance reasons (getting relationships and point-in-time)

Table nameDescription
grouper_abac_group_attributesRows for groups and attribute names and values
grouper_abac_subject_attributesRow 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 nameAttribute nameAttribute valueActiveNext start timeLast end time
ref:course:term:cis123campuspalmer


ref:course:term:cis123campussouthern


ref:course:term:cis123mode



ref:course:term:cis124campusnorthern


ref:course:term:cis124termStart8/1/2020 (note, this is actually integer seconds since 1970)


ref:course:term:cis124termEnd1/1/2020


ref:course:term:cis124thisTermT


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 nameAttribute marker nameAttribute nameAttribute valueActiveNext start time
ref:course:term:cis123etc:attribute:mySchool:course:courseetc:attribute:mySchool:course:campuspalmer

ref:course:term:cis123etc:attribute:mySchool:course:courseetc:attribute:mySchool:course:campussouthern

ref:course:term:cis124etc:attribute:mySchool:course:termStartetc:attribute:mySchool:course:termStart8/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 idSource idAttribute nameAttribute valueActiveNext start timeLast end time
jsmithpersonaffiliationstaffT

jsmithpersondeptmathT

jsmithpersondeptphysicsT

rjohnsonpersonschoolengineeringF
11/1/2020
wturnerpersonprimaryAffiliationfacultyT

Parse expression with JEXL

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)
 Click here to expand...
ASTJexlScript
- ASTOrNode
  - ASTERNode
    - ASTReference
      - ASTIdentifier: group
      - ASTIdentifier: campus
    - ASTReference
      - ASTArrayLiteral
        - ASTReference
          - ASTStringLiteral: palmer
        - ASTReference
          - ASTStringLiteral: southern
  - ASTReference
    - ASTReferenceExpression
      - ASTAndNode
        - ASTGTNode
          - ASTAdditiveNode
            - ASTReference
              - ASTIdentifier: group
              - ASTIdentifier: termStart
            - ASTAdditiveOperator: -
            - ASTNumberLiteral: 7
          - ASTReference
            - ASTIdentifier: sysdate
        - ASTLTNode
          - ASTAdditiveNode
            - ASTReference
              - ASTIdentifier: group
              - ASTIdentifier: termStart
            - ASTAdditiveOperator: -
            - ASTNumberLiteral: 7
          - ASTReference
            - ASTIdentifier: 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']
 Click here to expand...
ASTJexlScript
- ASTAndNode
  - ASTERNode
    - ASTReference
      - ASTIdentifier: person
      - ASTIdentifier: primaryAffiliation
    - ASTReference
      - ASTArrayLiteral
        - ASTReference
          - ASTStringLiteral: faculty
        - ASTReference
          - ASTStringLiteral: staff
  - ASTERNode
    - ASTReference
      - ASTIdentifier: person
      - ASTIdentifier: dept
    - ASTReference
      - ASTArrayLiteral
        - ASTReference
          - ASTStringLiteral: physics
        - ASTReference
          - ASTStringLiteral: 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

Loading groups that are used

We could have another table which links up expressions (policies) with the groups used in those policies.  Loader jobs which only load groups which are used (if a fraction of course groups are used) could key off that table to know that a group is used in a policy and needs to be populated.

  • No labels