Bläddra i källkod

SEC-2405: Use DirContextAdapter directly from search. Configure OBJECT_FACTORIES on DirContext created for ActiveDirectory.

Mattias Hellborg Arthursson 12 år sedan
förälder
incheckning
bc6fc518d3

+ 36 - 26
ldap/src/main/java/org/springframework/security/ldap/SpringSecurityLdapTemplate.java

@@ -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.
      *

+ 2 - 0
ldap/src/main/java/org/springframework/security/ldap/authentication/ad/ActiveDirectoryLdapAuthenticationProvider.java

@@ -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);

+ 15 - 13
ldap/src/test/java/org/springframework/security/ldap/authentication/ad/ActiveDirectoryLdapAuthenticationProviderTests.java

@@ -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 );