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.GlobalMetadata;
|
||||
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.impl.FileConfiguration;
|
||||
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.jms.server.config.impl.FileJMSConfiguration;
|
||||
|
||||
|
@ -116,6 +118,11 @@ public abstract class Configurable extends ActionAbstract {
|
|||
return brokerDTO;
|
||||
}
|
||||
|
||||
protected ManagementContextDTO getManagementDTO() throws Exception {
|
||||
String configuration = getManagementConfiguration();
|
||||
return ManagementFactory.createJmxAclConfiguration(configuration, getBrokerHome(), getBrokerInstance(), getBrokerURIInstance());
|
||||
}
|
||||
|
||||
protected String getConfiguration() {
|
||||
if (configuration == null) {
|
||||
File xmlFile = new File(new File(new File(getBrokerInstance()), "etc"), "bootstrap.xml");
|
||||
|
@ -130,4 +137,14 @@ public abstract class Configurable extends ActionAbstract {
|
|||
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_LOGGING_PROPERTIES = "etc/logging.properties";
|
||||
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_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
|
||||
filters.remove("${artemis.instance}");
|
||||
write(ETC_BOOTSTRAP_XML, filters, false);
|
||||
write(ETC_MANAGEMENT_XML, filters, false);
|
||||
write(ETC_JOLOKIA_ACCESS_XML, filters, false);
|
||||
|
||||
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.commands.tools.LockAbstract;
|
||||
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.components.ExternalComponent;
|
||||
import org.apache.activemq.artemis.core.server.management.ManagementContext;
|
||||
import org.apache.activemq.artemis.dto.BrokerDTO;
|
||||
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.bootstrap.ActiveMQBootstrapLogger;
|
||||
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);
|
||||
|
||||
private ManagementContext managementContext;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
|
@ -60,6 +65,9 @@ public class Run extends LockAbstract {
|
|||
public Object execute(ActionContext context) throws Exception {
|
||||
super.execute(context);
|
||||
|
||||
ManagementContextDTO managementDTO = getManagementDTO();
|
||||
managementContext = ManagementFactory.create(managementDTO);
|
||||
|
||||
Artemis.printBanner();
|
||||
|
||||
BrokerDTO broker = getBrokerDTO();
|
||||
|
@ -70,6 +78,7 @@ public class Run extends LockAbstract {
|
|||
|
||||
server = BrokerFactory.createServer(broker.server, security);
|
||||
|
||||
managementContext.start();
|
||||
server.start();
|
||||
|
||||
if (broker.web != null) {
|
||||
|
@ -121,11 +130,7 @@ public class Run extends LockAbstract {
|
|||
}
|
||||
if (file.exists()) {
|
||||
try {
|
||||
try {
|
||||
server.stop(true);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
stop();
|
||||
timer.cancel();
|
||||
} finally {
|
||||
System.out.println("Server stopped!");
|
||||
|
@ -142,13 +147,20 @@ public class Run extends LockAbstract {
|
|||
Runtime.getRuntime().addShutdownHook(new Thread("shutdown-hook") {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
server.stop(true);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
Run.this.stop();
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
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_LOGGING_PROPERTIES);
|
||||
openStream(Create.ETC_BOOTSTRAP_XML);
|
||||
openStream(Create.ETC_MANAGEMENT_XML);
|
||||
openStream(Create.ETC_BROKER_XML);
|
||||
openStream(Create.ETC_ARTEMIS_ROLES_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
|
||||
SecurityDTO
|
||||
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 -->
|
||||
<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**
|
||||
>
|
||||
> Remote connections to JMX are not enabled by default for security
|
||||
> reasons. 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`).
|
||||
> If JMX is enabled, Apache ActiveMQ Artemis can *not* be managed locally using `jconsole` when connecting as a local process,
|
||||
> this is because jconsole does not using any authentication when connecting this way. If you want to use jconsole you will
|
||||
either have to disable authentication, by removing the `authentication` element or enable remote access.
|
||||
|
||||
#### 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".
|
||||
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 -->
|
||||
<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
|
||||
|
||||
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
|
||||
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
|
||||
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:
|
||||
|
||||
{"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
|
||||
|
||||
The management API in ActiveMQ Artemis is accessed by sending Core Client messages
|
||||
|
|
|
@ -72,6 +72,7 @@ under the License.
|
|||
<goal>cli</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<debug>true</debug>
|
||||
<ignore>${noServer}</ignore>
|
||||
<spawn>true</spawn>
|
||||
<testURI>tcp://localhost:61616</testURI>
|
||||
|
|
|
@ -34,16 +34,12 @@ under the License.
|
|||
<h2>Example configuration</h2>
|
||||
|
||||
<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">
|
||||
<code>-Dcom.sun.management.jmxremote
|
||||
-Dcom.sun.management.jmxremote.port=3000
|
||||
-Dcom.sun.management.jmxremote.ssl=false
|
||||
-Dcom.sun.management.jmxremote.authenticate=false</code>
|
||||
<code><connector connector-port="1099" connector-host="127.0.0.1"/></code>
|
||||
</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>
|
||||
(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>3000</code>.</p>
|
||||
<p>If the example does not work then try changing the host to the ip address of the machine running this example on</p>
|
||||
<p>With these properties, ActiveMQ Artemis server will be manageable remotely using standard JMX URL on port <code>1099</code>.</p>
|
||||
</p>
|
||||
|
||||
<h2>Example step-by-step</h2>
|
||||
|
|
|
@ -44,7 +44,7 @@ import org.apache.activemq.artemis.jms.client.ActiveMQTextMessage;
|
|||
*/
|
||||
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 {
|
||||
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);
|
||||
|
||||
// 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
|
||||
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 {
|
||||
super.setUp();
|
||||
|
||||
createMBeanServer();
|
||||
}
|
||||
|
||||
protected void createMBeanServer() {
|
||||
mbeanServer = MBeanServerFactory.createMBeanServer();
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue