浏览代码

SEC-2449: <ldap-server> default port should fallback to dynamic value

Rob Winch 11 年之前
父节点
当前提交
04fac30d75

+ 20 - 4
config/src/integration-test/java/org/springframework/security/config/ldap/LdapServerBeanDefinitionParserTests.java

@@ -12,7 +12,10 @@
  */
 package org.springframework.security.config.ldap;
 
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertEquals;
+
+import java.io.IOException;
+import java.net.ServerSocket;
 
 import org.junit.After;
 import org.junit.Test;
@@ -50,10 +53,11 @@ public class LdapServerBeanDefinitionParserTests {
     }
 
     @Test
-    public void useOfUrlAttributeCreatesCorrectContextSource() {
+    public void useOfUrlAttributeCreatesCorrectContextSource() throws Exception {
+        int port = getDefaultPort();
         // Create second "server" with a url pointing at embedded one
-        appCtx = new InMemoryXmlApplicationContext("<ldap-server ldif='classpath:test-server.ldif' port='33388'/>" +
-                "<ldap-server ldif='classpath:test-server.ldif' id='blah' url='ldap://127.0.0.1:33388/dc=springframework,dc=org' />");
+        appCtx = new InMemoryXmlApplicationContext("<ldap-server ldif='classpath:test-server.ldif' port='" + port + "'/>" +
+                "<ldap-server ldif='classpath:test-server.ldif' id='blah' url='ldap://127.0.0.1:" + port + "/dc=springframework,dc=org' />");
 
         // Check the default context source is still there.
         appCtx.getBean(BeanIds.CONTEXT_SOURCE);
@@ -83,4 +87,16 @@ public class LdapServerBeanDefinitionParserTests {
 
         assertEquals("classpath*:*.ldif", ReflectionTestUtils.getField(dsContainer, "ldifResources"));
     }
+
+    private int getDefaultPort() throws IOException {
+        ServerSocket server = null;
+        try {
+            server = new ServerSocket(0);
+            return server.getLocalPort();
+        } finally {
+            try {
+                server.close();
+            } catch(IOException e) {}
+        }
+    }
 }

+ 32 - 2
config/src/main/java/org/springframework/security/config/ldap/LdapServerBeanDefinitionParser.java

@@ -1,5 +1,8 @@
 package org.springframework.security.config.ldap;
 
+import java.io.IOException;
+import java.net.ServerSocket;
+
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.springframework.beans.factory.config.BeanDefinition;
@@ -9,6 +12,7 @@ import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser;
 import org.springframework.beans.factory.xml.BeanDefinitionParser;
 import org.springframework.beans.factory.xml.ParserContext;
 import org.springframework.security.config.BeanIds;
+import org.springframework.security.ldap.server.ApacheDSContainer;
 import org.springframework.util.StringUtils;
 import org.w3c.dom.Element;
 
@@ -40,7 +44,8 @@ public class LdapServerBeanDefinitionParser implements BeanDefinitionParser {
 
     /** Defines the port the LDAP_PROVIDER server should run on */
     public static final String ATT_PORT = "port";
-    public static final String OPT_DEFAULT_PORT = "33389";
+    private static final int DEFAULT_PORT = 33389;
+    public static final String OPT_DEFAULT_PORT = String.valueOf(DEFAULT_PORT);
 
 
     public BeanDefinition parse(Element elt, ParserContext parserContext) {
@@ -101,7 +106,10 @@ public class LdapServerBeanDefinitionParser implements BeanDefinitionParser {
         String port = element.getAttribute(ATT_PORT);
 
         if (!StringUtils.hasText(port)) {
-            port = OPT_DEFAULT_PORT;
+            port = getDefaultPort();
+            if(logger.isDebugEnabled()) {
+                logger.debug("Using default port of " + port);
+            }
         }
 
         String url = "ldap://127.0.0.1:" + port + "/" + suffix;
@@ -134,4 +142,26 @@ public class LdapServerBeanDefinitionParser implements BeanDefinitionParser {
 
         return (RootBeanDefinition) contextSource.getBeanDefinition();
     }
+
+    private String getDefaultPort() {
+        ServerSocket serverSocket = null;
+        try {
+            try {
+                serverSocket = new ServerSocket(DEFAULT_PORT);
+            } catch (IOException e) {
+                try {
+                    serverSocket = new ServerSocket(0);
+                } catch(IOException e2) {
+                    return String.valueOf(DEFAULT_PORT);
+                }
+            }
+            return String.valueOf(serverSocket.getLocalPort());
+        } finally {
+            if(serverSocket != null) {
+                try {
+                    serverSocket.close();
+                } catch (IOException e) {}
+            }
+        }
+    }
 }