https://issues.apache.org/jira/browse/AMQ-5345 - improve ldap communication
Project: http://git-wip-us.apache.org/repos/asf/activemq/repo Commit: http://git-wip-us.apache.org/repos/asf/activemq/commit/22f2f3dd Tree: http://git-wip-us.apache.org/repos/asf/activemq/tree/22f2f3dd Diff: http://git-wip-us.apache.org/repos/asf/activemq/diff/22f2f3dd Branch: refs/heads/activemq-5.10.x Commit: 22f2f3dde757d31307da772d579815c1d169bc39 Parents: 6bdf4f8 Author: Dejan Bosanac <[email protected]> Authored: Mon Sep 8 13:51:25 2014 +0200 Committer: Hadrian Zbarcea <[email protected]> Committed: Wed Dec 17 19:53:53 2014 -0500 ---------------------------------------------------------------------- .../activemq/network/LdapNetworkConnector.java | 12 ++- .../activemq/security/LDAPAuthorizationMap.java | 8 +- .../SimpleCachedLDAPAuthorizationMap.java | 8 +- .../apache/activemq/jaas/LDAPLoginModule.java | 11 ++- .../activemq/jaas/LDAPLoginModuleTest.java | 27 +++++++ activemq-jaas/src/test/resources/login.config | 19 +++++ .../security/LDAPAuthenticationTest.java | 83 ++++++++++++++++++++ .../activemq/security/LDAPSecurityTest.java | 2 +- .../src/test/resources/login.config | 19 +++++ .../activemq/security/activemq-ldap-auth.xml | 46 +++++++++++ 10 files changed, 225 insertions(+), 10 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/activemq/blob/22f2f3dd/activemq-broker/src/main/java/org/apache/activemq/network/LdapNetworkConnector.java ---------------------------------------------------------------------- diff --git a/activemq-broker/src/main/java/org/apache/activemq/network/LdapNetworkConnector.java b/activemq-broker/src/main/java/org/apache/activemq/network/LdapNetworkConnector.java index 3445b5a..0d3342e 100644 --- a/activemq-broker/src/main/java/org/apache/activemq/network/LdapNetworkConnector.java +++ b/activemq-broker/src/main/java/org/apache/activemq/network/LdapNetworkConnector.java @@ -210,8 +210,16 @@ public class LdapNetworkConnector extends NetworkConnector implements NamespaceC env.put(Context.SECURITY_AUTHENTICATION, "none"); } else { LOG.debug(" login credentials [{}:******]", user); - env.put(Context.SECURITY_PRINCIPAL, user); - env.put(Context.SECURITY_CREDENTIALS, password); + if (user != null && !"".equals(user)) { + env.put(Context.SECURITY_PRINCIPAL, user); + } else { + throw new Exception("Empty username is not allowed"); + } + if (password != null && !"".equals(password)) { + env.put(Context.SECURITY_CREDENTIALS, password); + } else { + throw new Exception("Empty password is not allowed"); + } } boolean isConnected = false; while (!isConnected) { http://git-wip-us.apache.org/repos/asf/activemq/blob/22f2f3dd/activemq-broker/src/main/java/org/apache/activemq/security/LDAPAuthorizationMap.java ---------------------------------------------------------------------- diff --git a/activemq-broker/src/main/java/org/apache/activemq/security/LDAPAuthorizationMap.java b/activemq-broker/src/main/java/org/apache/activemq/security/LDAPAuthorizationMap.java index 011c2c1..2b89d12 100755 --- a/activemq-broker/src/main/java/org/apache/activemq/security/LDAPAuthorizationMap.java +++ b/activemq-broker/src/main/java/org/apache/activemq/security/LDAPAuthorizationMap.java @@ -469,11 +469,15 @@ public class LDAPAuthorizationMap implements AuthorizationMap { try { Hashtable<String, String> env = new Hashtable<String, String>(); env.put(Context.INITIAL_CONTEXT_FACTORY, initialContextFactory); - if (connectionUsername != null || !"".equals(connectionUsername)) { + if (connectionUsername != null && !"".equals(connectionUsername)) { env.put(Context.SECURITY_PRINCIPAL, connectionUsername); + } else { + throw new NamingException("Empty username is not allowed"); } - if (connectionPassword != null || !"".equals(connectionPassword)) { + if (connectionPassword != null && !"".equals(connectionPassword)) { env.put(Context.SECURITY_CREDENTIALS, connectionPassword); + } else { + throw new NamingException("Empty password is not allowed"); } env.put(Context.SECURITY_PROTOCOL, connectionProtocol); env.put(Context.PROVIDER_URL, connectionURL); http://git-wip-us.apache.org/repos/asf/activemq/blob/22f2f3dd/activemq-broker/src/main/java/org/apache/activemq/security/SimpleCachedLDAPAuthorizationMap.java ---------------------------------------------------------------------- diff --git a/activemq-broker/src/main/java/org/apache/activemq/security/SimpleCachedLDAPAuthorizationMap.java b/activemq-broker/src/main/java/org/apache/activemq/security/SimpleCachedLDAPAuthorizationMap.java index e01d5c0..9f888b9 100644 --- a/activemq-broker/src/main/java/org/apache/activemq/security/SimpleCachedLDAPAuthorizationMap.java +++ b/activemq-broker/src/main/java/org/apache/activemq/security/SimpleCachedLDAPAuthorizationMap.java @@ -125,11 +125,15 @@ public class SimpleCachedLDAPAuthorizationMap implements AuthorizationMap { protected DirContext createContext() throws NamingException { Hashtable<String, String> env = new Hashtable<String, String>(); env.put(Context.INITIAL_CONTEXT_FACTORY, initialContextFactory); - if (connectionUsername != null || !"".equals(connectionUsername)) { + if (connectionUsername != null && !"".equals(connectionUsername)) { env.put(Context.SECURITY_PRINCIPAL, connectionUsername); + } else { + throw new NamingException("Empty username is not allowed"); } - if (connectionPassword != null || !"".equals(connectionPassword)) { + if (connectionPassword != null && !"".equals(connectionPassword)) { env.put(Context.SECURITY_CREDENTIALS, connectionPassword); + } else { + throw new NamingException("Empty password is not allowed"); } env.put(Context.SECURITY_PROTOCOL, connectionProtocol); env.put(Context.PROVIDER_URL, connectionURL); http://git-wip-us.apache.org/repos/asf/activemq/blob/22f2f3dd/activemq-jaas/src/main/java/org/apache/activemq/jaas/LDAPLoginModule.java ---------------------------------------------------------------------- diff --git a/activemq-jaas/src/main/java/org/apache/activemq/jaas/LDAPLoginModule.java b/activemq-jaas/src/main/java/org/apache/activemq/jaas/LDAPLoginModule.java index 7dc6326..f0834a0 100644 --- a/activemq-jaas/src/main/java/org/apache/activemq/jaas/LDAPLoginModule.java +++ b/activemq-jaas/src/main/java/org/apache/activemq/jaas/LDAPLoginModule.java @@ -190,7 +190,7 @@ public class LDAPLoginModule implements LoginModule { try { String filter = userSearchMatchingFormat.format(new String[] { - username + doRFC2254Encoding(username) }); SearchControls constraints = new SearchControls(); if (userSearchSubtreeBool) { @@ -319,7 +319,7 @@ public class LDAPLoginModule implements LoginModule { return list; } String filter = roleSearchMatchingFormat.format(new String[] { - doRFC2254Encoding(dn), username + doRFC2254Encoding(dn), doRFC2254Encoding(username) }); SearchControls constraints = new SearchControls(); @@ -459,9 +459,14 @@ public class LDAPLoginModule implements LoginModule { env.put(Context.INITIAL_CONTEXT_FACTORY, getLDAPPropertyValue(INITIAL_CONTEXT_FACTORY)); if (isLoginPropertySet(CONNECTION_USERNAME)) { env.put(Context.SECURITY_PRINCIPAL, getLDAPPropertyValue(CONNECTION_USERNAME)); + } else { + throw new NamingException("Empty username is not allowed"); } + if (isLoginPropertySet(CONNECTION_PASSWORD)) { env.put(Context.SECURITY_CREDENTIALS, getLDAPPropertyValue(CONNECTION_PASSWORD)); + } else { + throw new NamingException("Empty password is not allowed"); } env.put(Context.SECURITY_PROTOCOL, getLDAPPropertyValue(CONNECTION_PROTOCOL)); env.put(Context.PROVIDER_URL, getLDAPPropertyValue(CONNECTION_URL)); @@ -484,7 +489,7 @@ public class LDAPLoginModule implements LoginModule { private boolean isLoginPropertySet(String propertyName) { for (int i=0; i < config.length; i++ ) { - if (config[i].getPropertyName() == propertyName && config[i].getPropertyValue() != null) + if (config[i].getPropertyName() == propertyName && (config[i].getPropertyValue() != null && !"".equals(config[i].getPropertyValue()))) return true; } return false; http://git-wip-us.apache.org/repos/asf/activemq/blob/22f2f3dd/activemq-jaas/src/test/java/org/apache/activemq/jaas/LDAPLoginModuleTest.java ---------------------------------------------------------------------- diff --git a/activemq-jaas/src/test/java/org/apache/activemq/jaas/LDAPLoginModuleTest.java b/activemq-jaas/src/test/java/org/apache/activemq/jaas/LDAPLoginModuleTest.java index d721b1f..e68b815 100644 --- a/activemq-jaas/src/test/java/org/apache/activemq/jaas/LDAPLoginModuleTest.java +++ b/activemq-jaas/src/test/java/org/apache/activemq/jaas/LDAPLoginModuleTest.java @@ -41,7 +41,9 @@ import java.net.URL; import java.util.HashSet; import java.util.Hashtable; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; @RunWith ( FrameworkRunner.class ) @CreateLdapServer(transports = {@CreateTransport(protocol = "LDAP", port=1024)}) @@ -121,4 +123,29 @@ public class LDAPLoginModuleTest extends AbstractLdapTestUnit { context.logout(); } + @Test + public void testUnauthenticated() throws LoginException { + LoginContext context = new LoginContext("UnAuthenticatedLDAPLogin", new CallbackHandler() { + public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException { + for (int i = 0; i < callbacks.length; i++) { + if (callbacks[i] instanceof NameCallback) { + ((NameCallback) callbacks[i]).setName("first"); + } else if (callbacks[i] instanceof PasswordCallback) { + ((PasswordCallback) callbacks[i]).setPassword("secret".toCharArray()); + } else { + throw new UnsupportedCallbackException(callbacks[i]); + } + } + } + }); + try { + context.login(); + } catch (LoginException le) { + assertEquals(le.getCause().getMessage(), "Empty password is not allowed"); + return; + } + fail("Should have failed authenticating"); + } + + } http://git-wip-us.apache.org/repos/asf/activemq/blob/22f2f3dd/activemq-jaas/src/test/resources/login.config ---------------------------------------------------------------------- diff --git a/activemq-jaas/src/test/resources/login.config b/activemq-jaas/src/test/resources/login.config index 6835c14..ae1371c 100644 --- a/activemq-jaas/src/test/resources/login.config +++ b/activemq-jaas/src/test/resources/login.config @@ -40,6 +40,25 @@ LDAPLogin { ; }; +UnAuthenticatedLDAPLogin { + org.apache.activemq.jaas.LDAPLoginModule required + debug=true + initialContextFactory=com.sun.jndi.ldap.LdapCtxFactory + connectionURL="ldap://localhost:1024" + connectionUsername="uid=admin,ou=system" + connectionPassword="" + connectionProtocol=s + authentication=simple + userBase="ou=system" + userSearchMatching="(uid={0})" + userSearchSubtree=false + roleBase="ou=system" + roleName=dummyRoleName + roleSearchMatching="(uid={1})" + roleSearchSubtree=false + ; +}; + ExpandedLDAPLogin { org.apache.activemq.jaas.LDAPLoginModule required debug=true http://git-wip-us.apache.org/repos/asf/activemq/blob/22f2f3dd/activemq-unit-tests/src/test/java/org/apache/activemq/security/LDAPAuthenticationTest.java ---------------------------------------------------------------------- diff --git a/activemq-unit-tests/src/test/java/org/apache/activemq/security/LDAPAuthenticationTest.java b/activemq-unit-tests/src/test/java/org/apache/activemq/security/LDAPAuthenticationTest.java new file mode 100644 index 0000000..4e77c01 --- /dev/null +++ b/activemq-unit-tests/src/test/java/org/apache/activemq/security/LDAPAuthenticationTest.java @@ -0,0 +1,83 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.activemq.security; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.fail; + +import javax.jms.Connection; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Queue; +import javax.jms.Session; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.directory.server.annotations.CreateLdapServer; +import org.apache.directory.server.annotations.CreateTransport; +import org.apache.directory.server.core.annotations.ApplyLdifFiles; +import org.apache.directory.server.core.integ.AbstractLdapTestUnit; +import org.apache.directory.server.core.integ.FrameworkRunner; +import org.apache.directory.server.ldap.LdapServer; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + + +@RunWith( FrameworkRunner.class ) +@CreateLdapServer(transports = {@CreateTransport(protocol = "LDAP", port=1024)}) +@ApplyLdifFiles( + "org/apache/activemq/security/activemq.ldif" +) +public class LDAPAuthenticationTest extends AbstractLdapTestUnit { + + public BrokerService broker; + + public static LdapServer ldapServer; + + @Before + public void setup() throws Exception { + System.setProperty("ldapPort", String.valueOf(getLdapServer().getPort())); + + broker = BrokerFactory.createBroker("xbean:org/apache/activemq/security/activemq-ldap-auth.xml"); + broker.start(); + broker.waitUntilStarted(); + } + + @After + public void shutdown() throws Exception { + broker.stop(); + broker.waitUntilStopped(); + } + + @Test + public void testWildcard() throws Exception { + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("tcp://localhost:61616"); + Connection conn = factory.createQueueConnection("*", "sunflower"); + try { + conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + } catch (Exception e) { + e.printStackTrace(); + return; + } + fail("Should have failed connecting"); + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/activemq/blob/22f2f3dd/activemq-unit-tests/src/test/java/org/apache/activemq/security/LDAPSecurityTest.java ---------------------------------------------------------------------- diff --git a/activemq-unit-tests/src/test/java/org/apache/activemq/security/LDAPSecurityTest.java b/activemq-unit-tests/src/test/java/org/apache/activemq/security/LDAPSecurityTest.java index 3642e0b..63c4cbd 100644 --- a/activemq-unit-tests/src/test/java/org/apache/activemq/security/LDAPSecurityTest.java +++ b/activemq-unit-tests/src/test/java/org/apache/activemq/security/LDAPSecurityTest.java @@ -44,7 +44,7 @@ import org.junit.runner.RunWith; @RunWith( FrameworkRunner.class ) -@CreateLdapServer(transports = {@CreateTransport(protocol = "LDAP")}) +@CreateLdapServer(transports = {@CreateTransport(protocol = "LDAP", port=1024)}) @ApplyLdifFiles( "org/apache/activemq/security/activemq.ldif" ) http://git-wip-us.apache.org/repos/asf/activemq/blob/22f2f3dd/activemq-unit-tests/src/test/resources/login.config ---------------------------------------------------------------------- diff --git a/activemq-unit-tests/src/test/resources/login.config b/activemq-unit-tests/src/test/resources/login.config index ed4dd2e..1f5f77c 100644 --- a/activemq-unit-tests/src/test/resources/login.config +++ b/activemq-unit-tests/src/test/resources/login.config @@ -65,4 +65,23 @@ broker2 { debug=true org.apache.activemq.jaas.textfiledn.user="org/apache/activemq/security/users2.properties" org.apache.activemq.jaas.textfiledn.group="org/apache/activemq/security/groups.properties"; +}; + +LDAPLogin { + org.apache.activemq.jaas.LDAPLoginModule required + debug=true + initialContextFactory=com.sun.jndi.ldap.LdapCtxFactory + connectionURL="ldap://localhost:1024" + connectionUsername="uid=admin,ou=system" + connectionPassword=secret + connectionProtocol=s + authentication=simple + userBase="ou=User,ou=ActiveMQ,ou=system" + userSearchMatching="(uid={0})" + userSearchSubtree=false + roleBase="ou=Group,ou=ActiveMQ,ou=system" + roleName=cn + roleSearchMatching="(uid={1})" + roleSearchSubtree=true + ; }; \ No newline at end of file http://git-wip-us.apache.org/repos/asf/activemq/blob/22f2f3dd/activemq-unit-tests/src/test/resources/org/apache/activemq/security/activemq-ldap-auth.xml ---------------------------------------------------------------------- diff --git a/activemq-unit-tests/src/test/resources/org/apache/activemq/security/activemq-ldap-auth.xml b/activemq-unit-tests/src/test/resources/org/apache/activemq/security/activemq-ldap-auth.xml new file mode 100644 index 0000000..8a11a6a --- /dev/null +++ b/activemq-unit-tests/src/test/resources/org/apache/activemq/security/activemq-ldap-auth.xml @@ -0,0 +1,46 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You 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 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<!-- START SNIPPET: xbean --> +<beans + xmlns="http://www.springframework.org/schema/beans" + xmlns:amq="http://activemq.apache.org/schema/core" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd + http://activemq.apache.org/schema/core http://activemq.apache.org/schema/core/activemq-core.xsd"> + + <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"/> + + <broker useJmx="false" xmlns="http://activemq.apache.org/schema/core" persistent="false"> + + <destinations> + <queue physicalName="ADMIN.FOO" /> + </destinations> + + <plugins> + <jaasAuthenticationPlugin configuration="LDAPLogin"/> + </plugins> + + + <transportConnectors> + <transportConnector uri="tcp://localhost:61616"/> + </transportConnectors> + + </broker> + +</beans> +<!-- END SNIPPET: xbean -->
