This applies to Grouper v2.6.16+
To enforce membership eligibility, you can use a composite, rules, JEXL scripted groups, or you can use this new feature. You can link an attribute with an eligibility group so that immediate memberships (not effective, composite, loaded) from a (probably) manual group will be veto-ed or removed when users are no longer eligible because they are no longer effectively in the eligible population group.
Steps to implement
These are explained below
- Identify coarse grained populations that manual groups could be constrained to
- Create attribute def(s) and attribute names.
- Make as many attribute defs as you want (equal to or less than the number of populations)
- The number of attribute names is 1-to-1 to the coarse grained populations.
- Allow certain groups to be able to read and assign the attribute (e.g. power users)
- Configure the attribute in grouper.properties to be linked to an eligibility group (e.g. employees)
- Configure the veto text in the externalized text file
- Configure the attribute to be assigned in the group edit screen (optional)
- We can allow attributes on stem edit screens in future
- Assign the attribute to groups or folders
- Note, loader groups are not affected
- Membership hook will veto membership adds if the user is not eligible
- Change log consumer will remove members when no longer eligible
- Full sync daemon will make sure everything is correct
- When members are removed a record is kept in the grouper_mship_req_change table
- A simple GSH script could easily rollback changes made by this module
Identify coarse grained populations
Note, these do not need to be direct members.
Create attributes
Allow certain people to be able to read and assign the attribute (e.g. power users)
Configure the attribute in grouper.properties to be linked to an eligibility group (e.g. employees)
# ui key to externalize text grouper.membershipRequirement.requireEmployee.uiKey = vetoRequireEmployee # attribute name that signifies this requirement grouper.membershipRequirement.requireEmployee.attributeName = etc:attribute:membershipRequirement:requireEmployee # group name which is the population group grouper.membershipRequirement.requireEmployee.requireGroupName = ref:employee # if the overall hook is enabled, is the hook for this specific config enabled? defaults to true. grouper.membershipRequirement.requireEmployee.hookEnable = true
Here is the base config which has general settings
######################################### ## Custom veto composites membership requirement ## This feature allows users to auto-veto ineligible members or remove them when they become ineligible. ## Note that each custom composite also needs to be defined in the Grouper UI text properties in order ## to provide a friendly description in the UI. customCompositeMinusEmployees and customCompositeIntersectIt are also defined as examples there. ######################################### # how long should logs of membership requirement logs be stored in database? grouper.membershipRequirement.keepLogsForDays = 90 # should hook for membership veto be enabled grouper.membershipRequirement.hookEnable = true # should changeLog for membership veto change log be enabled in general grouper.membershipRequirement.changeLogEnable = true # ui key to externalize text #grouper.membershipRequirement.someConfigId.uiKey = customVetoCompositeRequireEmployee # attribute name that signifies this requirement #grouper.membershipRequirement.someConfigId.attributeName = etc:attribute:customComposite:requireEmployee # group name which is the population group #grouper.membershipRequirement.someConfigId.requireGroupName = org:centralIt:staff:itStaff # if the overall hook is enabled, is the hook for this specific config enabled? defaults to true. #grouper.membershipRequirement.someConfigId.hookEnable = true
Configure the veto text in the externalized text file
veto.membershipVeto.customComposite.vetoRequireEmployee = Only employees can be members of this group
Configure the attribute to be assigned in the group edit screen (optional)
groupScreen.attribute.requireEmployee.attributeName = etc:attribute:membershipRequirement:requireEmployee groupScreen.attribute.requireEmployee.label = Require employee groupScreen.attribute.requireEmployee.description = Members of this group (or groups in folder) will be required to be employees, otherwise they will be vetoed or removed groupScreen.attribute.requireEmployee.index = 1
Assign the attribute to groups or folders
Note, this will remove direct members. Note, be careful about service principals, maybe those need to be in a different manual group?
Groups:
Folders
Membership hook will veto membership adds if the user is not eligible
Change log consumer will remove members when no longer eligible
Full sync daemon will make sure everything is correct
When members are removed a record is kept in the grouper_mship_req_change table
select gmrc.the_timestamp, gg.name as removed_from, gm.description, gg_elig.name as eligibility_group, gadn.name as attribute_name, gmrc.config_id, case when gmrc.engine = 'F' then 'fullDaemon' when gmrc.engine = 'C' then 'changeLog' else gmrc.engine end as engine from grouper_mship_req_change gmrc, grouper_members gm, grouper_groups gg, grouper_groups gg_elig, grouper_attribute_def_name gadn where gmrc.member_id = gm.id and gmrc.group_id = gg.id and gmrc.attribute_def_name_id = gadn.id and gmrc.require_group_id = gg_elig.id order by the_timestamp desc;
TO DO
More features can be added to this:
- Notifications (to managers or users)
- Grace periods
- Readonly mode
- Exclude groups which are "exclude" type (doesnt exist yet)
- Exclude groups by regex
- Include only manual groups
- Constrain subject sources
- Remove when membership remove in folder (e.g. job or title changes)
- Loader can restrict ineligible members
- Confirm that JEXL scripted groups are affected correctly