You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 12 Next »

Provisioning's job is to reflect Groups and their Memberships in other systems. Over the years, dozens of provisioners have been created -- some focused on a single destination type and others with some generic functionality combined with a very wide variety of options and capabilities.

In recent years, the Grouper Team and Users have concluded that the provisioning priorities should change: less flexibility and increased simplicity and performance. The Next Generation of the Grouper Provisioning Service Provider (aka PSPNG) was defined in Post PSP Provisioning and is expected to replace the older PSP components over time.

Development Status and Features

PSPNG's general structure should be ready to provision various targets, but its current implementation is limited to provisioning LDAP targets like:

  • -(Unix) LDAP Groups: (GroupOfUniqueNames, GroupOfNames, PosixGroup)
  • -Active Directory Groups
  • -LDAP Attributes (like eduPersonEntitlement)

Configuration

PSPNG's Configuration is done via the grouper-loader.properties file, with a paragraph for each provisioning destination, as well as an additional paragraph that enables and configures FullSync operation. There are several configuration options documented in the following spreadsheet, but most are optional: https://docs.google.com/spreadsheets/d/1FenN3hICohYR6cvr8Zxuk11VNyt82clvuouZQHgTT-w (this spreadsheet needs to move to the Grouper Wiki).

LDAP Properties

LDAP configuration is done based on the ldaptive library's property configuration. A paragraph of ldap configuration is created in grouper-loader.properties for each ldap endpoint, and that paragraph is referenced by the appropariate provisioners. For example:
ldap.groupOfNames.ldapUrl = ldaps://hostname
ldap.groupOfNames.bindDn = cn=xxxxxx,ou=xxxxx
 ldap.groupOfNames.bindCredential = xxxxx
 
changeLog.consumer.pspng_groupOfUniqueNames.ldapPoolName = groupOfNames

The range of properties supported by ldaptive does not seem to be assembled in once place. One simple example can be found here. Moving into more realistic examples will probably be helped by looking at the ldaptive configuration classes and the setters available within them: connectionspooling, binding (sasl, gssapix509, jks, etc). There is plenty of flexibility in ldaptive's configuration, but it does not seem to be designed for configuration via a single list of properties. As PSPNG is deployed into more and more ldap environments and requirements, we're going to learn, document and need to evolve how to tunnel a list of properties from grouper-loader.properties correctly into all the necessary ldaptive configuration classes. In case it is helpful, this is currently implemented in LdapProvisionerConfiguration.buildLdapConnectionPool
Additionally, some basic properties (and probably advanced ones, too) are different between vtldap and ldaptive. For example, vtldap uses 'url' while ldaptive requires 'ldapUrl'. Understandable and annoying. GRP-1306 discusses this and suggests that we implement some compatibility between the two libraries' configuration.

Group Selection

Groups can be enabled and disabled based on Group or Stem information and attributes. By default, two multivalued attributes are

used -- etc:attribute:userData:provision_to and ...:do_not_provision_to -- where the provisioner name is listed as values to enable or

disable downstream provisioning. Beyond this default, the group-selecting filter is a JEXL expression and can utilize Group information

and Stem & Group attributes.

Account creation

To facilitate (load) testing, Grouper PSPNG has limited ability to create accounts in a target system. This ability is very rudimentary and should not be used to maintain accounts in production; such maintenance should be done by an IdM product or some other ETL mechanism. If you choose to ignore this best practice, you'll probably run into two main problems:

  1. Grouper/PSPNG has no ability to keep accounts up to date; it only creates them if they're missing, and
  2. Your Grouper-subject mappings probably don't have some of the information needed for account provisioning. And, even if all you need is name, username, and email address (which are probably in your subject mappings), you'll still run into problem (1) where Grouper offers no mechanism to update name and email address when they change in your subject source.

Example Configurations:

GROUP OF UNIQUE NAMES:
changeLog.consumer.pspng_groupOfUniqueNames.class = edu.internet2.middleware.grouper.pspng.PspChangelogConsumerShim
changeLog.consumer.pspng_groupOfUniqueNames.type = edu.internet2.middleware.grouper.pspng.LdapGroupProvisioner
changeLog.consumer.pspng_groupOfUniqueNames.quartzCron = 0 * * * * ?
changeLog.consumer.pspng_groupOfUniqueNames.ldapPoolName = opendj
changeLog.consumer.pspng_groupOfUniqueNames.memberAttributeName = uniqueMember
changeLog.consumer.pspng_groupOfUniqueNames.memberAttributeValueFormat = ${ldapUser.getDn()}
changeLog.consumer.pspng_groupOfUniqueNames.groupSearchBaseDn = ou=grouper,ou=groups,dc=example,dc=edu
changeLog.consumer.pspng_groupOfUniqueNames.allGroupsSearchFilter = objectclass=groupOfUniqueNames
changeLog.consumer.pspng_groupOfUniqueNames.singleGroupSearchFilter = (&(objectclass=groupOfUniqueNames)(cn=${group.name}))
changeLog.consumer.pspng_groupOfUniqueNames.groupSearchAttributes=cn,gidNumber,objectclass

changeLog.consumer.pspng_groupOfUniqueNames.groupCreationLdifTemplate = dn: cn=${group.name}||cn: ${group.name}||objectclass: groupOfUniqueNames
changeLog.consumer.pspng_groupOfUniqueNames.userSearchBaseDn = cn=users,dc=example,dc=edu
changeLog.consumer.pspng_groupOfUniqueNames.userSearchFilter = uid=${subject.id}

POSIX GROUPS:
changeLog.consumer.pspng_posixGroup.class = edu.internet2.middleware.grouper.pspng.PspChangelogConsumerShim
changeLog.consumer.pspng_posixGroup.type = edu.internet2.middleware.grouper.pspng.LdapGroupProvisioner
changeLog.consumer.pspng_posixGroup.quartzCron = 0 * * * * ?
changeLog.consumer.pspng_posixGroup.ldapPoolName = opendj
changeLog.consumer.pspng_posixGroup.memberAttributeName = memberUid
changeLog.consumer.pspng_posixGroup.memberAttributeValueFormat = ${ldapUser.getStringValue("uid")}
changeLog.consumer.pspng_posixGroup.groupSearchBaseDn = ou=grouper-posix,ou=groups,dc=example,dc=edu
changeLog.consumer.pspng_posixGroup.allGroupsSearchFilter = objectclass=posixGroup
changeLog.consumer.pspng_posixGroup.singleGroupSearchFilter = (&(objectclass=posixGrouper)(cn=${group.name}))

changeLog.consumer.pspng_posixGroup.groupSearchAttributes=cn,gidNumber,objectclass

# Obviously, gidNumber should be based on a grouper-group attribute
changeLog.consumer.psong_posixGroup.groupCreationLdifTemplate = dn: cn=posix-${group.name}||cn: posix-${group.name}||objectclass: posixGroup||objectclass: groupOfNames||gidNumber: ${group.idIndex}
changeLog.consumer.pspng_posixGroup.userSearchBaseDn = cn=users,dc=example,dc=edu
changeLog.consumer.pspng_posixGroup.userSearchFilter = uid=${subject.id}

ACTIVE DIRECTORY GROUPS
changeLog.consumer.pspng_activedirectory.class = edu.internet2.middleware.grouper.pspng.PspChangelogConsumerShim
changeLog.consumer.pspng_activedirectory.type = edu.internet2.middleware.grouper.pspng.LdapGroupProvisioner
changeLog.consumer.pspng_activedirectory.quartzCron = 0 * * * * ?
changeLog.consumer.pspng_activedirectory.ldapPoolName = active_directory
changeLog.consumer.pspng_activedirectory.isActiveDirectory = true

changeLog.consumer.pspng_activedirectory.memberAttributeName = member
changeLog.consumer.pspng_activedirectory.memberAttributeValueFormat = ${ldapUser.getDn()}
changeLog.consumer.pspng_activedirectory.groupSearchBaseDn = ou=grouper,ou=groups,dc=example,dc=edu
changeLog.consumer.pspng_activedirectory.allGroupsSearchFilter = objectclass=group
changeLog.consumer.pspng_activedirectory.singleGroupSearchFilter = (&(objectclass=group)(cn=${group.name}))
changeLog.consumer.pspng_activedirectory.groupCreationLdifTemplate = dn: cn=${group.name}||cn: ${group.name}||objectclass: group
changeLog.consumer.pspng_activedirectory.userSearchBaseDn = cn=users,dc=example,dc=edu
changeLog.consumer.pspng_activedirectory.userSearchFilter = samAccountName=${subject.id}


NOTE: The DN of the group can be Bushy (one LDAP OU for each Folder/Stem of the group) by doing the following:
dn: utils.bushyDn(group.name, "cn", "ou")


USER ATTRIBUTES
changeLog.consumer.pspng_attributes.class = edu.internet2.middleware.grouper.pspng.PspChangelogConsumerShim
changeLog.consumer.pspng_attributes.type = edu.internet2.middleware.grouper.pspng.LdapAttributeProvisioner
changeLog.consumer.pspng_attributes.quartzCron = 0 * * * * ?
changeLog.consumer.pspng_attributes.retryOnError = true
changeLog.consumer.pspng_attributes.ldapPoolName = opendj
changeLog.consumer.pspng_attributes.provisionedAttributeName = eduPersonEntitlement
changeLog.consumer.pspng_attributes.provisionedAttributeValueFormat = g:${group.name}
changeLog.consumer.pspng_attributes.userSearchBaseDn = cn=users,dc=example,dc=edu
changeLog.consumer.pspng_attributes.userSearchFilter = uid=${subject.id}
changeLog.consumer.pspng_attributes.allProvisionedValuesPrefix=g:


FULL SYNC
changeLog.psp.fullSync.class = edu.internet2.middleware.grouper.pspng.FullSyncStarter
changeLog.psp.fullSync.quartzCron = 0 0 5 * * ?
# This happens in the background, so should usually be enabled, and should _definitely_
# be enabled when new provisioners are added
changeLog.psp.fullSync.runAtStartup = true

  • No labels