You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@activemq.apache.org by ma...@apache.org on 2016/08/08 12:20:55 UTC

[2/3] activemq-artemis git commit: ARTEMIS-601 load runtime security cfg file changes

ARTEMIS-601 load runtime security cfg file changes


Project: http://git-wip-us.apache.org/repos/asf/activemq-artemis/repo
Commit: http://git-wip-us.apache.org/repos/asf/activemq-artemis/commit/1ef9e74f
Tree: http://git-wip-us.apache.org/repos/asf/activemq-artemis/tree/1ef9e74f
Diff: http://git-wip-us.apache.org/repos/asf/activemq-artemis/diff/1ef9e74f

Branch: refs/heads/master
Commit: 1ef9e74f146d1f406053c1e719962017f0afee98
Parents: 85857ab
Author: jbertram <jb...@apache.org>
Authored: Wed Aug 3 17:27:26 2016 -0500
Committer: jbertram <jb...@apache.org>
Committed: Sun Aug 7 20:17:56 2016 -0500

----------------------------------------------------------------------
 .../activemq/cli/test/FileBrokerTest.java       | 76 ++++++++++++++++++++
 .../src/test/resources/broker-reload.xml        | 76 ++++++++++++++++++++
 .../config/ActiveMQDefaultConfiguration.java    |  7 ++
 .../config/impl/FileJMSConfiguration.java       |  3 +-
 .../artemis/core/config/Configuration.java      |  9 +++
 .../core/config/FileDeploymentManager.java      |  2 +-
 .../core/config/impl/ConfigurationImpl.java     | 27 +++++++
 .../core/config/impl/FileConfiguration.java     |  5 +-
 .../artemis/core/deployers/Deployable.java      |  3 +-
 .../deployers/impl/FileConfigurationParser.java |  2 +
 .../core/server/ActiveMQServerLogger.java       |  4 ++
 .../core/server/impl/ActiveMQServerImpl.java    | 40 +++++++++++
 .../core/settings/HierarchicalRepository.java   |  4 ++
 .../impl/HierarchicalObjectRepository.java      | 26 ++++++-
 .../resources/schema/artemis-configuration.xsd  |  8 +++
 .../core/config/impl/FileConfigurationTest.java |  1 +
 .../resources/ConfigurationTest-full-config.xml |  1 +
 17 files changed, 289 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/1ef9e74f/artemis-cli/src/test/java/org/apache/activemq/cli/test/FileBrokerTest.java
----------------------------------------------------------------------
diff --git a/artemis-cli/src/test/java/org/apache/activemq/cli/test/FileBrokerTest.java b/artemis-cli/src/test/java/org/apache/activemq/cli/test/FileBrokerTest.java
index 0feaf8f..7e34ccd 100644
--- a/artemis-cli/src/test/java/org/apache/activemq/cli/test/FileBrokerTest.java
+++ b/artemis-cli/src/test/java/org/apache/activemq/cli/test/FileBrokerTest.java
@@ -16,14 +16,31 @@
  */
 package org.apache.activemq.cli.test;
 
+import java.io.IOException;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.attribute.FileTime;
+
+import org.apache.activemq.artemis.api.core.client.ActiveMQClient;
+import org.apache.activemq.artemis.api.core.client.ClientProducer;
+import org.apache.activemq.artemis.api.core.client.ClientSession;
+import org.apache.activemq.artemis.api.core.client.ClientSessionFactory;
+import org.apache.activemq.artemis.api.core.client.ServerLocator;
+import org.apache.activemq.artemis.core.config.impl.SecurityConfiguration;
 import org.apache.activemq.artemis.core.server.impl.ActiveMQServerImpl;
 import org.apache.activemq.artemis.dto.ServerDTO;
 import org.apache.activemq.artemis.integration.FileBroker;
 import org.apache.activemq.artemis.jms.server.impl.JMSServerManagerImpl;
 import org.apache.activemq.artemis.spi.core.security.ActiveMQJAASSecurityManager;
+import org.apache.activemq.artemis.spi.core.security.jaas.InVMLoginModule;
 import org.junit.Assert;
 import org.junit.Test;
 
+import static org.junit.Assert.fail;
+
 public class FileBrokerTest {
 
    @Test
@@ -71,4 +88,63 @@ public class FileBrokerTest {
          broker.stop();
       }
    }
+
+   @Test
+   public void testConfigFileReload() throws Exception {
+      ServerDTO serverDTO = new ServerDTO();
+      serverDTO.configuration = "broker-reload.xml";
+      FileBroker broker = null;
+      String path = null;
+      try {
+         SecurityConfiguration securityConfiguration = new SecurityConfiguration();
+         securityConfiguration.addUser("myUser", "myPass");
+         securityConfiguration.addRole("myUser", "guest");
+         ActiveMQJAASSecurityManager securityManager = new ActiveMQJAASSecurityManager(InVMLoginModule.class.getName(), securityConfiguration);
+         broker = new FileBroker(serverDTO, securityManager);
+         broker.start();
+         ActiveMQServerImpl activeMQServer = (ActiveMQServerImpl) broker.getComponents().get("core");
+         Assert.assertNotNull(activeMQServer);
+         Assert.assertTrue(activeMQServer.isStarted());
+         Assert.assertTrue(broker.isStarted());
+         path = activeMQServer.getConfiguration().getConfigurationUrl().getPath();
+         Assert.assertNotNull(activeMQServer.getConfiguration().getConfigurationUrl());
+
+         Thread.sleep(activeMQServer.getConfiguration().getConfigurationFileRefreshPeriod() * 2);
+
+         ServerLocator locator = ActiveMQClient.createServerLocator("tcp://localhost:61616");
+         ClientSessionFactory sf = locator.createSessionFactory();
+         ClientSession session = sf.createSession("myUser", "myPass", false, true, false, false, 0);
+         ClientProducer producer = session.createProducer("jms.queue.DLQ");
+         producer.send(session.createMessage(true));
+
+         replacePatternInFile(path, "guest", "X");
+
+         Thread.sleep(activeMQServer.getConfiguration().getConfigurationFileRefreshPeriod() * 2);
+
+         try {
+            producer.send(session.createMessage(true));
+            fail("Should throw a security exception");
+         }
+         catch (Exception e) {
+         }
+
+         locator.close();
+      }
+      finally {
+         assert broker != null;
+         broker.stop();
+         if (path != null) {
+            replacePatternInFile(path, "X", "guest");
+         }
+      }
+   }
+
+   private void replacePatternInFile(String file, String regex, String replacement) throws IOException {
+      Path path = Paths.get(file);
+      Charset charset = StandardCharsets.UTF_8;
+      String content = new String(Files.readAllBytes(path), charset);
+      String replaced = content.replaceAll(regex, replacement);
+      Files.write(path, replaced.getBytes(charset));
+      Files.setLastModifiedTime(path, FileTime.fromMillis(System.currentTimeMillis()));
+   }
 }

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/1ef9e74f/artemis-cli/src/test/resources/broker-reload.xml
----------------------------------------------------------------------
diff --git a/artemis-cli/src/test/resources/broker-reload.xml b/artemis-cli/src/test/resources/broker-reload.xml
new file mode 100644
index 0000000..3063f5f
--- /dev/null
+++ b/artemis-cli/src/test/resources/broker-reload.xml
@@ -0,0 +1,76 @@
+<?xml version='1.0'?>
+<!--
+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.
+-->
+
+<configuration xmlns="urn:activemq">
+   <jms xmlns="urn:activemq:jms">
+      <queue name="DLQ"/>
+      <queue name="ExpiryQueue"/>
+   </jms>
+   <core xmlns="urn:activemq:core">
+      <paging-directory>./target/paging</paging-directory>
+
+      <bindings-directory>./target/bindings</bindings-directory>
+
+      <journal-directory>./target/journal</journal-directory>
+
+      <journal-min-files>2</journal-min-files>
+
+      <large-messages-directory>./target/large-messages</large-messages-directory>
+
+      <configuration-file-refresh-period>500</configuration-file-refresh-period>
+
+      <connectors>
+         <!-- Default Connector.  Returned to clients during broadcast and distributed around cluster.  See broadcast and discovery-groups -->
+         <connector name="activemq">tcp://${activemq.remoting.default.host:localhost}:${activemq.remoting.default.port:61616}</connector>
+      </connectors>
+
+      <acceptors>
+         <!-- Default ActiveMQ Artemis Acceptor.  Multi-protocol adapter.  Currently supports Core, OpenWire, Stomp and AMQP. -->
+         <acceptor name="activemq">tcp://${activemq.remoting.default.host:localhost}:${activemq.remoting.default.port:61616}</acceptor>
+
+         <!-- AMQP Acceptor.  Listens on default AMQP port for AMQP traffic.-->
+         <acceptor name="amqp">tcp://${activemq.remoting.amqp.host:localhost}:${activemq.remoting.amqp.port:5672}?protocols=AMQP</acceptor>
+
+         <!-- STOMP Acceptor. -->
+         <acceptor name="stomp">tcp://${activemq.remoting.stomp.host:localhost}:${activemq.remoting.stomp.port:61613}?protocols=STOMP</acceptor>
+
+         <!-- HornetQ Compatibility Acceptor.  Enables ActiveMQ Artemis Core and STOMP for legacy HornetQ clients. -->
+         <acceptor name="hornetq">tcp://${activemq.remoting.hornetq.host:localhost}:${activemq.remoting.hornetq.port:5445}?protocols=CORE,STOMP</acceptor>
+      </acceptors>
+
+      <security-settings>
+         <security-setting match="#">
+            <permission type="send" roles="guest"/>
+         </security-setting>
+      </security-settings>
+
+      <address-settings>
+         <!--default for catch all-->
+         <address-setting match="#">
+            <dead-letter-address>jms.queue.DLQ</dead-letter-address>
+            <expiry-address>jms.queue.ExpiryQueue</expiry-address>
+            <redelivery-delay>0</redelivery-delay>
+            <max-size-bytes>10485760</max-size-bytes>
+            <message-counter-history-day-limit>10</message-counter-history-day-limit>
+            <address-full-policy>BLOCK</address-full-policy>
+         </address-setting>
+      </address-settings>
+   </core>
+</configuration>

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/1ef9e74f/artemis-core-client/src/main/java/org/apache/activemq/artemis/api/config/ActiveMQDefaultConfiguration.java
----------------------------------------------------------------------
diff --git a/artemis-core-client/src/main/java/org/apache/activemq/artemis/api/config/ActiveMQDefaultConfiguration.java b/artemis-core-client/src/main/java/org/apache/activemq/artemis/api/config/ActiveMQDefaultConfiguration.java
index b95e515..aecf902 100644
--- a/artemis-core-client/src/main/java/org/apache/activemq/artemis/api/config/ActiveMQDefaultConfiguration.java
+++ b/artemis-core-client/src/main/java/org/apache/activemq/artemis/api/config/ActiveMQDefaultConfiguration.java
@@ -426,6 +426,9 @@ public final class ActiveMQDefaultConfiguration {
    // Default period to wait between connection TTL checks
    public static final long DEFAULT_CONNECTION_TTL_CHECK_INTERVAL = 2000;
 
+   // Default period to wait between configuration file checks
+   public static final long DEFAULT_CONFIGURATION_FILE_REFRESH_PERIOD = 5000;
+
    /**
     * If true then the ActiveMQ Artemis Server will make use of any Protocol Managers that are in available on the classpath. If false then only the core protocol will be available, unless in Embedded mode where users can inject their own Protocol Managers.
     */
@@ -1137,4 +1140,8 @@ public final class ActiveMQDefaultConfiguration {
    public static long getDefaultConnectionTtlCheckInterval() {
       return DEFAULT_CONNECTION_TTL_CHECK_INTERVAL;
    }
+
+   public static long getDefaultConfigurationFileRefreshPeriod() {
+      return DEFAULT_CONFIGURATION_FILE_REFRESH_PERIOD;
+   }
 }

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/1ef9e74f/artemis-jms-server/src/main/java/org/apache/activemq/artemis/jms/server/config/impl/FileJMSConfiguration.java
----------------------------------------------------------------------
diff --git a/artemis-jms-server/src/main/java/org/apache/activemq/artemis/jms/server/config/impl/FileJMSConfiguration.java b/artemis-jms-server/src/main/java/org/apache/activemq/artemis/jms/server/config/impl/FileJMSConfiguration.java
index 0a657eb..f17568d 100644
--- a/artemis-jms-server/src/main/java/org/apache/activemq/artemis/jms/server/config/impl/FileJMSConfiguration.java
+++ b/artemis-jms-server/src/main/java/org/apache/activemq/artemis/jms/server/config/impl/FileJMSConfiguration.java
@@ -33,6 +33,7 @@ import org.w3c.dom.Node;
 import org.w3c.dom.NodeList;
 
 import javax.management.MBeanServer;
+import java.net.URL;
 import java.util.ArrayList;
 import java.util.Map;
 
@@ -57,7 +58,7 @@ public class FileJMSConfiguration extends JMSConfigurationImpl implements Deploy
    private boolean parsed = false;
 
    @Override
-   public void parse(Element config) throws Exception {
+   public void parse(Element config, URL url) throws Exception {
       parseConfiguration(config);
       parsed = true;
    }

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/1ef9e74f/artemis-server/src/main/java/org/apache/activemq/artemis/core/config/Configuration.java
----------------------------------------------------------------------
diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/config/Configuration.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/config/Configuration.java
index 400709e..fc38155 100644
--- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/config/Configuration.java
+++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/config/Configuration.java
@@ -17,6 +17,7 @@
 package org.apache.activemq.artemis.core.config;
 
 import java.io.File;
+import java.net.URL;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -959,4 +960,12 @@ public interface Configuration {
 
    long getConnectionTtlCheckInterval();
 
+   URL getConfigurationUrl();
+
+   Configuration setConfigurationUrl(URL configurationUrl);
+
+   long getConfigurationFileRefreshPeriod();
+
+   Configuration setConfigurationFileRefreshPeriod(long configurationFileRefreshPeriod);
+
 }

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/1ef9e74f/artemis-server/src/main/java/org/apache/activemq/artemis/core/config/FileDeploymentManager.java
----------------------------------------------------------------------
diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/config/FileDeploymentManager.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/config/FileDeploymentManager.java
index abf0170..0f9794a 100644
--- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/config/FileDeploymentManager.java
+++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/config/FileDeploymentManager.java
@@ -83,7 +83,7 @@ public class FileDeploymentManager {
          if (root != null && children.getLength() > 0) {
             Node item = children.item(0);
             XMLUtil.validate(item, deployable.getSchema());
-            deployable.parse((Element) item);
+            deployable.parse((Element) item, url);
          }
       }
    }

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/1ef9e74f/artemis-server/src/main/java/org/apache/activemq/artemis/core/config/impl/ConfigurationImpl.java
----------------------------------------------------------------------
diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/config/impl/ConfigurationImpl.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/config/impl/ConfigurationImpl.java
index 8f1f6f5..216348c 100644
--- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/config/impl/ConfigurationImpl.java
+++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/config/impl/ConfigurationImpl.java
@@ -26,6 +26,7 @@ import java.io.Serializable;
 import java.io.StringWriter;
 import java.lang.reflect.Array;
 import java.net.URI;
+import java.net.URL;
 import java.security.AccessController;
 import java.security.PrivilegedExceptionAction;
 import java.util.ArrayList;
@@ -241,6 +242,10 @@ public class ConfigurationImpl implements Configuration, Serializable {
 
    private long connectionTtlCheckInterval = ActiveMQDefaultConfiguration.getDefaultConnectionTtlCheckInterval();
 
+   private URL configurationUrl;
+
+   private long configurationFileRefreshPeriod = ActiveMQDefaultConfiguration.getDefaultConfigurationFileRefreshPeriod();
+
    /**
     * Parent folder for all data folders.
     */
@@ -1759,6 +1764,28 @@ public class ConfigurationImpl implements Configuration, Serializable {
       return this;
    }
 
+   @Override
+   public URL getConfigurationUrl() {
+      return configurationUrl;
+   }
+
+   @Override
+   public ConfigurationImpl setConfigurationUrl(URL configurationUrl) {
+      this.configurationUrl = configurationUrl;
+      return this;
+   }
+
+   @Override
+   public long getConfigurationFileRefreshPeriod() {
+      return configurationFileRefreshPeriod;
+   }
+
+   @Override
+   public ConfigurationImpl setConfigurationFileRefreshPeriod(long configurationFileRefreshPeriod) {
+      this.configurationFileRefreshPeriod = configurationFileRefreshPeriod;
+      return this;
+   }
+
    /**
     * It will find the right location of a subFolder, related to artemisInstance
     */

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/1ef9e74f/artemis-server/src/main/java/org/apache/activemq/artemis/core/config/impl/FileConfiguration.java
----------------------------------------------------------------------
diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/config/impl/FileConfiguration.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/config/impl/FileConfiguration.java
index e0d9d44..b0c7440 100644
--- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/config/impl/FileConfiguration.java
+++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/config/impl/FileConfiguration.java
@@ -16,6 +16,7 @@
  */
 package org.apache.activemq.artemis.core.config.impl;
 
+import java.net.URL;
 import java.util.Map;
 
 import org.apache.activemq.artemis.core.deployers.Deployable;
@@ -44,7 +45,7 @@ public final class FileConfiguration extends ConfigurationImpl implements Deploy
    private boolean parsed = false;
 
    @Override
-   public void parse(Element config) throws Exception {
+   public void parse(Element config, URL url) throws Exception {
       FileConfigurationParser parser = new FileConfigurationParser();
 
       // https://jira.jboss.org/browse/HORNETQ-478 - We only want to validate AIO when
@@ -54,6 +55,8 @@ public final class FileConfiguration extends ConfigurationImpl implements Deploy
 
       parser.parseMainConfig(config, this);
 
+      setConfigurationUrl(url);
+
       parsed = true;
    }
 

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/1ef9e74f/artemis-server/src/main/java/org/apache/activemq/artemis/core/deployers/Deployable.java
----------------------------------------------------------------------
diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/deployers/Deployable.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/deployers/Deployable.java
index 7ab197e..20a0c2e 100644
--- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/deployers/Deployable.java
+++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/deployers/Deployable.java
@@ -21,6 +21,7 @@ import org.apache.activemq.artemis.spi.core.security.ActiveMQSecurityManager;
 import org.w3c.dom.Element;
 
 import javax.management.MBeanServer;
+import java.net.URL;
 import java.util.Map;
 
 /**
@@ -32,7 +33,7 @@ public interface Deployable {
    /*
    * parse the element from the xml configuration
    */
-   void parse(Element config) throws Exception;
+   void parse(Element config, URL url) throws Exception;
 
    /*
    * has this Deployable been parsed

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/1ef9e74f/artemis-server/src/main/java/org/apache/activemq/artemis/core/deployers/impl/FileConfigurationParser.java
----------------------------------------------------------------------
diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/deployers/impl/FileConfigurationParser.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/deployers/impl/FileConfigurationParser.java
index 5fdc9ca..c77157b 100644
--- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/deployers/impl/FileConfigurationParser.java
+++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/deployers/impl/FileConfigurationParser.java
@@ -280,6 +280,8 @@ public final class FileConfigurationParser extends XMLConfigurationUtil {
 
       config.setConnectionTtlCheckInterval(getLong(e, "connection-ttl-check-interval", config.getConnectionTtlCheckInterval(), Validators.GT_ZERO));
 
+      config.setConfigurationFileRefreshPeriod(getLong(e, "configuration-file-refresh-period", config.getConfigurationFileRefreshPeriod(), Validators.GT_ZERO));
+
       // parsing cluster password
       String passwordText = getString(e, "cluster-password", null, Validators.NO_CHECK);
 

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/1ef9e74f/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/ActiveMQServerLogger.java
----------------------------------------------------------------------
diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/ActiveMQServerLogger.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/ActiveMQServerLogger.java
index 51e6b42..342a592 100644
--- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/ActiveMQServerLogger.java
+++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/ActiveMQServerLogger.java
@@ -1498,4 +1498,8 @@ public interface ActiveMQServerLogger extends BasicLogger {
    @LogMessage(level = Logger.Level.ERROR)
    @Message(id = 224068, value = "Unable to stop component: {0}", format = Message.Format.MESSAGE_FORMAT)
    void errorStoppingComponent(@Cause Throwable t, String componentClassName);
+
+   @LogMessage(level = Logger.Level.ERROR)
+   @Message(id = 224069, value = "Change detected in broker configuration file, but reload failed", format = Message.Format.MESSAGE_FORMAT)
+   void configurationReloadFailed(@Cause Throwable t);
 }

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/1ef9e74f/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/impl/ActiveMQServerImpl.java
----------------------------------------------------------------------
diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/impl/ActiveMQServerImpl.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/impl/ActiveMQServerImpl.java
index 9067f86..2a8bacf 100644
--- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/impl/ActiveMQServerImpl.java
+++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/impl/ActiveMQServerImpl.java
@@ -23,6 +23,7 @@ import java.io.IOException;
 import java.io.PrintWriter;
 import java.io.StringWriter;
 import java.lang.management.ManagementFactory;
+import java.net.URL;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
 import java.util.ArrayList;
@@ -55,6 +56,7 @@ import org.apache.activemq.artemis.core.config.CoreQueueConfiguration;
 import org.apache.activemq.artemis.core.config.DivertConfiguration;
 import org.apache.activemq.artemis.core.config.StoreConfiguration;
 import org.apache.activemq.artemis.core.config.impl.ConfigurationImpl;
+import org.apache.activemq.artemis.core.deployers.impl.FileConfigurationParser;
 import org.apache.activemq.artemis.core.filter.Filter;
 import org.apache.activemq.artemis.core.filter.impl.FilterImpl;
 import org.apache.activemq.artemis.core.io.IOCriticalErrorListener;
@@ -450,6 +452,10 @@ public class ActiveMQServerImpl implements ActiveMQServer {
          // start connector service
          connectorsService = new ConnectorsService(configuration, storageManager, scheduledPool, postOffice, serviceRegistry);
          connectorsService.start();
+
+         if (configuration.getConfigurationUrl() != null && getScheduledPool() != null) {
+            getScheduledPool().scheduleWithFixedDelay(new ConfigurationFileReloader(this), configuration.getConfigurationFileRefreshPeriod(), configuration.getConfigurationFileRefreshPeriod(), TimeUnit.MILLISECONDS);
+         }
       }
       finally {
          // this avoids embedded applications using dirty contexts from startup
@@ -2351,4 +2357,38 @@ public class ActiveMQServerImpl implements ActiveMQServer {
       }
 
    }
+
+   private final class ConfigurationFileReloader extends Thread {
+      long lastModified;
+      boolean first = true;
+      ActiveMQServer server;
+
+      ConfigurationFileReloader(ActiveMQServer server) {
+         this.server = server;
+      }
+
+      public void run() {
+         try {
+            URL url = server.getConfiguration().getConfigurationUrl();
+            long currentLastModified = new File(url.toURI()).lastModified();
+            if (first) {
+               first = false;
+               lastModified = currentLastModified;
+               return;
+            }
+            if (currentLastModified > lastModified) {
+               if (ActiveMQServerLogger.LOGGER.isDebugEnabled()) {
+                  ActiveMQServerLogger.LOGGER.debug("Configuration file change detected. Reloading...");
+               }
+               Configuration config = new FileConfigurationParser().parseMainConfig(url.openStream());
+               securityRepository.swap(config.getSecurityRoles().entrySet());
+
+               lastModified = currentLastModified;
+            }
+         }
+         catch (Exception e) {
+            ActiveMQServerLogger.LOGGER.configurationReloadFailed(e);
+         }
+      }
+   }
 }

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/1ef9e74f/artemis-server/src/main/java/org/apache/activemq/artemis/core/settings/HierarchicalRepository.java
----------------------------------------------------------------------
diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/settings/HierarchicalRepository.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/settings/HierarchicalRepository.java
index 6e2ba77..1e1c8c4 100644
--- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/settings/HierarchicalRepository.java
+++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/settings/HierarchicalRepository.java
@@ -17,6 +17,8 @@
 package org.apache.activemq.artemis.core.settings;
 
 import java.util.List;
+import java.util.Map;
+import java.util.Set;
 
 /**
  * allows objects to be mapped against a regex pattern and held in order in a list
@@ -85,6 +87,8 @@ public interface HierarchicalRepository<T> {
     */
    void clear();
 
+   void swap(Set<Map.Entry<String, T>> entries);
+
    /**
     * Removes all listeners.
     */

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/1ef9e74f/artemis-server/src/main/java/org/apache/activemq/artemis/core/settings/impl/HierarchicalObjectRepository.java
----------------------------------------------------------------------
diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/settings/impl/HierarchicalObjectRepository.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/settings/impl/HierarchicalObjectRepository.java
index 5ec898e..6e032d1 100644
--- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/settings/impl/HierarchicalObjectRepository.java
+++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/settings/impl/HierarchicalObjectRepository.java
@@ -147,6 +147,10 @@ public class HierarchicalObjectRepository<T> implements HierarchicalRepository<T
     */
    @Override
    public void addMatch(final String match, final T value, final boolean immutableMatch) {
+      addMatch(match, value, immutableMatch, true);
+   }
+
+   private void addMatch(final String match, final T value, final boolean immutableMatch, boolean notifyListeners) {
       lock.writeLock().lock();
       try {
          clearCache();
@@ -164,7 +168,9 @@ public class HierarchicalObjectRepository<T> implements HierarchicalRepository<T
       }
 
       // Calling the onChange outside of the wrieLock as some listeners may be doing reads on the matches
-      onChange();
+      if (notifyListeners) {
+         onChange();
+      }
    }
 
    @Override
@@ -318,6 +324,24 @@ public class HierarchicalObjectRepository<T> implements HierarchicalRepository<T
    }
 
    @Override
+   public void swap(Set<Map.Entry<String, T>> entries) {
+      lock.writeLock().lock();
+      try {
+         clearCache();
+         immutables.clear();
+         matches.clear();
+         for (Map.Entry<String, T> entry : entries) {
+            addMatch(entry.getKey(), entry.getValue(), true, false);
+         }
+      }
+      finally {
+         lock.writeLock().unlock();
+      }
+
+      onChange();
+   }
+
+   @Override
    public void clearListeners() {
       listeners.clear();
    }

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/1ef9e74f/artemis-server/src/main/resources/schema/artemis-configuration.xsd
----------------------------------------------------------------------
diff --git a/artemis-server/src/main/resources/schema/artemis-configuration.xsd b/artemis-server/src/main/resources/schema/artemis-configuration.xsd
index 815ef7c..56c5e26 100644
--- a/artemis-server/src/main/resources/schema/artemis-configuration.xsd
+++ b/artemis-server/src/main/resources/schema/artemis-configuration.xsd
@@ -246,6 +246,14 @@
             </xsd:annotation>
          </xsd:element>
 
+         <xsd:element name="configuration-file-refresh-period" type="xsd:long" default="5000" maxOccurs="1" minOccurs="0">
+            <xsd:annotation>
+               <xsd:documentation>
+                  how often (in ms) to check the configuration file for modifications
+               </xsd:documentation>
+            </xsd:annotation>
+         </xsd:element>
+
          <xsd:element name="async-connection-execution-enabled" type="xsd:boolean" default="true" maxOccurs="1"
                       minOccurs="0">
             <xsd:annotation>

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/1ef9e74f/artemis-server/src/test/java/org/apache/activemq/artemis/core/config/impl/FileConfigurationTest.java
----------------------------------------------------------------------
diff --git a/artemis-server/src/test/java/org/apache/activemq/artemis/core/config/impl/FileConfigurationTest.java b/artemis-server/src/test/java/org/apache/activemq/artemis/core/config/impl/FileConfigurationTest.java
index 27c997f..ba2cb7f 100644
--- a/artemis-server/src/test/java/org/apache/activemq/artemis/core/config/impl/FileConfigurationTest.java
+++ b/artemis-server/src/test/java/org/apache/activemq/artemis/core/config/impl/FileConfigurationTest.java
@@ -104,6 +104,7 @@ public class FileConfigurationTest extends ConfigurationImplTest {
       Assert.assertEquals(12345, conf.getGracefulShutdownTimeout());
       Assert.assertEquals(true, conf.isPopulateValidatedUser());
       Assert.assertEquals(98765, conf.getConnectionTtlCheckInterval());
+      Assert.assertEquals(1234567, conf.getConfigurationFileRefreshPeriod());
 
       Assert.assertEquals("largemessagesdir", conf.getLargeMessagesDirectory());
       Assert.assertEquals(95, conf.getMemoryWarningThreshold());

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/1ef9e74f/artemis-server/src/test/resources/ConfigurationTest-full-config.xml
----------------------------------------------------------------------
diff --git a/artemis-server/src/test/resources/ConfigurationTest-full-config.xml b/artemis-server/src/test/resources/ConfigurationTest-full-config.xml
index 3639da4..78d55c2 100644
--- a/artemis-server/src/test/resources/ConfigurationTest-full-config.xml
+++ b/artemis-server/src/test/resources/ConfigurationTest-full-config.xml
@@ -52,6 +52,7 @@
       <persist-id-cache>true</persist-id-cache>
       <populate-validated-user>true</populate-validated-user>
       <connection-ttl-check-interval>98765</connection-ttl-check-interval>
+      <configuration-file-refresh-period>1234567</configuration-file-refresh-period>
       <remoting-incoming-interceptors>
          <class-name>org.apache.activemq.artemis.tests.unit.core.config.impl.TestInterceptor1</class-name>
          <class-name>org.apache.activemq.artemis.tests.unit.core.config.impl.TestInterceptor2</class-name>