======================================== Derive From Entry Configuration Options: ======================================== 0. Use Derive from Entry Property: authorization.deriveFromEntry as boolean 1a. List of groups' ldap entry attribute values. Can be cn, uid, dn etc. of the entry. These entries contain multivalued attributes which are member users or nested groups. Property: authorization.deriveFromEntryEntries as array of ldap entry attributes e.g.: array('cn=it,cn=groups,dc=ad,dc=myuniversity,dc=edu', 'cn=people,cn=groups,dc=ad,dc=myuniversity,dc=edu') e.g.: array('it', 'people') 1b. Attribute who's value is contained in 1a. This pair will be used to search from group entries. Property: authorization.deriveFromEntryEntriesAttr as LDAP attribute name e.g. 'dn', 'cn', ... 2. Name of multivalued attribute whose value contains members. Property: authorization.deriveFromEntryMembershipAttr as LDAP attribute name e.g.: 'uniquemember', 'member' 3. User's LDAP Entry Attribute which will be held in deriveFromEntryMembershipAttr Property: authorization.deriveFromEntryAttrMatchingUserAttr as LDAP attribute name e.g.: 'dn', 'cn' 4. Search all enabled LDAP servers for matching users Property: authorization.deriveFromEntrySearchAll as boolean 5. Include nested groups. Property: authorization.deriveFromEntryNested: boolean 6. Convert full dn to value of first attribute. Property: authorization.deriveFromEntryUseFirstAttr: boolean 7. Class of entries that represent groupgs. Property: server.groupObjectClass as LDAP attribute value held in objectClass. e.g.: 'groupOfUniqueNames', 'group' ======================================== Derive From Entry walk-through NOT nested: ======================================== --- configuration ------ 0. authorization.deriveFromEntry = 1 1. authorization.deriveFromEntryEntries = array('cn=it,cn=groups,dc=ad,dc=myuniversity,dc=edu', 'cn=people,cn=groups,dc=ad,dc=myuniversity,dc=edu') 1b. authorization.deriveFromEnryEntryAttribute' = 'distinguishedname' 2. authorization.deriveFromEntryMembershipAttr = 'uniquemember' 3. authorization.deriveFromEntryAttrMatchingUserAttr = 'dn' 4. authorization.deriveFromEntrySearchAll = 0 5. authorization.deriveFromEntryNested = 0 6. authorization.deriveFromEntryUseFirstAttr = 1 7. server.groupObjectClass = 'groupOfUniqueNames' user ldap entry in question: 'dn' => 'uid=joeprogrammer,ou=it,dc=ad,dc=myuniversity,dc=edu', 'cn' => 'joeprogrammer', 'uid' => 'joeprogrammer', 'mail' => array( 0 => 'joeprogrammer@myuniversity.edu'), 'uid' => array( 0 => 'joeprogrammer'), --- walk-through ------ 1). foreach base dn, execute the following query: (& (objectClass=groupOfUniqueNames) (|(distinguishedname=cn=it,cn=groups,dc=ad,dc=myuniversity,dc=edu)(distinguishedname=people,cn=groups,dc=ad,dc=myuniversity,dc=edu)) (uniquemember=cn=joeprogrammer,ou=it,dc=ad,dc=myuniversity,dc=edu) ) in psuedo code: (& (objectClass=[server.groupObjectClass]) (|([authorization.deriveFromEnryEntryAttribute]=[authorization.deriveFromEntryEntries[i]])...([authorization.deriveFromEnryEntryAttribute]=[authorization.deriveFromEntryEntries[n]])) ([authorization.deriveFromEntryMembershipAttr]=[user_ldap_entry[deriveFromEntryAttrMatchingUserAttr]]) ) 2. All entries returned represent groups that user is a member of. Their DNs are added to the list of authorizations or the first attribute value if authorization.deriveFromEntryUseFirstAttr is true. ======================================== Derive From Entry walk-through NESTED: ======================================== --- configuration ------ 0. authorization.deriveFromEntry = 1 1. authorization.deriveFromEntryEntries = array('cn=it,cn=groups,dc=ad,dc=myuniversity,dc=edu', 'cn=people,cn=groups,dc=ad,dc=myuniversity,dc=edu') 1b. authorization.deriveFromEnryEntryAttribute = 'distinguishedname' 2. authorization.deriveFromEntryMembershipAttr = 'uniquemember' 3. authorization.deriveFromEntryAttrMatchingUserAttr = 'dn' 4. authorization.deriveFromEntrySearchAll = 0 5. authorization.deriveFromEntryNested = 1 6. authorization.deriveFromEntryUseFirstAttr = 1 7. server.groupObjectClass = 'groupOfUniqueNames' user ldap entry in question: 'dn' => 'uid=joeprogrammer,ou=it,dc=ad,dc=myuniversity,dc=edu', 'mail' => array( 0 => 'joeprogrammer@myuniversity.edu'), 'uid' => array( 0 => 'joeprogrammer'), --- walk-through ------ 1). foreach base dn, execute the following query: (& (objectClass=groupOfUniqueNames) (|(distinguishedname=cn=it,cn=groups,dc=ad,dc=myuniversity,dc=edu)(cn=people,cn=groups,dc=ad,dc=myuniversity,dc=edu)) ) in psuedo code: (& (objectClass=[server.groupObjectClass]) (|([authorization.deriveFromEnryEntryAttribute]=[authorization.deriveFromEntryEntries[i]])...([authorization.deriveFromEnryEntryAttribute]=[authorization.deriveFromEntryEntries[n]])) ) 2. All entries returned represent groups that user MIGHT be a member of. examples: 'dn' => 'cn=it,cn=groups,dc=ad,dc=myuniversity,dc=edu', 'objectclass' => array( 0 => 'groupofuniquenames'), 'uniquemember' => array( 0 => 'cn=developers,cn=groups,dc=ad,dc=myuniversity,dc=edu', 1 => 'cn=sysadmins,cn=groups,dc=ad,dc=myuniversity,dc=edu', 2 => 'uid=joeprojectmanager,ou=it,dc=ad,dc=myuniversity,dc=edu', ), 'dn' => 'cn=people,cn=groups,dc=ad,dc=myuniversity,dc=edu', 'objectclass' => array( 0 => 'groupofuniquenames'), 'uniquemember' => array( 0 => 'cn=students,cn=groups,dc=ad,dc=myuniversity,dc=edu', 1 => 'cn=staff,cn=groups,dc=ad,dc=myuniversity,dc=edu', ), 3. foreach returned entry from query 1. (authorization.deriveFromEntryEntries): if 'uniquemember' contains a value matching 'uid=joeprogrammer,ou=it,dc=ad,dc=myuniversity,dc=edu', add that entry's DN to authorizations in psuedo code: if group[authorization.deriveFromEntryMembershipAttr] contains user[authorization.deriveFromEntryAttrMatchingUserAttr], add corresponding authorization.deriveFromEntryEntries entry to authorizations else recurse through uniquemembers. if user's entry is found, add corresponding authorization.deriveFromEntryEntries entry to authorizations (not the DN that has the user in uniquemembers) 4A. recursion: In the above example the first recursion query looks like: (& (objectClass=groupofuniquenames) (| (distinguishedname=cn=developers,cn=groups,dc=ad,dc=myuniversity,dc=edu) (distinguishedname=cn=sysadmins,cn=groups,dc=ad,dc=myuniversity,dc=eduu) (distinguishedname=uid=joeprojectmanager,ou=it,dc=ad,dc=myuniversity,dc=edu) ) ) which might return: 'dn' => 'cn=developers,cn=groups,dc=ad,dc=myuniversity,dc=edu', 'objectclass' => array( 0 => 'groupofuniquenames'), 'uniquemember' => array( 0 => 'uid=joeprogrammer,ou=it,dc=ad,dc=myuniversity,dc=edu', ), 'dn' => 'cn=sysadmins,cn=groups,dc=ad,dc=myuniversity,dc=edu', 'objectclass' => array( 0 => 'groupofuniquenames'), 'uniquemember' => array( 0 => 'uid=joeprogrammer,ou=it,dc=ad,dc=myuniversity,dc=edu', 1 => 'cn=sysadmins,cn=groups,dc=ad,dc=myuniversity,dc=edu', ), since uid=joeprogrammer,ou=it,dc=ad,dc=myuniversity,dc=edu is found in the first entry, cn=it,cn=groups,dc=ad,dc=myuniversity,dc=edu (the ancestor group) is added to the list of authorizations. Since authorization.deriveFromEntryUseFirstAttr = 1, its truncated to "it" 4B. In the above example the second recursion query would look like: (& (objectClass=groupofuniquenames) (| (distinguishedname=cn=students,cn=groups,dc=ad,dc=myuniversity,dc=edu) (distinguishedname=cn=staff,cn=groups,dc=ad,dc=myuniversity,dc=edu) ) ) which returns: 'dn' => 'cn=staff,cn=groups,dc=ad,dc=myuniversity,dc=edu', 'objectclass' => array( 0 => 'groupofuniquenames'), 'uniquemember' => array( 0 => 'cn=it,cn=groups,dc=ad,dc=myuniversity,dc=edu', 1 => 'uid=unkool,ou=lost,dc=ad,dc=myuniversity,dc=edu', ), 'dn' => 'cn=students,cn=groups,dc=ad,dc=myuniversity,dc=edu', 'objectclass' => array( 0 => 'groupofuniquenames'), 'uniquemember' => array( 0 => 'uid=jdoe,ou=campus accounts,dc=ad,dc=myuniversity,dc=edu', ), 4C. leading to the queries: (& (objectClass=groupofuniquenames) (| (distinguishedname=uid=jdoe,ou=campus accounts,dc=ad,dc=myuniversity,dc=edu) ) ) ...which returns no entries and 4D. (& (objectClass=groupofuniquenames) (| (distinguishedname=cn=it,cn=groups,dc=ad,dc=myuniversity,dc=edu) (distinguishedname=uid=unkool,ou=lost,dc=ad,dc=myuniversity,dc=edu) ) ) which returns: 'dn' => 'cn=it,cn=groups,dc=ad,dc=myuniversity,dc=edu', 'objectclass' => array( 0 => 'groupofuniquenames'), 'uniquemember' => array( 0 => 'cn=developers,cn=groups,dc=ad,dc=myuniversity,dc=edu', 1 => 'cn=sysadmins,cn=groups,dc=ad,dc=myuniversity,dc=edu', 2 => 'uid=joeprojectmanager,ou=it,dc=ad,dc=myuniversity,dc=edu', ), 4E. leading to the query: (& (objectClass=groupofuniquenames) (| (distinguishedname=cn=developers,cn=groups,dc=ad,dc=myuniversity,dc=edu) (distinguishedname=cn=sysadmins,cn=groups,dc=ad,dc=myuniversity,dc=edu) (distinguishedname=uid=joeprojectmanager,ou=it,dc=ad,dc=myuniversity,dc=edu) ) ) which returns: 'dn' => 'cn=developers,cn=groups,dc=ad,dc=myuniversity,dc=edu', 'objectclass' => array( 0 => 'groupofuniquenames'), 'uniquemember' => array( 0 => 'uid=joeprogrammer,ou=it,dc=ad,dc=myuniversity,dc=edu', ), 'dn' => 'cn=sysadmins,cn=groups,dc=ad,dc=myuniversity,dc=edu', 'objectclass' => array( 0 => 'groupofuniquenames'), 'uniquemember' => array( 0 => 'uid=joeprogrammer,ou=it,dc=ad,dc=myuniversity,dc=edu', 1 => 'cn=sysadmins,cn=groups,dc=ad,dc=myuniversity,dc=edu', ), since uid=joeprogrammer,ou=it,dc=ad,dc=myuniversity,dc=edu is found in the first entry, cn=people,cn=groups,dc=ad,dc=myuniversity,dc=edu (the ancestor group) is added to the list of authorizations. Since authorization.deriveFromEntryUseFirstAttr = 1, its truncated to "people" ==================================================================