ARTEMIS-2893 concurrent user admin actions can corrupt properties
When performing concurrent user admin actions (e.g. resetUser, addUser, removeUser on ActiveMQServerControl) when using the PropertiesLoginModule with reload=true the underlying user and role properties files can get corrupted. This commit fixes the issue via the following changes: - Add synchronization to the management commands - Add concurrency controls to underlying file access - Change CLI user commands to use remote methods instead of modifying the files directly. This avoids potential concurrent changes. This change forced me to modify the names of some of the commands' parameters to disambiguate them from connection-related parameters.
This commit is contained in:
parent
054b14829e
commit
276a8bb029
|
@ -18,45 +18,53 @@ package org.apache.activemq.artemis.cli.commands.user;
|
|||
|
||||
import io.airlift.airline.Command;
|
||||
import io.airlift.airline.Option;
|
||||
import org.apache.activemq.artemis.api.core.client.ClientMessage;
|
||||
import org.apache.activemq.artemis.api.core.management.ManagementHelper;
|
||||
import org.apache.activemq.artemis.cli.commands.AbstractAction;
|
||||
import org.apache.activemq.artemis.cli.commands.ActionContext;
|
||||
import org.apache.activemq.artemis.cli.commands.util.HashUtil;
|
||||
import org.apache.activemq.artemis.spi.core.security.jaas.PropertiesLoginModuleConfigurator;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
/**
|
||||
* Adding a new user, example:
|
||||
* ./artemis user add --user guest --role admin --password ***
|
||||
* ./artemis user add --user-command-user guest --role admin --user-command-password ***
|
||||
*/
|
||||
@Command(name = "add", description = "Add a new user")
|
||||
public class AddUser extends PasswordAction {
|
||||
|
||||
@Option(name = "--plaintext", description = "using plaintext (Default false)")
|
||||
@Option(name = "--plaintext", description = "store the password in plaintext (Default: false)")
|
||||
boolean plaintext = false;
|
||||
|
||||
@Override
|
||||
public Object execute(ActionContext context) throws Exception {
|
||||
super.execute(context);
|
||||
|
||||
checkInputUser();
|
||||
checkInputPassword();
|
||||
checkInputRole();
|
||||
|
||||
String hash = plaintext ? password : HashUtil.tryHash(context, password);
|
||||
add(hash, StringUtils.split(role, ","));
|
||||
|
||||
add();
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adding a new user
|
||||
* @param hash the password
|
||||
* @param role the role
|
||||
* @throws IllegalArgumentException if user exists
|
||||
* Add a new user
|
||||
*
|
||||
* @throws Exception if communication with the broker fails
|
||||
*/
|
||||
private void add(String hash, String... role) throws Exception {
|
||||
PropertiesLoginModuleConfigurator config = new PropertiesLoginModuleConfigurator(entry, getBrokerEtc());
|
||||
config.addNewUser(username, hash, role);
|
||||
config.save();
|
||||
context.out.println("User added successfully.");
|
||||
private void add() throws Exception {
|
||||
performCoreManagement(new AbstractAction.ManagementCallback<ClientMessage>() {
|
||||
@Override
|
||||
public void setUpInvocation(ClientMessage message) throws Exception {
|
||||
ManagementHelper.putOperationInvocation(message, "broker", "addUser", userCommandUser, userCommandPassword, role, plaintext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requestSuccessful(ClientMessage reply) throws Exception {
|
||||
context.out.println(userCommandUser + " added successfully.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requestFailed(ClientMessage reply) throws Exception {
|
||||
String errMsg = (String) ManagementHelper.getResult(reply, String.class);
|
||||
context.err.println("Failed to add user " + userCommandUser + ". Reason: " + errMsg);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,12 +16,15 @@
|
|||
*/
|
||||
package org.apache.activemq.artemis.cli.commands.user;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import javax.json.JsonArray;
|
||||
import javax.json.JsonObject;
|
||||
|
||||
import io.airlift.airline.Command;
|
||||
import org.apache.activemq.artemis.api.core.JsonUtil;
|
||||
import org.apache.activemq.artemis.api.core.client.ClientMessage;
|
||||
import org.apache.activemq.artemis.api.core.management.ManagementHelper;
|
||||
import org.apache.activemq.artemis.cli.commands.AbstractAction;
|
||||
import org.apache.activemq.artemis.cli.commands.ActionContext;
|
||||
import org.apache.activemq.artemis.spi.core.security.jaas.PropertiesLoginModuleConfigurator;
|
||||
|
||||
/**
|
||||
* list existing users, example:
|
||||
|
@ -40,20 +43,41 @@ public class ListUser extends UserAction {
|
|||
}
|
||||
|
||||
/**
|
||||
* list a single user or all users
|
||||
* if username is not specified
|
||||
* List a single user or all users if username is not specified
|
||||
*
|
||||
* @throws Exception if communication with the broker fails
|
||||
*/
|
||||
private void list() throws Exception {
|
||||
PropertiesLoginModuleConfigurator config = new PropertiesLoginModuleConfigurator(entry, getBrokerEtc());
|
||||
Map<String, Set<String>> result = config.listUser(username);
|
||||
StringBuilder logMessage = new StringBuilder("--- \"user\"(roles) ---\n");
|
||||
int userCount = 0;
|
||||
for (Map.Entry<String, Set<String>> entry : result.entrySet()) {
|
||||
logMessage.append("\"").append(entry.getKey()).append("\"(");
|
||||
int roleCount = 0;
|
||||
for (String role : entry.getValue()) {
|
||||
logMessage.append(role);
|
||||
if (++roleCount < entry.getValue().size()) {
|
||||
final String[] result = new String[1];
|
||||
|
||||
performCoreManagement(new AbstractAction.ManagementCallback<ClientMessage>() {
|
||||
@Override
|
||||
public void setUpInvocation(ClientMessage message) throws Exception {
|
||||
ManagementHelper.putOperationInvocation(message, "broker", "listUser", userCommandUser);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requestSuccessful(ClientMessage reply) throws Exception {
|
||||
result[0] = (String) ManagementHelper.getResult(reply, String.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requestFailed(ClientMessage reply) throws Exception {
|
||||
String errMsg = (String) ManagementHelper.getResult(reply, String.class);
|
||||
context.err.println("Failed to list user " + userCommandUser + ". Reason: " + errMsg);
|
||||
}
|
||||
});
|
||||
|
||||
// process the JSON results from the broker
|
||||
JsonArray array = JsonUtil.readJsonArray(result[0]);
|
||||
for (JsonObject object : array.getValuesAs(JsonObject.class)) {
|
||||
logMessage.append("\"").append(object.getString("username")).append("\"").append("(");
|
||||
JsonArray roles = object.getJsonArray("roles");
|
||||
for (int i = 0; i < roles.size(); i++) {
|
||||
logMessage.append(roles.getString(i));
|
||||
if ((i + 1) < roles.size()) {
|
||||
logMessage.append(",");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,17 +21,17 @@ import io.airlift.airline.Option;
|
|||
|
||||
public class PasswordAction extends UserAction {
|
||||
|
||||
@Option(name = "--password", description = "the password (Default: input)")
|
||||
String password;
|
||||
@Option(name = "--user-command-password", description = "The password to use for the chosen user command (Default: input)")
|
||||
String userCommandPassword;
|
||||
|
||||
void checkInputPassword() {
|
||||
if (password == null) {
|
||||
password = inputPassword("--password", "Please provide the password:", null);
|
||||
if (userCommandPassword == null) {
|
||||
userCommandPassword = inputPassword("--user-command-password", "Please provide the password to use for the chosen user command:", null);
|
||||
}
|
||||
}
|
||||
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
public void setUserCommandPassword(String userCommandPassword) {
|
||||
this.userCommandPassword = userCommandPassword;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -17,8 +17,10 @@
|
|||
package org.apache.activemq.artemis.cli.commands.user;
|
||||
|
||||
import io.airlift.airline.Command;
|
||||
import org.apache.activemq.artemis.api.core.client.ClientMessage;
|
||||
import org.apache.activemq.artemis.api.core.management.ManagementHelper;
|
||||
import org.apache.activemq.artemis.cli.commands.AbstractAction;
|
||||
import org.apache.activemq.artemis.cli.commands.ActionContext;
|
||||
import org.apache.activemq.artemis.spi.core.security.jaas.PropertiesLoginModuleConfigurator;
|
||||
|
||||
/**
|
||||
* Remove a user, example:
|
||||
|
@ -36,10 +38,23 @@ public class RemoveUser extends UserAction {
|
|||
}
|
||||
|
||||
private void remove() throws Exception {
|
||||
PropertiesLoginModuleConfigurator config = new PropertiesLoginModuleConfigurator(entry, getBrokerEtc());
|
||||
config.removeUser(username);
|
||||
config.save();
|
||||
context.out.println("User removed.");
|
||||
performCoreManagement(new AbstractAction.ManagementCallback<ClientMessage>() {
|
||||
@Override
|
||||
public void setUpInvocation(ClientMessage message) throws Exception {
|
||||
ManagementHelper.putOperationInvocation(message, "broker", "removeUser", userCommandUser);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requestSuccessful(ClientMessage reply) throws Exception {
|
||||
context.out.println(userCommandUser + " removed successfully.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requestFailed(ClientMessage reply) throws Exception {
|
||||
String errMsg = (String) ManagementHelper.getResult(reply, String.class);
|
||||
context.err.println("Failed to remove user " + userCommandUser + ". Reason: " + errMsg);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -18,10 +18,10 @@ package org.apache.activemq.artemis.cli.commands.user;
|
|||
|
||||
import io.airlift.airline.Command;
|
||||
import io.airlift.airline.Option;
|
||||
import org.apache.activemq.artemis.api.core.client.ClientMessage;
|
||||
import org.apache.activemq.artemis.api.core.management.ManagementHelper;
|
||||
import org.apache.activemq.artemis.cli.commands.AbstractAction;
|
||||
import org.apache.activemq.artemis.cli.commands.ActionContext;
|
||||
import org.apache.activemq.artemis.cli.commands.util.HashUtil;
|
||||
import org.apache.activemq.artemis.spi.core.security.jaas.PropertiesLoginModuleConfigurator;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
/**
|
||||
* Reset a user's password or roles, example:
|
||||
|
@ -30,37 +30,35 @@ import org.apache.commons.lang3.StringUtils;
|
|||
@Command(name = "reset", description = "Reset user's password or roles")
|
||||
public class ResetUser extends PasswordAction {
|
||||
|
||||
@Option(name = "--plaintext", description = "using plaintext (Default false)")
|
||||
@Option(name = "--plaintext", description = "store the password in plaintext (Default: false)")
|
||||
boolean plaintext = false;
|
||||
|
||||
@Override
|
||||
public Object execute(ActionContext context) throws Exception {
|
||||
super.execute(context);
|
||||
|
||||
checkInputUser();
|
||||
checkInputPassword();
|
||||
|
||||
if (password != null) {
|
||||
password = plaintext ? password : HashUtil.tryHash(context, password);
|
||||
}
|
||||
|
||||
String[] roles = null;
|
||||
if (role != null) {
|
||||
roles = StringUtils.split(role, ",");
|
||||
}
|
||||
|
||||
reset(password, roles);
|
||||
reset();
|
||||
return null;
|
||||
}
|
||||
|
||||
private void reset(String password, String[] roles) throws Exception {
|
||||
if (password == null && roles == null) {
|
||||
context.err.println("Nothing to update.");
|
||||
return;
|
||||
}
|
||||
PropertiesLoginModuleConfigurator config = new PropertiesLoginModuleConfigurator(entry, getBrokerEtc());
|
||||
config.updateUser(username, password, roles);
|
||||
config.save();
|
||||
context.out.println("User updated");
|
||||
private void reset() throws Exception {
|
||||
performCoreManagement(new AbstractAction.ManagementCallback<ClientMessage>() {
|
||||
@Override
|
||||
public void setUpInvocation(ClientMessage message) throws Exception {
|
||||
ManagementHelper.putOperationInvocation(message, "broker", "resetUser", userCommandUser, userCommandPassword, role, plaintext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requestSuccessful(ClientMessage reply) throws Exception {
|
||||
context.out.println(userCommandUser + " reset successfully.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requestFailed(ClientMessage reply) throws Exception {
|
||||
String errMsg = (String) ManagementHelper.getResult(reply, String.class);
|
||||
context.err.println("Failed to reset user " + userCommandUser + ". Reason: " + errMsg);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,22 +17,19 @@
|
|||
package org.apache.activemq.artemis.cli.commands.user;
|
||||
|
||||
import io.airlift.airline.Option;
|
||||
import org.apache.activemq.artemis.cli.commands.InputAbstract;
|
||||
import org.apache.activemq.artemis.cli.commands.AbstractAction;
|
||||
|
||||
public abstract class UserAction extends InputAbstract {
|
||||
public abstract class UserAction extends AbstractAction {
|
||||
|
||||
@Option(name = "--role", description = "user's role(s), comma separated")
|
||||
String role;
|
||||
|
||||
@Option(name = "--user", description = "The user name (Default: input)")
|
||||
String username = null;
|
||||
|
||||
@Option(name = "--entry", description = "The appConfigurationEntry (default: activemq)")
|
||||
String entry = "activemq";
|
||||
@Option(name = "--user-command-user", description = "The username to use for the chosen user command (Default: input)")
|
||||
String userCommandUser = null;
|
||||
|
||||
void checkInputUser() {
|
||||
if (username == null) {
|
||||
username = input("--user", "Please provider the userName:", null);
|
||||
if (userCommandUser == null) {
|
||||
userCommandUser = input("--user-command-user", "Please provide the username to use for the chosen user command:", null);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -42,8 +39,8 @@ public abstract class UserAction extends InputAbstract {
|
|||
}
|
||||
}
|
||||
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
public void setUserCommandUser(String userCommandUser) {
|
||||
this.userCommandUser = userCommandUser;
|
||||
}
|
||||
|
||||
public void setRole(String role) {
|
||||
|
|
|
@ -344,144 +344,163 @@ public class ArtemisTest extends CliTestBase {
|
|||
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");
|
||||
Artemis.main("create", instance1.getAbsolutePath(), "--silent", "--no-autotune", "--no-web", "--require-login");
|
||||
System.setProperty("artemis.instance", instance1.getAbsolutePath());
|
||||
Artemis.internalExecute("run");
|
||||
|
||||
File userFile = new File(instance1.getAbsolutePath() + "/etc/artemis-users.properties");
|
||||
File roleFile = new File(instance1.getAbsolutePath() + "/etc/artemis-roles.properties");
|
||||
|
||||
ListUser listCmd = new ListUser();
|
||||
TestActionContext context = new TestActionContext();
|
||||
listCmd.execute(context);
|
||||
|
||||
String result = context.getStdout();
|
||||
log.debug("output1:\n" + result);
|
||||
|
||||
//default only one user admin with role amq
|
||||
assertTrue(result.contains("\"admin\"(amq)"));
|
||||
checkRole("admin", roleFile, "amq");
|
||||
|
||||
//add a simple user
|
||||
AddUser addCmd = new AddUser();
|
||||
addCmd.setUsername("guest");
|
||||
addCmd.setPassword("guest123");
|
||||
addCmd.setRole("admin");
|
||||
addCmd.execute(new TestActionContext());
|
||||
|
||||
//verify use list cmd
|
||||
context = new TestActionContext();
|
||||
listCmd.execute(context);
|
||||
result = context.getStdout();
|
||||
log.debug("output2:\n" + result);
|
||||
|
||||
assertTrue(result.contains("\"admin\"(amq)"));
|
||||
assertTrue(result.contains("\"guest\"(admin)"));
|
||||
|
||||
checkRole("guest", roleFile, "admin");
|
||||
assertTrue(checkPassword("guest", "guest123", userFile));
|
||||
|
||||
//add a user with 2 roles
|
||||
addCmd = new AddUser();
|
||||
addCmd.setUsername("scott");
|
||||
addCmd.setPassword("tiger");
|
||||
addCmd.setRole("admin,operator");
|
||||
addCmd.execute(ActionContext.system());
|
||||
|
||||
//verify
|
||||
context = new TestActionContext();
|
||||
listCmd.execute(context);
|
||||
result = context.getStdout();
|
||||
log.debug("output3:\n" + result);
|
||||
|
||||
assertTrue(result.contains("\"admin\"(amq)"));
|
||||
assertTrue(result.contains("\"guest\"(admin)"));
|
||||
assertTrue(result.contains("\"scott\"(admin,operator)"));
|
||||
|
||||
checkRole("scott", roleFile, "admin", "operator");
|
||||
assertTrue(checkPassword("scott", "tiger", userFile));
|
||||
|
||||
//add an existing user
|
||||
addCmd = new AddUser();
|
||||
addCmd.setUsername("scott");
|
||||
addCmd.setPassword("password");
|
||||
addCmd.setRole("visitor");
|
||||
try {
|
||||
File userFile = new File(instance1.getAbsolutePath() + "/etc/artemis-users.properties");
|
||||
File roleFile = new File(instance1.getAbsolutePath() + "/etc/artemis-roles.properties");
|
||||
|
||||
ListUser listCmd = new ListUser();
|
||||
TestActionContext context = new TestActionContext();
|
||||
listCmd.setUser("admin");
|
||||
listCmd.setPassword("admin");
|
||||
listCmd.execute(context);
|
||||
|
||||
String result = context.getStdout();
|
||||
log.debug("output1:\n" + result);
|
||||
|
||||
//default only one user admin with role amq
|
||||
assertTrue(result.contains("\"admin\"(amq)"));
|
||||
checkRole("admin", roleFile, "amq");
|
||||
|
||||
//add a simple user
|
||||
AddUser addCmd = new AddUser();
|
||||
addCmd.setUserCommandUser("guest");
|
||||
addCmd.setUserCommandPassword("guest123");
|
||||
addCmd.setRole("admin");
|
||||
addCmd.setUser("admin");
|
||||
addCmd.setPassword("admin");
|
||||
addCmd.execute(new TestActionContext());
|
||||
|
||||
//verify use list cmd
|
||||
context = new TestActionContext();
|
||||
listCmd.execute(context);
|
||||
result = context.getStdout();
|
||||
log.debug("output2:\n" + result);
|
||||
|
||||
assertTrue(result.contains("\"admin\"(amq)"));
|
||||
assertTrue(result.contains("\"guest\"(admin)"));
|
||||
|
||||
checkRole("guest", roleFile, "admin");
|
||||
assertTrue(checkPassword("guest", "guest123", userFile));
|
||||
|
||||
//add a user with 2 roles
|
||||
addCmd = new AddUser();
|
||||
addCmd.setUserCommandUser("scott");
|
||||
addCmd.setUserCommandPassword("tiger");
|
||||
addCmd.setRole("admin,operator");
|
||||
addCmd.setUser("admin");
|
||||
addCmd.setPassword("admin");
|
||||
addCmd.execute(ActionContext.system());
|
||||
fail("should throw an exception if adding a existing user");
|
||||
} catch (IllegalArgumentException expected) {
|
||||
}
|
||||
|
||||
//check existing users are intact
|
||||
context = new TestActionContext();
|
||||
listCmd.execute(context);
|
||||
result = context.getStdout();
|
||||
log.debug("output4:\n" + result);
|
||||
//verify
|
||||
context = new TestActionContext();
|
||||
listCmd.execute(context);
|
||||
result = context.getStdout();
|
||||
log.debug("output3:\n" + result);
|
||||
|
||||
assertTrue(result.contains("\"admin\"(amq)"));
|
||||
assertTrue(result.contains("\"guest\"(admin)"));
|
||||
assertTrue(result.contains("\"scott\"(admin,operator)"));
|
||||
assertTrue(result.contains("\"admin\"(amq)"));
|
||||
assertTrue(result.contains("\"guest\"(admin)"));
|
||||
assertTrue(result.contains("\"scott\"(admin,operator)"));
|
||||
|
||||
//remove a user
|
||||
RemoveUser rmCmd = new RemoveUser();
|
||||
rmCmd.setUsername("guest");
|
||||
rmCmd.execute(ActionContext.system());
|
||||
checkRole("scott", roleFile, "admin", "operator");
|
||||
assertTrue(checkPassword("scott", "tiger", userFile));
|
||||
|
||||
//check
|
||||
context = new TestActionContext();
|
||||
listCmd.execute(context);
|
||||
result = context.getStdout();
|
||||
log.debug("output5:\n" + result);
|
||||
//add an existing user
|
||||
addCmd = new AddUser();
|
||||
addCmd.setUserCommandUser("scott");
|
||||
addCmd.setUserCommandPassword("password");
|
||||
addCmd.setRole("visitor");
|
||||
addCmd.setUser("admin");
|
||||
addCmd.setPassword("admin");
|
||||
context = new TestActionContext();
|
||||
addCmd.execute(context);
|
||||
result = context.getStderr();
|
||||
assertTrue(result.contains("Failed to add user scott. Reason: AMQ229223: User scott already exists"));
|
||||
|
||||
assertTrue(result.contains("\"admin\"(amq)"));
|
||||
assertFalse(result.contains("\"guest\"(admin)"));
|
||||
assertTrue(result.contains("\"scott\"(admin,operator)") || result.contains("\"scott\"(operator,admin)"));
|
||||
assertTrue(result.contains("Total: 2"));
|
||||
//check existing users are intact
|
||||
context = new TestActionContext();
|
||||
listCmd.execute(context);
|
||||
result = context.getStdout();
|
||||
log.debug("output4:\n" + result);
|
||||
|
||||
//remove another
|
||||
rmCmd = new RemoveUser();
|
||||
rmCmd.setUsername("scott");
|
||||
rmCmd.execute(ActionContext.system());
|
||||
assertTrue(result.contains("\"admin\"(amq)"));
|
||||
assertTrue(result.contains("\"guest\"(admin)"));
|
||||
assertTrue(result.contains("\"scott\"(admin,operator)"));
|
||||
|
||||
//check
|
||||
context = new TestActionContext();
|
||||
listCmd.execute(context);
|
||||
result = context.getStdout();
|
||||
log.debug("output6:\n" + result);
|
||||
|
||||
assertTrue(result.contains("\"admin\"(amq)"));
|
||||
assertFalse(result.contains("\"guest\"(admin)"));
|
||||
assertFalse(result.contains("\"scott\"(admin,operator)") || result.contains("\"scott\"(operator,admin)"));
|
||||
assertTrue(result.contains("Total: 1"));
|
||||
|
||||
//remove non-exist
|
||||
rmCmd = new RemoveUser();
|
||||
rmCmd.setUsername("alien");
|
||||
try {
|
||||
//remove a user
|
||||
RemoveUser rmCmd = new RemoveUser();
|
||||
rmCmd.setUserCommandUser("guest");
|
||||
rmCmd.setUser("admin");
|
||||
rmCmd.setPassword("admin");
|
||||
rmCmd.execute(ActionContext.system());
|
||||
fail("should throw exception when removing a non-existing user");
|
||||
} catch (IllegalArgumentException expected) {
|
||||
|
||||
//check
|
||||
context = new TestActionContext();
|
||||
listCmd.execute(context);
|
||||
result = context.getStdout();
|
||||
log.debug("output5:\n" + result);
|
||||
|
||||
assertTrue(result.contains("\"admin\"(amq)"));
|
||||
assertFalse(result.contains("\"guest\"(admin)"));
|
||||
assertTrue(result.contains("\"scott\"(admin,operator)") || result.contains("\"scott\"(operator,admin)"));
|
||||
assertTrue(result.contains("Total: 2"));
|
||||
|
||||
//remove another
|
||||
rmCmd = new RemoveUser();
|
||||
rmCmd.setUserCommandUser("scott");
|
||||
rmCmd.setUser("admin");
|
||||
rmCmd.setPassword("admin");
|
||||
rmCmd.execute(ActionContext.system());
|
||||
|
||||
//check
|
||||
context = new TestActionContext();
|
||||
listCmd.execute(context);
|
||||
result = context.getStdout();
|
||||
log.debug("output6:\n" + result);
|
||||
|
||||
assertTrue(result.contains("\"admin\"(amq)"));
|
||||
assertFalse(result.contains("\"guest\"(admin)"));
|
||||
assertFalse(result.contains("\"scott\"(admin,operator)") || result.contains("\"scott\"(operator,admin)"));
|
||||
assertTrue(result.contains("Total: 1"));
|
||||
|
||||
//remove non-exist
|
||||
rmCmd = new RemoveUser();
|
||||
rmCmd.setUserCommandUser("alien");
|
||||
rmCmd.setUser("admin");
|
||||
rmCmd.setPassword("admin");
|
||||
context = new TestActionContext();
|
||||
rmCmd.execute(context);
|
||||
result = context.getStderr();
|
||||
assertTrue(result.contains("Failed to remove user alien. Reason: AMQ229224: User alien does not exist"));
|
||||
|
||||
//check
|
||||
context = new TestActionContext();
|
||||
listCmd.execute(context);
|
||||
result = context.getStdout();
|
||||
log.debug("output7:\n" + result);
|
||||
assertTrue(result.contains("\"admin\"(amq)"));
|
||||
assertTrue(result.contains("Total: 1"));
|
||||
|
||||
//now remove last
|
||||
rmCmd = new RemoveUser();
|
||||
rmCmd.setUserCommandUser("admin");
|
||||
rmCmd.setUser("admin");
|
||||
rmCmd.setPassword("admin");
|
||||
rmCmd.execute(ActionContext.system());
|
||||
|
||||
//check
|
||||
context = new TestActionContext();
|
||||
listCmd.execute(context);
|
||||
result = context.getStdout();
|
||||
log.debug("output8:\n" + result);
|
||||
|
||||
assertTrue(result.contains("Total: 0"));
|
||||
} finally {
|
||||
stopServer();
|
||||
}
|
||||
|
||||
//check
|
||||
context = new TestActionContext();
|
||||
listCmd.execute(context);
|
||||
result = context.getStdout();
|
||||
log.debug("output7:\n" + result);
|
||||
assertTrue(result.contains("\"admin\"(amq)"));
|
||||
assertTrue(result.contains("Total: 1"));
|
||||
|
||||
//now remove last
|
||||
rmCmd = new RemoveUser();
|
||||
rmCmd.setUsername("admin");
|
||||
rmCmd.execute(ActionContext.system());
|
||||
|
||||
//check
|
||||
context = new TestActionContext();
|
||||
listCmd.execute(context);
|
||||
result = context.getStdout();
|
||||
log.debug("output8:\n" + result);
|
||||
|
||||
assertTrue(result.contains("Total: 0"));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -687,98 +706,223 @@ public class ArtemisTest extends CliTestBase {
|
|||
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");
|
||||
Artemis.main("create", instance1.getAbsolutePath(), "--silent", "--no-autotune", "--no-web", "--require-login");
|
||||
System.setProperty("artemis.instance", instance1.getAbsolutePath());
|
||||
Artemis.internalExecute("run");
|
||||
|
||||
File userFile = new File(instance1.getAbsolutePath() + "/etc/artemis-users.properties");
|
||||
File roleFile = new File(instance1.getAbsolutePath() + "/etc/artemis-roles.properties");
|
||||
try {
|
||||
File userFile = new File(instance1.getAbsolutePath() + "/etc/artemis-users.properties");
|
||||
File roleFile = new File(instance1.getAbsolutePath() + "/etc/artemis-roles.properties");
|
||||
|
||||
ListUser listCmd = new ListUser();
|
||||
TestActionContext context = new TestActionContext();
|
||||
listCmd.execute(context);
|
||||
ListUser listCmd = new ListUser();
|
||||
listCmd.setUser("admin");
|
||||
listCmd.setPassword("admin");
|
||||
TestActionContext context = new TestActionContext();
|
||||
listCmd.execute(context);
|
||||
|
||||
String result = context.getStdout();
|
||||
log.debug("output1:\n" + result);
|
||||
String result = context.getStdout();
|
||||
log.debug("output1:\n" + result);
|
||||
|
||||
//default only one user admin with role amq
|
||||
assertTrue(result.contains("\"admin\"(amq)"));
|
||||
//default only one user admin with role amq
|
||||
assertTrue(result.contains("\"admin\"(amq)"));
|
||||
|
||||
//remove a user
|
||||
RemoveUser rmCmd = new RemoveUser();
|
||||
rmCmd.setUsername("admin");
|
||||
rmCmd.execute(ActionContext.system());
|
||||
//remove a user
|
||||
RemoveUser rmCmd = new RemoveUser();
|
||||
rmCmd.setUserCommandUser("admin");
|
||||
rmCmd.setUser("admin");
|
||||
rmCmd.setPassword("admin");
|
||||
rmCmd.execute(ActionContext.system());
|
||||
|
||||
//check
|
||||
context = new TestActionContext();
|
||||
listCmd.execute(context);
|
||||
result = context.getStdout();
|
||||
log.debug("output8:\n" + result);
|
||||
//check
|
||||
context = new TestActionContext();
|
||||
listCmd.execute(context);
|
||||
result = context.getStdout();
|
||||
log.debug("output8:\n" + result);
|
||||
|
||||
assertTrue(result.contains("Total: 0"));
|
||||
assertTrue(result.contains("Total: 0"));
|
||||
|
||||
//add some users
|
||||
AddUser addCmd = new AddUser();
|
||||
addCmd.setUsername("guest");
|
||||
addCmd.setPassword("guest123");
|
||||
addCmd.setRole("admin");
|
||||
addCmd.execute(new TestActionContext());
|
||||
//add some users
|
||||
AddUser addCmd = new AddUser();
|
||||
addCmd.setUserCommandUser("guest");
|
||||
addCmd.setUserCommandPassword("guest123");
|
||||
addCmd.setRole("admin");
|
||||
addCmd.setUser("admin");
|
||||
addCmd.setPassword("admin");
|
||||
addCmd.execute(new TestActionContext());
|
||||
|
||||
addCmd.setUsername("user1");
|
||||
addCmd.setPassword("password1");
|
||||
addCmd.setRole("admin,manager");
|
||||
addCmd.execute(new TestActionContext());
|
||||
assertTrue(checkPassword("user1", "password1", userFile));
|
||||
addCmd.setUserCommandUser("user1");
|
||||
addCmd.setUserCommandPassword("password1");
|
||||
addCmd.setRole("admin,manager");
|
||||
addCmd.execute(new TestActionContext());
|
||||
assertTrue(checkPassword("user1", "password1", userFile));
|
||||
|
||||
addCmd.setUsername("user2");
|
||||
addCmd.setPassword("password2");
|
||||
addCmd.setRole("admin,manager,master");
|
||||
addCmd.execute(new TestActionContext());
|
||||
addCmd.setUserCommandUser("user2");
|
||||
addCmd.setUserCommandPassword("password2");
|
||||
addCmd.setRole("admin,manager,master");
|
||||
addCmd.execute(new TestActionContext());
|
||||
|
||||
addCmd.setUsername("user3");
|
||||
addCmd.setPassword("password3");
|
||||
addCmd.setRole("system,master");
|
||||
addCmd.execute(new TestActionContext());
|
||||
addCmd.setUserCommandUser("user3");
|
||||
addCmd.setUserCommandPassword("password3");
|
||||
addCmd.setRole("system,master");
|
||||
addCmd.execute(new TestActionContext());
|
||||
|
||||
//verify use list cmd
|
||||
context = new TestActionContext();
|
||||
listCmd.execute(context);
|
||||
result = context.getStdout();
|
||||
log.debug("output2:\n" + result);
|
||||
//verify use list cmd
|
||||
context = new TestActionContext();
|
||||
listCmd.execute(context);
|
||||
result = context.getStdout();
|
||||
log.debug("output2:\n" + result);
|
||||
|
||||
assertTrue(result.contains("Total: 4"));
|
||||
assertTrue(result.contains("\"guest\"(admin)"));
|
||||
assertTrue(Pattern.compile("\"user1\"\\((admin|manager),(admin|manager)\\)").matcher(result).find());
|
||||
assertTrue(Pattern.compile("\"user2\"\\((admin|manager|master),(admin|manager|master),(admin|manager|master)\\)").matcher(result).find());
|
||||
assertTrue(Pattern.compile("\"user3\"\\((master|system),(master|system)\\)").matcher(result).find());
|
||||
assertTrue(result.contains("Total: 4"));
|
||||
assertTrue(result.contains("\"guest\"(admin)"));
|
||||
assertTrue(Pattern
|
||||
.compile("\"user1\"\\((admin|manager),(admin|manager)\\)")
|
||||
.matcher(result)
|
||||
.find());
|
||||
assertTrue(Pattern
|
||||
.compile("\"user2\"\\((admin|manager|master),(admin|manager|master),(admin|manager|master)\\)")
|
||||
.matcher(result)
|
||||
.find());
|
||||
assertTrue(Pattern
|
||||
.compile("\"user3\"\\((master|system),(master|system)\\)")
|
||||
.matcher(result)
|
||||
.find());
|
||||
|
||||
checkRole("user1", roleFile, "admin", "manager");
|
||||
checkRole("user1", roleFile, "admin", "manager");
|
||||
|
||||
//reset password
|
||||
context = new TestActionContext();
|
||||
ResetUser resetCommand = new ResetUser();
|
||||
resetCommand.setUsername("user1");
|
||||
resetCommand.setPassword("newpassword1");
|
||||
resetCommand.execute(context);
|
||||
//reset password
|
||||
context = new TestActionContext();
|
||||
ResetUser resetCommand = new ResetUser();
|
||||
resetCommand.setUserCommandUser("user1");
|
||||
resetCommand.setUserCommandPassword("newpassword1");
|
||||
resetCommand.setUser("admin");
|
||||
resetCommand.setPassword("admin");
|
||||
resetCommand.execute(context);
|
||||
|
||||
checkRole("user1", roleFile, "admin", "manager");
|
||||
assertFalse(checkPassword("user1", "password1", userFile));
|
||||
assertTrue(checkPassword("user1", "newpassword1", userFile));
|
||||
checkRole("user1", roleFile, "admin", "manager");
|
||||
assertFalse(checkPassword("user1", "password1", userFile));
|
||||
assertTrue(checkPassword("user1", "newpassword1", userFile));
|
||||
|
||||
//reset role
|
||||
resetCommand.setUsername("user2");
|
||||
resetCommand.setRole("manager,master,operator");
|
||||
resetCommand.execute(new TestActionContext());
|
||||
//reset role
|
||||
resetCommand.setUserCommandUser("user2");
|
||||
resetCommand.setRole("manager,master,operator");
|
||||
resetCommand.execute(new TestActionContext());
|
||||
|
||||
checkRole("user2", roleFile, "manager", "master", "operator");
|
||||
checkRole("user2", roleFile, "manager", "master", "operator");
|
||||
|
||||
//reset both
|
||||
resetCommand.setUsername("user3");
|
||||
resetCommand.setPassword("newpassword3");
|
||||
resetCommand.setRole("admin,system");
|
||||
resetCommand.execute(new ActionContext());
|
||||
//reset both
|
||||
resetCommand.setUserCommandUser("user3");
|
||||
resetCommand.setUserCommandPassword("newpassword3");
|
||||
resetCommand.setRole("admin,system");
|
||||
resetCommand.execute(new ActionContext());
|
||||
|
||||
checkRole("user3", roleFile, "admin", "system");
|
||||
assertTrue(checkPassword("user3", "newpassword3", userFile));
|
||||
checkRole("user3", roleFile, "admin", "system");
|
||||
assertTrue(checkPassword("user3", "newpassword3", userFile));
|
||||
} finally {
|
||||
stopServer();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConcurrentUserAdministration() 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", "--require-login");
|
||||
System.setProperty("artemis.instance", instance1.getAbsolutePath());
|
||||
Artemis.internalExecute("run");
|
||||
|
||||
try {
|
||||
File userFile = new File(instance1.getAbsolutePath() + "/etc/artemis-users.properties");
|
||||
File roleFile = new File(instance1.getAbsolutePath() + "/etc/artemis-roles.properties");
|
||||
|
||||
TestActionContext context = new TestActionContext();
|
||||
ListUser listCmd = new ListUser();
|
||||
listCmd.setUser("admin");
|
||||
listCmd.setPassword("admin");
|
||||
listCmd.execute(context);
|
||||
|
||||
String result = context.getStdout();
|
||||
log.debug("output1:\n" + result);
|
||||
|
||||
assertTrue(result.contains("Total: 1"));
|
||||
assertTrue(result.contains("\"admin\"(amq)"));
|
||||
|
||||
int nThreads = 4;
|
||||
|
||||
UserAdmin[] userAdminThreads = new UserAdmin[nThreads];
|
||||
for (int j = 0; j < 25; j++) {
|
||||
|
||||
for (int i = 0; i < nThreads; i++) {
|
||||
userAdminThreads[i] = new UserAdmin();
|
||||
}
|
||||
|
||||
for (int i = 0; i < nThreads; i++) {
|
||||
userAdminThreads[i].start();
|
||||
}
|
||||
|
||||
for (UserAdmin userAdmin : userAdminThreads) {
|
||||
userAdmin.join();
|
||||
}
|
||||
}
|
||||
|
||||
context = new TestActionContext();
|
||||
listCmd = new ListUser();
|
||||
listCmd.setUser("admin");
|
||||
listCmd.setPassword("admin");
|
||||
listCmd.execute(context);
|
||||
|
||||
result = context.getStdout();
|
||||
log.debug("output2:\n" + result);
|
||||
|
||||
// make sure the admin user is still in tact (i.e. that the file wasn't corrupted via concurrent access)
|
||||
assertTrue(result.contains("\"admin\"(amq)"));
|
||||
checkRole("admin", roleFile, "amq");
|
||||
checkPassword("admin", "admin", userFile);
|
||||
} finally {
|
||||
stopServer();
|
||||
}
|
||||
}
|
||||
|
||||
private class UserAdmin extends Thread {
|
||||
@Override
|
||||
public void run() {
|
||||
//remove "myuser""
|
||||
RemoveUser rmCmd = new RemoveUser();
|
||||
rmCmd.setUserCommandUser("myuser");
|
||||
rmCmd.setUser("admin");
|
||||
rmCmd.setPassword("admin");
|
||||
try {
|
||||
rmCmd.execute(new TestActionContext());
|
||||
} catch (Exception e) {
|
||||
// this could fail if the user doesn't exist
|
||||
}
|
||||
|
||||
//create user 'myuser' with password 'mypassword'
|
||||
AddUser addCmd = new AddUser();
|
||||
addCmd.setUserCommandUser("myuser");
|
||||
addCmd.setUserCommandPassword("mypassword");
|
||||
addCmd.setRole("foo");
|
||||
addCmd.setUser("admin");
|
||||
addCmd.setPassword("admin");
|
||||
try {
|
||||
addCmd.execute(new TestActionContext());
|
||||
} catch (Exception e) {
|
||||
// this could fail if the user already exists
|
||||
}
|
||||
|
||||
//reset 'myuser' with role 'myrole'
|
||||
ResetUser resetCmd = new ResetUser();
|
||||
resetCmd.setUserCommandUser("myuser");
|
||||
resetCmd.setUserCommandPassword("mypassword");
|
||||
resetCmd.setRole("myrole");
|
||||
resetCmd.setUser("admin");
|
||||
resetCmd.setPassword("admin");
|
||||
try {
|
||||
resetCmd.execute(new TestActionContext());
|
||||
} catch (Exception e) {
|
||||
// this could fail if the user doesn't exist
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -787,21 +931,28 @@ public class ArtemisTest extends CliTestBase {
|
|||
Run.setEmbedded(true);
|
||||
File instanceRole = new File(temporaryFolder.getRoot(), "instance_role");
|
||||
System.setProperty("java.security.auth.login.config", instanceRole.getAbsolutePath() + "/etc/login.config");
|
||||
Artemis.main("create", instanceRole.getAbsolutePath(), "--silent", "--no-autotune", "--role", roleWithSpaces);
|
||||
Artemis.main("create", instanceRole.getAbsolutePath(), "--silent", "--no-autotune", "--no-web", "--require-login", "--role", roleWithSpaces);
|
||||
System.setProperty("artemis.instance", instanceRole.getAbsolutePath());
|
||||
Artemis.internalExecute("run");
|
||||
|
||||
File roleFile = new File(instanceRole.getAbsolutePath() + "/etc/artemis-roles.properties");
|
||||
try {
|
||||
File roleFile = new File(instanceRole.getAbsolutePath() + "/etc/artemis-roles.properties");
|
||||
|
||||
ListUser listCmd = new ListUser();
|
||||
TestActionContext context = new TestActionContext();
|
||||
listCmd.execute(context);
|
||||
ListUser listCmd = new ListUser();
|
||||
listCmd.setUser("admin");
|
||||
listCmd.setPassword("admin");
|
||||
TestActionContext context = new TestActionContext();
|
||||
listCmd.execute(context);
|
||||
|
||||
String result = context.getStdout();
|
||||
log.debug("output1:\n" + result);
|
||||
String result = context.getStdout();
|
||||
log.debug("output1:\n" + result);
|
||||
|
||||
assertTrue(result.contains("\"admin\"(" + roleWithSpaces + ")"));
|
||||
assertTrue(result.contains("\"admin\"(" + roleWithSpaces + ")"));
|
||||
|
||||
checkRole("admin", roleFile, roleWithSpaces);
|
||||
checkRole("admin", roleFile, roleWithSpaces);
|
||||
} finally {
|
||||
stopServer();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -155,9 +155,8 @@ public class ActiveMQServerControlImpl extends AbstractControl implements Active
|
|||
private final NotificationBroadcasterSupport broadcaster;
|
||||
|
||||
private final AtomicLong notifSeq = new AtomicLong(0);
|
||||
// Static --------------------------------------------------------
|
||||
|
||||
// Constructors --------------------------------------------------
|
||||
private final Object userLock = new Object();
|
||||
|
||||
public ActiveMQServerControlImpl(final PostOffice postOffice,
|
||||
final Configuration configuration,
|
||||
|
@ -4183,18 +4182,16 @@ public class ActiveMQServerControlImpl extends AbstractControl implements Active
|
|||
|
||||
@Override
|
||||
public void addUser(String username, String password, String roles, boolean plaintext) throws Exception {
|
||||
if (AuditLogger.isEnabled()) {
|
||||
AuditLogger.addUser(this.server, username, "****", roles, plaintext);
|
||||
synchronized (userLock) {
|
||||
if (AuditLogger.isEnabled()) {
|
||||
AuditLogger.addUser(this.server, username, "****", roles, plaintext);
|
||||
}
|
||||
tcclInvoke(ActiveMQServerControlImpl.class.getClassLoader(), () -> {
|
||||
PropertiesLoginModuleConfigurator config = getPropertiesLoginModuleConfigurator();
|
||||
config.addNewUser(username, plaintext ? password : PasswordMaskingUtil.getHashProcessor().hash(password), roles.split(","));
|
||||
config.save();
|
||||
});
|
||||
}
|
||||
|
||||
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() {
|
||||
|
@ -4203,64 +4200,67 @@ public class ActiveMQServerControlImpl extends AbstractControl implements Active
|
|||
|
||||
@Override
|
||||
public String listUser(String username) throws Exception {
|
||||
if (AuditLogger.isEnabled()) {
|
||||
AuditLogger.listUser(this.server, username);
|
||||
}
|
||||
|
||||
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()) {
|
||||
JsonObjectBuilder user = JsonLoader.createObjectBuilder();
|
||||
user.add("username", entry.getKey());
|
||||
JsonArrayBuilder roles = JsonLoader.createArrayBuilder();
|
||||
for (String role : entry.getValue()) {
|
||||
roles.add(role);
|
||||
synchronized (userLock) {
|
||||
if (AuditLogger.isEnabled()) {
|
||||
AuditLogger.listUser(this.server, username);
|
||||
}
|
||||
user.add("roles", roles);
|
||||
users.add(user);
|
||||
|
||||
return (String) tcclCall(ActiveMQServerControlImpl.class.getClassLoader(), () -> {
|
||||
PropertiesLoginModuleConfigurator config = getPropertiesLoginModuleConfigurator();
|
||||
Map<String, Set<String>> info = config.listUser(username);
|
||||
JsonArrayBuilder users = JsonLoader.createArrayBuilder();
|
||||
for (Entry<String, Set<String>> entry : info.entrySet()) {
|
||||
JsonObjectBuilder user = JsonLoader.createObjectBuilder();
|
||||
user.add("username", entry.getKey());
|
||||
JsonArrayBuilder roles = JsonLoader.createArrayBuilder();
|
||||
for (String role : entry.getValue()) {
|
||||
roles.add(role);
|
||||
}
|
||||
user.add("roles", roles);
|
||||
users.add(user);
|
||||
}
|
||||
return users.build().toString();
|
||||
});
|
||||
}
|
||||
return users.build().toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeUser(String username) throws Exception {
|
||||
if (AuditLogger.isEnabled()) {
|
||||
AuditLogger.removeUser(this.server, username);
|
||||
synchronized (userLock) {
|
||||
if (AuditLogger.isEnabled()) {
|
||||
AuditLogger.removeUser(this.server, username);
|
||||
}
|
||||
tcclInvoke(ActiveMQServerControlImpl.class.getClassLoader(), () -> {
|
||||
PropertiesLoginModuleConfigurator config = getPropertiesLoginModuleConfigurator();
|
||||
config.removeUser(username);
|
||||
config.save();
|
||||
});
|
||||
}
|
||||
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, boolean plaintext) throws Exception {
|
||||
if (AuditLogger.isEnabled()) {
|
||||
AuditLogger.resetUser(this.server, username, "****", roles, plaintext);
|
||||
synchronized (userLock) {
|
||||
if (AuditLogger.isEnabled()) {
|
||||
AuditLogger.resetUser(this.server, username, "****", roles, plaintext);
|
||||
}
|
||||
tcclInvoke(ActiveMQServerControlImpl.class.getClassLoader(), () -> {
|
||||
PropertiesLoginModuleConfigurator config = getPropertiesLoginModuleConfigurator();
|
||||
// don't hash a null password even if plaintext = false
|
||||
config.updateUser(username, password == null ? password : plaintext ? password : PasswordMaskingUtil
|
||||
.getHashProcessor()
|
||||
.hash(password), roles == null ? null : roles.split(","));
|
||||
config.save();
|
||||
});
|
||||
}
|
||||
tcclInvoke(ActiveMQServerControlImpl.class.getClassLoader(), () -> internalresetUser(username, password, roles, plaintext));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resetUser(String username, String password, String roles) throws Exception {
|
||||
// no need to synchronize here because the method we call is synchronized
|
||||
resetUser(username, password, roles, true);
|
||||
}
|
||||
|
||||
private void internalresetUser(String username, String password, String roles, boolean plaintext) throws Exception {
|
||||
PropertiesLoginModuleConfigurator config = getPropertiesLoginModuleConfigurator();
|
||||
// don't hash a null password even if plaintext = false
|
||||
config.updateUser(username, password == null ? password : plaintext ? password : PasswordMaskingUtil.getHashProcessor().hash(password), roles == null ? null : roles.split(","));
|
||||
config.save();
|
||||
}
|
||||
|
||||
private PropertiesLoginModuleConfigurator getPropertiesLoginModuleConfigurator() throws Exception {
|
||||
URL configurationUrl = server.getConfiguration().getConfigurationUrl();
|
||||
if (configurationUrl == null) {
|
||||
|
|
|
@ -134,8 +134,13 @@ public class PropertiesLoginModuleConfigurator {
|
|||
}
|
||||
|
||||
public void save() throws Exception {
|
||||
userBuilder.save();
|
||||
roleBuilder.save();
|
||||
ReloadableProperties.LOCK.writeLock().lock();
|
||||
try {
|
||||
userBuilder.save();
|
||||
roleBuilder.save();
|
||||
} finally {
|
||||
ReloadableProperties.LOCK.writeLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public void removeUser(String username) {
|
||||
|
|
|
@ -24,6 +24,8 @@ import java.util.HashSet;
|
|||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.locks.ReadWriteLock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.regex.PatternSyntaxException;
|
||||
|
||||
|
@ -34,6 +36,9 @@ public class ReloadableProperties {
|
|||
|
||||
private static final Logger logger = Logger.getLogger(ReloadableProperties.class);
|
||||
|
||||
// use this whenever writing to the underlying properties files from another component
|
||||
public static final ReadWriteLock LOCK = new ReentrantReadWriteLock();
|
||||
|
||||
private Properties props = new Properties();
|
||||
private Map<String, String> invertedProps;
|
||||
private Map<String, Set<String>> invertedValueProps;
|
||||
|
@ -121,6 +126,7 @@ public class ReloadableProperties {
|
|||
}
|
||||
|
||||
private void load(final File source, Properties props) throws IOException {
|
||||
LOCK.readLock().lock();
|
||||
try (FileInputStream in = new FileInputStream(source)) {
|
||||
props.load(in);
|
||||
// if (key.isDecrypt()) {
|
||||
|
@ -132,7 +138,8 @@ public class ReloadableProperties {
|
|||
// ActiveMQServerLogger.LOGGER.info("jasypt is not on the classpath: password decryption disabled.");
|
||||
// }
|
||||
// }
|
||||
|
||||
} finally {
|
||||
LOCK.readLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue