After some trial and error, I finally got a working configuration with only some restrictions (take a look at the bottom of this page...) --hp 18-Mar-2008 04:46 PDT
First of all I made an custom configuration for all Ldap-Settings:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN/EN" "http://www.springframework.org/dtd/spring-beans.dtd" >
<beans>
<bean id="initialDirContextFactory"
class="org.acegisecurity.ldap.DefaultInitialDirContextFactory">
<constructor-arg value="ldap://${ldap_host}"/>
<property name="managerDn" value="${ldap_user}" />
<property name="managerPassword" value="${ldap_password}" />
<property name="extraEnvVars">
<map>
<entry key="java.naming.referral" value="follow" />
<entry key="java.naming.security.authentication" value="simple" />
</map>
</property>
</bean>
<bean id="userSearch" class="org.acegisecurity.ldap.search.FilterBasedLdapUserSearch">
<constructor-arg index="0" value="${ldap_base_dn}" />
<constructor-arg index="1" value="(sAMAccountName={0})" />
<constructor-arg index="2" ref="initialDirContextFactory" />
<property name="searchSubtree" value="true" />
<property name="derefLinkFlag" value="true" />
</bean>
<bean id="ldapAuthProvider" class="org.acegisecurity.providers.ldap.LdapAuthenticationProvider">
<constructor-arg>
<bean class="org.acegisecurity.providers.ldap.authenticator.BindAuthenticator">
<constructor-arg><ref local="initialDirContextFactory"/></constructor-arg>
<property name="userSearch" ref="userSearch"/>
</bean>
</constructor-arg>
<constructor-arg>
<bean class="my.JAMWikiLdapAuthoritiesPopulator">
<constructor-arg>
<ref local="initialDirContextFactory"/>
</constructor-arg>
<constructor-arg value="${ldap_group_base_dn}" />
<property name="groupRoleAttribute" value="cn" />
<property name="additionalRoles">
<list>
<bean class="org.acegisecurity.GrantedAuthorityImpl">
<constructor-arg value="ROLE_USER"/>
</bean>
<bean class="org.acegisecurity.GrantedAuthorityImpl">
<constructor-arg value="ROLE_NO_ACCOUNT"/>
</bean>
</list>
</property>
<property name="roleMap">
<map>
<entry key="exampleGroup1">
<list>
<value>ROLE_EDIT_NEW</value>
<value>ROLE_EDIT_EXISTING</value>
</list>
</entry>
<entry key="exampleAdminGroup">
<list>
<value>ROLE_ADMIN</value>
</list>
</entry>
</map>
</property>
<property name="searchSubtree" value="true" />
</bean>
</constructor-arg>
</bean>
</beans>
In applicationContext-acegi-security.xml I imported this config and made only few changes on the existing lines, to use the ldapAuthProvider:
<bean id="authenticationManager" class="org.acegisecurity.providers.ProviderManager"> <property name="providers"> <list> <ref bean="ldapAuthProvider"/> <!-- <ref local="daoAuthenticationProvider" />--> <ref local="anonymousAuthenticationProvider" /> <ref local="rememberMeAuthenticationProvider" /> </list> </property> </bean>
Of course the Implementation of my.JAMWikiLdapAuthoritiesPopulator is necessary:
package my;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.naming.directory.SearchControls;
import org.acegisecurity.GrantedAuthority;
import org.acegisecurity.GrantedAuthorityImpl;
import org.acegisecurity.ldap.InitialDirContextFactory;
import org.acegisecurity.ldap.LdapDataAccessException;
import org.acegisecurity.ldap.LdapTemplate;
import org.acegisecurity.providers.ldap.LdapAuthoritiesPopulator;
import org.acegisecurity.userdetails.ldap.LdapUserDetails;
import org.jamwiki.utils.WikiLogger;
public class JAMWikiLdapAuthoritiesPopulator implements LdapAuthoritiesPopulator {
private static final WikiLogger logger = WikiLogger.getLogger(JAMWikiLdapAuthoritiesPopulator.class.getName());
private final String groupSearchBase;
private String groupSearchFilter = "(member={0})";
private String groupRoleAttribute = "cn";
private LdapTemplate ldapTemplate;
private SearchControls searchControls = new SearchControls();
private String rolePrefix = "ROLE_";
private boolean convertToUpperCase = true;
private List additionalRoles = new ArrayList();
private Map roleMap;
public JAMWikiLdapAuthoritiesPopulator(
InitialDirContextFactory initialDirContextFactory,
String groupSearchBase) {
this.ldapTemplate = new LdapTemplate(initialDirContextFactory);
this.ldapTemplate.setSearchControls(searchControls);
this.groupSearchBase = groupSearchBase;
}
public GrantedAuthority[] getGrantedAuthorities(LdapUserDetails userDetails)
throws LdapDataAccessException {
String userDn = userDetails.getDn();
logger.finest("Getting authorities for user " + userDn);
Set roles = getGroupMembershipRoles(userDn, userDetails.getUsername());
List extraRoles = getAdditionalRoles();
if (extraRoles != null) {
roles.addAll(extraRoles);
}
return (GrantedAuthority[]) roles.toArray(new GrantedAuthority[roles.size()]);
}
protected List getMappedRolesFor(String role) {
List ret = new ArrayList();
List list = (List) roleMap.get(role);
if (list != null) {
Iterator it = list.iterator();
while (it.hasNext()) {
ret.add(new GrantedAuthorityImpl((String) it.next()));
}
}
return ret;
}
public Set getGroupMembershipRoles(String userDn, String username) {
Set authorities = new HashSet();
if (groupSearchBase == null) {
return authorities;
}
logger.finest("Searching for roles for user '" + username + "', DN = " + "'" + userDn + "', with filter "
+ groupSearchFilter + " in search base '" + getGroupSearchBase() + "'");
Set userRoles = ldapTemplate.searchForSingleAttributeValues(getGroupSearchBase(), groupSearchFilter,
new String[]{userDn, username}, groupRoleAttribute);
logger.fine("Roles from search: " + userRoles);
Iterator it = userRoles.iterator();
while (it.hasNext()) {
String role = (String) it.next();
if (convertToUpperCase) {
role = role.toUpperCase();
}
authorities.add(new GrantedAuthorityImpl(rolePrefix + role));
authorities.addAll(getMappedRolesFor(role.toUpperCase()));
}
return authorities;
}
public String getGroupSearchBase() {
return groupSearchBase;
}
public void setAdditionalRoles(List additionalRoles) {
this.additionalRoles.addAll(additionalRoles);
}
public List getAdditionalRoles() {
return additionalRoles;
}
public void setGroupSearchFilter(String groupSearchFilter) {
this.groupSearchFilter = groupSearchFilter;
}
public void setGroupRoleAttribute(String groupRoleAttribute) {
this.groupRoleAttribute = groupRoleAttribute;
}
public void setSearchSubtree(boolean searchSubtree) {
int searchScope = searchSubtree ? SearchControls.SUBTREE_SCOPE : SearchControls.ONELEVEL_SCOPE;
searchControls.setSearchScope(searchScope);
}
public void setConvertToUpperCase(boolean convertToUpperCase) {
this.convertToUpperCase = convertToUpperCase;
}
public void setRolePrefix(String rolePrefix) {
this.rolePrefix = rolePrefix;
}
public void setRoleMap(Map roleMap) {
this.roleMap = new HashMap();
Iterator it = roleMap.keySet().iterator();
while (it.hasNext()) {
String key = (String) it.next();
String upperCase = key.toUpperCase();
this.roleMap.put(upperCase, roleMap.get(key));
}
}
}
The Implementation is quite similar to DefaultLdapAuthoritiesPopulator from Acegi with slight modifications:
* it allows a list of additionalRoles instead of a defaultRole * it allows a map<string, list<string>> for mapping ldap-groups to roles
With this configuration I was able to log-in and out again, because of Authentication.getPrincipal() is no instance of WikiUserAuth anymore (as with daoAuthenticationProvider), the Username is null.
By adding just a few lines to WikiUserAuth.initWikiUserAuth, the Username is displayed after Login:
public static WikiUserAuth initWikiUserAuth(Authentication auth) throws AuthenticationCredentialsNotFoundException {
if (auth == null) {
throw new AuthenticationCredentialsNotFoundException("No authentication credential available");
}
if (auth.getPrincipal() instanceof WikiUserAuth) {
// logged-in user
return (WikiUserAuth)auth.getPrincipal();
}
WikiUserAuth user = new WikiUserAuth();
// -- new from here
try {
user = new WikiUserAuth(auth.getName());
} catch (Exception e) {
logger.severe(e.getMessage());
user = new WikiUserAuth();
}
// ... to here
user.setAuthorities(auth.getAuthorities());
return user;
}