ARTEMIS-1463 - add role based authentication to the JMX objects
This is done by creating a guard and using JAAS to check for access to mbean objects and their methods. NB this also implements https://issues.apache.org/jira/browse/ARTEMIS-534 https://issues.apache.org/jira/browse/ARTEMIS-1463
This commit is contained in:
parent
d0f3f67193
commit
62a2b14dd0
|
@ -27,9 +27,11 @@ import io.airlift.airline.model.CommandGroupMetadata;
|
||||||
import io.airlift.airline.model.CommandMetadata;
|
import io.airlift.airline.model.CommandMetadata;
|
||||||
import io.airlift.airline.model.GlobalMetadata;
|
import io.airlift.airline.model.GlobalMetadata;
|
||||||
import org.apache.activemq.artemis.cli.factory.BrokerFactory;
|
import org.apache.activemq.artemis.cli.factory.BrokerFactory;
|
||||||
|
import org.apache.activemq.artemis.cli.factory.jmx.ManagementFactory;
|
||||||
import org.apache.activemq.artemis.core.config.FileDeploymentManager;
|
import org.apache.activemq.artemis.core.config.FileDeploymentManager;
|
||||||
import org.apache.activemq.artemis.core.config.impl.FileConfiguration;
|
import org.apache.activemq.artemis.core.config.impl.FileConfiguration;
|
||||||
import org.apache.activemq.artemis.dto.BrokerDTO;
|
import org.apache.activemq.artemis.dto.BrokerDTO;
|
||||||
|
import org.apache.activemq.artemis.dto.ManagementContextDTO;
|
||||||
import org.apache.activemq.artemis.integration.bootstrap.ActiveMQBootstrapLogger;
|
import org.apache.activemq.artemis.integration.bootstrap.ActiveMQBootstrapLogger;
|
||||||
import org.apache.activemq.artemis.jms.server.config.impl.FileJMSConfiguration;
|
import org.apache.activemq.artemis.jms.server.config.impl.FileJMSConfiguration;
|
||||||
|
|
||||||
|
@ -116,6 +118,11 @@ public abstract class Configurable extends ActionAbstract {
|
||||||
return brokerDTO;
|
return brokerDTO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected ManagementContextDTO getManagementDTO() throws Exception {
|
||||||
|
String configuration = getManagementConfiguration();
|
||||||
|
return ManagementFactory.createJmxAclConfiguration(configuration, getBrokerHome(), getBrokerInstance(), getBrokerURIInstance());
|
||||||
|
}
|
||||||
|
|
||||||
protected String getConfiguration() {
|
protected String getConfiguration() {
|
||||||
if (configuration == null) {
|
if (configuration == null) {
|
||||||
File xmlFile = new File(new File(new File(getBrokerInstance()), "etc"), "bootstrap.xml");
|
File xmlFile = new File(new File(new File(getBrokerInstance()), "etc"), "bootstrap.xml");
|
||||||
|
@ -130,4 +137,14 @@ public abstract class Configurable extends ActionAbstract {
|
||||||
return configuration;
|
return configuration;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected String getManagementConfiguration() {
|
||||||
|
File xmlFile = new File(new File(new File(getBrokerInstance()), "etc"), "management.xml");
|
||||||
|
String configuration = "xml:" + xmlFile.toURI().toString().substring("file:".length());
|
||||||
|
|
||||||
|
// To support Windows paths as explained above.
|
||||||
|
configuration = configuration.replace("\\", "/");
|
||||||
|
|
||||||
|
return configuration;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -82,6 +82,7 @@ public class Create extends InputAbstract {
|
||||||
public static final String ETC_ARTEMIS_PROFILE = "etc/artemis.profile";
|
public static final String ETC_ARTEMIS_PROFILE = "etc/artemis.profile";
|
||||||
public static final String ETC_LOGGING_PROPERTIES = "etc/logging.properties";
|
public static final String ETC_LOGGING_PROPERTIES = "etc/logging.properties";
|
||||||
public static final String ETC_BOOTSTRAP_XML = "etc/bootstrap.xml";
|
public static final String ETC_BOOTSTRAP_XML = "etc/bootstrap.xml";
|
||||||
|
public static final String ETC_MANAGEMENT_XML = "etc/management.xml";
|
||||||
public static final String ETC_BROKER_XML = "etc/broker.xml";
|
public static final String ETC_BROKER_XML = "etc/broker.xml";
|
||||||
|
|
||||||
public static final String ETC_ARTEMIS_ROLES_PROPERTIES = "etc/artemis-roles.properties";
|
public static final String ETC_ARTEMIS_ROLES_PROPERTIES = "etc/artemis-roles.properties";
|
||||||
|
@ -689,6 +690,7 @@ public class Create extends InputAbstract {
|
||||||
// we want this variable to remain unchanged so that it will use the value set in the profile
|
// we want this variable to remain unchanged so that it will use the value set in the profile
|
||||||
filters.remove("${artemis.instance}");
|
filters.remove("${artemis.instance}");
|
||||||
write(ETC_BOOTSTRAP_XML, filters, false);
|
write(ETC_BOOTSTRAP_XML, filters, false);
|
||||||
|
write(ETC_MANAGEMENT_XML, filters, false);
|
||||||
write(ETC_JOLOKIA_ACCESS_XML, filters, false);
|
write(ETC_JOLOKIA_ACCESS_XML, filters, false);
|
||||||
|
|
||||||
context.out.println("");
|
context.out.println("");
|
||||||
|
|
|
@ -25,10 +25,13 @@ import io.airlift.airline.Option;
|
||||||
import org.apache.activemq.artemis.cli.Artemis;
|
import org.apache.activemq.artemis.cli.Artemis;
|
||||||
import org.apache.activemq.artemis.cli.commands.tools.LockAbstract;
|
import org.apache.activemq.artemis.cli.commands.tools.LockAbstract;
|
||||||
import org.apache.activemq.artemis.cli.factory.BrokerFactory;
|
import org.apache.activemq.artemis.cli.factory.BrokerFactory;
|
||||||
|
import org.apache.activemq.artemis.cli.factory.jmx.ManagementFactory;
|
||||||
import org.apache.activemq.artemis.cli.factory.security.SecurityManagerFactory;
|
import org.apache.activemq.artemis.cli.factory.security.SecurityManagerFactory;
|
||||||
import org.apache.activemq.artemis.components.ExternalComponent;
|
import org.apache.activemq.artemis.components.ExternalComponent;
|
||||||
|
import org.apache.activemq.artemis.core.server.management.ManagementContext;
|
||||||
import org.apache.activemq.artemis.dto.BrokerDTO;
|
import org.apache.activemq.artemis.dto.BrokerDTO;
|
||||||
import org.apache.activemq.artemis.dto.ComponentDTO;
|
import org.apache.activemq.artemis.dto.ComponentDTO;
|
||||||
|
import org.apache.activemq.artemis.dto.ManagementContextDTO;
|
||||||
import org.apache.activemq.artemis.integration.Broker;
|
import org.apache.activemq.artemis.integration.Broker;
|
||||||
import org.apache.activemq.artemis.integration.bootstrap.ActiveMQBootstrapLogger;
|
import org.apache.activemq.artemis.integration.bootstrap.ActiveMQBootstrapLogger;
|
||||||
import org.apache.activemq.artemis.spi.core.security.ActiveMQSecurityManager;
|
import org.apache.activemq.artemis.spi.core.security.ActiveMQSecurityManager;
|
||||||
|
@ -44,6 +47,8 @@ public class Run extends LockAbstract {
|
||||||
|
|
||||||
public static final ReusableLatch latchRunning = new ReusableLatch(0);
|
public static final ReusableLatch latchRunning = new ReusableLatch(0);
|
||||||
|
|
||||||
|
private ManagementContext managementContext;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This will disable the System.exit at the end of the server.stop, as that means there are other things
|
* This will disable the System.exit at the end of the server.stop, as that means there are other things
|
||||||
* happening on the same VM.
|
* happening on the same VM.
|
||||||
|
@ -60,6 +65,9 @@ public class Run extends LockAbstract {
|
||||||
public Object execute(ActionContext context) throws Exception {
|
public Object execute(ActionContext context) throws Exception {
|
||||||
super.execute(context);
|
super.execute(context);
|
||||||
|
|
||||||
|
ManagementContextDTO managementDTO = getManagementDTO();
|
||||||
|
managementContext = ManagementFactory.create(managementDTO);
|
||||||
|
|
||||||
Artemis.printBanner();
|
Artemis.printBanner();
|
||||||
|
|
||||||
BrokerDTO broker = getBrokerDTO();
|
BrokerDTO broker = getBrokerDTO();
|
||||||
|
@ -70,6 +78,7 @@ public class Run extends LockAbstract {
|
||||||
|
|
||||||
server = BrokerFactory.createServer(broker.server, security);
|
server = BrokerFactory.createServer(broker.server, security);
|
||||||
|
|
||||||
|
managementContext.start();
|
||||||
server.start();
|
server.start();
|
||||||
|
|
||||||
if (broker.web != null) {
|
if (broker.web != null) {
|
||||||
|
@ -121,11 +130,7 @@ public class Run extends LockAbstract {
|
||||||
}
|
}
|
||||||
if (file.exists()) {
|
if (file.exists()) {
|
||||||
try {
|
try {
|
||||||
try {
|
stop();
|
||||||
server.stop(true);
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
timer.cancel();
|
timer.cancel();
|
||||||
} finally {
|
} finally {
|
||||||
System.out.println("Server stopped!");
|
System.out.println("Server stopped!");
|
||||||
|
@ -142,13 +147,20 @@ public class Run extends LockAbstract {
|
||||||
Runtime.getRuntime().addShutdownHook(new Thread("shutdown-hook") {
|
Runtime.getRuntime().addShutdownHook(new Thread("shutdown-hook") {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
Run.this.stop();
|
||||||
server.stop(true);
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void stop() {
|
||||||
|
try {
|
||||||
|
server.stop(true);
|
||||||
|
if (managementContext != null) {
|
||||||
|
managementContext.stop();
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
* <p>
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* <p>
|
||||||
|
* 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.artemis.cli.factory.jmx;
|
||||||
|
|
||||||
|
import org.apache.activemq.artemis.dto.ManagementContextDTO;
|
||||||
|
|
||||||
|
import java.net.URI;
|
||||||
|
|
||||||
|
public interface JmxAclHandler {
|
||||||
|
ManagementContextDTO createJmxAcl(URI configURI, String artemisHome, String artemisInstance, URI artemisURIInstance) throws Exception;
|
||||||
|
}
|
|
@ -0,0 +1,134 @@
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
* <p>
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* <p>
|
||||||
|
* 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.artemis.cli.factory.jmx;
|
||||||
|
|
||||||
|
|
||||||
|
import org.apache.activemq.artemis.cli.ConfigurationException;
|
||||||
|
import org.apache.activemq.artemis.core.config.JMXConnectorConfiguration;
|
||||||
|
import org.apache.activemq.artemis.core.server.management.ManagementContext;
|
||||||
|
import org.apache.activemq.artemis.dto.AccessDTO;
|
||||||
|
import org.apache.activemq.artemis.dto.AuthorisationDTO;
|
||||||
|
import org.apache.activemq.artemis.dto.EntryDTO;
|
||||||
|
import org.apache.activemq.artemis.dto.JMXConnectorDTO;
|
||||||
|
import org.apache.activemq.artemis.dto.ManagementContextDTO;
|
||||||
|
import org.apache.activemq.artemis.dto.MatchDTO;
|
||||||
|
import org.apache.activemq.artemis.core.server.management.JMXAccessControlList;
|
||||||
|
import org.apache.activemq.artemis.utils.FactoryFinder;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class ManagementFactory {
|
||||||
|
|
||||||
|
private static ManagementContextDTO createJmxAclConfiguration(URI configURI,
|
||||||
|
String artemisHome,
|
||||||
|
String artemisInstance,
|
||||||
|
URI artemisURIInstance) throws Exception {
|
||||||
|
if (configURI.getScheme() == null) {
|
||||||
|
throw new ConfigurationException("Invalid configuration URI, no scheme specified: " + configURI);
|
||||||
|
}
|
||||||
|
|
||||||
|
JmxAclHandler factory = null;
|
||||||
|
try {
|
||||||
|
FactoryFinder finder = new FactoryFinder("META-INF/services/org/apache/activemq/artemis/broker/jmx/");
|
||||||
|
factory = (JmxAclHandler) finder.newInstance(configURI.getScheme());
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
throw new ConfigurationException("Invalid configuration URI, can't find configuration scheme: " + configURI.getScheme());
|
||||||
|
}
|
||||||
|
return factory.createJmxAcl(configURI, artemisHome, artemisInstance, artemisURIInstance);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ManagementContextDTO createJmxAclConfiguration(String configuration,
|
||||||
|
String artemisHome,
|
||||||
|
String artemisInstance,
|
||||||
|
URI artemisURIInstance) throws Exception {
|
||||||
|
return createJmxAclConfiguration(new URI(configuration), artemisHome, artemisInstance, artemisURIInstance);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ManagementContext create(ManagementContextDTO config) {
|
||||||
|
ManagementContext context = new ManagementContext();
|
||||||
|
|
||||||
|
if (config.getAuthorisation() != null) {
|
||||||
|
AuthorisationDTO authorisation = config.getAuthorisation();
|
||||||
|
JMXAccessControlList accessControlList = new JMXAccessControlList();
|
||||||
|
List<EntryDTO> entries = authorisation.getWhiteList().getEntries();
|
||||||
|
for (EntryDTO entry : entries) {
|
||||||
|
accessControlList.addToWhiteList(entry.domain, entry.key);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<AccessDTO> accessList = authorisation.getDefaultAccess().getAccess();
|
||||||
|
for (AccessDTO access : accessList) {
|
||||||
|
String[] split = access.roles.split(",");
|
||||||
|
accessControlList.addToDefaultAccess(access.method, split);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<MatchDTO> matches = authorisation.getRoleAccess().getMatch();
|
||||||
|
for (MatchDTO match : matches) {
|
||||||
|
List<AccessDTO> accesses = match.getAccess();
|
||||||
|
for (AccessDTO access : accesses) {
|
||||||
|
String[] split = access.roles.split(",");
|
||||||
|
accessControlList.addToRoleAccess(match.getDomain(), match.getKey(), access.method, split);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
context.setAccessControlList(accessControlList);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config.getJmxConnector() != null) {
|
||||||
|
JMXConnectorDTO jmxConnector = config.getJmxConnector();
|
||||||
|
JMXConnectorConfiguration jmxConnectorConfiguration = new JMXConnectorConfiguration();
|
||||||
|
|
||||||
|
jmxConnectorConfiguration.setConnectorPort(jmxConnector.getConnectorPort());
|
||||||
|
if (jmxConnector.getConnectorHost() != null) {
|
||||||
|
jmxConnectorConfiguration.setConnectorHost(jmxConnector.getConnectorHost());
|
||||||
|
}
|
||||||
|
if (jmxConnector.getJmxRealm() != null) {
|
||||||
|
jmxConnectorConfiguration.setJmxRealm(jmxConnector.getJmxRealm());
|
||||||
|
}
|
||||||
|
if (jmxConnector.getAuthenticatorType() != null) {
|
||||||
|
jmxConnectorConfiguration.setAuthenticatorType(jmxConnector.getAuthenticatorType());
|
||||||
|
}
|
||||||
|
if (jmxConnector.getKeyStorePath() != null) {
|
||||||
|
jmxConnectorConfiguration.setKeyStorePath(jmxConnector.getKeyStorePath());
|
||||||
|
}
|
||||||
|
if (jmxConnector.getKeyStoreProvider() != null) {
|
||||||
|
jmxConnectorConfiguration.setKeyStoreProvider(jmxConnector.getKeyStoreProvider());
|
||||||
|
}
|
||||||
|
if (jmxConnector.getKeyStorePassword() != null) {
|
||||||
|
jmxConnectorConfiguration.setKeyStorePassword(jmxConnector.getKeyStorePassword());
|
||||||
|
}
|
||||||
|
if (jmxConnector.getTrustStorePath() != null) {
|
||||||
|
jmxConnectorConfiguration.setTrustStorePath(jmxConnector.getTrustStorePath());
|
||||||
|
}
|
||||||
|
if (jmxConnector.getTrustStoreProvider() != null) {
|
||||||
|
jmxConnectorConfiguration.setTrustStoreProvider(jmxConnector.getTrustStoreProvider());
|
||||||
|
}
|
||||||
|
if (jmxConnector.getTrustStorePassword() != null) {
|
||||||
|
jmxConnectorConfiguration.setTrustStorePassword(jmxConnector.getTrustStorePassword());
|
||||||
|
}
|
||||||
|
if (jmxConnector.getObjectName() != null) {
|
||||||
|
jmxConnectorConfiguration.setObjectName(jmxConnector.getObjectName());
|
||||||
|
}
|
||||||
|
if (jmxConnector.isSecured() != null) {
|
||||||
|
jmxConnectorConfiguration.setSecured(jmxConnector.isSecured());
|
||||||
|
}
|
||||||
|
context.setJmxConnectorConfiguration(jmxConnectorConfiguration);
|
||||||
|
}
|
||||||
|
|
||||||
|
return context;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
* <p>
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* <p>
|
||||||
|
* 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.artemis.cli.factory.jmx;
|
||||||
|
|
||||||
|
|
||||||
|
import org.apache.activemq.artemis.cli.ConfigurationException;
|
||||||
|
import org.apache.activemq.artemis.dto.ManagementContextDTO;
|
||||||
|
import org.apache.activemq.artemis.dto.XmlUtil;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.net.URI;
|
||||||
|
|
||||||
|
public class XmlJmxAclHandler implements JmxAclHandler {
|
||||||
|
@Override
|
||||||
|
public ManagementContextDTO createJmxAcl(URI configURI, String artemisHome, String artemisInstance, URI artemisURIInstance) throws Exception {
|
||||||
|
File file = new File(configURI.getSchemeSpecificPart());
|
||||||
|
if (!file.exists()) {
|
||||||
|
throw new ConfigurationException("Invalid configuration URI, can't find file: " + file.getName());
|
||||||
|
}
|
||||||
|
return XmlUtil.decode(ManagementContextDTO.class, file, artemisHome, artemisInstance, artemisURIInstance);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
## ---------------------------------------------------------------------------
|
||||||
|
## 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.
|
||||||
|
## ---------------------------------------------------------------------------
|
||||||
|
class=org.apache.activemq.artemis.cli.factory.jmx.XmlJmxAclHandler
|
|
@ -0,0 +1,49 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||||
|
<!--
|
||||||
|
~ 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.
|
||||||
|
-->
|
||||||
|
<management-context xmlns="http://activemq.org/schema">
|
||||||
|
<!--<connector connector-port="1099"/>-->
|
||||||
|
<authorisation>
|
||||||
|
<whitelist>
|
||||||
|
<entry domain="hawtio"/>
|
||||||
|
</whitelist>
|
||||||
|
<default-access>
|
||||||
|
<access method="list*" roles="view,update,amq"/>
|
||||||
|
<access method="get*" roles="view,update,amq"/>
|
||||||
|
<access method="is*" roles="view,update,amq"/>
|
||||||
|
<access method="set*" roles="update,amq"/>
|
||||||
|
<access method="*" roles="amq"/>
|
||||||
|
</default-access>
|
||||||
|
<role-access>
|
||||||
|
<match domain="org.apache.activemq.apache">
|
||||||
|
<access method="list*" roles="view,update,amq"/>
|
||||||
|
<access method="get*" roles="view,update,amq"/>
|
||||||
|
<access method="is*" roles="view,update,amq"/>
|
||||||
|
<access method="set*" roles="update,amq"/>
|
||||||
|
<access method="*" roles="amq"/>
|
||||||
|
</match>
|
||||||
|
<!--example of how to configure a specific object-->
|
||||||
|
<!--<match domain="org.apache.activemq.apache" key="subcomponent=queues">
|
||||||
|
<access method="list*" roles="view,update,amq"/>
|
||||||
|
<access method="get*" roles="view,update,amq"/>
|
||||||
|
<access method="is*" roles="view,update,amq"/>
|
||||||
|
<access method="set*" roles="update,amq"/>
|
||||||
|
<access method="*" roles="amq"/>
|
||||||
|
</match>-->
|
||||||
|
</role-access>
|
||||||
|
</authorisation>
|
||||||
|
</management-context>
|
|
@ -39,6 +39,7 @@ public class StreamClassPathTest {
|
||||||
openStream(Create.ETC_ARTEMIS_PROFILE);
|
openStream(Create.ETC_ARTEMIS_PROFILE);
|
||||||
openStream(Create.ETC_LOGGING_PROPERTIES);
|
openStream(Create.ETC_LOGGING_PROPERTIES);
|
||||||
openStream(Create.ETC_BOOTSTRAP_XML);
|
openStream(Create.ETC_BOOTSTRAP_XML);
|
||||||
|
openStream(Create.ETC_MANAGEMENT_XML);
|
||||||
openStream(Create.ETC_BROKER_XML);
|
openStream(Create.ETC_BROKER_XML);
|
||||||
openStream(Create.ETC_ARTEMIS_ROLES_PROPERTIES);
|
openStream(Create.ETC_ARTEMIS_ROLES_PROPERTIES);
|
||||||
openStream(Create.ETC_ARTEMIS_USERS_PROPERTIES);
|
openStream(Create.ETC_ARTEMIS_USERS_PROPERTIES);
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
* <p>
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* <p>
|
||||||
|
* 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.artemis.dto;
|
||||||
|
|
||||||
|
|
||||||
|
import javax.xml.bind.annotation.XmlAccessType;
|
||||||
|
import javax.xml.bind.annotation.XmlAccessorType;
|
||||||
|
import javax.xml.bind.annotation.XmlAttribute;
|
||||||
|
import javax.xml.bind.annotation.XmlRootElement;
|
||||||
|
|
||||||
|
@XmlRootElement(name = "access")
|
||||||
|
@XmlAccessorType(XmlAccessType.FIELD)
|
||||||
|
public class AccessDTO {
|
||||||
|
|
||||||
|
@XmlAttribute
|
||||||
|
public String method;
|
||||||
|
|
||||||
|
@XmlAttribute
|
||||||
|
public String roles;
|
||||||
|
}
|
|
@ -0,0 +1,49 @@
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
* <p>
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* <p>
|
||||||
|
* 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.artemis.dto;
|
||||||
|
|
||||||
|
|
||||||
|
import javax.xml.bind.annotation.XmlAccessType;
|
||||||
|
import javax.xml.bind.annotation.XmlAccessorType;
|
||||||
|
import javax.xml.bind.annotation.XmlElementRef;
|
||||||
|
import javax.xml.bind.annotation.XmlRootElement;
|
||||||
|
|
||||||
|
@XmlRootElement(name = "authorisation")
|
||||||
|
@XmlAccessorType(XmlAccessType.FIELD)
|
||||||
|
public class AuthorisationDTO {
|
||||||
|
|
||||||
|
@XmlElementRef
|
||||||
|
WhiteListDTO whitelist;
|
||||||
|
|
||||||
|
@XmlElementRef
|
||||||
|
DefaultAccessDTO defaultAccess;
|
||||||
|
|
||||||
|
@XmlElementRef
|
||||||
|
RoleAccessDTO roleAccess;
|
||||||
|
|
||||||
|
public WhiteListDTO getWhiteList() {
|
||||||
|
return whitelist;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DefaultAccessDTO getDefaultAccess() {
|
||||||
|
return defaultAccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RoleAccessDTO getRoleAccess() {
|
||||||
|
return roleAccess;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
* <p>
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* <p>
|
||||||
|
* 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.artemis.dto;
|
||||||
|
|
||||||
|
|
||||||
|
import javax.xml.bind.annotation.XmlAccessType;
|
||||||
|
import javax.xml.bind.annotation.XmlAccessorType;
|
||||||
|
import javax.xml.bind.annotation.XmlElementRef;
|
||||||
|
import javax.xml.bind.annotation.XmlRootElement;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@XmlRootElement(name = "default-access")
|
||||||
|
@XmlAccessorType(XmlAccessType.FIELD)
|
||||||
|
public class DefaultAccessDTO {
|
||||||
|
|
||||||
|
@XmlElementRef
|
||||||
|
List<AccessDTO> access;
|
||||||
|
|
||||||
|
public List<AccessDTO> getAccess() {
|
||||||
|
return access;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
* <p>
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* <p>
|
||||||
|
* 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.artemis.dto;
|
||||||
|
|
||||||
|
|
||||||
|
import javax.xml.bind.annotation.XmlAccessType;
|
||||||
|
import javax.xml.bind.annotation.XmlAccessorType;
|
||||||
|
import javax.xml.bind.annotation.XmlAttribute;
|
||||||
|
import javax.xml.bind.annotation.XmlRootElement;
|
||||||
|
|
||||||
|
@XmlRootElement(name = "entry")
|
||||||
|
@XmlAccessorType(XmlAccessType.FIELD)
|
||||||
|
public class EntryDTO {
|
||||||
|
|
||||||
|
@XmlAttribute
|
||||||
|
public String domain;
|
||||||
|
|
||||||
|
@XmlAttribute
|
||||||
|
public String key;
|
||||||
|
}
|
|
@ -0,0 +1,112 @@
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
* <p>
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* <p>
|
||||||
|
* 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.artemis.dto;
|
||||||
|
|
||||||
|
|
||||||
|
import javax.xml.bind.annotation.XmlAccessType;
|
||||||
|
import javax.xml.bind.annotation.XmlAccessorType;
|
||||||
|
import javax.xml.bind.annotation.XmlAttribute;
|
||||||
|
import javax.xml.bind.annotation.XmlRootElement;
|
||||||
|
|
||||||
|
@XmlRootElement(name = "connector")
|
||||||
|
@XmlAccessorType(XmlAccessType.FIELD)
|
||||||
|
public class JMXConnectorDTO {
|
||||||
|
|
||||||
|
@XmlAttribute (name = "connector-host")
|
||||||
|
String connectorHost;
|
||||||
|
|
||||||
|
@XmlAttribute (name = "connector-port", required = true)
|
||||||
|
Integer connectorPort;
|
||||||
|
|
||||||
|
@XmlAttribute (name = "jmx-realm")
|
||||||
|
String jmxRealm;
|
||||||
|
|
||||||
|
@XmlAttribute (name = "object-name")
|
||||||
|
String objectName;
|
||||||
|
|
||||||
|
@XmlAttribute (name = "authenticator-type")
|
||||||
|
String authenticatorType;
|
||||||
|
|
||||||
|
@XmlAttribute (name = "secured")
|
||||||
|
Boolean secured;
|
||||||
|
|
||||||
|
@XmlAttribute (name = "key-store-provider")
|
||||||
|
String keyStoreProvider;
|
||||||
|
|
||||||
|
@XmlAttribute (name = "key-store-path")
|
||||||
|
String keyStorePath;
|
||||||
|
|
||||||
|
@XmlAttribute (name = "key-store-password")
|
||||||
|
String keyStorePassword;
|
||||||
|
|
||||||
|
@XmlAttribute (name = "trust-store-provider")
|
||||||
|
String trustStoreProvider;
|
||||||
|
|
||||||
|
@XmlAttribute (name = "trust-store-path")
|
||||||
|
String trustStorePath;
|
||||||
|
|
||||||
|
@XmlAttribute (name = "trust-store-password")
|
||||||
|
String trustStorePassword;
|
||||||
|
|
||||||
|
public String getConnectorHost() {
|
||||||
|
return connectorHost;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getConnectorPort() {
|
||||||
|
return connectorPort;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getJmxRealm() {
|
||||||
|
return jmxRealm;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getObjectName() {
|
||||||
|
return objectName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAuthenticatorType() {
|
||||||
|
return authenticatorType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean isSecured() {
|
||||||
|
return secured;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getKeyStoreProvider() {
|
||||||
|
return keyStoreProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getKeyStorePath() {
|
||||||
|
return keyStorePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getKeyStorePassword() {
|
||||||
|
return keyStorePassword;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTrustStoreProvider() {
|
||||||
|
return trustStoreProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTrustStorePath() {
|
||||||
|
return trustStorePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTrustStorePassword() {
|
||||||
|
return trustStorePassword;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,41 @@
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
* <p>
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* <p>
|
||||||
|
* 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.artemis.dto;
|
||||||
|
|
||||||
|
import javax.xml.bind.annotation.XmlAccessType;
|
||||||
|
import javax.xml.bind.annotation.XmlAccessorType;
|
||||||
|
import javax.xml.bind.annotation.XmlElementRef;
|
||||||
|
import javax.xml.bind.annotation.XmlRootElement;
|
||||||
|
|
||||||
|
@XmlRootElement(name = "management-context")
|
||||||
|
@XmlAccessorType(XmlAccessType.FIELD)
|
||||||
|
public class ManagementContextDTO {
|
||||||
|
|
||||||
|
@XmlElementRef (required = false)
|
||||||
|
JMXConnectorDTO jmxConnector;
|
||||||
|
|
||||||
|
@XmlElementRef (required = false)
|
||||||
|
AuthorisationDTO authorisation;
|
||||||
|
|
||||||
|
public JMXConnectorDTO getJmxConnector() {
|
||||||
|
return jmxConnector;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AuthorisationDTO getAuthorisation() {
|
||||||
|
return authorisation;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,53 @@
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
* <p>
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* <p>
|
||||||
|
* 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.artemis.dto;
|
||||||
|
|
||||||
|
|
||||||
|
import javax.xml.bind.annotation.XmlAccessType;
|
||||||
|
import javax.xml.bind.annotation.XmlAccessorType;
|
||||||
|
import javax.xml.bind.annotation.XmlAttribute;
|
||||||
|
import javax.xml.bind.annotation.XmlElementRef;
|
||||||
|
import javax.xml.bind.annotation.XmlRootElement;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@XmlRootElement(name = "match")
|
||||||
|
@XmlAccessorType(XmlAccessType.FIELD)
|
||||||
|
public class MatchDTO {
|
||||||
|
|
||||||
|
|
||||||
|
@XmlAttribute
|
||||||
|
public String domain;
|
||||||
|
|
||||||
|
@XmlAttribute
|
||||||
|
public String key;
|
||||||
|
|
||||||
|
@XmlElementRef
|
||||||
|
List<AccessDTO> access;
|
||||||
|
|
||||||
|
public String getDomain() {
|
||||||
|
return domain;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getKey() {
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<AccessDTO> getAccess() {
|
||||||
|
return access;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
* <p>
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* <p>
|
||||||
|
* 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.artemis.dto;
|
||||||
|
|
||||||
|
|
||||||
|
import javax.xml.bind.annotation.XmlAccessType;
|
||||||
|
import javax.xml.bind.annotation.XmlAccessorType;
|
||||||
|
import javax.xml.bind.annotation.XmlElementRef;
|
||||||
|
import javax.xml.bind.annotation.XmlRootElement;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@XmlRootElement(name = "role-access")
|
||||||
|
@XmlAccessorType(XmlAccessType.FIELD)
|
||||||
|
public class RoleAccessDTO {
|
||||||
|
|
||||||
|
@XmlElementRef
|
||||||
|
List<MatchDTO> match;
|
||||||
|
|
||||||
|
public List<MatchDTO> getMatch() {
|
||||||
|
return match;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
* <p>
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* <p>
|
||||||
|
* 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.artemis.dto;
|
||||||
|
|
||||||
|
|
||||||
|
import javax.xml.bind.annotation.XmlAccessType;
|
||||||
|
import javax.xml.bind.annotation.XmlAccessorType;
|
||||||
|
import javax.xml.bind.annotation.XmlElementRef;
|
||||||
|
import javax.xml.bind.annotation.XmlRootElement;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@XmlRootElement(name = "whitelist")
|
||||||
|
@XmlAccessorType(XmlAccessType.FIELD)
|
||||||
|
public class WhiteListDTO {
|
||||||
|
|
||||||
|
@XmlElementRef
|
||||||
|
List<EntryDTO> entry;
|
||||||
|
|
||||||
|
public List<EntryDTO> getEntries() {
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
}
|
|
@ -17,4 +17,5 @@
|
||||||
BrokerDTO
|
BrokerDTO
|
||||||
SecurityDTO
|
SecurityDTO
|
||||||
JaasSecurityDTO
|
JaasSecurityDTO
|
||||||
|
ManagementContextDTO
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,149 @@
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
* <p>
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* <p>
|
||||||
|
* 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.artemis.core.config;
|
||||||
|
|
||||||
|
public class JMXConnectorConfiguration {
|
||||||
|
private int rmiRegistryPort;
|
||||||
|
private String connectorHost = "localhost";
|
||||||
|
private int connectorPort = 1099;
|
||||||
|
|
||||||
|
private String connectorPath = "/jmxrmi";
|
||||||
|
|
||||||
|
private String jmxRealm = "activemq";
|
||||||
|
private String objectName = "connector:name=rmi";
|
||||||
|
private String authenticatorType = "password";
|
||||||
|
private boolean secured = false;
|
||||||
|
private String keyStoreProvider;
|
||||||
|
private String keyStorePath;
|
||||||
|
private String keyStorePassword;
|
||||||
|
private String trustStoreProvider;
|
||||||
|
private String trustStorePath;
|
||||||
|
private String trustStorePassword;
|
||||||
|
|
||||||
|
public int getRmiRegistryPort() {
|
||||||
|
return rmiRegistryPort;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRmiRegistryPort(int rmiRegistryPort) {
|
||||||
|
this.rmiRegistryPort = rmiRegistryPort;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getConnectorHost() {
|
||||||
|
return connectorHost;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setConnectorHost(String connectorHost) {
|
||||||
|
this.connectorHost = connectorHost;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getConnectorPort() {
|
||||||
|
return connectorPort;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setConnectorPort(int connectorPort) {
|
||||||
|
this.connectorPort = connectorPort;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getJmxRealm() {
|
||||||
|
return jmxRealm;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setJmxRealm(String jmxRealm) {
|
||||||
|
this.jmxRealm = jmxRealm;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getServiceUrl() {
|
||||||
|
String rmiServer = "";
|
||||||
|
if (rmiRegistryPort != 0) {
|
||||||
|
// This is handy to use if you have a firewall and need to force JMX to use fixed ports.
|
||||||
|
rmiServer = "" + getConnectorHost() + ":" + rmiRegistryPort;
|
||||||
|
}
|
||||||
|
return "service:jmx:rmi://" + rmiServer + "/jndi/rmi://" + getConnectorHost() + ":" + connectorPort + connectorPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAuthenticatorType() {
|
||||||
|
return authenticatorType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAuthenticatorType(String authenticatorType) {
|
||||||
|
this.authenticatorType = authenticatorType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isSecured() {
|
||||||
|
return secured;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getKeyStoreProvider() {
|
||||||
|
return keyStoreProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setKeyStoreProvider(String keyStoreProvider) {
|
||||||
|
this.keyStoreProvider = keyStoreProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getKeyStorePath() {
|
||||||
|
return keyStorePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setKeyStorePath(String keyStorePath) {
|
||||||
|
this.keyStorePath = keyStorePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getKeyStorePassword() {
|
||||||
|
return keyStorePassword;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setKeyStorePassword(String keyStorePassword) {
|
||||||
|
this.keyStorePassword = keyStorePassword;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTrustStoreProvider() {
|
||||||
|
return trustStoreProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTrustStoreProvider(String trustStoreProvider) {
|
||||||
|
this.trustStoreProvider = trustStoreProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTrustStorePath() {
|
||||||
|
return trustStorePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTrustStorePath(String trustStorePath) {
|
||||||
|
this.trustStorePath = trustStorePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTrustStorePassword() {
|
||||||
|
return trustStorePassword;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTrustStorePassword(String trustStorePassword) {
|
||||||
|
this.trustStorePassword = trustStorePassword;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setObjectName(String objectName) {
|
||||||
|
this.objectName = objectName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getObjectName() {
|
||||||
|
return objectName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSecured(Boolean secured) {
|
||||||
|
this.secured = secured;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,90 @@
|
||||||
|
/*
|
||||||
|
* 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.artemis.core.server.management;
|
||||||
|
|
||||||
|
import java.lang.reflect.InvocationHandler;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.lang.reflect.Proxy;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import javax.management.MBeanServer;
|
||||||
|
import javax.management.MBeanServerBuilder;
|
||||||
|
import javax.management.MBeanServerDelegate;
|
||||||
|
|
||||||
|
public class ArtemisMBeanServerBuilder extends MBeanServerBuilder {
|
||||||
|
|
||||||
|
private static volatile InvocationHandler guard;
|
||||||
|
|
||||||
|
public static void setGuard(InvocationHandler guardHandler) {
|
||||||
|
guard = guardHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ArtemisMBeanServerGuard getArtemisMBeanServerGuard() {
|
||||||
|
return (ArtemisMBeanServerGuard) guard;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MBeanServer newMBeanServer(String defaultDomain, MBeanServer outer, MBeanServerDelegate delegate) {
|
||||||
|
InvocationHandler handler = new MBeanInvocationHandler(super.newMBeanServer(defaultDomain, outer, delegate));
|
||||||
|
return (MBeanServer) Proxy.newProxyInstance(getClass().getClassLoader(), new Class[]{MBeanServer.class}, handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class MBeanInvocationHandler implements InvocationHandler {
|
||||||
|
|
||||||
|
private final MBeanServer wrapped;
|
||||||
|
private final List<String> guarded = Collections.unmodifiableList(Arrays.asList("invoke", "getAttribute", "getAttributes", "setAttribute", "setAttributes"));
|
||||||
|
|
||||||
|
MBeanInvocationHandler(MBeanServer mbeanServer) {
|
||||||
|
wrapped = mbeanServer;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
|
||||||
|
if (guarded.contains(method.getName())) {
|
||||||
|
if (ArtemisMBeanServerBuilder.guard == null) {
|
||||||
|
throw new IllegalStateException("ArtemisMBeanServerBuilder not initialized");
|
||||||
|
}
|
||||||
|
guard.invoke(proxy, method, args);
|
||||||
|
}
|
||||||
|
if (method.getName().equals("queryMBeans")) {
|
||||||
|
guard.invoke(wrapped, method, args);
|
||||||
|
}
|
||||||
|
if (method.getName().equals("equals")
|
||||||
|
&& method.getParameterTypes().length == 1
|
||||||
|
&& method.getParameterTypes()[0] == Object.class) {
|
||||||
|
Object target = args[0];
|
||||||
|
if (target != null && Proxy.isProxyClass(target.getClass())) {
|
||||||
|
InvocationHandler handler = Proxy.getInvocationHandler(target);
|
||||||
|
if (handler instanceof MBeanInvocationHandler) {
|
||||||
|
args[0] = ((MBeanInvocationHandler) handler).wrapped;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (method.getName().equals("finalize") && method.getParameterTypes().length == 0) {
|
||||||
|
// special case finalize, don't route through to delegate because that will get its own call
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return method.invoke(wrapped, args);
|
||||||
|
} catch (InvocationTargetException ite) {
|
||||||
|
throw ite.getCause();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,162 @@
|
||||||
|
/*
|
||||||
|
* 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.artemis.core.server.management;
|
||||||
|
|
||||||
|
|
||||||
|
import javax.management.Attribute;
|
||||||
|
import javax.management.AttributeList;
|
||||||
|
import javax.management.JMException;
|
||||||
|
import javax.management.MBeanAttributeInfo;
|
||||||
|
import javax.management.MBeanInfo;
|
||||||
|
import javax.management.MBeanServer;
|
||||||
|
import javax.management.ObjectName;
|
||||||
|
import javax.security.auth.Subject;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.lang.reflect.InvocationHandler;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.security.AccessControlContext;
|
||||||
|
import java.security.AccessController;
|
||||||
|
import java.security.Principal;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class ArtemisMBeanServerGuard implements InvocationHandler {
|
||||||
|
|
||||||
|
private JMXAccessControlList jmxAccessControlList = JMXAccessControlList.createDefaultList();
|
||||||
|
|
||||||
|
public void init() {
|
||||||
|
ArtemisMBeanServerBuilder.setGuard(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
|
||||||
|
if (method.getParameterTypes().length == 0)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
if (!ObjectName.class.isAssignableFrom(method.getParameterTypes()[0]))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
ObjectName objectName = (ObjectName) args[0];
|
||||||
|
if ("getAttribute".equals(method.getName())) {
|
||||||
|
handleGetAttribute((MBeanServer) proxy, objectName, (String) args[1]);
|
||||||
|
} else if ("getAttributes".equals(method.getName())) {
|
||||||
|
handleGetAttributes((MBeanServer) proxy, objectName, (String[]) args[1]);
|
||||||
|
} else if ("setAttribute".equals(method.getName())) {
|
||||||
|
handleSetAttribute((MBeanServer) proxy, objectName, (Attribute) args[1]);
|
||||||
|
} else if ("setAttributes".equals(method.getName())) {
|
||||||
|
handleSetAttributes((MBeanServer) proxy, objectName, (AttributeList) args[1]);
|
||||||
|
} else if ("invoke".equals(method.getName())) {
|
||||||
|
handleInvoke(objectName, (String) args[1], (Object[]) args[2], (String[]) args[3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleGetAttribute(MBeanServer proxy, ObjectName objectName, String attributeName) throws JMException, IOException {
|
||||||
|
MBeanInfo info = proxy.getMBeanInfo(objectName);
|
||||||
|
String prefix = null;
|
||||||
|
for (MBeanAttributeInfo attr : info.getAttributes()) {
|
||||||
|
if (attr.getName().equals(attributeName)) {
|
||||||
|
prefix = attr.isIs() ? "is" : "get";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (prefix == null) {
|
||||||
|
//ActiveMQServerLogger.LOGGER.debug("Attribute " + attributeName + " can not be found for MBean " + objectName.toString());
|
||||||
|
} else {
|
||||||
|
handleInvoke(objectName, prefix + attributeName, new Object[]{}, new String[]{});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleGetAttributes(MBeanServer proxy, ObjectName objectName, String[] attributeNames) throws JMException, IOException {
|
||||||
|
for (String attr : attributeNames) {
|
||||||
|
handleGetAttribute(proxy, objectName, attr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleSetAttribute(MBeanServer proxy, ObjectName objectName, Attribute attribute) throws JMException, IOException {
|
||||||
|
String dataType = null;
|
||||||
|
MBeanInfo info = proxy.getMBeanInfo(objectName);
|
||||||
|
for (MBeanAttributeInfo attr : info.getAttributes()) {
|
||||||
|
if (attr.getName().equals(attribute.getName())) {
|
||||||
|
dataType = attr.getType();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dataType == null)
|
||||||
|
throw new IllegalStateException("Attribute data type can not be found");
|
||||||
|
|
||||||
|
handleInvoke(objectName, "set" + attribute.getName(), new Object[]{attribute.getValue()}, new String[]{dataType});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleSetAttributes(MBeanServer proxy, ObjectName objectName, AttributeList attributes) throws JMException, IOException {
|
||||||
|
for (Attribute attr : attributes.asList()) {
|
||||||
|
handleSetAttribute(proxy, objectName, attr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean canBypassRBAC(ObjectName objectName) {
|
||||||
|
return jmxAccessControlList.isInWhiteList(objectName);
|
||||||
|
}
|
||||||
|
|
||||||
|
void handleInvoke(ObjectName objectName, String operationName, Object[] params, String[] signature) throws IOException {
|
||||||
|
if (canBypassRBAC(objectName)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
List<String> requiredRoles = getRequiredRoles(objectName, operationName, params, signature);
|
||||||
|
for (String role : requiredRoles) {
|
||||||
|
if (currentUserHasRole(role))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
throw new SecurityException("Insufficient roles/credentials for operation");
|
||||||
|
}
|
||||||
|
|
||||||
|
List<String> getRequiredRoles(ObjectName objectName, String methodName, Object[] params, String[] signature) throws IOException {
|
||||||
|
return jmxAccessControlList.getRolesForObject(objectName, methodName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setJMXAccessControlList(JMXAccessControlList JMXAccessControlList) {
|
||||||
|
this.jmxAccessControlList = JMXAccessControlList;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean currentUserHasRole(String requestedRole) {
|
||||||
|
|
||||||
|
String clazz;
|
||||||
|
String role;
|
||||||
|
int index = requestedRole.indexOf(':');
|
||||||
|
if (index > 0) {
|
||||||
|
clazz = requestedRole.substring(0, index);
|
||||||
|
role = requestedRole.substring(index + 1);
|
||||||
|
} else {
|
||||||
|
clazz = "org.apache.activemq.artemis.spi.core.security.jaas.RolePrincipal";
|
||||||
|
role = requestedRole;
|
||||||
|
}
|
||||||
|
AccessControlContext acc = AccessController.getContext();
|
||||||
|
if (acc == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Subject subject = Subject.getSubject(acc);
|
||||||
|
if (subject == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (Principal p : subject.getPrincipals()) {
|
||||||
|
if (clazz.equals(p.getClass().getName()) && role.equals(p.getName())) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,282 @@
|
||||||
|
/*
|
||||||
|
* 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.artemis.core.server.management;
|
||||||
|
|
||||||
|
import org.apache.activemq.artemis.core.remoting.impl.ssl.SSLSupport;
|
||||||
|
|
||||||
|
import javax.management.JMException;
|
||||||
|
import javax.management.MBeanServer;
|
||||||
|
import javax.management.ObjectName;
|
||||||
|
import javax.management.remote.JMXConnectorServer;
|
||||||
|
import javax.management.remote.JMXConnectorServerFactory;
|
||||||
|
import javax.management.remote.JMXServiceURL;
|
||||||
|
import javax.management.remote.rmi.RMIConnectorServer;
|
||||||
|
import javax.net.ServerSocketFactory;
|
||||||
|
import javax.net.ssl.SSLContext;
|
||||||
|
import javax.net.ssl.SSLServerSocket;
|
||||||
|
import javax.net.ssl.SSLServerSocketFactory;
|
||||||
|
import javax.rmi.ssl.SslRMIClientSocketFactory;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.InetAddress;
|
||||||
|
import java.net.ServerSocket;
|
||||||
|
import java.rmi.server.RMIClientSocketFactory;
|
||||||
|
import java.rmi.server.RMIServerSocketFactory;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class ConnectorServerFactory {
|
||||||
|
|
||||||
|
public void setkeyStoreProvider(String keyStoreProvider) {
|
||||||
|
this.keyStoreProvider = keyStoreProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setKeyStorePassword(String keyStorePassword) {
|
||||||
|
this.keyStorePassword = keyStorePassword;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTrustStorePath(String trustStorePath) {
|
||||||
|
this.trustStorePath = trustStorePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTrustStoreProvider(String trustStoreProvider) {
|
||||||
|
this.trustStoreProvider = trustStoreProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTrustStorePassword(String trustStorePassword) {
|
||||||
|
this.trustStorePassword = trustStorePassword;
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum AuthenticatorType { NONE, PASSWORD, CERTIFICATE };
|
||||||
|
|
||||||
|
private MBeanServer server;
|
||||||
|
private String serviceUrl;
|
||||||
|
private String rmiServerHost;
|
||||||
|
private Map environment;
|
||||||
|
private ObjectName objectName;
|
||||||
|
private JMXConnectorServer connectorServer;
|
||||||
|
|
||||||
|
private AuthenticatorType authenticatorType = AuthenticatorType.PASSWORD;
|
||||||
|
|
||||||
|
private boolean secured;
|
||||||
|
|
||||||
|
private String keyStoreProvider;
|
||||||
|
|
||||||
|
private String keyStorePath;
|
||||||
|
|
||||||
|
private String keyStorePassword;
|
||||||
|
|
||||||
|
private String trustStoreProvider;
|
||||||
|
|
||||||
|
private String trustStorePath;
|
||||||
|
|
||||||
|
private String trustStorePassword;
|
||||||
|
|
||||||
|
|
||||||
|
public String getKeyStoreProvider() {
|
||||||
|
return keyStoreProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getKeyStorePath() {
|
||||||
|
return keyStorePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setKeyStorePath(String keyStorePath) {
|
||||||
|
this.keyStorePath = keyStorePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getKeyStorePassword() {
|
||||||
|
return keyStorePassword;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTrustStoreProvider() {
|
||||||
|
return trustStoreProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTrustStorePath() {
|
||||||
|
return trustStorePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTrustStorePassword() {
|
||||||
|
return trustStorePassword;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MBeanServer getServer() {
|
||||||
|
return server;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setServer(MBeanServer server) {
|
||||||
|
this.server = server;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getServiceUrl() {
|
||||||
|
return serviceUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setServiceUrl(String serviceUrl) {
|
||||||
|
this.serviceUrl = serviceUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getRmiServerHost() {
|
||||||
|
return this.rmiServerHost;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRmiServerHost(String rmiServerHost) {
|
||||||
|
this.rmiServerHost = rmiServerHost;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map getEnvironment() {
|
||||||
|
return environment;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEnvironment(Map environment) {
|
||||||
|
this.environment = environment;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ObjectName getObjectName() {
|
||||||
|
return objectName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setObjectName(ObjectName objectName) {
|
||||||
|
this.objectName = objectName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAuthenticatorType() {
|
||||||
|
return this.authenticatorType.name().toLowerCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Authenticator type to use. Acceptable values are "none", "password", and "certificate"
|
||||||
|
*
|
||||||
|
* @param value
|
||||||
|
*/
|
||||||
|
public void setAuthenticatorType(String value) {
|
||||||
|
this.authenticatorType = AuthenticatorType.valueOf(value.toUpperCase());
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isSecured() {
|
||||||
|
return this.secured;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSecured(boolean secured) {
|
||||||
|
this.secured = secured;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isClientAuth() {
|
||||||
|
return this.authenticatorType.equals(AuthenticatorType.CERTIFICATE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void init() throws Exception {
|
||||||
|
|
||||||
|
if (this.server == null) {
|
||||||
|
throw new IllegalArgumentException("server must be set");
|
||||||
|
}
|
||||||
|
JMXServiceURL url = new JMXServiceURL(this.serviceUrl);
|
||||||
|
setupArtemisRMIServerSocketFactory();
|
||||||
|
if (isClientAuth()) {
|
||||||
|
this.secured = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.secured) {
|
||||||
|
this.setupSsl();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!AuthenticatorType.PASSWORD.equals(this.authenticatorType)) {
|
||||||
|
this.environment.remove("jmx.remote.authenticator");
|
||||||
|
}
|
||||||
|
|
||||||
|
this.connectorServer = JMXConnectorServerFactory.newJMXConnectorServer(url, this.environment, this.server);
|
||||||
|
if (this.objectName != null) {
|
||||||
|
this.server.registerMBean(this.connectorServer, this.objectName);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
this.connectorServer.start();
|
||||||
|
} catch (Exception ex) {
|
||||||
|
doUnregister(this.objectName);
|
||||||
|
throw ex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void destroy() throws Exception {
|
||||||
|
try {
|
||||||
|
if (this.connectorServer != null) {
|
||||||
|
this.connectorServer.stop();
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
doUnregister(this.objectName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void doUnregister(ObjectName objectName) {
|
||||||
|
try {
|
||||||
|
if (this.objectName != null && this.server.isRegistered(objectName)) {
|
||||||
|
this.server.unregisterMBean(objectName);
|
||||||
|
}
|
||||||
|
} catch (JMException ex) {
|
||||||
|
// Ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//todo fix
|
||||||
|
private void setupSsl() throws Exception {
|
||||||
|
SSLContext context = SSLSupport.createContext(keyStoreProvider, keyStorePath, keyStorePassword, trustStoreProvider, trustStorePath, trustStorePassword);
|
||||||
|
SSLServerSocketFactory sssf = context.getServerSocketFactory();
|
||||||
|
RMIServerSocketFactory rssf = new ArtemisSslRMIServerSocketFactory(sssf, this.isClientAuth(), rmiServerHost);
|
||||||
|
RMIClientSocketFactory rcsf = new SslRMIClientSocketFactory();
|
||||||
|
environment.put(RMIConnectorServer.RMI_SERVER_SOCKET_FACTORY_ATTRIBUTE, rssf);
|
||||||
|
environment.put(RMIConnectorServer.RMI_CLIENT_SOCKET_FACTORY_ATTRIBUTE, rcsf);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setupArtemisRMIServerSocketFactory() {
|
||||||
|
RMIServerSocketFactory rmiServerSocketFactory = new ArtemisRMIServerSocketFactory(getRmiServerHost());
|
||||||
|
environment.put(RMIConnectorServer.RMI_SERVER_SOCKET_FACTORY_ATTRIBUTE, rmiServerSocketFactory);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class ArtemisSslRMIServerSocketFactory implements RMIServerSocketFactory {
|
||||||
|
private SSLServerSocketFactory sssf;
|
||||||
|
private boolean clientAuth;
|
||||||
|
private String rmiServerHost;
|
||||||
|
|
||||||
|
ArtemisSslRMIServerSocketFactory(SSLServerSocketFactory sssf, boolean clientAuth, String rmiServerHost) {
|
||||||
|
this.sssf = sssf;
|
||||||
|
this.clientAuth = clientAuth;
|
||||||
|
this.rmiServerHost = rmiServerHost;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ServerSocket createServerSocket(int port) throws IOException {
|
||||||
|
SSLServerSocket ss = (SSLServerSocket) sssf.createServerSocket(port, 50, InetAddress.getByName(rmiServerHost));
|
||||||
|
ss.setNeedClientAuth(clientAuth);
|
||||||
|
return ss;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class ArtemisRMIServerSocketFactory implements RMIServerSocketFactory {
|
||||||
|
private String rmiServerHost;
|
||||||
|
|
||||||
|
ArtemisRMIServerSocketFactory(String rmiServerHost) {
|
||||||
|
this.rmiServerHost = rmiServerHost;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ServerSocket createServerSocket(int port) throws IOException {
|
||||||
|
ServerSocket serverSocket = (ServerSocket) ServerSocketFactory.getDefault().createServerSocket(port, 50, InetAddress.getByName(rmiServerHost));
|
||||||
|
return serverSocket;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,203 @@
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
* <p>
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* <p>
|
||||||
|
* 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.artemis.core.server.management;
|
||||||
|
|
||||||
|
import javax.management.ObjectName;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Hashtable;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
public class JMXAccessControlList {
|
||||||
|
|
||||||
|
private Access defaultAccess = new Access("*");
|
||||||
|
private Map<String, Access> domainAccess = new HashMap<>();
|
||||||
|
private ConcurrentHashMap<String, List<String>> whitelist = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
|
||||||
|
public void addToWhiteList(String domain, String match) {
|
||||||
|
List<String> list = new ArrayList<>();
|
||||||
|
list = whitelist.putIfAbsent(domain, list);
|
||||||
|
if (list == null) {
|
||||||
|
list = whitelist.get(domain);
|
||||||
|
}
|
||||||
|
list.add(match != null ? match : "*");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public List<String> getRolesForObject(ObjectName objectName, String methodName) {
|
||||||
|
Hashtable<String, String> keyPropertyList = objectName.getKeyPropertyList();
|
||||||
|
for (Map.Entry<String, String> keyEntry : keyPropertyList.entrySet()) {
|
||||||
|
String key = keyEntry.getKey() + "=" + keyEntry.getValue();
|
||||||
|
Access access = domainAccess.get(getObjectID(objectName.getDomain(), key));
|
||||||
|
if (access != null) {
|
||||||
|
return access.getMatchingRolesForMethod(methodName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (Map.Entry<String, String> keyEntry : keyPropertyList.entrySet()) {
|
||||||
|
String key = keyEntry.getKey() + "=*";
|
||||||
|
Access access = domainAccess.get(getObjectID(objectName.getDomain(), key));
|
||||||
|
if (access != null) {
|
||||||
|
return access.getMatchingRolesForMethod(methodName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Access access = domainAccess.get(objectName.getDomain());
|
||||||
|
if (access == null) {
|
||||||
|
access = defaultAccess;
|
||||||
|
}
|
||||||
|
return access.getMatchingRolesForMethod(methodName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isInWhiteList(ObjectName objectName) {
|
||||||
|
List<String> matches = whitelist.get(objectName.getDomain());
|
||||||
|
if (matches != null) {
|
||||||
|
for (String match : matches) {
|
||||||
|
if (match.equals("*")) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
String[] split = match.split("=");
|
||||||
|
String key = split[0];
|
||||||
|
String val = split[1];
|
||||||
|
String propVal = objectName.getKeyProperty(key);
|
||||||
|
if (propVal != null && (val.equals("*") || propVal.equals(val))) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addToDefaultAccess(String method, String... roles) {
|
||||||
|
if (roles != null) {
|
||||||
|
if ( method.equals("*")) {
|
||||||
|
defaultAccess.addCatchAll(roles);
|
||||||
|
} else if (method.endsWith("*")) {
|
||||||
|
String prefix = method.replace("*", "");
|
||||||
|
defaultAccess.addMethodsPrefixes(prefix, roles);
|
||||||
|
} else {
|
||||||
|
defaultAccess.addMethods(method, roles);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addToRoleAccess(String domain,String key, String method, String... roles) {
|
||||||
|
String id = getObjectID(domain, key);
|
||||||
|
Access access = domainAccess.get(id);
|
||||||
|
if (access == null) {
|
||||||
|
access = new Access(domain);
|
||||||
|
domainAccess.put(id, access);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (method.endsWith("*")) {
|
||||||
|
String prefix = method.replace("*", "");
|
||||||
|
access.addMethodsPrefixes(prefix, roles);
|
||||||
|
} else {
|
||||||
|
access.addMethods(method, roles);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getObjectID(String domain, String key) {
|
||||||
|
String id = domain;
|
||||||
|
|
||||||
|
if (key != null) {
|
||||||
|
String actualKey = key;
|
||||||
|
if (key.endsWith("\"")) {
|
||||||
|
actualKey = actualKey.replace("\"", "");
|
||||||
|
}
|
||||||
|
id += ":" + actualKey;
|
||||||
|
}
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
static class Access {
|
||||||
|
private final String domain;
|
||||||
|
List<String> catchAllRoles = new ArrayList<>();
|
||||||
|
Map<String, List<String>> methodRoles = new HashMap<>();
|
||||||
|
Map<String, List<String>> methodPrefixRoles = new HashMap<>();
|
||||||
|
|
||||||
|
Access(String domain) {
|
||||||
|
this.domain = domain;
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void addMethods(String prefix, String... roles) {
|
||||||
|
List<String> rolesList = methodRoles.get(prefix);
|
||||||
|
if (rolesList == null) {
|
||||||
|
rolesList = new ArrayList<>();
|
||||||
|
methodRoles.put(prefix, rolesList);
|
||||||
|
}
|
||||||
|
for (String role : roles) {
|
||||||
|
rolesList.add(role);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void addMethodsPrefixes(String prefix, String... roles) {
|
||||||
|
List<String> rolesList = methodPrefixRoles.get(prefix);
|
||||||
|
if (rolesList == null) {
|
||||||
|
rolesList = new ArrayList<>();
|
||||||
|
methodPrefixRoles.put(prefix, rolesList);
|
||||||
|
}
|
||||||
|
for (String role : roles) {
|
||||||
|
rolesList.add(role);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addCatchAll(String... roles) {
|
||||||
|
for (String role : roles) {
|
||||||
|
catchAllRoles.add(role);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDomain() {
|
||||||
|
return domain;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getMatchingRolesForMethod(String methodName) {
|
||||||
|
List<String> roles = methodRoles.get(methodName);
|
||||||
|
if (roles != null) {
|
||||||
|
return roles;
|
||||||
|
}
|
||||||
|
for (Map.Entry<String, List<String>> entry : methodPrefixRoles.entrySet()) {
|
||||||
|
if (methodName.startsWith(entry.getKey())) {
|
||||||
|
return entry.getValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return catchAllRoles;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static JMXAccessControlList createDefaultList() {
|
||||||
|
JMXAccessControlList accessControlList = new JMXAccessControlList();
|
||||||
|
|
||||||
|
accessControlList.addToWhiteList("hawtio", "type=*");
|
||||||
|
|
||||||
|
accessControlList.addToRoleAccess("org.apache.activemq.apache", null, "list*", "view", "update", "amq");
|
||||||
|
accessControlList.addToRoleAccess("org.apache.activemq.apache", null,"get*", "view", "update", "amq");
|
||||||
|
accessControlList.addToRoleAccess("org.apache.activemq.apache", null,"is*", "view", "update", "amq");
|
||||||
|
accessControlList.addToRoleAccess("org.apache.activemq.apache", null,"set*","update", "amq");
|
||||||
|
accessControlList.addToRoleAccess("org.apache.activemq.apache", null,"*", "amq");
|
||||||
|
|
||||||
|
accessControlList.addToDefaultAccess("list*", "view", "update", "amq");
|
||||||
|
accessControlList.addToDefaultAccess("get*", "view", "update", "amq");
|
||||||
|
accessControlList.addToDefaultAccess("is*", "view", "update", "amq");
|
||||||
|
accessControlList.addToDefaultAccess("set*", "update", "amq");
|
||||||
|
accessControlList.addToDefaultAccess("*", "amq");
|
||||||
|
|
||||||
|
return accessControlList;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,82 @@
|
||||||
|
/*
|
||||||
|
* 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.artemis.core.server.management;
|
||||||
|
|
||||||
|
import javax.management.remote.JMXAuthenticator;
|
||||||
|
import javax.security.auth.Subject;
|
||||||
|
import javax.security.auth.callback.Callback;
|
||||||
|
import javax.security.auth.callback.CallbackHandler;
|
||||||
|
import javax.security.auth.callback.NameCallback;
|
||||||
|
import javax.security.auth.callback.PasswordCallback;
|
||||||
|
import javax.security.auth.callback.UnsupportedCallbackException;
|
||||||
|
import javax.security.auth.login.LoginContext;
|
||||||
|
import javax.security.auth.login.LoginException;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class JaasAuthenticator implements JMXAuthenticator {
|
||||||
|
|
||||||
|
private String realm;
|
||||||
|
|
||||||
|
public String getRealm() {
|
||||||
|
return realm;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRealm(String realm) {
|
||||||
|
this.realm = realm;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Subject authenticate(Object credentials) throws SecurityException {
|
||||||
|
if (!(credentials instanceof String[])) {
|
||||||
|
throw new IllegalArgumentException("Expected String[2], got "
|
||||||
|
+ (credentials != null ? credentials.getClass().getName() : null));
|
||||||
|
}
|
||||||
|
|
||||||
|
final String[] params = (String[]) credentials;
|
||||||
|
if (params.length != 2) {
|
||||||
|
throw new IllegalArgumentException("Expected String[2] but length was " + params.length);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
Subject subject = new Subject();
|
||||||
|
LoginContext loginContext = new LoginContext(realm, subject, new CallbackHandler() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
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(params[0]);
|
||||||
|
} else if (callbacks[i] instanceof PasswordCallback) {
|
||||||
|
((PasswordCallback) callbacks[i]).setPassword((params[1].toCharArray()));
|
||||||
|
} else {
|
||||||
|
throw new UnsupportedCallbackException(callbacks[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
loginContext.login();
|
||||||
|
|
||||||
|
/* if (subject.getPrincipals().size() == 0) {
|
||||||
|
// there must be some Principals, but which ones required are tested later
|
||||||
|
throw new FailedLoginException("User does not have the required role");
|
||||||
|
}*/
|
||||||
|
|
||||||
|
return subject;
|
||||||
|
} catch (LoginException e) {
|
||||||
|
throw new SecurityException("Authentication failed", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,100 @@
|
||||||
|
/*
|
||||||
|
* 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.artemis.core.server.management;
|
||||||
|
|
||||||
|
import javax.management.MBeanServer;
|
||||||
|
import java.lang.management.ManagementFactory;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class MBeanServerFactory {
|
||||||
|
|
||||||
|
private boolean locateExistingServerIfPossible = false;
|
||||||
|
private String defaultDomain;
|
||||||
|
private boolean registerWithFactory = true;
|
||||||
|
private MBeanServer server;
|
||||||
|
private boolean newlyRegistered = false;
|
||||||
|
|
||||||
|
public boolean isLocateExistingServerIfPossible() {
|
||||||
|
return locateExistingServerIfPossible;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLocateExistingServerIfPossible(boolean locateExistingServerIfPossible) {
|
||||||
|
this.locateExistingServerIfPossible = locateExistingServerIfPossible;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDefaultDomain() {
|
||||||
|
return defaultDomain;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDefaultDomain(String defaultDomain) {
|
||||||
|
this.defaultDomain = defaultDomain;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isRegisterWithFactory() {
|
||||||
|
return registerWithFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRegisterWithFactory(boolean registerWithFactory) {
|
||||||
|
this.registerWithFactory = registerWithFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isNewlyRegistered() {
|
||||||
|
return newlyRegistered;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNewlyRegistered(boolean newlyRegistered) {
|
||||||
|
this.newlyRegistered = newlyRegistered;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MBeanServer getServer() throws Exception {
|
||||||
|
if (this.server == null) {
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
return server;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void init() throws Exception {
|
||||||
|
if (this.locateExistingServerIfPossible) {
|
||||||
|
List servers = javax.management.MBeanServerFactory.findMBeanServer(null);
|
||||||
|
if (servers != null && servers.size() > 0) {
|
||||||
|
this.server = (MBeanServer) servers.get(0);
|
||||||
|
}
|
||||||
|
if (this.server == null) {
|
||||||
|
this.server = ManagementFactory.getPlatformMBeanServer();
|
||||||
|
}
|
||||||
|
if (this.server == null) {
|
||||||
|
throw new Exception("Unable to locate MBeanServer");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (this.server == null) {
|
||||||
|
if (this.registerWithFactory) {
|
||||||
|
this.server = javax.management.MBeanServerFactory.createMBeanServer(this.defaultDomain);
|
||||||
|
} else {
|
||||||
|
this.server = javax.management.MBeanServerFactory.newMBeanServer(this.defaultDomain);
|
||||||
|
}
|
||||||
|
this.newlyRegistered = this.registerWithFactory;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void destroy() throws Exception {
|
||||||
|
|
||||||
|
if (this.newlyRegistered) {
|
||||||
|
javax.management.MBeanServerFactory.releaseMBeanServer(this.server);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,114 @@
|
||||||
|
/*
|
||||||
|
* 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.artemis.core.server.management;
|
||||||
|
|
||||||
|
import org.apache.activemq.artemis.core.config.JMXConnectorConfiguration;
|
||||||
|
import org.apache.activemq.artemis.core.server.ActiveMQComponent;
|
||||||
|
import org.apache.activemq.artemis.core.server.ActiveMQServerLogger;
|
||||||
|
|
||||||
|
import javax.management.MBeanServer;
|
||||||
|
import javax.management.ObjectName;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
|
||||||
|
public class ManagementConnector implements ActiveMQComponent {
|
||||||
|
|
||||||
|
private final JMXConnectorConfiguration configuration;
|
||||||
|
private ConnectorServerFactory connectorServerFactory;
|
||||||
|
private RmiRegistryFactory rmiRegistryFactory;
|
||||||
|
private MBeanServerFactory mbeanServerFactory;
|
||||||
|
|
||||||
|
public ManagementConnector(JMXConnectorConfiguration configuration) {
|
||||||
|
this.configuration = configuration;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isStarted() {
|
||||||
|
return rmiRegistryFactory != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void start() throws Exception {
|
||||||
|
ArtemisMBeanServerGuard guard = new ArtemisMBeanServerGuard();
|
||||||
|
guard.init();
|
||||||
|
|
||||||
|
rmiRegistryFactory = new RmiRegistryFactory();
|
||||||
|
rmiRegistryFactory.setPort(configuration.getConnectorPort());
|
||||||
|
rmiRegistryFactory.init();
|
||||||
|
|
||||||
|
mbeanServerFactory = new MBeanServerFactory();
|
||||||
|
mbeanServerFactory.setLocateExistingServerIfPossible(true);
|
||||||
|
mbeanServerFactory.init();
|
||||||
|
|
||||||
|
MBeanServer mbeanServer = mbeanServerFactory.getServer();
|
||||||
|
|
||||||
|
JaasAuthenticator jaasAuthenticator = new JaasAuthenticator();
|
||||||
|
jaasAuthenticator.setRealm(configuration.getJmxRealm());
|
||||||
|
|
||||||
|
connectorServerFactory = new ConnectorServerFactory();
|
||||||
|
connectorServerFactory.setServer(mbeanServer);
|
||||||
|
connectorServerFactory.setServiceUrl(configuration.getServiceUrl());
|
||||||
|
connectorServerFactory.setRmiServerHost(configuration.getConnectorHost());
|
||||||
|
connectorServerFactory.setObjectName(new ObjectName(configuration.getObjectName()));
|
||||||
|
Map<String, Object> environment = new HashMap<>();
|
||||||
|
environment.put("jmx.remote.authenticator", jaasAuthenticator);
|
||||||
|
try {
|
||||||
|
connectorServerFactory.setEnvironment(environment);
|
||||||
|
connectorServerFactory.setAuthenticatorType(configuration.getAuthenticatorType());
|
||||||
|
connectorServerFactory.setSecured(configuration.isSecured());
|
||||||
|
connectorServerFactory.setKeyStorePath(configuration.getKeyStorePath());
|
||||||
|
connectorServerFactory.setkeyStoreProvider(configuration.getKeyStoreProvider());
|
||||||
|
connectorServerFactory.setKeyStorePassword(configuration.getKeyStorePassword());
|
||||||
|
connectorServerFactory.setTrustStorePath(configuration.getTrustStorePath());
|
||||||
|
connectorServerFactory.setTrustStoreProvider(configuration.getTrustStoreProvider());
|
||||||
|
connectorServerFactory.setTrustStorePassword(configuration.getTrustStorePassword());
|
||||||
|
connectorServerFactory.init();
|
||||||
|
} catch (Exception e) {
|
||||||
|
ActiveMQServerLogger.LOGGER.error("Can't init JMXConnectorServer: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void stop() {
|
||||||
|
if (connectorServerFactory != null) {
|
||||||
|
try {
|
||||||
|
connectorServerFactory.destroy();
|
||||||
|
} catch (Exception e) {
|
||||||
|
ActiveMQServerLogger.LOGGER.warn("Error destroying ConnectorServerFactory", e);
|
||||||
|
}
|
||||||
|
connectorServerFactory = null;
|
||||||
|
}
|
||||||
|
if (mbeanServerFactory != null) {
|
||||||
|
try {
|
||||||
|
mbeanServerFactory.destroy();
|
||||||
|
} catch (Exception e) {
|
||||||
|
ActiveMQServerLogger.LOGGER.warn("Error destroying MBeanServerFactory", e);
|
||||||
|
}
|
||||||
|
mbeanServerFactory = null;
|
||||||
|
}
|
||||||
|
if (rmiRegistryFactory != null) {
|
||||||
|
try {
|
||||||
|
rmiRegistryFactory.destroy();
|
||||||
|
} catch (Exception e) {
|
||||||
|
ActiveMQServerLogger.LOGGER.warn("Error destroying RMIRegistryFactory", e);
|
||||||
|
}
|
||||||
|
rmiRegistryFactory = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,74 @@
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
* <p>
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* <p>
|
||||||
|
* 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.artemis.core.server.management;
|
||||||
|
|
||||||
|
|
||||||
|
import org.apache.activemq.artemis.core.config.JMXConnectorConfiguration;
|
||||||
|
import org.apache.activemq.artemis.core.server.ActiveMQComponent;
|
||||||
|
|
||||||
|
public class ManagementContext implements ActiveMQComponent {
|
||||||
|
private boolean isStarted = false;
|
||||||
|
private JMXAccessControlList accessControlList;
|
||||||
|
private JMXConnectorConfiguration jmxConnectorConfiguration;
|
||||||
|
private ManagementConnector mBeanServer;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void start() throws Exception {
|
||||||
|
if (accessControlList != null) {
|
||||||
|
//if we are configured then assume we want to use the guard so set the system property
|
||||||
|
System.setProperty("javax.management.builder.initial", ArtemisMBeanServerBuilder.class.getCanonicalName());
|
||||||
|
ArtemisMBeanServerGuard guardHandler = new ArtemisMBeanServerGuard();
|
||||||
|
guardHandler.setJMXAccessControlList(accessControlList);
|
||||||
|
ArtemisMBeanServerBuilder.setGuard(guardHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (jmxConnectorConfiguration != null) {
|
||||||
|
mBeanServer = new ManagementConnector(jmxConnectorConfiguration);
|
||||||
|
mBeanServer.start();
|
||||||
|
}
|
||||||
|
isStarted = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void stop() throws Exception {
|
||||||
|
isStarted = false;
|
||||||
|
if (mBeanServer != null) {
|
||||||
|
mBeanServer.stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isStarted() {
|
||||||
|
return isStarted;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAccessControlList(JMXAccessControlList accessControlList) {
|
||||||
|
this.accessControlList = accessControlList;
|
||||||
|
}
|
||||||
|
|
||||||
|
public JMXAccessControlList getAccessControlList() {
|
||||||
|
return accessControlList;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setJmxConnectorConfiguration(JMXConnectorConfiguration jmxConnectorConfiguration) {
|
||||||
|
this.jmxConnectorConfiguration = jmxConnectorConfiguration;
|
||||||
|
}
|
||||||
|
|
||||||
|
public JMXConnectorConfiguration getJmxConnectorConfiguration() {
|
||||||
|
return jmxConnectorConfiguration;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,56 @@
|
||||||
|
/*
|
||||||
|
* 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.artemis.core.server.management;
|
||||||
|
|
||||||
|
import java.net.UnknownHostException;
|
||||||
|
import java.rmi.RemoteException;
|
||||||
|
import java.rmi.registry.LocateRegistry;
|
||||||
|
import java.rmi.registry.Registry;
|
||||||
|
import java.rmi.server.UnicastRemoteObject;
|
||||||
|
|
||||||
|
public class RmiRegistryFactory {
|
||||||
|
|
||||||
|
private int port = Registry.REGISTRY_PORT;
|
||||||
|
private Registry registry;
|
||||||
|
/**
|
||||||
|
* @return the port
|
||||||
|
*/
|
||||||
|
public int getPort() {
|
||||||
|
return port;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param port the port to set
|
||||||
|
*/
|
||||||
|
public void setPort(int port) {
|
||||||
|
this.port = port;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object getObject() throws Exception {
|
||||||
|
return registry;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void init() throws RemoteException, UnknownHostException {
|
||||||
|
registry = LocateRegistry.createRegistry(port);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void destroy() throws RemoteException {
|
||||||
|
if (registry != null) {
|
||||||
|
UnicastRemoteObject.unexportObject(registry, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,153 @@
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
* <p>
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* <p>
|
||||||
|
* 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.artemis.core.server.management;
|
||||||
|
|
||||||
|
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import javax.management.MalformedObjectNameException;
|
||||||
|
import javax.management.ObjectName;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class JMXAccessControlListTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBasicDomain() throws MalformedObjectNameException {
|
||||||
|
JMXAccessControlList controlList = new JMXAccessControlList();
|
||||||
|
controlList.addToWhiteList("org.myDomain", null);
|
||||||
|
controlList.addToWhiteList("org.myDomain.foo", null);
|
||||||
|
Assert.assertTrue(controlList.isInWhiteList(new ObjectName("org.myDomain:*")));
|
||||||
|
Assert.assertTrue(controlList.isInWhiteList(new ObjectName("org.myDomain.foo:*")));
|
||||||
|
Assert.assertFalse(controlList.isInWhiteList(new ObjectName("org.myDomain.bar:*")));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBasicDomainWithProperty() throws MalformedObjectNameException {
|
||||||
|
JMXAccessControlList controlList = new JMXAccessControlList();
|
||||||
|
controlList.addToWhiteList("org.myDomain", "type=foo");
|
||||||
|
controlList.addToWhiteList("org.myDomain.foo", "type=bar");
|
||||||
|
Assert.assertFalse(controlList.isInWhiteList(new ObjectName("org.myDomain:*")));
|
||||||
|
Assert.assertFalse(controlList.isInWhiteList(new ObjectName("org.myDomain.foo:*")));
|
||||||
|
Assert.assertFalse(controlList.isInWhiteList(new ObjectName("org.myDomain.bar:*")));
|
||||||
|
Assert.assertFalse(controlList.isInWhiteList(new ObjectName("org.myDomain:subType=foo")));
|
||||||
|
|
||||||
|
Assert.assertTrue(controlList.isInWhiteList(new ObjectName("org.myDomain:type=foo")));
|
||||||
|
Assert.assertTrue(controlList.isInWhiteList(new ObjectName("org.myDomain:subType=bar,type=foo")));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBasicDomainWithWildCardProperty() throws MalformedObjectNameException {
|
||||||
|
JMXAccessControlList controlList = new JMXAccessControlList();
|
||||||
|
controlList.addToWhiteList("org.myDomain", "type=*");
|
||||||
|
Assert.assertFalse(controlList.isInWhiteList(new ObjectName("org.myDomain:*")));
|
||||||
|
Assert.assertFalse(controlList.isInWhiteList(new ObjectName("org.myDomain.foo:*")));
|
||||||
|
Assert.assertFalse(controlList.isInWhiteList(new ObjectName("org.myDomain.bar:*")));
|
||||||
|
Assert.assertTrue(controlList.isInWhiteList(new ObjectName("org.myDomain:type=foo")));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBasicRole() throws MalformedObjectNameException {
|
||||||
|
JMXAccessControlList controlList = new JMXAccessControlList();
|
||||||
|
controlList.addToRoleAccess("org.myDomain", null,"listSomething", "admin");
|
||||||
|
List<String> roles = controlList.getRolesForObject(new ObjectName("org.myDomain:*"), "listSomething");
|
||||||
|
Assert.assertArrayEquals(roles.toArray(), new String[]{"admin"});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBasicRoleWithKey() throws MalformedObjectNameException {
|
||||||
|
JMXAccessControlList controlList = new JMXAccessControlList();
|
||||||
|
controlList.addToRoleAccess("org.myDomain", "type=foo","listSomething", "admin");
|
||||||
|
controlList.addToRoleAccess("org.myDomain", null,"listSomething", "view");
|
||||||
|
List<String> roles = controlList.getRolesForObject(new ObjectName("org.myDomain:type=foo"), "listSomething");
|
||||||
|
Assert.assertArrayEquals(roles.toArray(), new String[]{"admin"});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBasicRoleWithKeyContainingQuotes() throws MalformedObjectNameException {
|
||||||
|
JMXAccessControlList controlList = new JMXAccessControlList();
|
||||||
|
controlList.addToRoleAccess("org.myDomain", "type=foo","listSomething", "admin");
|
||||||
|
controlList.addToRoleAccess("org.myDomain", null,"listSomething", "view");
|
||||||
|
List<String> roles = controlList.getRolesForObject(new ObjectName("org.myDomain:type=\"foo\""), "listSomething");
|
||||||
|
Assert.assertArrayEquals(roles.toArray(), new String[]{"admin"});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBasicRoleWithWildcardKey() throws MalformedObjectNameException {
|
||||||
|
JMXAccessControlList controlList = new JMXAccessControlList();
|
||||||
|
controlList.addToRoleAccess("org.myDomain", "type=*","listSomething", "admin");
|
||||||
|
controlList.addToRoleAccess("org.myDomain", null,"listSomething", "view");
|
||||||
|
List<String> roles = controlList.getRolesForObject(new ObjectName("org.myDomain:type=foo"), "listSomething");
|
||||||
|
Assert.assertArrayEquals(roles.toArray(), new String[]{"admin"});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMutipleBasicRoles() throws MalformedObjectNameException {
|
||||||
|
JMXAccessControlList controlList = new JMXAccessControlList();
|
||||||
|
controlList.addToRoleAccess("org.myDomain", null, "listSomething", "admin", "view", "update");
|
||||||
|
List<String> roles = controlList.getRolesForObject(new ObjectName("org.myDomain:*"), "listSomething");
|
||||||
|
Assert.assertArrayEquals(roles.toArray(), new String[]{"admin", "view", "update"});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBasicRoleWithPrefix() throws MalformedObjectNameException {
|
||||||
|
JMXAccessControlList controlList = new JMXAccessControlList();
|
||||||
|
controlList.addToRoleAccess("org.myDomain", null,"list*", "admin");
|
||||||
|
List<String> roles = controlList.getRolesForObject(new ObjectName("org.myDomain:*"), "listSomething");
|
||||||
|
Assert.assertArrayEquals(roles.toArray(), new String[]{"admin"});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBasicRoleWithBoth() throws MalformedObjectNameException {
|
||||||
|
JMXAccessControlList controlList = new JMXAccessControlList();
|
||||||
|
controlList.addToRoleAccess("org.myDomain", null,"listSomething", "admin");
|
||||||
|
controlList.addToRoleAccess("org.myDomain", null,"list*", "view");
|
||||||
|
List<String> roles = controlList.getRolesForObject(new ObjectName("org.myDomain:*"), "listSomething");
|
||||||
|
Assert.assertArrayEquals(roles.toArray(), new String[]{"admin"});
|
||||||
|
roles = controlList.getRolesForObject(new ObjectName("org.myDomain:*"), "listSomethingMore");
|
||||||
|
Assert.assertArrayEquals(roles.toArray(), new String[]{"view"});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBasicRoleWithDefaultsPrefix() throws MalformedObjectNameException {
|
||||||
|
JMXAccessControlList controlList = new JMXAccessControlList();
|
||||||
|
controlList.addToDefaultAccess("setSomething","admin");
|
||||||
|
controlList.addToRoleAccess("org.myDomain", null,"list*", "view");
|
||||||
|
List<String> roles = controlList.getRolesForObject(new ObjectName("org.myDomain.foo:*"), "setSomething");
|
||||||
|
Assert.assertArrayEquals(roles.toArray(), new String[]{"admin"});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBasicRoleWithDefaultsWildcardPrefix() throws MalformedObjectNameException {
|
||||||
|
JMXAccessControlList controlList = new JMXAccessControlList();
|
||||||
|
controlList.addToDefaultAccess("setSomething","admin");
|
||||||
|
controlList.addToDefaultAccess("set*","admin");
|
||||||
|
controlList.addToRoleAccess("org.myDomain", null,"list*", "view");
|
||||||
|
List<String> roles = controlList.getRolesForObject(new ObjectName("org.myDomain.foo:*"), "setSomethingMore");
|
||||||
|
Assert.assertArrayEquals(roles.toArray(), new String[]{"admin"});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBasicRoleWithDefaultscatchAllPrefix() throws MalformedObjectNameException {
|
||||||
|
JMXAccessControlList controlList = new JMXAccessControlList();
|
||||||
|
controlList.addToDefaultAccess("setSomething","admin");
|
||||||
|
controlList.addToDefaultAccess("*","admin");
|
||||||
|
controlList.addToRoleAccess("org.myDomain", null,"list*", "view");
|
||||||
|
List<String> roles = controlList.getRolesForObject(new ObjectName("org.myDomain.foo:*"), "setSomethingMore");
|
||||||
|
Assert.assertArrayEquals(roles.toArray(), new String[]{"admin"});
|
||||||
|
}
|
||||||
|
}
|
|
@ -296,16 +296,132 @@ setting `jmx-management-enabled` to `false` in
|
||||||
|
|
||||||
<!-- false to disable JMX management for Apache ActiveMQ Artemis -->
|
<!-- false to disable JMX management for Apache ActiveMQ Artemis -->
|
||||||
<jmx-management-enabled>false</jmx-management-enabled>
|
<jmx-management-enabled>false</jmx-management-enabled>
|
||||||
|
|
||||||
|
#### Role Based Authentication with JMX
|
||||||
|
|
||||||
If JMX is enabled, Apache ActiveMQ Artemis can be managed locally using `jconsole`.
|
Although by default Artemis uses the Java Virtual Machine's `Platform MBeanServer`
|
||||||
|
this is guarded using role based authentication that leverages Artemis's JAAS plugin support.
|
||||||
|
This is configured via the `authorisation` element in the `management.xml` configuration file
|
||||||
|
and can be used to restrict access to attributes and methods on mbeans.
|
||||||
|
|
||||||
|
There are 3 elements within the `authorisation` element, `whitelist`, `default-access` and
|
||||||
|
`role-access`, Lets discuss each in turn.
|
||||||
|
|
||||||
|
Whitelist contains a list of mBeans that will by pass the authentication, this is typically
|
||||||
|
used for any mbeans that are needed by the console to run etc. The default configuration is:
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<whitelist>
|
||||||
|
<entry domain="hawtio"/>
|
||||||
|
</whitelist>
|
||||||
|
```
|
||||||
|
This means that any mbean with the domain `hawtio` will be allowed access without authorisation. for instance
|
||||||
|
`hawtio:plugin=artemis`. You can also use wildcards for the mBean properties so the following would also match.
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<whitelist>
|
||||||
|
<entry domain="hawtio" key="type=*"/>
|
||||||
|
</whitelist>
|
||||||
|
```
|
||||||
|
|
||||||
|
The `role-access`defines how roles are mapped to particular mBeans and its attributes and methods,
|
||||||
|
the default configuration looks like:
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<role-access>
|
||||||
|
<match domain="org.apache.activemq.apache">
|
||||||
|
<access method="list*" roles="view,update,amq"/>
|
||||||
|
<access method="get*" roles="view,update,amq"/>
|
||||||
|
<access method="is*" roles="view,update,amq"/>
|
||||||
|
<access method="set*" roles="update,amq"/>
|
||||||
|
<access method="*" roles="amq"/>
|
||||||
|
</match>
|
||||||
|
</role-access>
|
||||||
|
```
|
||||||
|
This contains 1 match and will be applied to any mBean that has the domain `org.apache.activemq.apache`.
|
||||||
|
Any access to any mBeans that have this domain are controlled by the `access` elements which contain a
|
||||||
|
method and a set of roles. The method being invoked will be used to pick the closest matching method and
|
||||||
|
the roles for this will be applied for access. For instance if you try the invoke a method called `listMessages` on an mBean
|
||||||
|
with the `org.apache.activemq.apache` domain then this would match the `access` with the method of `list*`.
|
||||||
|
You could also explicitly configure this by using the full method name, like so:
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<access method="listMessages" roles="view,update,amq"/>
|
||||||
|
```
|
||||||
|
You can also match specific mBeans within a domain by adding a key attribute that is used to match one of the properties
|
||||||
|
on the mBean, like:
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<match domain="org.apache.activemq.apache" key="subcomponent=queues">
|
||||||
|
<access method="list*" roles="view,update,amq"/>
|
||||||
|
<access method="get*" roles="view,update,amq"/>
|
||||||
|
<access method="is*" roles="view,update,amq"/>
|
||||||
|
<access method="set*" roles="update,amq"/>
|
||||||
|
<access method="*" roles="amq"/>
|
||||||
|
</match>
|
||||||
|
```
|
||||||
|
You could also match a specific queue for instance :
|
||||||
|
|
||||||
|
`org.apache.activemq.artemis:broker=<brokerName>,component=addresses,address="exampleAddress",subcomponent=queues,routing-type="anycast",queue="exampleQueue"`
|
||||||
|
|
||||||
|
by configuring:
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<match domain="org.apache.activemq.apache" key="queue=exampleQueue">
|
||||||
|
<access method="list*" roles="view,update,amq"/>
|
||||||
|
<access method="get*" roles="view,update,amq"/>
|
||||||
|
<access method="is*" roles="view,update,amq"/>
|
||||||
|
<access method="set*" roles="update,amq"/>
|
||||||
|
<access method="*" roles="amq"/>
|
||||||
|
</match>
|
||||||
|
```
|
||||||
|
|
||||||
|
Access to JMX mBean attributes are converted to method calls so these are controlled via the `set*`, `get*` and `is*`.
|
||||||
|
The `*` access is the catch all for everything other method that isnt specifically matched.
|
||||||
|
|
||||||
|
The `default-access` element is basically the catch all for every method call that isn't handled via the `role-access` configuration.
|
||||||
|
This has teh same semantics as a `match` element.
|
||||||
|
|
||||||
> **Note**
|
> **Note**
|
||||||
>
|
>
|
||||||
> Remote connections to JMX are not enabled by default for security
|
> If JMX is enabled, Apache ActiveMQ Artemis can *not* be managed locally using `jconsole` when connecting as a local process,
|
||||||
> reasons. Please refer to [Java Management
|
> this is because jconsole does not using any authentication when connecting this way. If you want to use jconsole you will
|
||||||
> guide](http://docs.oracle.com/javase/8/docs/technotes/guides/management/agent.html)
|
either have to disable authentication, by removing the `authentication` element or enable remote access.
|
||||||
> to configure the server for remote management (system properties must
|
|
||||||
> be set in `artemis.profile`).
|
#### Configuring remote JMX Access
|
||||||
|
|
||||||
|
By default remote JMX access to Artemis is disabled for security reasons.
|
||||||
|
|
||||||
|
Artemis has a JMX agent which allows access to JMX mBeans remotely. This is configured via the `connector` element in the
|
||||||
|
`management.xml` configuration file. To enable this you simpl ad the following xml:
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<connector connector-port="1099"/>
|
||||||
|
```
|
||||||
|
|
||||||
|
This exposes the agent remotely on the port 1099. If you were connecting via jconsole you would connect as a remote process
|
||||||
|
using the service url `service:jmx:rmi:///jndi/rmi://localhost:1099/jmxrmi` and an appropriate user name and password.
|
||||||
|
|
||||||
|
You can also configure the connector using the following:
|
||||||
|
|
||||||
|
- connector-host The host to expose the agent on
|
||||||
|
- connector-port The port to expose the agent on
|
||||||
|
- jmx-realm The jmx realm to use for authentication, defaults to `activemq` to match the JAAS configuration.
|
||||||
|
- object-name The object name to expose the remote connector on, default is `connector:name=rmi`
|
||||||
|
|
||||||
|
> **Note**
|
||||||
|
>
|
||||||
|
> It is important to note that the rmi registry will pick an ip address to bind to, If you have a multi IP addresses/NICs
|
||||||
|
> present on the system then you can choose the ip address to use by adding the following to artemis.profile
|
||||||
|
> `-Djava.rmi.server.hostname=localhost`
|
||||||
|
|
||||||
|
> **Note**
|
||||||
|
>
|
||||||
|
> Remote connections using the default JVM Agent not enabled by default as Artemis exposes the mBean Server via its own configuration.
|
||||||
|
> This is so Artemis can leverage the JAAS authentication layer via JMX. If you want to expose this then you will need to
|
||||||
|
> disable both the connector and the authorisation by removing them from the `management.xml` configuration.
|
||||||
|
> Please refer to [Java Management guide](http://docs.oracle.com/javase/8/docs/technotes/guides/management/agent.html)
|
||||||
|
> to configure the server for remote management (system properties must be set in `artemis.profile`).
|
||||||
|
|
||||||
By default, Apache ActiveMQ Artemis server uses the JMX domain "org.apache.activemq.artemis".
|
By default, Apache ActiveMQ Artemis server uses the JMX domain "org.apache.activemq.artemis".
|
||||||
To manage several Apache ActiveMQ Artemis servers from the *same* MBeanServer, the JMX
|
To manage several Apache ActiveMQ Artemis servers from the *same* MBeanServer, the JMX
|
||||||
|
@ -315,12 +431,6 @@ domain can be configured for each individual Apache ActiveMQ Artemis server by s
|
||||||
<!-- use a specific JMX domain for ActiveMQ Artemis MBeans -->
|
<!-- use a specific JMX domain for ActiveMQ Artemis MBeans -->
|
||||||
<jmx-domain>my.org.apache.activemq</jmx-domain>
|
<jmx-domain>my.org.apache.activemq</jmx-domain>
|
||||||
|
|
||||||
#### MBeanServer configuration
|
|
||||||
|
|
||||||
When Apache ActiveMQ Artemis is run in standalone, it uses the Java Virtual Machine's
|
|
||||||
`Platform MBeanServer` to register its MBeans. By default, [Jolokia](http://www.jolokia.org/)
|
|
||||||
is also deployed to allow access to the MBean server via [REST](https://en.wikipedia.org/wiki/Representational_state_transfer).
|
|
||||||
|
|
||||||
### Example
|
### Example
|
||||||
|
|
||||||
See the [Examples](examples.md) chapter for an example which shows how to use a remote connection to JMX
|
See the [Examples](examples.md) chapter for an example which shows how to use a remote connection to JMX
|
||||||
|
@ -333,12 +443,23 @@ HTTP agent deployed as a Web Application. Jolokia is a remote
|
||||||
JMX-over-HTTP bridge that exposes MBeans. For a full guide as
|
JMX-over-HTTP bridge that exposes MBeans. For a full guide as
|
||||||
to how to use it refer to [Jolokia Documentation](http://www.jolokia.org/documentation.html),
|
to how to use it refer to [Jolokia Documentation](http://www.jolokia.org/documentation.html),
|
||||||
however a simple example to query the broker's version would
|
however a simple example to query the broker's version would
|
||||||
be to use a browser and go to the URL [http://localhost:8161/jolokia/read/org.apache.activemq.artemis:broker="0.0.0.0"/Version]().
|
be to use a browser and go to the URL [http://username:password@localhost:8161/jolokia/read/org.apache.activemq.artemis:broker="0.0.0.0"/Version]().
|
||||||
|
|
||||||
This would give you back something like the following:
|
This would give you back something like the following:
|
||||||
|
|
||||||
{"request":{"mbean":"org.apache.activemq.artemis:broker=\"0.0.0.0\"","attribute":"Version","type":"read"},"value":"2.0.0-SNAPSHOT","timestamp":1487017918,"status":200}
|
{"request":{"mbean":"org.apache.activemq.artemis:broker=\"0.0.0.0\"","attribute":"Version","type":"read"},"value":"2.0.0-SNAPSHOT","timestamp":1487017918,"status":200}
|
||||||
|
|
||||||
|
### JMX and the Console
|
||||||
|
|
||||||
|
The console that ships with Artemis uses Jolokia under the covers which in turn uses JMX. This will use the authentication
|
||||||
|
configuration in the `management.xml` file as described in the previous section. This means that when mBeans are accessed
|
||||||
|
via the console the credentials used to log into the console and the roles associated with them. By default access to the
|
||||||
|
console is only allow via users with the amq role. This is configured in the `artemis.profile` via the system property `-Dhawtio.role=amq`.
|
||||||
|
You can configure multiple roles by changing this to `-Dhawtio.roles=amq,view,update`.
|
||||||
|
|
||||||
|
If a user doesn't have the correct role to invoke a specific operation then this will display an authorisation exception
|
||||||
|
in the console.
|
||||||
|
|
||||||
## Using Management Via Apache ActiveMQ Artemis API
|
## Using Management Via Apache ActiveMQ Artemis API
|
||||||
|
|
||||||
The management API in ActiveMQ Artemis is accessed by sending Core Client messages
|
The management API in ActiveMQ Artemis is accessed by sending Core Client messages
|
||||||
|
|
|
@ -72,6 +72,7 @@ under the License.
|
||||||
<goal>cli</goal>
|
<goal>cli</goal>
|
||||||
</goals>
|
</goals>
|
||||||
<configuration>
|
<configuration>
|
||||||
|
<debug>true</debug>
|
||||||
<ignore>${noServer}</ignore>
|
<ignore>${noServer}</ignore>
|
||||||
<spawn>true</spawn>
|
<spawn>true</spawn>
|
||||||
<testURI>tcp://localhost:61616</testURI>
|
<testURI>tcp://localhost:61616</testURI>
|
||||||
|
|
|
@ -34,16 +34,12 @@ under the License.
|
||||||
<h2>Example configuration</h2>
|
<h2>Example configuration</h2>
|
||||||
|
|
||||||
<p>ActiveMQ Artemis exposes its managed resources by default on the platform MBeanServer.</p>
|
<p>ActiveMQ Artemis exposes its managed resources by default on the platform MBeanServer.</p>
|
||||||
<p>To access this MBeanServer remotely, the Java Virtual machine must be started with system properties:
|
<p>To access this MBeanServer remotely, add the following to the management.xml configuration:
|
||||||
<pre class="prettyprint">
|
<pre class="prettyprint">
|
||||||
<code>-Dcom.sun.management.jmxremote
|
<code><connector connector-port="1099" connector-host="127.0.0.1"/></code>
|
||||||
-Dcom.sun.management.jmxremote.port=3000
|
|
||||||
-Dcom.sun.management.jmxremote.ssl=false
|
|
||||||
-Dcom.sun.management.jmxremote.authenticate=false</code>
|
|
||||||
</pre>
|
</pre>
|
||||||
<p>These properties are explained in the Java <a href="http://docs.oracle.com/javase/8/docs/technotes/guides/management/agent.html#gdenl">management guide</a>
|
<p>If the example does not work then try changing the host to the ip address of the machine running this example on</p>
|
||||||
(please note that for this example, we will disable user authentication for simplicity sake).</p>
|
<p>With these properties, ActiveMQ Artemis server will be manageable remotely using standard JMX URL on port <code>1099</code>.</p>
|
||||||
<p>With these properties, ActiveMQ Artemis server will be manageable remotely using standard JMX URL on port <code>3000</code>.</p>
|
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h2>Example step-by-step</h2>
|
<h2>Example step-by-step</h2>
|
||||||
|
|
|
@ -44,7 +44,7 @@ import org.apache.activemq.artemis.jms.client.ActiveMQTextMessage;
|
||||||
*/
|
*/
|
||||||
public class JMXExample {
|
public class JMXExample {
|
||||||
|
|
||||||
private static final String JMX_URL = "service:jmx:rmi:///jndi/rmi://localhost:3000/jmxrmi";
|
private static final String JMX_URL = "service:jmx:rmi:///jndi/rmi://localhost:1099/jmxrmi";
|
||||||
|
|
||||||
public static void main(final String[] args) throws Exception {
|
public static void main(final String[] args) throws Exception {
|
||||||
QueueConnection connection = null;
|
QueueConnection connection = null;
|
||||||
|
@ -79,7 +79,11 @@ public class JMXExample {
|
||||||
ObjectName on = ObjectNameBuilder.DEFAULT.getQueueObjectName(SimpleString.toSimpleString(queue.getQueueName()), SimpleString.toSimpleString(queue.getQueueName()), RoutingType.ANYCAST);
|
ObjectName on = ObjectNameBuilder.DEFAULT.getQueueObjectName(SimpleString.toSimpleString(queue.getQueueName()), SimpleString.toSimpleString(queue.getQueueName()), RoutingType.ANYCAST);
|
||||||
|
|
||||||
// Step 10. Create JMX Connector to connect to the server's MBeanServer
|
// Step 10. Create JMX Connector to connect to the server's MBeanServer
|
||||||
JMXConnector connector = JMXConnectorFactory.connect(new JMXServiceURL(JMXExample.JMX_URL), new HashMap());
|
HashMap env = new HashMap();
|
||||||
|
String[] creds = {"admin", "password"};
|
||||||
|
env.put(JMXConnector.CREDENTIALS, creds);
|
||||||
|
|
||||||
|
JMXConnector connector = JMXConnectorFactory.connect(new JMXServiceURL(JMXExample.JMX_URL), env);
|
||||||
|
|
||||||
// Step 11. Retrieve the MBeanServerConnection
|
// Step 11. Retrieve the MBeanServerConnection
|
||||||
MBeanServerConnection mbsc = connector.getMBeanServerConnection();
|
MBeanServerConnection mbsc = connector.getMBeanServerConnection();
|
||||||
|
|
|
@ -0,0 +1,49 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||||
|
<!--
|
||||||
|
~ 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.
|
||||||
|
-->
|
||||||
|
<management-context xmlns="http://activemq.org/schema">
|
||||||
|
<connector connector-port="1099" connector-host="127.0.0.1"/>
|
||||||
|
<authorisation>
|
||||||
|
<whitelist>
|
||||||
|
<entry domain="hawtio"/>
|
||||||
|
</whitelist>
|
||||||
|
<default-access>
|
||||||
|
<access method="list*" roles="view,update,amq"/>
|
||||||
|
<access method="get*" roles="view,update,amq"/>
|
||||||
|
<access method="is*" roles="view,update,amq"/>
|
||||||
|
<access method="set*" roles="update,amq"/>
|
||||||
|
<access method="*" roles="amq"/>
|
||||||
|
</default-access>
|
||||||
|
<role-access>
|
||||||
|
<match domain="org.apache.activemq.apache">
|
||||||
|
<access method="list*" roles="view,update,amq"/>
|
||||||
|
<access method="get*" roles="view,update,amq"/>
|
||||||
|
<access method="is*" roles="view,update,amq"/>
|
||||||
|
<access method="set*" roles="update,amq"/>
|
||||||
|
<access method="*" roles="amq"/>
|
||||||
|
</match>
|
||||||
|
<!--example of how to configure a specific object-->
|
||||||
|
<!--<match domain="org.apache.activemq.apache" key="subcomponent=queues">
|
||||||
|
<access method="list*" roles="view,update,amq"/>
|
||||||
|
<access method="get*" roles="view,update,amq"/>
|
||||||
|
<access method="is*" roles="view,update,amq"/>
|
||||||
|
<access method="set*" roles="update,amq"/>
|
||||||
|
<access method="*" roles="amq"/>
|
||||||
|
</match>-->
|
||||||
|
</role-access>
|
||||||
|
</authorisation>
|
||||||
|
</management-context>
|
|
@ -0,0 +1,94 @@
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
* <p>
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* <p>
|
||||||
|
* 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.artemis.tests.integration.management;
|
||||||
|
|
||||||
|
|
||||||
|
import org.apache.activemq.artemis.spi.core.security.jaas.RolePrincipal;
|
||||||
|
|
||||||
|
import javax.security.auth.Subject;
|
||||||
|
import javax.security.auth.callback.Callback;
|
||||||
|
import javax.security.auth.callback.CallbackHandler;
|
||||||
|
import javax.security.auth.callback.NameCallback;
|
||||||
|
import javax.security.auth.callback.PasswordCallback;
|
||||||
|
import javax.security.auth.callback.UnsupportedCallbackException;
|
||||||
|
import javax.security.auth.login.FailedLoginException;
|
||||||
|
import javax.security.auth.login.LoginException;
|
||||||
|
import javax.security.auth.spi.LoginModule;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class DummyLoginModule implements LoginModule {
|
||||||
|
private Subject subject;
|
||||||
|
private CallbackHandler callbackHandler;
|
||||||
|
private Map<String, ?> sharedState;
|
||||||
|
private Map<String, ?> options;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initialize(Subject subject, CallbackHandler callbackHandler, Map<String, ?> sharedState, Map<String, ?> options) {
|
||||||
|
this.subject = subject;
|
||||||
|
this.callbackHandler = callbackHandler;
|
||||||
|
this.sharedState = sharedState;
|
||||||
|
this.options = options;
|
||||||
|
System.out.println("DummyLoginModule.initialize");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean login() throws LoginException {
|
||||||
|
Callback[] callbacks = new Callback[2];
|
||||||
|
|
||||||
|
callbacks[0] = new NameCallback("Username: ");
|
||||||
|
callbacks[1] = new PasswordCallback("Password: ", false);
|
||||||
|
try {
|
||||||
|
callbackHandler.handle(callbacks);
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
throw new LoginException(ioe.getMessage());
|
||||||
|
} catch (UnsupportedCallbackException uce) {
|
||||||
|
throw new LoginException(uce.getMessage() + " not available to obtain information from user");
|
||||||
|
}
|
||||||
|
String user = ((NameCallback) callbacks[0]).getName();
|
||||||
|
char[] tmpPassword = ((PasswordCallback) callbacks[1]).getPassword();
|
||||||
|
if (tmpPassword == null) {
|
||||||
|
tmpPassword = new char[0];
|
||||||
|
}
|
||||||
|
if (user == null) {
|
||||||
|
throw new FailedLoginException("User is null");
|
||||||
|
}
|
||||||
|
subject.getPrincipals().add(new RolePrincipal("amq"));
|
||||||
|
// String password = users.getProperty(user);
|
||||||
|
|
||||||
|
/*if (password == null) {
|
||||||
|
throw new FailedLoginException("User does not exist: " + user);
|
||||||
|
}*/
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean commit() throws LoginException {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean abort() throws LoginException {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean logout() throws LoginException {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
|
@ -76,6 +76,10 @@ public abstract class ManagementTestBase extends ActiveMQTestBase {
|
||||||
public void setUp() throws Exception {
|
public void setUp() throws Exception {
|
||||||
super.setUp();
|
super.setUp();
|
||||||
|
|
||||||
|
createMBeanServer();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void createMBeanServer() {
|
||||||
mbeanServer = MBeanServerFactory.createMBeanServer();
|
mbeanServer = MBeanServerFactory.createMBeanServer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue