Skip to content

Commit

Permalink
GUACAMOLE-793: Refactor CAS group parsing to leverage LDAP-aware abst…
Browse files Browse the repository at this point in the history
…ractions and parameters.
  • Loading branch information
mike-jumper committed Dec 12, 2020
1 parent 749e53b commit 1303dab
Show file tree
Hide file tree
Showing 4 changed files with 252 additions and 87 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@

package org.apache.guacamole.auth.cas.conf;

import org.apache.guacamole.auth.cas.group.GroupFormat;
import org.apache.guacamole.properties.EnumGuacamoleProperty;
import org.apache.guacamole.properties.URIGuacamoleProperty;
import org.apache.guacamole.properties.StringGuacamoleProperty;

Expand Down Expand Up @@ -71,8 +73,8 @@ private CASGuacamoleProperties() {}
};

/**
* The attribute used for group membership
* example: memberOf (case sensitive)
* The name of the CAS attribute used for group membership, such as
* "memberOf". This attribute is case sensitive.
*/
public static final StringGuacamoleProperty CAS_GROUP_ATTRIBUTE =
new StringGuacamoleProperty() {
Expand All @@ -83,14 +85,37 @@ private CASGuacamoleProperties() {}
};

/**
* The name of the attribute used for group membership, such as "memberOf".
* This attribute is case sensitive.
* The format used by CAS to represent group names. Possible formats are
* "plain" (simple text names) or "ldap" (fully-qualified LDAP DNs).
*/
public static final StringGuacamoleProperty CAS_GROUP_DN_FORMAT =
public static final EnumGuacamoleProperty<GroupFormat> CAS_GROUP_FORMAT =
new EnumGuacamoleProperty<GroupFormat>(GroupFormat.class) {

@Override
public String getName() { return "cas-group-format"; }

};

/**
* The LDAP base DN to require for all CAS groups.
*/
public static final LdapNameGuacamoleProperty CAS_GROUP_LDAP_BASE_DN =
new LdapNameGuacamoleProperty() {

@Override
public String getName() { return "cas-group-ldap-base-dn"; }

};

/**
* The LDAP attribute to require for the names of CAS groups.
*/
public static final StringGuacamoleProperty CAS_GROUP_LDAP_ATTRIBUTE =
new StringGuacamoleProperty() {

@Override
public String getName() { return "cas-group-dn-format"; }
public String getName() { return "cas-group-ldap-attribute"; }

};

}
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,14 @@
import com.google.inject.Inject;
import java.net.URI;
import java.security.PrivateKey;
import javax.naming.ldap.LdapName;
import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.GuacamoleServerException;
import org.apache.guacamole.auth.cas.group.GroupFormat;
import org.apache.guacamole.environment.Environment;
import org.apache.guacamole.auth.cas.group.GroupParser;
import org.apache.guacamole.auth.cas.group.LDAPGroupParser;
import org.apache.guacamole.auth.cas.group.PlainGroupParser;

/**
* Service for retrieving configuration information regarding the CAS service.
Expand Down Expand Up @@ -86,8 +92,9 @@ public PrivateKey getClearpassKey() throws GuacamoleException {
}

/**
* Returns the attribute used to determine group memberships
* in CAS, or null if not defined.
* Returns the CAS attribute that should be used to determine group
* memberships in CAS, such as "memberOf". If no attribute has been
* specified, null is returned.
*
* @return
* The attribute name used to determine group memberships in CAS,
Expand All @@ -101,24 +108,85 @@ public String getGroupAttribute() throws GuacamoleException {
}

/**
* Returns the full DN specification used to format group DN's in CAS,
* or null if not defined.
* If CAS is backed by LDAP, it will return an LDAP DN, such as
* CN=foo,OU=bar,DC=example,DC=com. This DN specification may be set to
* CN=%s,OU=bar,DC=example,DC=com and given the example above, would result
* in a group called "foo". CAS backed by something other than LDAP would
* likely not need this.
* Returns the format that CAS is expected to use for its group names, such
* as {@link GroupFormat#PLAIN} (simple plain-text names) or
* {@link GroupFormat#LDAP} (fully-qualified LDAP DNs). If not specified,
* PLAIN is used by default.
*
* @return
* The DN format specification.
* The format that CAS is expected to use for its group names.
*
* @throws GuacamoleException
* If the format specified within guacamole.properties is not valid.
*/
public GroupFormat getGroupFormat() throws GuacamoleException {
return environment.getProperty(CASGuacamoleProperties.CAS_GROUP_FORMAT, GroupFormat.PLAIN);
}

/**
* Returns the base DN that all LDAP-formatted CAS groups must reside
* beneath. Any groups that are not beneath this base DN should be ignored.
* If no such base DN is provided, the tree structure of the ancestors of
* LDAP-formatted CAS groups should not be considered.
*
* @return
* The base DN that all LDAP-formatted CAS groups must reside beneath,
* or null if the tree structure of the ancestors of LDAP-formatted
* CAS groups should not be considered.
*
* @throws GuacamoleException
* If the provided base DN is not a valid LDAP DN.
*/
public LdapName getGroupLDAPBaseDN() throws GuacamoleException {
return environment.getProperty(CASGuacamoleProperties.CAS_GROUP_LDAP_BASE_DN);
}

/**
* Returns the LDAP attribute that should be required for all LDAP-formatted
* CAS groups. Any groups that do not use this attribute as the last
* (leftmost) attribute of their DN should be ignored. If no such LDAP
* attribute is provided, the last (leftmost) attribute should still be
* used to determine the group name, but the specific attribute involved
* should not be considered.
*
* @return
* The LDAP attribute that should be required for all LDAP-formatted
* CAS groups, or null if any attribute should be allowed.
*
* @throws GuacamoleException
* If guacamole.properties cannot be parsed.
*/
public String getGroupDnFormat() throws GuacamoleException {
return environment.getProperty(CASGuacamoleProperties.CAS_GROUP_DN_FORMAT);
public String getGroupLDAPAttribute() throws GuacamoleException {
return environment.getProperty(CASGuacamoleProperties.CAS_GROUP_LDAP_ATTRIBUTE);
}

/**
* Returns a GroupParser instance that can be used to parse CAS group
* names. The parser returned will take into account the configured CAS
* group format, as well as any configured LDAP-specific restrictions.
*
* @return
* A GroupParser instance that can be used to parse CAS group names as
* configured in guacamole.properties.
*
* @throws GuacamoleException
* If guacamole.properties cannot be parsed.
*/
public GroupParser getGroupParser() throws GuacamoleException {
switch (getGroupFormat()) {

// Simple, plain-text groups
case PLAIN:
return new PlainGroupParser();

// LDAP DNs
case LDAP:
return new LDAPGroupParser(getGroupLDAPAttribute(), getGroupLDAPBaseDN());

default:
throw new GuacamoleServerException("Unsupported CAS group format: " + getGroupFormat());

}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

package org.apache.guacamole.auth.cas.conf;

import javax.naming.InvalidNameException;
import javax.naming.ldap.LdapName;
import org.apache.guacamole.properties.GuacamoleProperty;
import org.apache.guacamole.GuacamoleServerException;

/**
* A GuacamoleProperty whose value is an LDAP DN.
*/
public abstract class LdapNameGuacamoleProperty implements GuacamoleProperty<LdapName> {

@Override
public LdapName parseValue(String value) throws GuacamoleServerException {

// Consider null/empty values to be empty
if (value == null || value.isEmpty())
return null;

// Parse provided value as an LDAP DN
try {
return new LdapName(value);
}
catch (InvalidNameException e) {
throw new GuacamoleServerException("Invalid LDAP distinguished name.", e);
}

}

}
Loading

0 comments on commit 1303dab

Please sign in to comment.