diff --git a/extensions/guacamole-auth-ldap/README b/extensions/guacamole-auth-ldap/README index 223cbf7cb..345806cb0 100644 --- a/extensions/guacamole-auth-ldap/README +++ b/extensions/guacamole-auth-ldap/README @@ -89,13 +89,15 @@ guacamole.properties such that the authentication provider is available. # The base DN within which all guacConfig objects can be found. ldap-config-base-dn: dc=example,dc=net + # The base DN within which all role based groups can be found. + ldap-group-base-dn: ou=groups,dc=example,dc=net ------------------------------------------------------------ Reporting problems ------------------------------------------------------------ -Please report any bugs encountered by opening a new ticket at the Trac system +Please report any bugs encountered by opening a new issue in the JIRA system hosted at: - http://guac-dev.org/trac/ + http://glyptodon.org/jira/ diff --git a/extensions/guacamole-auth-ldap/doc/examples/exampleConfigGroup.ldif b/extensions/guacamole-auth-ldap/doc/examples/exampleConfigGroup.ldif index d1508cde0..bae301385 100644 --- a/extensions/guacamole-auth-ldap/doc/examples/exampleConfigGroup.ldif +++ b/extensions/guacamole-auth-ldap/doc/examples/exampleConfigGroup.ldif @@ -9,3 +9,4 @@ guacConfigParameter: port=5900 guacConfigParameter: password=secret member: cn=user1,dc=example,dc=com member: cn=user2,dc=example,dc=com +seeAlso: ou=admins,ou=groups,dc=example,dc=com diff --git a/extensions/guacamole-auth-ldap/src/main/java/org/glyptodon/guacamole/auth/ldap/ConfigurationService.java b/extensions/guacamole-auth-ldap/src/main/java/org/glyptodon/guacamole/auth/ldap/ConfigurationService.java index ae4a90a76..83e8e8b23 100644 --- a/extensions/guacamole-auth-ldap/src/main/java/org/glyptodon/guacamole/auth/ldap/ConfigurationService.java +++ b/extensions/guacamole-auth-ldap/src/main/java/org/glyptodon/guacamole/auth/ldap/ConfigurationService.java @@ -135,6 +135,24 @@ public class ConfigurationService { ); } + /** + * Returns the base DN under which all Guacamole role based access control + * (RBAC) groups will be stored within the LDAP directory. If RBAC will not + * be used, null is returned. + * + * @return + * The base DN under which all Guacamole RBAC groups will be stored + * within the LDAP directory, or null if RBAC will not be used. + * + * @throws GuacamoleException + * If guacamole.properties cannot be parsed. + */ + public String getGroupBaseDN() throws GuacamoleException { + return environment.getProperty( + LDAPGuacamoleProperties.LDAP_GROUP_BASE_DN + ); + } + /** * Returns the DN that should be used when searching for the DNs of users * attempting to authenticate. If no such search should be performed, null diff --git a/extensions/guacamole-auth-ldap/src/main/java/org/glyptodon/guacamole/auth/ldap/LDAPGuacamoleProperties.java b/extensions/guacamole-auth-ldap/src/main/java/org/glyptodon/guacamole/auth/ldap/LDAPGuacamoleProperties.java index 283584e28..39e884861 100644 --- a/extensions/guacamole-auth-ldap/src/main/java/org/glyptodon/guacamole/auth/ldap/LDAPGuacamoleProperties.java +++ b/extensions/guacamole-auth-ldap/src/main/java/org/glyptodon/guacamole/auth/ldap/LDAPGuacamoleProperties.java @@ -63,6 +63,18 @@ public class LDAPGuacamoleProperties { }; + /** + * The base DN of role based access control (RBAC) groups. All groups which + * will be used for RBAC must be contained somewhere within the subtree of + * this DN. + */ + public static final StringGuacamoleProperty LDAP_GROUP_BASE_DN = new StringGuacamoleProperty() { + + @Override + public String getName() { return "ldap-group-base-dn"; } + + }; + /** * The attribute or attributes which identify users. One of these * attributes must be present within each Guacamole user's record in the diff --git a/extensions/guacamole-auth-ldap/src/main/java/org/glyptodon/guacamole/auth/ldap/connection/ConnectionService.java b/extensions/guacamole-auth-ldap/src/main/java/org/glyptodon/guacamole/auth/ldap/connection/ConnectionService.java index 9d2abe06c..017bb65c4 100644 --- a/extensions/guacamole-auth-ldap/src/main/java/org/glyptodon/guacamole/auth/ldap/connection/ConnectionService.java +++ b/extensions/guacamole-auth-ldap/src/main/java/org/glyptodon/guacamole/auth/ldap/connection/ConnectionService.java @@ -109,11 +109,18 @@ public class ConnectionService { // possibly be null assert(userDN != null); - // Find all Guacamole connections for the given user + // Get the search filter for finding connections accessible by the + // current user + String connectionSearchFilter = getConnectionSearchFilter(userDN, ldapConnection); + + // Find all Guacamole connections for the given user by + // looking for direct membership in the guacConfigGroup + // and possibly any groups the user is a member of that are + // referred to in the seeAlso attribute of the guacConfigGroup. LDAPSearchResults results = ldapConnection.search( configurationBaseDN, LDAPConnection.SCOPE_SUB, - "(&(objectClass=guacConfigGroup)(member=" + escapingService.escapeLDAPSearchFilter(userDN) + "))", + connectionSearchFilter, null, false ); @@ -195,4 +202,68 @@ public class ConnectionService { } + /** + * Returns an LDAP search filter which queries all connections accessible + * by the user having the given DN. + * + * @param userDN + * DN of the user to search for associated guacConfigGroup connections. + * + * @param ldapConnection + * LDAP connection to use if additional information must be queried to + * produce the filter, such as groups driving RBAC. + * + * @return + * An LDAP search filter which queries all guacConfigGroup objects + * accessible by the user having the given DN. + * + * @throws LDAPException + * If an error occurs preventing retrieval of user groups. + * + * @throws GuacamoleException + * If an error occurs retrieving the group base DN. + */ + private String getConnectionSearchFilter(String userDN, + LDAPConnection ldapConnection) + throws LDAPException, GuacamoleException { + + // Create a search filter for the connection search + StringBuilder connectionSearchFilter = new StringBuilder(); + + // Add the prefix to the search filter, prefix filter searches for guacConfigGroups with the userDN as the member attribute value + connectionSearchFilter.append("(&(objectClass=guacConfigGroup)(|(member="); + connectionSearchFilter.append(escapingService.escapeLDAPSearchFilter(userDN)); + connectionSearchFilter.append(")"); + + // If group base DN is specified search for user groups + String groupBaseDN = confService.getGroupBaseDN(); + if (groupBaseDN != null) { + + // Get all groups the user is a member of starting at the groupBaseDN, excluding guacConfigGroups + LDAPSearchResults userRoleGroupResults = ldapConnection.search( + groupBaseDN, + LDAPConnection.SCOPE_SUB, + "(&(!(objectClass=guacConfigGroup))(member=" + escapingService.escapeLDAPSearchFilter(userDN) + "))", + null, + false + ); + + // Append the additional user groups to the LDAP filter + // Now the filter will also look for guacConfigGroups that refer + // to groups the user is a member of + // The guacConfig group uses the seeAlso attribute to refer + // to these other groups + while (userRoleGroupResults.hasMore()) { + LDAPEntry entry = userRoleGroupResults.next(); + connectionSearchFilter.append("(seeAlso=").append(escapingService.escapeLDAPSearchFilter(entry.getDN())).append(")"); + } + } + + // Complete the search filter. + connectionSearchFilter.append("))"); + + return connectionSearchFilter.toString(); + } + } +