mirror of
https://github.com/spring-projects/spring-security.git
synced 2025-05-30 16:52:13 +00:00
SEC-2405: Use DirContextAdapter directly from search. Configure OBJECT_FACTORIES on DirContext created for ActiveDirectory.
This commit is contained in:
parent
9dbe30c81d
commit
bc6fc518d3
@ -1,10 +1,11 @@
|
||||
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed 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
|
||||
* 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,
|
||||
@ -12,23 +13,8 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.ldap;
|
||||
|
||||
import java.text.MessageFormat;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.naming.CompositeName;
|
||||
import javax.naming.NamingEnumeration;
|
||||
import javax.naming.NamingException;
|
||||
import javax.naming.PartialResultException;
|
||||
import javax.naming.directory.Attributes;
|
||||
import javax.naming.directory.DirContext;
|
||||
import javax.naming.directory.SearchControls;
|
||||
import javax.naming.directory.SearchResult;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.dao.IncorrectResultSizeDataAccessException;
|
||||
@ -42,6 +28,18 @@ import org.springframework.ldap.core.LdapEncoder;
|
||||
import org.springframework.ldap.core.LdapTemplate;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import javax.naming.NamingEnumeration;
|
||||
import javax.naming.NamingException;
|
||||
import javax.naming.PartialResultException;
|
||||
import javax.naming.directory.Attributes;
|
||||
import javax.naming.directory.DirContext;
|
||||
import javax.naming.directory.SearchControls;
|
||||
import javax.naming.directory.SearchResult;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
|
||||
/**
|
||||
* Extension of Spring LDAP's LdapTemplate class which adds extra functionality required by Spring Security.
|
||||
@ -55,6 +53,7 @@ public class SpringSecurityLdapTemplate extends LdapTemplate {
|
||||
private static final Log logger = LogFactory.getLog(SpringSecurityLdapTemplate.class);
|
||||
|
||||
public static final String[] NO_ATTRS = new String[0];
|
||||
private static final boolean RETURN_OBJECT = true;
|
||||
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
@ -207,7 +206,7 @@ public class SpringSecurityLdapTemplate extends LdapTemplate {
|
||||
String base, String filter, Object[] params) throws NamingException {
|
||||
final DistinguishedName ctxBaseDn = new DistinguishedName(ctx.getNameInNamespace());
|
||||
final DistinguishedName searchBaseDn = new DistinguishedName(base);
|
||||
final NamingEnumeration<SearchResult> resultsEnum = ctx.search(searchBaseDn, filter, params, searchControls);
|
||||
final NamingEnumeration<SearchResult> resultsEnum = ctx.search(searchBaseDn, filter, params, buildControls(searchControls));
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Searching for entry under DN '" + ctxBaseDn
|
||||
@ -218,17 +217,13 @@ public class SpringSecurityLdapTemplate extends LdapTemplate {
|
||||
try {
|
||||
while (resultsEnum.hasMore()) {
|
||||
SearchResult searchResult = resultsEnum.next();
|
||||
// Work out the DN of the matched entry
|
||||
DistinguishedName dn = new DistinguishedName(new CompositeName(searchResult.getName()));
|
||||
|
||||
if (base.length() > 0) {
|
||||
dn.prepend(searchBaseDn);
|
||||
}
|
||||
DirContextAdapter dca = (DirContextAdapter) searchResult.getObject();
|
||||
Assert.notNull(dca, "No object returned by search, DirContext is not correctly configured");
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Found DN: " + dn);
|
||||
logger.debug("Found DN: " + dca.getDn());
|
||||
}
|
||||
results.add(new DirContextAdapter(searchResult.getAttributes(), dn, ctxBaseDn));
|
||||
results.add(dca);
|
||||
}
|
||||
} catch (PartialResultException e) {
|
||||
LdapUtils.closeEnumeration(resultsEnum);
|
||||
@ -246,6 +241,21 @@ public class SpringSecurityLdapTemplate extends LdapTemplate {
|
||||
return results.iterator().next();
|
||||
}
|
||||
|
||||
/**
|
||||
* We need to make sure the search controls has the return object flag set to true, in order for
|
||||
* the search to return DirContextAdapter instances.
|
||||
* @param originalControls
|
||||
* @return
|
||||
*/
|
||||
private static SearchControls buildControls(SearchControls originalControls) {
|
||||
return new SearchControls(originalControls.getSearchScope(),
|
||||
originalControls.getCountLimit(),
|
||||
originalControls.getTimeLimit(),
|
||||
originalControls.getReturningAttributes(),
|
||||
RETURN_OBJECT,
|
||||
originalControls.getDerefLinkFlag());
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the search controls which will be used for search operations by the template.
|
||||
*
|
||||
|
@ -15,6 +15,7 @@ package org.springframework.security.ldap.authentication.ad;
|
||||
import org.springframework.dao.IncorrectResultSizeDataAccessException;
|
||||
import org.springframework.ldap.core.DirContextOperations;
|
||||
import org.springframework.ldap.core.DistinguishedName;
|
||||
import org.springframework.ldap.core.support.DefaultDirObjectFactory;
|
||||
import org.springframework.ldap.support.LdapUtils;
|
||||
import org.springframework.security.authentication.AccountExpiredException;
|
||||
import org.springframework.security.authentication.BadCredentialsException;
|
||||
@ -174,6 +175,7 @@ public final class ActiveDirectoryLdapAuthenticationProvider extends AbstractLda
|
||||
env.put(Context.PROVIDER_URL, bindUrl);
|
||||
env.put(Context.SECURITY_CREDENTIALS, password);
|
||||
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
|
||||
env.put(Context.OBJECT_FACTORIES, DefaultDirObjectFactory.class.getName());
|
||||
|
||||
try {
|
||||
return contextFactory.createContext(env);
|
||||
|
@ -12,16 +12,14 @@
|
||||
*/
|
||||
package org.springframework.security.ldap.authentication.ad;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
import static org.springframework.security.ldap.authentication.ad.ActiveDirectoryLdapAuthenticationProvider.ContextFactory;
|
||||
|
||||
import org.apache.directory.shared.ldap.util.EmptyEnumeration;
|
||||
import org.hamcrest.BaseMatcher;
|
||||
import org.hamcrest.CoreMatchers;
|
||||
import org.hamcrest.Description;
|
||||
import org.hamcrest.Matcher;
|
||||
import org.junit.*;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
import org.springframework.dao.IncorrectResultSizeDataAccessException;
|
||||
import org.springframework.ldap.core.DirContextAdapter;
|
||||
@ -33,8 +31,6 @@ import org.springframework.security.authentication.DisabledException;
|
||||
import org.springframework.security.authentication.LockedException;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
|
||||
import javax.naming.AuthenticationException;
|
||||
import javax.naming.CommunicationException;
|
||||
@ -45,7 +41,15 @@ import javax.naming.NamingException;
|
||||
import javax.naming.directory.DirContext;
|
||||
import javax.naming.directory.SearchControls;
|
||||
import javax.naming.directory.SearchResult;
|
||||
import java.util.*;
|
||||
import java.util.Hashtable;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.mockito.Mockito.any;
|
||||
import static org.mockito.Mockito.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.springframework.security.ldap.authentication.ad.ActiveDirectoryLdapAuthenticationProvider.ContextFactory;
|
||||
|
||||
/**
|
||||
* @author Luke Taylor
|
||||
@ -75,7 +79,7 @@ public class ActiveDirectoryLdapAuthenticationProviderTests {
|
||||
when(ctx.getNameInNamespace()).thenReturn("");
|
||||
|
||||
DirContextAdapter dca = new DirContextAdapter();
|
||||
SearchResult sr = new SearchResult("CN=Joe Jannsen,CN=Users", null, dca.getAttributes());
|
||||
SearchResult sr = new SearchResult("CN=Joe Jannsen,CN=Users", dca, dca.getAttributes());
|
||||
when(ctx.search(any(Name.class), any(String.class), any(Object[].class), any(SearchControls.class)))
|
||||
.thenReturn(new MockNamingEnumeration(sr))
|
||||
.thenReturn(new MockNamingEnumeration(sr));
|
||||
@ -88,8 +92,6 @@ public class ActiveDirectoryLdapAuthenticationProviderTests {
|
||||
|
||||
dca.addAttributeValue("memberOf","CN=Admin,CN=Users,DC=mydomain,DC=eu");
|
||||
|
||||
sr.setAttributes(dca.getAttributes());
|
||||
|
||||
result = provider.authenticate(joe);
|
||||
|
||||
assertEquals(1, result.getAuthorities().size());
|
||||
@ -102,7 +104,7 @@ public class ActiveDirectoryLdapAuthenticationProviderTests {
|
||||
when(ctx.getNameInNamespace()).thenReturn("");
|
||||
|
||||
DirContextAdapter dca = new DirContextAdapter();
|
||||
SearchResult sr = new SearchResult("CN=Joe Jannsen,CN=Users", null, dca.getAttributes());
|
||||
SearchResult sr = new SearchResult("CN=Joe Jannsen,CN=Users", dca, dca.getAttributes());
|
||||
when(ctx.search(eq(new DistinguishedName("DC=mydomain,DC=eu")), any(String.class), any(Object[].class), any(SearchControls.class)))
|
||||
.thenReturn(new MockNamingEnumeration(sr));
|
||||
provider.contextFactory = createContextFactoryReturning(ctx);
|
||||
@ -149,7 +151,7 @@ public class ActiveDirectoryLdapAuthenticationProviderTests {
|
||||
NamingEnumeration<SearchResult> searchResults = mock(NamingEnumeration.class);
|
||||
when(searchResults.hasMore()).thenReturn(true,true,false);
|
||||
SearchResult searchResult = mock(SearchResult.class);
|
||||
when(searchResult.getName()).thenReturn("ou=1","ou=2");
|
||||
when(searchResult.getObject()).thenReturn(new DirContextAdapter("ou=1"),new DirContextAdapter("ou=2"));
|
||||
when(searchResults.next()).thenReturn(searchResult);
|
||||
when(ctx.search(any(Name.class), any(String.class), any(Object[].class), any(SearchControls.class)))
|
||||
.thenReturn(searchResults );
|
||||
|
Loading…
x
Reference in New Issue
Block a user