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

Compare with Current View Page History

« Previous Version 2 Next »


We will make a SQL provisioner in Grouper v2.5.

Configuration

Common config attributes for LDAP are below.

ConfigExampleDescriptionNotes
class

edu.internet2.middleware.grouper.app.sqlProvisioning.SqlMembershipProvisioner

Class extends the base provisioner classThis class informs configuration decisions. Required. Read-only.
hasSubjectLink

true

false

If the subject API is needed to resolve attribute on subjectrequired, drives requirements of other configurations. defaults to false.
hasTargetUserLink

true

false

If subjects need to be resolved in the target before provisioning

defaults to false. required.
hasTargetGroupLink

true

false

If groups need to be resolved in the target before provisioningdefaults to false. required.
subjectSourcesToProvisionpennpersonsubject sources to provisionrequired. defaults to all except g:gsa, grouperExternal, g:isa, localEntities. comma separated list. checkboxes. 
userTableNameuserstable to query to lookup usersrequired if hasTargetUserLink
userSearchAttributeNameemployee_idcolumn to filter onrequired if hasTargetUserLink
userSearchAttributeValueFormat

${subject.id}
${targetEntity.attributes['uid']}

value for the user search attribute namerequired if hasTargetUserLink
membershipTableNamemembershipstable where memberships go

required

syncMemberToId2AttributeValueFormat${targetEntity.attributes['user_id']}main identifier of the user on the target sideshow = false
syncMemberToId3AttributeValueFormat${targetEntity.attributes['uid']}identifier of the user as referred to by the membershipshow = false
syncMemberFromId2AttributeValueFormat${targetEntity.attributes['netId']}

target attribute value that helps look up user

show = false
syncMemberFromId3AttributeValueFormat${subject.attributes['myLdapId']}

subject attribute value that helps look up user

show = false
syncGroupToId2AttributeValueFormat${targetGroup.attributes['group_id']}main identifier of the group on the target sideshow = false
syncGroupToId3AttributeValueFormat${targetEntity.attributes['gid']}identifier of the group as referred to by the membershipshow = false
syncGroupFromId2AttributeValueFormat${targetEntity.attributes['groupName']}target attribute value that helps look up groupshow = false
userSearchAttributesuser_id, name, emailcolumns to search when getting usersoptional. show if hasTargetUserLink.
createMissingUserstrue or false
defaults false, optional. show if hasTargetUserLink
createMissingGroupstrue or false
defaults to true. show if hasTargetGroupLink
groupSearchAttributeNamegid_numbercolumn name to filter on

show if hasTargetGroupLink 

required

groupSearchAttributeValueFormat${syncGroup.groupIdIndex}value to filter group on

show if hasTargetGroupLink 

required

groupSearchAttributescn,gidNumber,samAccountName,objectclassattributes to get if searching for groups

optional

show if hasTargetGroupLink 

deleteGroupsInTargetIfInTargetAndNotGroupertrue or falseif groups in full sync should be deleted if in group all query and not in grouper
or for attributes delete other attribute not provisioned by grouper
default to false
deleteGroupsInTargetIfDeletedInGroupertrue or falseif groups that were created in grouper were deleted should it be deleted in ldap?
or for attributes, delete attribute value if deleted in grouper
default to true
deleteMembershipsInTargetIfInTargetAndNotGrouper
if memberships in full sync should be deleted if in membership all query and not in grouper
or for attributes delete other attribute not provisioned by grouper
default to false
deleteMembershipsInTargetIfInTargetAndNotGrouper
if memberships that were created in grouper were deleted should it be deleted in ldap?
or for attributes, delete attribute value if deleted in grouper
default to true
membershipFields

members

read,admin

update,admin

admin

if provisioning normal memberships or privilegesdefault to "members" for normal memberships
dbExternalSystemConfigIdwarehouselinks to DB external system in grouper-loader.propertiesrequired






TypeConfigExampleDescriptionNotes
UseruserSearchBaseDnou=userswhere users areoptional. show if hasTargetUserLink
UseruserSearchFilter

employeeID=$userSearchAttributeValueFormat$

how to find a user

optional. show if hasTargetUserLink

UseruserSearchAllFilteremployeeID=*

filter users when searching all (needed?)

optional. show if hasTargetUserLink
UseruserObjectClasspersonif want to specify person object classoptional. show if hasTargetUserLink
UseruserCreationParentDnou=usersbaseDn to create users (is this appended to ldap base dn if not included?)required. show if createMissingUsers
User

userCreationNumberOfAttributes

integer between 1 and 10
required. show if createMissingUsers
UseruserCreationLdifTemplate_attr_0
cnthe 0th attribute namerequired if createMissingUsers
UseruserCreationLdifTemplate_val_0${syncMember.memberToId2}

the 0th attribute value

required if createMissingUsers
UseruserCreationLdifTemplate_attr_1objectclassthe 1st attribute namerequired if createMissingUsers
UseruserCreationLdifTemplate_val_1personthe 1st attribute valuerequired if createMissingUsers
GroupgroupSearchBaseDnou=groups
optional. show if hasTargetGroupLink
GroupgroupSearchFilter

(&(objectclass=group)(gidNumber=${syncGroup.groupIdIndex}))   -or-

dn=${syncGroup.groupToId2}

find a single group (other than by DN)optional. show if hasTargetGroupLink
GroupgroupsSearchAllFilter(&(objectclass=group)(gidNumber=*))find all groupsoptional. show if hasTargetGroupLink
GroupgroupDnTypebushy or flatbushy makes an ou for each folder and cn is extension.  flat is cn is group name

required

flat dn will be: 
cn=${groupName},ou=grouper,ou=groups,dc=example,dc=edu

bushy dn will be: 
${grouperUtil.convertNameToCnAndOus(groupName)},ou=grouper,ou=groups,dc=example,dc=edu

GroupgroupObjectClassgroupOfUniqueNamesdefault object classoptional
Group

groupCreationNumberOfAttributes

integer between 1 and 10
required. show if createMissingGroups
GroupgroupCreationLdifTemplate_attr_[0 to 9]
cnthe 0th attribute namerequired if createMissingGroups
GroupgroupCreationLdifTemplate_val_[0 to 9]${syncGroup.groupToId2}

the 0th attribute value

required if createMissingGroups
GroupgroupCreationLdifTemplate_maxLength_[0 to 9]900max length of this attribute, abbreviate after that (ellipses)helpful e.g. for description in active directory
Group
User
Attribute
provisionedAttributeNameattribute to provision toattribute of person or group that has memberships
Group
User
Attribute
provisionedAttributeValueFormat${syncGroup.groupName} or ${syncMember.memberToId2}how to get the value for the attribute
AttributeallProvisionedValuesPrefix
prefix of attributes to manage.  e.g. delete if not in grouper

LDAP provisioning types

grouperLdapProvisioningCases

Discussion topics

  • Should we use DAO for LDAP so we can unit test everything but the LDAP stuff?  Also for dry run?  (smile)
    Yes

  • User cache / group cache / subject cache
    • Need a provisioner col for last retrieved
      Update cache with nightly full sync, on error, refresh subject and ldap user from target, and try again
    • How daemon works
      syncing and the cache updating.  Note: it can use the subject source data from the nonblocking state inside the blocking state
      1. Nonblocking, unless over a threshold.  Few changes, start blocking after know changes, get the state from both sides for those changes, make the changes, unblock.
      2. If over a certain threshold (need algorithm for number of objects: groups or users), block, and recalculate and sync
    • How cached fields stored in db?  JSON?  cols?
      Keep a col for the lookups to query on, and a col for json representation of group and user
    • Store subject attributes?  use member table?  add a couple cols?  identifier1, identifier2..5?  update periodically?
      Lookup attributes will be in the sync tables
  • Pulling data from grouper, only certain columns?
    Dont pull from hibernate, just use simple query like grouper_memberships_lw_v but without distinct (maybe groupId and memberId)
  • User sync?
    Yes, we should plan for this
  • Folder sync
    Do individual groups if its inside a threshold or full refresh from outside the threshold.  If group deletes in ldap are needed, a full sync is needed
  • Selecting subjects
    • Use the subject cache, and tune that as needed to fully prime
    • If errors resolve subjects without cache
  • Batch size, should be at ldap or provisioner level?  do we need different for users and groups? e.g. userSearch_batchSize
    Default batch size at LDAP level, override for provisioner.  If over threshold, get all, otherwise, cycle through.  Could leave "all" filter blank if known not to provision a lot of groups
    • Need a batch size for updates?  How do batches work?
      Theres no batch size for objects, one at a time.  Attributes have batch size with default at ldap level
    • Can this be in the LDAP framework (and it will batch things up, thats what we do for jdbc)    yes
  • Supports empty groups, at ldap or provisioner level?
    Could have null member, could delete group if no members.  Default at ldap level.
  • Should errors be stored in the sync objects so they can be absorbed?   yes
    • Message for processing errors?  yes and timestamp
    • Group, user, membership errors?  yes, list the error and skip (based on configuration)
  • Search result paging is at ldap or provisioner level?  defaults at ldap level
  • Do we need an isActiveDirectory flag?  keep this, TODO add back in
  • Support dry run? 
    For grouper admins to test what will happen if configuration changes.
    For a single group, do a "pretend is provisionable" in ui jvm...
    For single group or user, this would just happen synchronously in ui, or have the ajax updating screen thing (upcoming)
  • Assume gid will not change?  name?  dn?  How do we track groups that move?  i.e. in the grouper_sync_group table?
    The cached DN needs to not change until the provisioner can make sure theres a way to reference the old object to do updates and not delete/insert
  • Ldif templates, lets change the config of this.  maybe json?  or at least user $newline$?  Need for jexl things?   Escaping?
    Yes, do this, and use $newline$
  • Replacing grouperIsAuthoritative to be more explicit
    Yes do this
  • Logging like change log consumer or database provisioning
    Yes
  • Does memberOf and hasMember always use the DN of the user or group?   generally yes
  • Do we need to support updating group and user or will updating the group handle it?   this is an attribute provisioner
  • Convert to some simple object structure from ldap?  or use the ldap objects for jexl?  do we need these with the sync groups? We have a low-memory object structure
    • Single valued attributes strings unless configured attributes are multivalued (use arrays since lightweight) Yes, single valued objects or array of strings
    • Last updated columns in ldap?  numbers: number of millis from epoch  Not used
    • User
      • Bean with single and multivalued attribute Similar to pspng, bean with dn and name/value pair attributes
  • Can we support getting memberships or privileges (e.g. ADMIN/READ) Yes, interface to get memberships
  • Option to constrain to subject source? Yes
  • Do we know the types of ldap attributes?  Is there a metadata schema query? Shilen says generally strings
  • Group DNs, can it be dynamic?  Can it be handled upstream in provisioning framework? We would like it to happen in the provisioning framework.  Note, complicates the all group filter
  • Is memberOf or hasMember the only multi-valued attributes?  do types of attributes matter?  e.g. integer vs string?  objectclass is multivalued, and memberships, other attributes are arrays of strings

LDAP operations

If batches fail, do each individually.  This is the DAO implemented three ways: read/write to LDAP, mock for testing, and readonly dry run

OperationDescription
Create objectWith DN and list of attributes
Delete objectBy DN
Modify attribute batch

For one object by DN, modify an object
Batch up the attribute modifications
Return report and try individually if failure

Modify attribute indivIf error on batch of attribute modifies, do individually
Move objectFrom one DN to another
ReadBy DN with attributes
SearchBy filter with attributes

Caching

Sync objects can cache information in LDAP.  Synced from full sync (if doesnt exist or if errors), incremental (if doesnt exist or if errors), and the nightly (scheduled) subject resolution daemon (full refresh)

ObjectFieldCached data
gcGrouperSyncGroupgroupToId2group DN
gcGrouperSyncGroupgroupToId3whatever attribute value the user attribute refers to
gcGrouperSyncGroupgroupFromId2ldap group object attribute value that looks up group
gcGrouperSyncMembermemberToId2user DN
gcGrouperSyncMembermemberToId3whatever attribute value the group attribute refers to users as
gcGrouperSyncMembermemberFromId2ldap person object attribute value that looks up user
gcGrouperSyncMembermemberFromId3subject attribute value that helps look up user

Group of unique names example

ldapProvisioner.myOpenLdap.ldapPoolName = myOpenLdapServer
ldapProvisioner.myOpenLdap.ldapProvisioningType = groupMembershipsLdapLink
ldapProvisioner.myOpenLdap.subjectSourcesToProvision = mySubjectSource
ldapProvisioner.myOpenLdap.userSearchBaseDn = cn=users,dc=example,dc=edu
ldapProvisioner.myOpenLdap.userSearchAttributeName = uid
ldapProvisioner.myOpenLdap.userSearchAttributeValueFormat = ${syncMember.getSubjectId()}
ldapProvisioner.myOpenLdap.groupSearchBaseDn = ou=grouper,ou=groups,dc=example,dc=edu
ldapProvisioner.myOpenLdap.groupSearchAttributeName = gidNumber
ldapProvisioner.myOpenLdap.groupSearchAttributeValueFormat = ${syncGroup.getGroupIdIndex()}
ldapProvisioner.myOpenLdap.groupObjectClass = groupOfUniqueNames
ldapProvisioner.myOpenLdap.provisionedAttributeName = uniqueMember
ldapProvisioner.myOpenLdap.provisionedAttributeValueFormat = ${ldapUser.getDn()}
ldapProvisioner.myOpenLdap.groupDnType = flat

This will assume the following:

ItemDescription
userSearchFilter(uid=${syncMember.getSubjectId()})
userSearchAllFilter(uid=*)
userSearchAttributesuid,dn
groupSearchAttributesgidNumber,objectclass,cn,dn
groupSearchFilter(&(objectclass=groupOfUniqueNames)(cn=${syncGroup.getGroupName()})
groupsSearchAllFilter(&(objectclass=groupOfUniqueNames)(cn=*))
groupCreationLdifTemplatedn=${groupName},ou=grouper,ou=groups,dc=example,dc=edu
cn=${groupName}
objectclass=groupOfUniqueNames

Active Directory groups example

ldapProvisioner.myActiveDirectory.ldapPoolName = myActiveDirectoryServer
ldapProvisioner.myActiveDirectory.isActiveDirectory = true
ldapProvisioner.myActiveDirectory.ldapProvisioningType = groupMembershipsLdapLink
ldapProvisioner.myActiveDirectory.subjectSourcesToProvision = mySubjectSource
ldapProvisioner.myActiveDirectory.userSearchBaseDn = cn=users,dc=example,dc=edu
ldapProvisioner.myActiveDirectory.userSearchAttributeName = samAccountName
ldapProvisioner.myActiveDirectory.userSearchAttributeValueFormat = ${syncMember.getSubjectIdentifier()}
ldapProvisioner.myActiveDirectory.groupSearchBaseDn = ou=grouper,ou=groups,dc=example,dc=edu
ldapProvisioner.myActiveDirectory.groupDnType = bushy
ldapProvisioner.myActiveDirectory.groupCreationLdifTemplate_attr_0 = displayname
ldapProvisioner.myActiveDirectory.groupCreationLdifTemplate_val_0 = ${group.getDisplayExtension()}
ldapProvisioner.myActiveDirectory.groupCreationLdifTemplate_attr_1 = description
ldapProvisioner.myActiveDirectory.groupCreationLdifTemplate_val_1 = ${group.getDescription()}
ldapProvisioner.myActiveDirectory.groupCreationLdifTemplate_maxLength_1 = 900

This will assume the following:

ItemDescription
userSearchFilter(samAccountName=${syncMember.getSubjectIdentifier()})
userSearchAllFilter(samAccountName=*)
userSearchAttributessamAccountName,dn
groupObjectClassgroup
groupSearchAttributeNamegidNumber
groupSearchAttributeValueFormat${syncGroup.getGroupIdIndex()}
groupSearchAttributesgidNumber,objectclass,cn,dn,displayname,description
groupSearchFilter(&(objectclass=groupObjectClass )(gidNumber=${syncGroup.getGroupIdIndex()})
groupsSearchAllFilter(&(objectclass=groupObjectClass )(gidNumber=*))
groupCreationLdifTemplate

dn=${grouperUtil.convertNameToCnAndOus(groupName)},ou=grouper,ou=groups,dc=example,dc=edu
cn=${groupExtension}
objectclass=groupObjectClass 
gidNumber=${syncGroup.getGroupIdIndex()}
displayname=${group.getDisplayExtension()}
description=${group.getDescription()}

provisionedAttributeNamemember
provisionedAttributeValueFormat${syncMember.getMemberToId2()}

User attributes example

ldapProvisioner.openLdapUserAttributes.ldapPoolName = myOpenLdapServer
ldapProvisioner.openLdapUserAttributes.ldapProvisioningType = userAttributesSimple
ldapProvisioner.openLdapUserAttributes.subjectSourcesToProvision = mySubjectSource
ldapProvisioner.openLdapUserAttributes.userSearchBaseDn = cn=users,dc=example,dc=edu
ldapProvisioner.openLdapUserAttributes.userSearchAttributeName = uid
ldapProvisioner.openLdapUserAttributes.userSearchAttributeValueFormat = ${syncMember.getSubjectId()}
ldapProvisioner.openLdapUserAttributes.provisionedAttributeName = eduPersonEntitlement
ldapProvisioner.openLdapUserAttributes.provisionedAttributeValueFormat = g:${group.name}
ldapProvisioner.openLdapUserAttributes.allProvisionedValuesPrefix = g:

This will assume the following:

ItemDescription
userSearchFilter(uid=${syncMember.getSubjectId()})
userSearchAllFilter(uid=*)
userSearchAttributesuid,eduPersonEntitlement
  • No labels