LDAP group names are now available as-is for the use in authorization. No upper casing / no 'ROLE_' prefix.

Originally-Committed-As: a8e4957438e468f772613a0647f0e7fdb1dcf938
This commit is contained in:
Kohsuke Kawaguchi 2011-03-18 23:28:34 -07:00
parent 7697934967
commit 1ed5e6e5e8
2 changed files with 37 additions and 30 deletions

View file

@ -39,6 +39,7 @@ import org.acegisecurity.AuthenticationManager;
import org.acegisecurity.GrantedAuthority; import org.acegisecurity.GrantedAuthority;
import org.acegisecurity.AcegiSecurityException; import org.acegisecurity.AcegiSecurityException;
import org.acegisecurity.AuthenticationException; import org.acegisecurity.AuthenticationException;
import org.acegisecurity.GrantedAuthorityImpl;
import org.acegisecurity.ldap.InitialDirContextFactory; import org.acegisecurity.ldap.InitialDirContextFactory;
import org.acegisecurity.ldap.LdapDataAccessException; import org.acegisecurity.ldap.LdapDataAccessException;
import org.acegisecurity.ldap.LdapTemplate; import org.acegisecurity.ldap.LdapTemplate;
@ -70,7 +71,9 @@ import java.net.InetAddress;
import java.net.Socket; import java.net.Socket;
import java.net.UnknownHostException; import java.net.UnknownHostException;
import java.util.Collections; import java.util.Collections;
import java.util.HashSet;
import java.util.Hashtable; import java.util.Hashtable;
import java.util.Iterator;
import java.util.Set; import java.util.Set;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
@ -367,29 +370,8 @@ public class LDAPSecurityRealm extends AbstractPasswordBasedSecurityRealm {
return getSecurityComponents().userDetails.loadUserByUsername(username); return getSecurityComponents().userDetails.loadUserByUsername(username);
} }
/**
* Lookup a group; given input must match the configured syntax for group names
* in WEB-INF/security/LDAPBindSecurityRealm.groovy's authoritiesPopulator entry.
* The defaults are a prefix of "ROLE_" and using all uppercase. This method will
* not return any data if the given name lacks the proper prefix and/or case.
*/
@Override @Override
public GroupDetails loadGroupByGroupname(String groupname) throws UsernameNotFoundException, DataAccessException { public GroupDetails loadGroupByGroupname(String groupname) throws UsernameNotFoundException, DataAccessException {
// Check proper syntax based on acegi configuration
String prefix = "";
boolean onlyUpperCase = false;
try {
AuthoritiesPopulatorImpl api = (AuthoritiesPopulatorImpl)
((LDAPUserDetailsService)getSecurityComponents().userDetails).authoritiesPopulator;
prefix = api.rolePrefix;
onlyUpperCase = api.convertToUpperCase;
} catch (Exception ignore) { }
if (onlyUpperCase && !groupname.equals(groupname.toUpperCase()))
throw new UsernameNotFoundException(groupname + " should be all uppercase");
if (!groupname.startsWith(prefix))
throw new UsernameNotFoundException(groupname + " is missing prefix: " + prefix);
groupname = groupname.substring(prefix.length());
// TODO: obtain a DN instead so that we can obtain multiple attributes later // TODO: obtain a DN instead so that we can obtain multiple attributes later
String searchBase = groupSearchBase != null ? groupSearchBase : ""; String searchBase = groupSearchBase != null ? groupSearchBase : "";
final Set<String> groups = (Set<String>)ldapTemplate.searchForSingleAttributeValues(searchBase, GROUP_SEARCH, final Set<String> groups = (Set<String>)ldapTemplate.searchForSingleAttributeValues(searchBase, GROUP_SEARCH,
@ -493,13 +475,14 @@ public class LDAPSecurityRealm extends AbstractPasswordBasedSecurityRealm {
*/ */
public static final class AuthoritiesPopulatorImpl extends DefaultLdapAuthoritiesPopulator { public static final class AuthoritiesPopulatorImpl extends DefaultLdapAuthoritiesPopulator {
// Make these available (private in parent class and no get methods!) // Make these available (private in parent class and no get methods!)
String rolePrefix; String rolePrefix = "ROLE_";
boolean convertToUpperCase; boolean convertToUpperCase = true;
public AuthoritiesPopulatorImpl(InitialDirContextFactory initialDirContextFactory, String groupSearchBase) { public AuthoritiesPopulatorImpl(InitialDirContextFactory initialDirContextFactory, String groupSearchBase) {
super(initialDirContextFactory, fixNull(groupSearchBase)); super(initialDirContextFactory, fixNull(groupSearchBase));
// These match the defaults in acegi 1.0.5; set again to store in non-private fields:
setRolePrefix("ROLE_"); super.setRolePrefix("");
setConvertToUpperCase(true); super.setConvertToUpperCase(false);
} }
@Override @Override
@ -509,15 +492,41 @@ public class LDAPSecurityRealm extends AbstractPasswordBasedSecurityRealm {
@Override @Override
public void setRolePrefix(String rolePrefix) { public void setRolePrefix(String rolePrefix) {
super.setRolePrefix(rolePrefix); // super.setRolePrefix(rolePrefix);
this.rolePrefix = rolePrefix; this.rolePrefix = rolePrefix;
} }
@Override @Override
public void setConvertToUpperCase(boolean convertToUpperCase) { public void setConvertToUpperCase(boolean convertToUpperCase) {
super.setConvertToUpperCase(convertToUpperCase); // super.setConvertToUpperCase(convertToUpperCase);
this.convertToUpperCase = convertToUpperCase; this.convertToUpperCase = convertToUpperCase;
} }
/**
* Retrieves the group membership in two ways.
*
* We'd like to retain the original name, but we historically used to do "ROLE_GROUPNAME".
* So to remain backward compatible, we make the super class pass the unmodified "groupName",
* then do the backward compatible translation here, so that the user gets both "ROLE_GROUPNAME" and "groupName".
*/
@Override
public Set getGroupMembershipRoles(String userDn, String username) {
Set<GrantedAuthority> names = super.getGroupMembershipRoles(userDn,username);
Set<GrantedAuthority> r = new HashSet<GrantedAuthority>(names.size()*2);
r.addAll(names);
for (GrantedAuthority ga : names) {
String role = ga.getAuthority();
// backward compatible name mangling
if (convertToUpperCase)
role = role.toUpperCase();
r.add(new GrantedAuthorityImpl(rolePrefix + role));
}
return r;
}
} }
@Extension @Extension

View file

@ -65,8 +65,6 @@ authoritiesPopulator(AuthoritiesPopulatorImpl, initialDirContextFactory, instanc
// see DefaultLdapAuthoritiesPopulator for other possible configurations // see DefaultLdapAuthoritiesPopulator for other possible configurations
searchSubtree = true; searchSubtree = true;
groupSearchFilter = "(| (member={0}) (uniqueMember={0}) (memberUid={1}))"; groupSearchFilter = "(| (member={0}) (uniqueMember={0}) (memberUid={1}))";
// rolePrefix = "ROLE_"; // Default is "ROLE_"
// convertToUpperCase = false; // Default is true
} }
authenticationManager(ProviderManager) { authenticationManager(ProviderManager) {