ARTEMIS-2243 Fixing ClassLoding and dependency to security domain on method parameter

This commit is contained in:
Clebert Suconic 2019-02-25 12:05:56 -05:00
parent 299e444009
commit da3d7a2940
11 changed files with 110 additions and 89 deletions

View File

@ -410,67 +410,67 @@ public class ArtemisTest extends CliTestBase {
File roleFile = new File(instance1.getAbsolutePath() + "/etc/artemis-roles.properties");
//default only one user admin with role amq
String jsonResult = activeMQServerControl.listUser("", "activemq");
String jsonResult = activeMQServerControl.listUser("");
contains(JsonUtil.readJsonArray(jsonResult), "admin", "amq");
checkRole("admin", roleFile, "amq");
//add a simple user
activeMQServerControl.addUser("guest", "guest123", "admin", true, "activemq");
activeMQServerControl.addUser("guest", "guest123", "admin", true);
//verify add
jsonResult = activeMQServerControl.listUser("", "activemq");
jsonResult = activeMQServerControl.listUser("");
contains(JsonUtil.readJsonArray(jsonResult), "guest", "admin");
checkRole("guest", roleFile, "admin");
assertTrue(checkPassword("guest", "guest123", userFile));
//add a user with 2 roles
activeMQServerControl.addUser("scott", "tiger", "admin,operator", true, "activemq");
activeMQServerControl.addUser("scott", "tiger", "admin,operator", true);
//verify add
jsonResult = activeMQServerControl.listUser("", "activemq");
jsonResult = activeMQServerControl.listUser("");
contains(JsonUtil.readJsonArray(jsonResult), "scott", "admin");
contains(JsonUtil.readJsonArray(jsonResult), "scott", "operator");
checkRole("scott", roleFile, "admin", "operator");
assertTrue(checkPassword("scott", "tiger", userFile));
try {
activeMQServerControl.addUser("scott", "password", "visitor", true, "activemq");
activeMQServerControl.addUser("scott", "password", "visitor", true);
fail("should throw an exception if adding a existing user");
} catch (IllegalArgumentException expected) {
}
//check existing users are intact
jsonResult = activeMQServerControl.listUser("", "activemq");
jsonResult = activeMQServerControl.listUser("");
contains(JsonUtil.readJsonArray(jsonResult), "admin", "amq");
contains(JsonUtil.readJsonArray(jsonResult), "guest", "admin");
contains(JsonUtil.readJsonArray(jsonResult), "scott", "admin");
contains(JsonUtil.readJsonArray(jsonResult), "scott", "operator");
//check listing with just one user
jsonResult = activeMQServerControl.listUser("admin", "activemq");
jsonResult = activeMQServerControl.listUser("admin");
contains(JsonUtil.readJsonArray(jsonResult), "admin", "amq");
contains(JsonUtil.readJsonArray(jsonResult), "guest", "admin", false);
contains(JsonUtil.readJsonArray(jsonResult), "scott", "admin", false);
contains(JsonUtil.readJsonArray(jsonResult), "scott", "operator", false);
//check listing with another single user
jsonResult = activeMQServerControl.listUser("guest", "activemq");
jsonResult = activeMQServerControl.listUser("guest");
contains(JsonUtil.readJsonArray(jsonResult), "admin", "amq", false);
contains(JsonUtil.readJsonArray(jsonResult), "guest", "admin");
contains(JsonUtil.readJsonArray(jsonResult), "scott", "admin", false);
contains(JsonUtil.readJsonArray(jsonResult), "scott", "operator", false);
//remove a user
activeMQServerControl.removeUser("guest", "activemq");
jsonResult = activeMQServerControl.listUser("", "activemq");
activeMQServerControl.removeUser("guest");
jsonResult = activeMQServerControl.listUser("");
contains(JsonUtil.readJsonArray(jsonResult), "admin", "amq");
contains(JsonUtil.readJsonArray(jsonResult), "guest", "admin", false);
contains(JsonUtil.readJsonArray(jsonResult), "scott", "admin");
contains(JsonUtil.readJsonArray(jsonResult), "scott", "operator");
//remove another
activeMQServerControl.removeUser("scott", "activemq");
jsonResult = activeMQServerControl.listUser("", "activemq");
activeMQServerControl.removeUser("scott");
jsonResult = activeMQServerControl.listUser("");
contains(JsonUtil.readJsonArray(jsonResult), "admin", "amq");
contains(JsonUtil.readJsonArray(jsonResult), "guest", "admin", false);
contains(JsonUtil.readJsonArray(jsonResult), "scott", "admin", false);
@ -478,43 +478,23 @@ public class ArtemisTest extends CliTestBase {
//remove non-exist
try {
activeMQServerControl.removeUser("alien", "activemq");
activeMQServerControl.removeUser("alien");
fail("should throw exception when removing a non-existing user");
} catch (IllegalArgumentException expected) {
}
//check
jsonResult = activeMQServerControl.listUser("", "activemq");
jsonResult = activeMQServerControl.listUser("");
contains(JsonUtil.readJsonArray(jsonResult), "admin", "amq");
//now remove last
activeMQServerControl.removeUser("admin", "activemq");
jsonResult = activeMQServerControl.listUser("", "activemq");
activeMQServerControl.removeUser("admin");
jsonResult = activeMQServerControl.listUser("");
contains(JsonUtil.readJsonArray(jsonResult), "admin", "amq", false);
stopServer();
}
@Test
public void testBadSecurityEntryNameViaManagement() throws Exception {
Run.setEmbedded(true);
File instance1 = new File(temporaryFolder.getRoot(), "instance_user");
System.setProperty("java.security.auth.login.config", instance1.getAbsolutePath() + "/etc/login.config");
Artemis.main("create", instance1.getAbsolutePath(), "--silent", "--no-autotune", "--no-web", "--no-amqp-acceptor", "--no-mqtt-acceptor", "--no-stomp-acceptor", "--no-hornetq-acceptor");
System.setProperty("artemis.instance", instance1.getAbsolutePath());
Object result = Artemis.internalExecute("run");
ActiveMQServer activeMQServer = ((Pair<ManagementContext, ActiveMQServer>)result).getB();
ActiveMQServerControl activeMQServerControl = activeMQServer.getActiveMQServerControl();
try {
activeMQServerControl.listUser("", "activemqx");
fail();
} catch (ActiveMQIllegalStateException expected) {
}
stopServer();
}
@Test
public void testMissingUserFileViaManagement() throws Exception {
Run.setEmbedded(true);
@ -531,7 +511,7 @@ public class ArtemisTest extends CliTestBase {
// File roleFile = new File(instance1.getAbsolutePath() + "/etc/artemis-roles.properties");
try {
activeMQServerControl.listUser("", "activemq");
activeMQServerControl.listUser("");
fail();
} catch (ActiveMQIllegalStateException expected) {
}
@ -554,7 +534,7 @@ public class ArtemisTest extends CliTestBase {
roleFile.delete();
try {
activeMQServerControl.listUser("", "activemq");
activeMQServerControl.listUser("");
fail();
} catch (ActiveMQIllegalStateException expected) {
}
@ -676,25 +656,25 @@ public class ArtemisTest extends CliTestBase {
File roleFile = new File(instance1.getAbsolutePath() + "/etc/artemis-roles.properties");
//default only one user admin with role amq
String jsonResult = activeMQServerControl.listUser("", "activemq");
String jsonResult = activeMQServerControl.listUser("");
contains(JsonUtil.readJsonArray(jsonResult), "admin", "amq");
checkRole("admin", roleFile, "amq");
//remove a user
activeMQServerControl.removeUser("admin", "activemq");
jsonResult = activeMQServerControl.listUser("", "activemq");
activeMQServerControl.removeUser("admin");
jsonResult = activeMQServerControl.listUser("");
contains(JsonUtil.readJsonArray(jsonResult), "admin", "amq", false);
//add some users
activeMQServerControl.addUser("guest", "guest123", "admin", true, "activemq");
activeMQServerControl.addUser("user1", "password1", "admin,manager", true, "activemq");
activeMQServerControl.addUser("guest", "guest123", "admin", true);
activeMQServerControl.addUser("user1", "password1", "admin,manager", true);
assertTrue(checkPassword("user1", "password1", userFile));
activeMQServerControl.addUser("user2", "password2", "admin,manager,master", true, "activemq");
activeMQServerControl.addUser("user3", "password3", "system,master", true, "activemq");
activeMQServerControl.addUser("user2", "password2", "admin,manager,master", true);
activeMQServerControl.addUser("user3", "password3", "system,master", true);
//verify use list cmd
jsonResult = activeMQServerControl.listUser("", "activemq");
jsonResult = activeMQServerControl.listUser("");
contains(JsonUtil.readJsonArray(jsonResult), "guest", "admin");
contains(JsonUtil.readJsonArray(jsonResult), "user1", "admin");
contains(JsonUtil.readJsonArray(jsonResult), "user1", "manager");
@ -707,20 +687,20 @@ public class ArtemisTest extends CliTestBase {
checkRole("user1", roleFile, "admin", "manager");
//reset password
activeMQServerControl.resetUser("user1", "newpassword1", null, "activemq");
activeMQServerControl.resetUser("user1", "newpassword1", null);
checkRole("user1", roleFile, "admin", "manager");
assertFalse(checkPassword("user1", "password1", userFile));
assertTrue(checkPassword("user1", "newpassword1", userFile));
//reset role
activeMQServerControl.resetUser("user2", null, "manager,master,operator", "activemq");
activeMQServerControl.resetUser("user2", null, "manager,master,operator");
checkRole("user2", roleFile, "manager", "master", "operator");
assertTrue(checkPassword("user2", "password2", userFile));
//reset both
activeMQServerControl.resetUser("user3", "newpassword3", "admin,system", "activemq");
activeMQServerControl.resetUser("user3", "newpassword3", "admin,system");
checkRole("user3", roleFile, "admin", "system");
assertTrue(checkPassword("user3", "newpassword3", userFile));

View File

@ -1352,52 +1352,43 @@ public interface ActiveMQServerControl {
* @param username
* @param password
* @param roles
* @param entryName
* @throws Exception
*/
@Operation(desc = "add a user (only applicable when using the JAAS PropertiesLoginModule)", impact = MBeanOperationInfo.ACTION)
void addUser(@Parameter(name = "username", desc = "Name of the user") String username,
@Parameter(name = "password", desc = "User's password") String password,
@Parameter(name = "roles (comma separated)", desc = "User's role") String roles,
@Parameter(name = "plaintext", desc = "whether or not to store the password in plaintext or hash it") boolean plaintext,
@Parameter(name = "entryName", desc = "Name of entry in login.config ('activemq' by default)") String entryName) throws Exception;
@Parameter(name = "roles", desc = "User's role (comma separated)") String roles,
@Parameter(name = "plaintext", desc = "whether or not to store the password in plaintext or hash it") boolean plaintext) throws Exception;
/**
* List the information about a user or all users if no username is supplied (only applicable when using the JAAS PropertiesLoginModule).
*
* @param username
* @param entryName
* @return JSON array of user & role information
* @throws Exception
*/
@Operation(desc = "list info about a user or all users if no username is supplied (only applicable when using the JAAS PropertiesLoginModule)", impact = MBeanOperationInfo.ACTION)
String listUser(@Parameter(name = "username", desc = "Name of the user; leave null to list all known users") String username,
@Parameter(name = "entryName", desc = "Name of entry in login.config ('activemq' by default)") String entryName) throws Exception;
String listUser(@Parameter(name = "username", desc = "Name of the user; leave null to list all known users") String username) throws Exception;
/**
* Remove a user (only applicable when using the JAAS PropertiesLoginModule).
*
* @param username
* @param entryName
* @throws Exception
*/
@Operation(desc = "remove a user (only applicable when using the JAAS PropertiesLoginModule)", impact = MBeanOperationInfo.ACTION)
void removeUser(@Parameter(name = "username", desc = "Name of the user") String username,
@Parameter(name = "entryName", desc = "Name of entry in login.config ('activemq' by default)") String entryName) throws Exception;
void removeUser(@Parameter(name = "username", desc = "Name of the user") String username) throws Exception;
/**
* Set new properties on an existing user (only applicable when using the JAAS PropertiesLoginModule).
*
* @param username
* @param password
* @param roles
* @param entryName
* @throws Exception
*/
@Operation(desc = "set new properties on an existing user (only applicable when using the JAAS PropertiesLoginModule)", impact = MBeanOperationInfo.ACTION)
void resetUser(@Parameter(name = "username", desc = "Name of the user") String username,
@Parameter(name = "password", desc = "User's password") String password,
@Parameter(name = "roles (comma separated)", desc = "User's role") String roles,
@Parameter(name = "entryName", desc = "Name of entry in login.config ('activemq' by default)") String entryName) throws Exception;
@Parameter(name = "roles", desc = "User's role (comma separated)") String roles) throws Exception;
}

View File

@ -94,6 +94,7 @@
<include>commons-logging:commons-logging</include>
<include>commons-collections:commons-collections</include>
<include>org.apache.commons:commons-configuration2</include>
<include>org.apache.commons:commons-text</include>
<include>org.apache.commons:commons-lang3</include>
<include>org.fusesource.hawtbuf:hawtbuf</include>
<include>org.jgroups:jgroups</include>

View File

@ -46,7 +46,7 @@ fi
# Set Defaults Properties
JAVA_ARGS="-XX:+UseParallelGC -Xms512M -Xmx1024M"
CLASSPATH="$ARTEMIS_HOME/lib/*"
CLASSPATH="$ARTEMIS_HOME/lib/artemis-boot.jar"
# OS specific support.
cygwin=false;

View File

@ -50,7 +50,7 @@ set JAVA_ARGS=-XX:+UseParallelGC -Xms512M -Xmx1024M
rem "Create full JVM Args"
set JVM_ARGS=%JAVA_ARGS%
if not "%ARTEMIS_CLUSTER_PROPS%"=="" set JVM_ARGS=%JVM_ARGS% %ARTEMIS_CLUSTER_PROPS%
set JVM_ARGS=%JVM_ARGS% -classpath %ARTEMIS_HOME%\lib\*
set JVM_ARGS=%JVM_ARGS% -classpath %ARTEMIS_HOME%\lib\artemis-boot.jar
set JVM_ARGS=%JVM_ARGS% -Dartemis.home=%ARTEMIS_HOME%
if not "%DEBUG_ARGS%"=="" set JVM_ARGS=%JVM_ARGS% %DEBUG_ARGS%

View File

@ -24,6 +24,7 @@ import javax.management.StandardMBean;
import java.nio.ByteBuffer;
import java.util.Collections;
import java.util.Map;
import java.util.concurrent.Callable;
import org.apache.activemq.artemis.api.core.Message;
import org.apache.activemq.artemis.api.core.SimpleString;
@ -33,6 +34,7 @@ import org.apache.activemq.artemis.core.persistence.impl.journal.DummyOperationC
import org.apache.activemq.artemis.core.server.ActiveMQServer;
import org.apache.activemq.artemis.core.server.ServerSession;
import org.apache.activemq.artemis.utils.Base64;
import org.apache.activemq.artemis.utils.RunnableEx;
import org.apache.activemq.artemis.utils.UUIDGenerator;
public abstract class AbstractControl extends StandardMBean {
@ -82,6 +84,26 @@ public abstract class AbstractControl extends StandardMBean {
protected abstract MBeanAttributeInfo[] fillMBeanAttributeInfo();
protected Object tcclCall(ClassLoader loader, Callable<Object> callable) throws Exception {
ClassLoader originalTCCL = Thread.currentThread().getContextClassLoader();
try {
Thread.currentThread().setContextClassLoader(loader);
return callable.call();
} finally {
Thread.currentThread().setContextClassLoader(originalTCCL);
}
}
protected void tcclInvoke(ClassLoader loader, RunnableEx runnableEx) throws Exception {
ClassLoader originalTCCL = Thread.currentThread().getContextClassLoader();
try {
Thread.currentThread().setContextClassLoader(loader);
runnableEx.run();
} finally {
Thread.currentThread().setContextClassLoader(originalTCCL);
}
}
@Override
public MBeanInfo getMBeanInfo() {
MBeanInfo info = super.getMBeanInfo();

View File

@ -2966,15 +2966,28 @@ public class ActiveMQServerControlImpl extends AbstractControl implements Active
}
@Override
public void addUser(String username, String password, String roles, boolean plaintext, String entryName) throws Exception {
PropertiesLoginModuleConfigurator config = getPropertiesLoginModuleConfigurator(entryName);
public void addUser(String username, String password, String roles, boolean plaintext) throws Exception {
tcclInvoke(ActiveMQServerControlImpl.class.getClassLoader(), () -> internalAddUser(username, password, roles, plaintext));
}
private void internalAddUser(String username, String password, String roles, boolean plaintext) throws Exception {
PropertiesLoginModuleConfigurator config = getPropertiesLoginModuleConfigurator();
config.addNewUser(username, plaintext ? password : PasswordMaskingUtil.getHashProcessor().hash(password), roles.split(","));
config.save();
}
private String getSecurityDomain() {
return server.getSecurityManager().getDomain();
}
@Override
public String listUser(String username, String entryName) throws Exception {
PropertiesLoginModuleConfigurator config = getPropertiesLoginModuleConfigurator(entryName);
public String listUser(String username) throws Exception {
return (String)tcclCall(ActiveMQServerControlImpl.class.getClassLoader(), () -> internaListUser(username));
}
private String internaListUser(String username) throws Exception {
PropertiesLoginModuleConfigurator config = getPropertiesLoginModuleConfigurator();
Map<String, Set<String>> info = config.listUser(username);
JsonArrayBuilder users = JsonLoader.createArrayBuilder();
for (Entry<String, Set<String>> entry : info.entrySet()) {
@ -2991,26 +3004,32 @@ public class ActiveMQServerControlImpl extends AbstractControl implements Active
}
@Override
public void removeUser(String username, String entryName) throws Exception {
PropertiesLoginModuleConfigurator config = getPropertiesLoginModuleConfigurator(entryName);
public void removeUser(String username) throws Exception {
tcclInvoke(ActiveMQServerControlImpl.class.getClassLoader(), () -> internalRemoveUser(username));
}
private void internalRemoveUser(String username) throws Exception {
PropertiesLoginModuleConfigurator config = getPropertiesLoginModuleConfigurator();
config.removeUser(username);
config.save();
}
@Override
public void resetUser(String username, String password, String roles, String entryName) throws Exception {
PropertiesLoginModuleConfigurator config = getPropertiesLoginModuleConfigurator(entryName);
public void resetUser(String username, String password, String roles) throws Exception {
tcclInvoke(ActiveMQServerControlImpl.class.getClassLoader(), () -> internalresetUser(username, password, roles));
}
private void internalresetUser(String username, String password, String roles) throws Exception {
PropertiesLoginModuleConfigurator config = getPropertiesLoginModuleConfigurator();
config.updateUser(username, password, roles == null ? null : roles.split(","));
config.save();
}
private PropertiesLoginModuleConfigurator getPropertiesLoginModuleConfigurator(String entryName) throws Exception {
private PropertiesLoginModuleConfigurator getPropertiesLoginModuleConfigurator() throws Exception {
URL configurationUrl = server.getConfiguration().getConfigurationUrl();
if (configurationUrl == null) {
throw ActiveMQMessageBundle.BUNDLE.failedToLocateConfigURL();
}
String path = configurationUrl.getPath();
return new PropertiesLoginModuleConfigurator(entryName, path.substring(0, path.lastIndexOf("/")));
return new PropertiesLoginModuleConfigurator(getSecurityDomain(), path.substring(0, path.lastIndexOf("/")));
}
}

View File

@ -83,6 +83,11 @@ public class ActiveMQJAASSecurityManager implements ActiveMQSecurityManager3 {
this.certificateConfiguration = certificateConfiguration;
}
@Override
public String getDomain() {
return configurationName;
}
@Override
public boolean validateUser(String user, String password) {
throw new UnsupportedOperationException("Invoke validateUser(String, String, X509Certificate[]) instead");

View File

@ -27,6 +27,10 @@ import org.apache.activemq.artemis.core.security.Role;
*/
public interface ActiveMQSecurityManager {
default String getDomain() {
return "activemq";
}
/**
* is this a valid user.
*

View File

@ -2736,7 +2736,7 @@ public class ActiveMQServerControlTest extends ManagementTestBase {
public void testAddUser() throws Exception {
ActiveMQServerControl serverControl = createManagementControl();
try {
serverControl.addUser("x", "x", "x", true, "x");
serverControl.addUser("x", "x", "x", true);
fail();
} catch (Exception expected) {
}
@ -2746,7 +2746,7 @@ public class ActiveMQServerControlTest extends ManagementTestBase {
public void testRemoveUser() throws Exception {
ActiveMQServerControl serverControl = createManagementControl();
try {
serverControl.removeUser("x", "x");
serverControl.removeUser("x");
fail();
} catch (Exception expected) {
}
@ -2756,7 +2756,7 @@ public class ActiveMQServerControlTest extends ManagementTestBase {
public void testListUser() throws Exception {
ActiveMQServerControl serverControl = createManagementControl();
try {
serverControl.listUser("x", "x");
serverControl.listUser("x");
fail();
} catch (Exception expected) {
}
@ -2766,7 +2766,7 @@ public class ActiveMQServerControlTest extends ManagementTestBase {
public void testResetUser() throws Exception {
ActiveMQServerControl serverControl = createManagementControl();
try {
serverControl.resetUser("x","x","x", "x");
serverControl.resetUser("x","x","x");
fail();
} catch (Exception expected) {
}

View File

@ -341,25 +341,24 @@ public class ActiveMQServerControlUsingCoreTest extends ActiveMQServerControlTes
public void addUser(String username,
String password,
String role,
boolean plaintext,
String entryName) throws Exception {
proxy.invokeOperation("addUser", username, password, role, plaintext, entryName);
boolean plaintext) throws Exception {
proxy.invokeOperation("addUser", username, password, role, plaintext);
}
@Override
public String listUser(String username, String entryName) throws Exception {
return (String) proxy.invokeOperation("listUser", username, entryName, String.class);
public String listUser(String username) throws Exception {
return (String) proxy.invokeOperation("listUser", username, String.class);
}
@Override
public void removeUser(String username, String entryName) throws Exception {
proxy.invokeOperation("removeUser", username, entryName);
public void removeUser(String username) throws Exception {
proxy.invokeOperation("removeUser", username);
}
@Override
public void resetUser(String username, String password, String roles, String entryName) throws Exception {
proxy.invokeOperation("resetUser", username, password, roles, entryName);
public void resetUser(String username, String password, String roles) throws Exception {
proxy.invokeOperation("resetUser", username, password, roles);
}
@Override