Return-Path: X-Original-To: apmail-activemq-commits-archive@www.apache.org Delivered-To: apmail-activemq-commits-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id D7A4610AF0 for ; Wed, 12 Mar 2014 14:13:34 +0000 (UTC) Received: (qmail 97873 invoked by uid 500); 12 Mar 2014 14:13:30 -0000 Delivered-To: apmail-activemq-commits-archive@activemq.apache.org Received: (qmail 97763 invoked by uid 500); 12 Mar 2014 14:13:28 -0000 Mailing-List: contact commits-help@activemq.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@activemq.apache.org Delivered-To: mailing list commits@activemq.apache.org Received: (qmail 95723 invoked by uid 99); 12 Mar 2014 14:13:11 -0000 Received: from tyr.zones.apache.org (HELO tyr.zones.apache.org) (140.211.11.114) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 12 Mar 2014 14:13:11 +0000 Received: by tyr.zones.apache.org (Postfix, from userid 65534) id 68E4C941CAF; Wed, 12 Mar 2014 14:13:10 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: hadrian@apache.org To: commits@activemq.apache.org Date: Wed, 12 Mar 2014 14:13:18 -0000 Message-Id: In-Reply-To: References: X-Mailer: ASF-Git Admin Mailer Subject: [09/13] git commit: https://issues.apache.org/jira/browse/AMQ-4849 - runtime modifications to simpleAuthenticationPlugin plugin implemented with test https://issues.apache.org/jira/browse/AMQ-4849 - runtime modifications to simpleAuthenticationPlugin plugin implemented with test Project: http://git-wip-us.apache.org/repos/asf/activemq/repo Commit: http://git-wip-us.apache.org/repos/asf/activemq/commit/9753a43d Tree: http://git-wip-us.apache.org/repos/asf/activemq/tree/9753a43d Diff: http://git-wip-us.apache.org/repos/asf/activemq/diff/9753a43d Branch: refs/heads/activemq-5.9 Commit: 9753a43df6d99e3b21e2c79b92dc9f7231986b7e Parents: 554efe3 Author: gtully Authored: Tue Nov 5 20:37:31 2013 +0000 Committer: Hadrian Zbarcea Committed: Wed Mar 12 09:01:33 2014 -0400 ---------------------------------------------------------------------- .../activemq/security/AuthenticationUser.java | 3 + .../security/SimpleAuthenticationBroker.java | 12 ++- .../security/SimpleAuthenticationPlugin.java | 12 +++ .../plugin/RuntimeConfigurationBroker.java | 83 ++++++++++++++++---- .../src/main/resources/binding.xjb | 8 ++ .../org/apache/activemq/AuthenticationTest.java | 71 +++++++++++++++++ .../activemq/authenticationTest-two-users.xml | 59 ++++++++++++++ .../activemq/authenticationTest-users.xml | 54 +++++++++++++ 8 files changed, 286 insertions(+), 16 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/activemq/blob/9753a43d/activemq-broker/src/main/java/org/apache/activemq/security/AuthenticationUser.java ---------------------------------------------------------------------- diff --git a/activemq-broker/src/main/java/org/apache/activemq/security/AuthenticationUser.java b/activemq-broker/src/main/java/org/apache/activemq/security/AuthenticationUser.java index edd0eab..65d34d5 100644 --- a/activemq-broker/src/main/java/org/apache/activemq/security/AuthenticationUser.java +++ b/activemq-broker/src/main/java/org/apache/activemq/security/AuthenticationUser.java @@ -28,6 +28,9 @@ public class AuthenticationUser { String password; String groups; + public AuthenticationUser() { + } + public AuthenticationUser(String username, String password, String groups) { this.username = username; this.password = password; http://git-wip-us.apache.org/repos/asf/activemq/blob/9753a43d/activemq-broker/src/main/java/org/apache/activemq/security/SimpleAuthenticationBroker.java ---------------------------------------------------------------------- diff --git a/activemq-broker/src/main/java/org/apache/activemq/security/SimpleAuthenticationBroker.java b/activemq-broker/src/main/java/org/apache/activemq/security/SimpleAuthenticationBroker.java index 6e61e88..46544f7 100644 --- a/activemq-broker/src/main/java/org/apache/activemq/security/SimpleAuthenticationBroker.java +++ b/activemq-broker/src/main/java/org/apache/activemq/security/SimpleAuthenticationBroker.java @@ -34,8 +34,8 @@ public class SimpleAuthenticationBroker extends AbstractAuthenticationBroker { private boolean anonymousAccessAllowed = false; private String anonymousUser; private String anonymousGroup; - private final Map userPasswords; - private final Map> userGroups; + private Map userPasswords; + private Map> userGroups; public SimpleAuthenticationBroker(Broker next, Map userPasswords, Map> userGroups) { super(next); @@ -55,6 +55,14 @@ public class SimpleAuthenticationBroker extends AbstractAuthenticationBroker { this.anonymousGroup = anonymousGroup; } + public void setUserPasswords(Map value) { + userPasswords = value; + } + + public void setUserGroups(Map> value) { + userGroups = value; + } + @Override public void addConnection(ConnectionContext context, ConnectionInfo info) throws Exception { http://git-wip-us.apache.org/repos/asf/activemq/blob/9753a43d/activemq-broker/src/main/java/org/apache/activemq/security/SimpleAuthenticationPlugin.java ---------------------------------------------------------------------- diff --git a/activemq-broker/src/main/java/org/apache/activemq/security/SimpleAuthenticationPlugin.java b/activemq-broker/src/main/java/org/apache/activemq/security/SimpleAuthenticationPlugin.java index 7d518ea..a334a98 100644 --- a/activemq-broker/src/main/java/org/apache/activemq/security/SimpleAuthenticationPlugin.java +++ b/activemq-broker/src/main/java/org/apache/activemq/security/SimpleAuthenticationPlugin.java @@ -93,14 +93,26 @@ public class SimpleAuthenticationPlugin implements BrokerPlugin { this.anonymousAccessAllowed = anonymousAccessAllowed; } + public boolean isAnonymousAccessAllowed() { + return anonymousAccessAllowed; + } + public void setAnonymousUser(String anonymousUser) { this.anonymousUser = anonymousUser; } + public String getAnonymousUser() { + return anonymousUser; + } + public void setAnonymousGroup(String anonymousGroup) { this.anonymousGroup = anonymousGroup; } + public String getAnonymousGroup() { + return anonymousGroup; + } + /** * Sets the groups a user is in. The key is the user name and the value is a * Set of groups http://git-wip-us.apache.org/repos/asf/activemq/blob/9753a43d/activemq-runtime-config/src/main/java/org/apache/activemq/plugin/RuntimeConfigurationBroker.java ---------------------------------------------------------------------- diff --git a/activemq-runtime-config/src/main/java/org/apache/activemq/plugin/RuntimeConfigurationBroker.java b/activemq-runtime-config/src/main/java/org/apache/activemq/plugin/RuntimeConfigurationBroker.java index b541542..82a5ee3 100644 --- a/activemq-runtime-config/src/main/java/org/apache/activemq/plugin/RuntimeConfigurationBroker.java +++ b/activemq-runtime-config/src/main/java/org/apache/activemq/plugin/RuntimeConfigurationBroker.java @@ -17,7 +17,6 @@ package org.apache.activemq.plugin; import java.io.IOException; -import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.MalformedURLException; import java.util.ArrayList; @@ -69,10 +68,12 @@ import org.apache.activemq.broker.region.virtual.VirtualTopic; import org.apache.activemq.command.ActiveMQDestination; import org.apache.activemq.command.ActiveMQQueue; import org.apache.activemq.command.ActiveMQTopic; +import org.apache.activemq.command.ConnectionInfo; import org.apache.activemq.filter.DestinationMapEntry; import org.apache.activemq.network.DiscoveryNetworkConnector; import org.apache.activemq.network.NetworkConnector; import org.apache.activemq.plugin.jmx.RuntimeConfigurationView; +import org.apache.activemq.schema.core.DtoAuthenticationUser; import org.apache.activemq.schema.core.DtoAuthorizationEntry; import org.apache.activemq.schema.core.DtoAuthorizationMap; import org.apache.activemq.schema.core.DtoAuthorizationPlugin; @@ -83,11 +84,15 @@ import org.apache.activemq.schema.core.DtoNetworkConnector; import org.apache.activemq.schema.core.DtoPolicyEntry; import org.apache.activemq.schema.core.DtoPolicyMap; import org.apache.activemq.schema.core.DtoQueue; +import org.apache.activemq.schema.core.DtoSimpleAuthenticationPlugin; import org.apache.activemq.schema.core.DtoTopic; import org.apache.activemq.schema.core.DtoVirtualDestinationInterceptor; import org.apache.activemq.schema.core.DtoVirtualTopic; +import org.apache.activemq.security.AuthenticationUser; import org.apache.activemq.security.AuthorizationBroker; import org.apache.activemq.security.AuthorizationMap; +import org.apache.activemq.security.SimpleAuthenticationBroker; +import org.apache.activemq.security.SimpleAuthenticationPlugin; import org.apache.activemq.security.TempDestinationAuthorizationEntry; import org.apache.activemq.security.XBeanAuthorizationEntry; import org.apache.activemq.security.XBeanAuthorizationMap; @@ -95,9 +100,7 @@ import org.apache.activemq.spring.Utils; import org.apache.activemq.util.IntrospectionSupport; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.FactoryBean; -import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer; import org.springframework.beans.factory.xml.PluggableSchemaResolver; import org.springframework.core.io.Resource; import org.w3c.dom.Document; @@ -112,13 +115,15 @@ public class RuntimeConfigurationBroker extends BrokerFilter { public static final Logger LOG = LoggerFactory.getLogger(RuntimeConfigurationBroker.class); public static final String objectNamePropsAppendage = ",service=RuntimeConfiguration,name=Plugin"; private final ReentrantReadWriteLock addDestinationBarrier = new ReentrantReadWriteLock(); + private final ReentrantReadWriteLock addConnectionBarrier = new ReentrantReadWriteLock(); PropertiesPlaceHolderUtil placeHolderUtil = null; private long checkPeriod; private long lastModified = -1; private Resource configToMonitor; private DtoBroker currentConfiguration; private Runnable monitorTask; - private ConcurrentLinkedQueue destinationInterceptorUpdateWork = new ConcurrentLinkedQueue(); + private ConcurrentLinkedQueue addDestinationWork = new ConcurrentLinkedQueue(); + private ConcurrentLinkedQueue addConnectionWork = new ConcurrentLinkedQueue(); private ObjectName objectName; private String infoString; private Schema schema; @@ -184,13 +189,13 @@ public class RuntimeConfigurationBroker extends BrokerFilter { // modification to virtual destinations interceptor needs exclusive access to destination add @Override public Destination addDestination(ConnectionContext context, ActiveMQDestination destination, boolean createIfTemporary) throws Exception { - Runnable work = destinationInterceptorUpdateWork.poll(); + Runnable work = addDestinationWork.poll(); if (work != null) { try { addDestinationBarrier.writeLock().lockInterruptibly(); do { work.run(); - work = destinationInterceptorUpdateWork.poll(); + work = addDestinationWork.poll(); } while (work != null); return super.addDestination(context, destination, createIfTemporary); } finally { @@ -206,6 +211,31 @@ public class RuntimeConfigurationBroker extends BrokerFilter { } } + // modification to authentication plugin needs exclusive access to connection add + @Override + public void addConnection(ConnectionContext context, ConnectionInfo info) throws Exception { + Runnable work = addConnectionWork.poll(); + if (work != null) { + try { + addConnectionBarrier.writeLock().lockInterruptibly(); + do { + work.run(); + work = addConnectionWork.poll(); + } while (work != null); + super.addConnection(context, info); + } finally { + addConnectionBarrier.writeLock().unlock(); + } + } else { + try { + addConnectionBarrier.readLock().lockInterruptibly(); + super.addConnection(context, info); + } finally { + addConnectionBarrier.readLock().unlock(); + } + } + } + public String updateNow() { LOG.info("Manual configuration update triggered"); infoString = ""; @@ -235,7 +265,7 @@ public class RuntimeConfigurationBroker extends BrokerFilter { } private void info(String s) { - LOG.info(s); + LOG.info(filterPasswords(s)); if (infoString != null) { infoString += s; infoString += ";"; @@ -243,7 +273,7 @@ public class RuntimeConfigurationBroker extends BrokerFilter { } private void info(String s, Throwable t) { - LOG.info(s, t); + LOG.info(filterPasswords(s), t); if (infoString != null) { infoString += s; infoString += ", " + t; @@ -255,8 +285,8 @@ public class RuntimeConfigurationBroker extends BrokerFilter { DtoBroker changed = loadConfiguration(configToMonitor); if (changed != null && !currentConfiguration.equals(changed)) { LOG.info("change in " + configToMonitor + " at: " + new Date(lastModified)); - LOG.debug("current:" + currentConfiguration); - LOG.debug("new :" + changed); + LOG.debug("current:" + filterPasswords(currentConfiguration)); + LOG.debug("new :" + filterPasswords(changed)); processSelectiveChanges(currentConfiguration, changed); currentConfiguration = changed; } else { @@ -320,7 +350,7 @@ public class RuntimeConfigurationBroker extends BrokerFilter { answer.add(val); } } catch (NoSuchMethodException mappingIncomplete) { - LOG.debug(o + " has no modifiable elements"); + LOG.debug(filterPasswords(o) + " has no modifiable elements"); } catch (Exception e) { info("Failed to access getContents for " + o + ", runtime modifications not supported", e); } @@ -360,6 +390,24 @@ public class RuntimeConfigurationBroker extends BrokerFilter { info("failed to apply modified AuthorizationMap to AuthorizationBroker", e); } + } else if (candidate instanceof DtoSimpleAuthenticationPlugin) { + try { + final SimpleAuthenticationPlugin updatedPlugin = fromDto(candidate, new SimpleAuthenticationPlugin()); + final SimpleAuthenticationBroker authenticationBroker = + (SimpleAuthenticationBroker) getBrokerService().getBroker().getAdaptor(SimpleAuthenticationBroker.class); + addConnectionWork.add(new Runnable() { + public void run() { + authenticationBroker.setUserGroups(updatedPlugin.getUserGroups()); + authenticationBroker.setUserPasswords(updatedPlugin.getUserPasswords()); + authenticationBroker.setAnonymousAccessAllowed(updatedPlugin.isAnonymousAccessAllowed()); + authenticationBroker.setAnonymousUser(updatedPlugin.getAnonymousUser()); + authenticationBroker.setAnonymousGroup(updatedPlugin.getAnonymousGroup()); + } + }); + } catch (Exception e) { + info("failed to apply SimpleAuthenticationPlugin modifications to SimpleAuthenticationBroker", e); + } + } else if (candidate instanceof DtoPolicyMap) { List existingEntries = filter(existing, DtoPolicyMap.PolicyEntries.class); @@ -450,7 +498,7 @@ public class RuntimeConfigurationBroker extends BrokerFilter { } } else if (o instanceof DtoVirtualDestinationInterceptor) { // whack it - destinationInterceptorUpdateWork.add(new Runnable() { + addDestinationWork.add(new Runnable() { public void run() { List interceptorsList = new ArrayList(); for (DestinationInterceptor candidate : getBrokerService().getDestinationInterceptors()) { @@ -500,7 +548,7 @@ public class RuntimeConfigurationBroker extends BrokerFilter { } } else if (o instanceof DtoVirtualDestinationInterceptor) { final DtoVirtualDestinationInterceptor dto = (DtoVirtualDestinationInterceptor) o; - destinationInterceptorUpdateWork.add(new Runnable() { + addDestinationWork.add(new Runnable() { public void run() { boolean updatedExistingInterceptor = false; @@ -570,7 +618,7 @@ public class RuntimeConfigurationBroker extends BrokerFilter { Properties properties = new Properties(); IntrospectionSupport.getProperties(dto, properties, null); replacePlaceHolders(properties); - LOG.trace("applying props: " + properties + ", to " + instance.getClass().getSimpleName()); + LOG.trace("applying props: " + filterPasswords(properties) + ", to " + instance.getClass().getSimpleName()); IntrospectionSupport.setProperties(instance, properties); // deal with nested elements @@ -599,6 +647,11 @@ public class RuntimeConfigurationBroker extends BrokerFilter { return instance; } + Pattern matchPassword = Pattern.compile("password=.*,"); + private String filterPasswords(Object toEscape) { + return matchPassword.matcher(toEscape.toString()).replaceAll("password=???,"); + } + private Object matchType(List parameterValues, Class aClass) { Object result = parameterValues; if (Set.class.isAssignableFrom(aClass)) { @@ -612,6 +665,8 @@ public class RuntimeConfigurationBroker extends BrokerFilter { return new ActiveMQTopic(); } else if (DtoQueue.class.isAssignableFrom(elementContent.getClass())) { return new ActiveMQQueue(); + } else if (DtoAuthenticationUser.class.isAssignableFrom(elementContent.getClass())) { + return new AuthenticationUser(); } else { info("update not supported for dto: " + elementContent); return new Object(); http://git-wip-us.apache.org/repos/asf/activemq/blob/9753a43d/activemq-runtime-config/src/main/resources/binding.xjb ---------------------------------------------------------------------- diff --git a/activemq-runtime-config/src/main/resources/binding.xjb b/activemq-runtime-config/src/main/resources/binding.xjb index b5a5334..c73d406 100644 --- a/activemq-runtime-config/src/main/resources/binding.xjb +++ b/activemq-runtime-config/src/main/resources/binding.xjb @@ -108,5 +108,13 @@ + + + + + + + + http://git-wip-us.apache.org/repos/asf/activemq/blob/9753a43d/activemq-runtime-config/src/test/java/org/apache/activemq/AuthenticationTest.java ---------------------------------------------------------------------- diff --git a/activemq-runtime-config/src/test/java/org/apache/activemq/AuthenticationTest.java b/activemq-runtime-config/src/test/java/org/apache/activemq/AuthenticationTest.java new file mode 100644 index 0000000..eae6223 --- /dev/null +++ b/activemq-runtime-config/src/test/java/org/apache/activemq/AuthenticationTest.java @@ -0,0 +1,71 @@ +/** + * 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; + +import javax.jms.JMSException; +import javax.jms.Session; +import org.junit.Test; + +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +public class AuthenticationTest extends RuntimeConfigTestSupport { + + String configurationSeed = "authenticationTest"; + + @Test + public void testMod() throws Exception { + final String brokerConfig = configurationSeed + "-authentication-broker"; + applyNewConfig(brokerConfig, configurationSeed + "-users"); + startBroker(brokerConfig); + assertTrue("broker alive", brokerService.isStarted()); + + assertAllowed("test_user_password", "USERS.A"); + assertDenied("another_test_user_password", "USERS.A"); + + // anonymous + assertDenied(null, "USERS.A"); + + applyNewConfig(brokerConfig, configurationSeed + "-two-users", SLEEP); + + assertAllowed("test_user_password", "USERS.A"); + assertAllowed("another_test_user_password", "USERS.A"); + assertAllowed(null, "USERS.A"); + + } + + private void assertDenied(String userPass, String destination) { + try { + assertAllowed(userPass, destination); + fail("Expected not allowed exception"); + } catch (JMSException expected) { + LOG.debug("got:" + expected, expected); + } + } + + private void assertAllowed(String userPass, String dest) throws JMSException { + ActiveMQConnection connection = new ActiveMQConnectionFactory("vm://localhost").createActiveMQConnection(userPass, userPass); + connection.start(); + try { + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + session.createConsumer(session.createQueue(dest)); + } finally { + connection.close(); + } + } + +} http://git-wip-us.apache.org/repos/asf/activemq/blob/9753a43d/activemq-runtime-config/src/test/resources/org/apache/activemq/authenticationTest-two-users.xml ---------------------------------------------------------------------- diff --git a/activemq-runtime-config/src/test/resources/org/apache/activemq/authenticationTest-two-users.xml b/activemq-runtime-config/src/test/resources/org/apache/activemq/authenticationTest-two-users.xml new file mode 100644 index 0000000..9fa2c6a --- /dev/null +++ b/activemq-runtime-config/src/test/resources/org/apache/activemq/authenticationTest-two-users.xml @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + http://git-wip-us.apache.org/repos/asf/activemq/blob/9753a43d/activemq-runtime-config/src/test/resources/org/apache/activemq/authenticationTest-users.xml ---------------------------------------------------------------------- diff --git a/activemq-runtime-config/src/test/resources/org/apache/activemq/authenticationTest-users.xml b/activemq-runtime-config/src/test/resources/org/apache/activemq/authenticationTest-users.xml new file mode 100644 index 0000000..9ed5535 --- /dev/null +++ b/activemq-runtime-config/src/test/resources/org/apache/activemq/authenticationTest-users.xml @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +