9 changed files with 241 additions and 48 deletions
@ -0,0 +1,51 @@
@@ -0,0 +1,51 @@
|
||||
package org.springframework.security.config; |
||||
|
||||
import org.springframework.security.ldap.SpringSecurityContextSource; |
||||
import org.springframework.beans.factory.config.BeanFactoryPostProcessor; |
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; |
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry; |
||||
import org.springframework.beans.factory.support.RootBeanDefinition; |
||||
import org.springframework.beans.BeansException; |
||||
import org.springframework.core.Ordered; |
||||
|
||||
import java.util.Map; |
||||
|
||||
/** |
||||
* @author Luke Taylor |
||||
* @version $Id$ |
||||
* @since 2.0 |
||||
*/ |
||||
class LdapConfigUtils { |
||||
|
||||
/** Checks for the presence of a ContextSource instance */ |
||||
private static class ContextSourceSettingPostProcessor implements BeanFactoryPostProcessor, Ordered { |
||||
public void postProcessBeanFactory(ConfigurableListableBeanFactory bf) throws BeansException { |
||||
Map beans = bf.getBeansOfType(SpringSecurityContextSource.class); |
||||
|
||||
if (beans.size() == 0) { |
||||
throw new SecurityConfigurationException("No SpringSecurityContextSource instances found. Have you " + |
||||
"added an <" + Elements.LDAP_SERVER + " /> element to your application context?"); |
||||
} |
||||
|
||||
// else if (beans.size() > 1) {
|
||||
// throw new SecurityConfigurationException("More than one SpringSecurityContextSource instance found. " +
|
||||
// "Please specify a specific server id when configuring your <" + Elements.LDAP_PROVIDER + "> " +
|
||||
// "or <" + Elements.LDAP_USER_SERVICE + ">.");
|
||||
// }
|
||||
} |
||||
|
||||
public int getOrder() { |
||||
return LOWEST_PRECEDENCE; |
||||
} |
||||
} |
||||
|
||||
static void registerPostProcessorIfNecessary(BeanDefinitionRegistry registry) { |
||||
if (registry.containsBeanDefinition(BeanIds.CONTEXT_SOURCE_SETTING_POST_PROCESSOR)) { |
||||
return; |
||||
} |
||||
|
||||
registry.registerBeanDefinition(BeanIds.CONTEXT_SOURCE_SETTING_POST_PROCESSOR, |
||||
new RootBeanDefinition(ContextSourceSettingPostProcessor.class)); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,78 @@
@@ -0,0 +1,78 @@
|
||||
package org.springframework.security.config; |
||||
|
||||
import org.springframework.security.userdetails.ldap.LdapUserDetailsService; |
||||
import org.springframework.security.ldap.search.FilterBasedLdapUserSearch; |
||||
import org.springframework.security.ldap.populator.DefaultLdapAuthoritiesPopulator; |
||||
import org.springframework.beans.factory.xml.ParserContext; |
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder; |
||||
import org.springframework.beans.factory.support.RootBeanDefinition; |
||||
import org.springframework.beans.factory.config.RuntimeBeanReference; |
||||
import org.springframework.beans.factory.config.BeanDefinition; |
||||
import org.springframework.util.StringUtils; |
||||
import org.springframework.util.Assert; |
||||
|
||||
import org.w3c.dom.Element; |
||||
|
||||
/** |
||||
* @author Luke Taylor |
||||
* @version $Id$ |
||||
* @since 2.0 |
||||
*/ |
||||
public class LdapUserServiceBeanDefinitionParser extends AbstractUserDetailsServiceBeanDefinitionParser { |
||||
private static final String ATT_SERVER = "server-ref"; |
||||
public static final String ATT_USER_SEARCH_FILTER = "user-search-filter"; |
||||
public static final String ATT_USER_SEARCH_BASE = "user-search-base"; |
||||
public static final String DEF_USER_SEARCH_BASE = ""; |
||||
|
||||
public static final String ATT_GROUP_SEARCH_FILTER = "group-search-filter"; |
||||
public static final String ATT_GROUP_SEARCH_BASE = "group-search-base"; |
||||
public static final String DEF_GROUP_SEARCH_FILTER = "(uniqueMember={0})"; |
||||
public static final String DEF_GROUP_SEARCH_BASE = "ou=groups"; |
||||
|
||||
protected Class getBeanClass(Element element) { |
||||
return LdapUserDetailsService.class; |
||||
} |
||||
|
||||
protected void doParse(Element elt, ParserContext parserContext, BeanDefinitionBuilder builder) { |
||||
String server = elt.getAttribute(ATT_SERVER); |
||||
|
||||
if (!StringUtils.hasText(server)) { |
||||
server = BeanIds.CONTEXT_SOURCE; |
||||
} |
||||
|
||||
String userSearchFilter = elt.getAttribute(ATT_USER_SEARCH_FILTER); |
||||
Assert.hasText(userSearchFilter, "User search filter must be supplied"); |
||||
String userSearchBase = elt.getAttribute(ATT_USER_SEARCH_BASE); |
||||
|
||||
if (!StringUtils.hasText(userSearchBase)) { |
||||
userSearchBase = DEF_USER_SEARCH_BASE; |
||||
} |
||||
|
||||
String groupSearchFilter = elt.getAttribute(ATT_GROUP_SEARCH_FILTER); |
||||
String groupSearchBase = elt.getAttribute(ATT_GROUP_SEARCH_BASE); |
||||
|
||||
if (!StringUtils.hasText(groupSearchFilter)) { |
||||
groupSearchFilter = DEF_GROUP_SEARCH_FILTER; |
||||
} |
||||
|
||||
if (!StringUtils.hasText(groupSearchBase)) { |
||||
groupSearchBase = DEF_GROUP_SEARCH_BASE; |
||||
} |
||||
|
||||
RuntimeBeanReference contextSource = new RuntimeBeanReference(server); |
||||
BeanDefinition search = new RootBeanDefinition(FilterBasedLdapUserSearch.class); |
||||
search.getConstructorArgumentValues().addIndexedArgumentValue(0, userSearchBase); |
||||
search.getConstructorArgumentValues().addIndexedArgumentValue(1, userSearchFilter); |
||||
search.getConstructorArgumentValues().addIndexedArgumentValue(2, contextSource); |
||||
|
||||
BeanDefinition populator = new RootBeanDefinition(DefaultLdapAuthoritiesPopulator.class); |
||||
populator.getConstructorArgumentValues().addIndexedArgumentValue(0, contextSource); |
||||
populator.getConstructorArgumentValues().addIndexedArgumentValue(1, groupSearchBase); |
||||
populator.getPropertyValues().addPropertyValue("groupSearchFilter", groupSearchFilter); |
||||
|
||||
builder.addConstructorArg(search); |
||||
builder.addConstructorArg(populator); |
||||
|
||||
LdapConfigUtils.registerPostProcessorIfNecessary(parserContext.getRegistry()); |
||||
} |
||||
} |
||||
@ -0,0 +1,44 @@
@@ -0,0 +1,44 @@
|
||||
package org.springframework.security.config; |
||||
|
||||
import org.springframework.security.util.InMemoryXmlApplicationContext; |
||||
import org.springframework.security.userdetails.UserDetailsService; |
||||
import org.springframework.security.userdetails.UserDetails; |
||||
|
||||
import org.junit.Test; |
||||
import org.junit.After; |
||||
import static org.junit.Assert.assertEquals; |
||||
|
||||
/** |
||||
* @author Luke Taylor |
||||
* @version $Id$ |
||||
*/ |
||||
public class LdapUserServiceBeanDefinitionParserTests { |
||||
private InMemoryXmlApplicationContext appCtx; |
||||
|
||||
@After |
||||
public void closeAppContext() { |
||||
if (appCtx != null) { |
||||
appCtx.close(); |
||||
appCtx = null; |
||||
} |
||||
} |
||||
|
||||
@Test |
||||
public void minimalConfigurationIsParsedOk() throws Exception { |
||||
setContext("<ldap-user-service user-search-filter='(uid={0})' /><ldap-server url='ldap://127.0.0.1:343/dc=springframework,dc=org' />"); |
||||
} |
||||
|
||||
@Test |
||||
public void userServiceReturnsExpectedData() throws Exception { |
||||
setContext("<ldap-user-service id='ldapUDS' user-search-filter='(uid={0})' group-search-filter='member={0}' /><ldap-server />"); |
||||
|
||||
UserDetailsService uds = (UserDetailsService) appCtx.getBean("ldapUDS"); |
||||
UserDetails ben = uds.loadUserByUsername("ben"); |
||||
|
||||
assertEquals(2, ben.getAuthorities().length); |
||||
} |
||||
|
||||
private void setContext(String context) { |
||||
appCtx = new InMemoryXmlApplicationContext(context); |
||||
} |
||||
} |
||||
Loading…
Reference in new issue