RHQ will be modified to allow LDAP groups to map to RHQ Roles that will enable LDAP users to inherit role based authorization schemes after authentication is complete.
User Login --> User Auth LDAP -> User also local user? (no) -> create local user in db automatically -> query LDAP groups for user
(yes) -> query LDAP groups to user
LDAP group query --> Query groups for LDAP user based on full user DN -> Sync user LDAP groups
Sync user LDAP groups -> update Subject/Role tables using LDAP Group/Role mapping table
LDAP Configuration Screen
Role Edit Screen
Add LDAP group to Role Screen
Modified Role with new LDAP Group
we will need to add a column, named IS_LDAP that will track if the subject to role mapping was created via a ldap group
this one will be similar to the resource group map table but we will be tracking the mapping between LDAP groups to roles instead of resource groups. Two columns need to be added to track the Role Id and then the LDAP Group name
A new field will need to be added to track the LDAP Group Search Query. The source files SystemConfigForm.java, RHQConstants.java, LDAPForm.jsp and ApplicationsResources.properties need to be modified to support the new Group Search Query that will be added to the database as a label, value pair.
This will be very similar to the Groups (resource) that are added to roles. There will be an extra box underneath the existing Groups Box that is seen on the Role assignment page. The existing groups will be renamed to "Resource Groups" to distinguish itself from the new LDAP Group box. A query will need to occur to grab all the available groups from the LDAP page. Groups added to the role will be stored in the RHQ_ROLE_LDAP_GROUP_MAP Table
The existing LDAPLoginModule.java, SubjectManagerBean.java will either need to be modified or logic will need to be adapted in another java source file to handle the ldap group search queries. Currently we are using JNDI calls based on the LDAP configuration module properties. JNDI will also be used for the group search queries.
Logic needs to be added to determine what groups a user is a member of. Currently three are two approaches due to the way LDAP servers model their group members. AD users a attribute (that other ldap servers apparently use as well) named memberOf that hangs off the user objects and then users a attribute named member that hangs off the group objects. OpenLDAP does things a big differently but we can still query the groups based off the full DN of the user that is logging in but requires two separate queries due to the different approaches.
An example of using ldapsearch for AD:
ldapsearch -h example.ad.redhat.com -x -D "cn=Administrator,cn=Users,dc=2k8domain,dc=gss" -W -b "dc=2k8domain,dc=gss" -x '(&(objectclass=group)(member=CN=Jeremy Agee,CN=Users,DC=2k8domain,DC=gss))'
An example of using ldapsearch for OpenLDAP:
ldapsearch -H ldap://example.open.redhat.com:389 -b dc=open,dc=redhat,dc=com -x '(&(objectclass=groupOfUniqueNames)(uniqueMember=uid=shaggy,ou=People, dc=open, dc=redhat, dc=com))'
Both of the searches above returns a list of group(s) for the users DN.
At user login we need to make sure that we update the RHQ_SUBJECT_ROLE_MAP if the ldap user logging in is part of a group that has a role assigned to it in the new RHQ_ROLE_LDAP_GROUP_MAP table. similar, we need to remove entries that have lost the ldap group to role assignments. this can occur in the ldaploginmodule.java source file
if we know some user is an ldap-based user...do we want to control the role-subject mappings through the sync process ONLY, or do we also want to allow users to manually modify that list? if so, then we should disable removing ldap-based role-subject mappings, right?
alternate solution would be to have two mapping tables: the current rhq_subject_role_map and a new rhq_subject_role_ldap_map. then, we have two @ManyToMany sets of mappings, one for ldap-synced mappings, the
other for regular mappings setup through the RHQ UI.
any additions/removals from the ldap-based collection would also add/remove from the regular collection. authorization would still be done through the regular collection.
new column IS_LDAP on the RHQ_SUBJECT_ROLE_MAP table
current @ManyToMany mappings will not let you access that metadata column on the linking table, so...
need to create new entity called SubjectRoleEntity
need OneToMany mapping from Role->SubjectRoleEntity (called 'roleSubjects')
need OneToMany mapping from Subject->SubjectRoleEntity (called 'subjectRoles')
need to enhance RoleManagerBean methods to handle LDAP logic
add new methods for LDAP management (CRUD for 'roleSubjects' collection according to the sync results)
add / remove rows as necessary, but only those where IS_LDAP is true
modify removeSubjectsFromRole and removeRolesFromSubject methods to disallow removal of rows where IS_LDAP=true (in other words, manual additions/deletions can only affect manually added role/subject mappings)
Does not duplicate data, instead relies on a bit field to denote regular- or ldap-context
Can easily extend this design in the future by making IS_LDAP into an enumerated field
The values today might be "database" and "ldap", but adding support for a new type is a simple matter of adding a new enumerated value
JPQL slightly more complex
Get LDAP roles for subject "SELECT sr.role FROM SubjectRole sr WHERE sr.isLdap = true AND sr.subject.id = :someUserId"
Get regular roles for subject "SELECT sr.role FROM SubjectRole sr WHERE sr.isLdap = false AND sr.subject.id = :someUserId"
Can not easily get the appropriate set at the object layer
Might be able to use collection-filtering feature of Hibernate, but it should be discouraged because it's not part of EJB 3 spec (yet)
Take a look at PersistenceUtility.createPaginationFilter for how we use Hibernate collection filters in the product today
Have two different mapping sets for the same data (the original @ManyToMany set, and the two new @OneToMany mappings)
This might be confusing for new members needing to change something in that part of the code, so we would need to document the purpose and intent for each mapping set clearly for maintainability in the future
new mapping table, to keep LDAP-based mappings completely seperate from manually created ones
create new linking table called RHQ_SUBJECT_ROLE_LDAP_MAP
no new entities needed
add ManyToMany mapping from Role->Subject (called 'ldapSubjects')
add ManyToMany mapping from Subject->Role (called 'ldapRoles')
need to enhance RoleManagerBean methods to handle LDAP logic
add new methods for LDAP management (CRUD for 'ldapRoles' collection according to the sync results)
as elements are added to / removed from 'ldapRoles', add / remove the same from 'roles'
modify removeSubjectsFromRole/removeRolesFromSubject methods to disallow removal of elements from 'roles' if the same element exists in 'ldapRoles'
Duplicates data and logic - since the authorization check actually occurs against the original RHQ_SUBJECT_ROLE_MAP table, any row modifications (add / remove) against RHQ_SUBJECT_ROLE_LDAP_MAP also need to be duplicated against RHQ_SUBJECT_ROLE_MAP
Design is relatively static
In order to extend this to support another type of mapping between a role and a group, you would need to:
use the above solution (on either the 'roles/subject' or 'ldapRoles/ldapSubjects' mapping sets)
add another set of @ManyToMany mappings to represent the new type of mapping that you want to maintain between subjects and roles
Simple JPQL
Get LDAP roles for subject "SELECT r FROM Subject s JOIN s.ldapRoles r WHERE s.id = :someUserId"
Get regular roles for subject "SELECT r FROM Subject s JOIN s.roles r WHERE s.id = :someUserId"
Can very easily get the appropriate set at the object layer
someSubject.getLdapRoles() or someSubject.getRoles()
someRole.getLdapSubjects() or someRole.getSubjects()
Clear distinction between each set of mappings, since they actually refer to different data collections