ARTEMIS-584 add validated user to msg
Implements a new feature to aid in security auditing by adding the name of the validated user to the messages it sends.
This commit is contained in:
parent
2b62bc74fa
commit
765b225924
|
@ -390,6 +390,9 @@ public final class ActiveMQDefaultConfiguration {
|
||||||
// Will this backup server come live on a normal server shutdown
|
// Will this backup server come live on a normal server shutdown
|
||||||
private static boolean DEFAULT_FAILOVER_ON_SERVER_SHUTDOWN = false;
|
private static boolean DEFAULT_FAILOVER_ON_SERVER_SHUTDOWN = false;
|
||||||
|
|
||||||
|
// Will the broker populate the message with the name of the validated user
|
||||||
|
private static boolean DEFAULT_POPULATE_VALIDATED_USER = false;
|
||||||
|
|
||||||
// its possible that you only want a server to partake in scale down as a receiver, via a group. In this case set scale-down to false
|
// its possible that you only want a server to partake in scale down as a receiver, via a group. In this case set scale-down to false
|
||||||
private static boolean DEFAULT_SCALE_DOWN_ENABLED = true;
|
private static boolean DEFAULT_SCALE_DOWN_ENABLED = true;
|
||||||
|
|
||||||
|
@ -1060,6 +1063,13 @@ public final class ActiveMQDefaultConfiguration {
|
||||||
return DEFAULT_FAILOVER_ON_SERVER_SHUTDOWN;
|
return DEFAULT_FAILOVER_ON_SERVER_SHUTDOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Will the broker populate the message with the name of the validated user
|
||||||
|
*/
|
||||||
|
public static boolean isDefaultPopulateValidatedUser() {
|
||||||
|
return DEFAULT_POPULATE_VALIDATED_USER;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* its possible that you only want a server to partake in scale down as a receiver, via a group. In this case set scale-down to false
|
* its possible that you only want a server to partake in scale down as a receiver, via a group. In this case set scale-down to false
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -106,6 +106,11 @@ public interface Message {
|
||||||
*/
|
*/
|
||||||
SimpleString HDR_CONTENT_TYPE = new SimpleString("_AMQ_CONTENT_TYPE");
|
SimpleString HDR_CONTENT_TYPE = new SimpleString("_AMQ_CONTENT_TYPE");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name of the validated user who sent the message. Useful for auditing.
|
||||||
|
*/
|
||||||
|
SimpleString HDR_VALIDATED_USER = new SimpleString("_AMQ_VALIDATED_USER");
|
||||||
|
|
||||||
byte DEFAULT_TYPE = 0;
|
byte DEFAULT_TYPE = 0;
|
||||||
|
|
||||||
byte OBJECT_TYPE = 2;
|
byte OBJECT_TYPE = 2;
|
||||||
|
|
|
@ -49,6 +49,8 @@ public class MessageUtil {
|
||||||
|
|
||||||
public static final String JMSXGROUPID = "JMSXGroupID";
|
public static final String JMSXGROUPID = "JMSXGroupID";
|
||||||
|
|
||||||
|
public static final String JMSXUSERID = "JMSXUserID";
|
||||||
|
|
||||||
public static final SimpleString CONNECTION_ID_PROPERTY_NAME = new SimpleString("__AMQ_CID");
|
public static final SimpleString CONNECTION_ID_PROPERTY_NAME = new SimpleString("__AMQ_CID");
|
||||||
|
|
||||||
// public static ActiveMQBuffer getBodyBuffer(Message message) {
|
// public static ActiveMQBuffer getBodyBuffer(Message message) {
|
||||||
|
@ -155,6 +157,7 @@ public class MessageUtil {
|
||||||
|
|
||||||
public static boolean propertyExists(Message message, String name) {
|
public static boolean propertyExists(Message message, String name) {
|
||||||
return message.containsProperty(new SimpleString(name)) || name.equals(MessageUtil.JMSXDELIVERYCOUNT) ||
|
return message.containsProperty(new SimpleString(name)) || name.equals(MessageUtil.JMSXDELIVERYCOUNT) ||
|
||||||
MessageUtil.JMSXGROUPID.equals(name) && message.containsProperty(Message.HDR_GROUP_ID);
|
(MessageUtil.JMSXGROUPID.equals(name) && message.containsProperty(Message.HDR_GROUP_ID)) ||
|
||||||
|
(MessageUtil.JMSXUSERID.equals(name) && message.containsProperty(Message.HDR_VALIDATED_USER));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -581,6 +581,9 @@ public class ActiveMQMessage implements javax.jms.Message {
|
||||||
if (MessageUtil.JMSXGROUPID.equals(name)) {
|
if (MessageUtil.JMSXGROUPID.equals(name)) {
|
||||||
return message.getStringProperty(org.apache.activemq.artemis.api.core.Message.HDR_GROUP_ID);
|
return message.getStringProperty(org.apache.activemq.artemis.api.core.Message.HDR_GROUP_ID);
|
||||||
}
|
}
|
||||||
|
else if (MessageUtil.JMSXUSERID.equals(name)) {
|
||||||
|
return message.getStringProperty(org.apache.activemq.artemis.api.core.Message.HDR_VALIDATED_USER);
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
return message.getStringProperty(new SimpleString(name));
|
return message.getStringProperty(new SimpleString(name));
|
||||||
}
|
}
|
||||||
|
@ -656,7 +659,10 @@ public class ActiveMQMessage implements javax.jms.Message {
|
||||||
public void setStringProperty(final String name, final String value) throws JMSException {
|
public void setStringProperty(final String name, final String value) throws JMSException {
|
||||||
checkProperty(name);
|
checkProperty(name);
|
||||||
|
|
||||||
if (handleGroupID(name, value)) {
|
if (handleCoreProperty(name, value, MessageUtil.JMSXGROUPID, org.apache.activemq.artemis.api.core.Message.HDR_GROUP_ID)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (handleCoreProperty(name, value, MessageUtil.JMSXUSERID, org.apache.activemq.artemis.api.core.Message.HDR_VALIDATED_USER)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -666,7 +672,11 @@ public class ActiveMQMessage implements javax.jms.Message {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setObjectProperty(final String name, final Object value) throws JMSException {
|
public void setObjectProperty(final String name, final Object value) throws JMSException {
|
||||||
if (handleGroupID(name, value)) {
|
if (handleCoreProperty(name, value, MessageUtil.JMSXGROUPID, org.apache.activemq.artemis.api.core.Message.HDR_GROUP_ID)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (handleCoreProperty(name, value, MessageUtil.JMSXUSERID, org.apache.activemq.artemis.api.core.Message.HDR_VALIDATED_USER)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -954,11 +964,11 @@ public class ActiveMQMessage implements javax.jms.Message {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean handleGroupID(final String name, final Object value) {
|
private boolean handleCoreProperty(final String name, final Object value, String jmsPropertyName, SimpleString corePropertyName) {
|
||||||
boolean result = false;
|
boolean result = false;
|
||||||
|
|
||||||
if (MessageUtil.JMSXGROUPID.equals(name)) {
|
if (jmsPropertyName.equals(name)) {
|
||||||
message.putStringProperty(org.apache.activemq.artemis.api.core.Message.HDR_GROUP_ID, SimpleString.toSimpleString(value.toString()));
|
message.putStringProperty(corePropertyName, SimpleString.toSimpleString(value.toString()));
|
||||||
|
|
||||||
result = true;
|
result = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -166,7 +166,7 @@ public final class JMSOpenTypeSupport {
|
||||||
rc.put(JMSCompositeDataConstants.JMS_REDELIVERED, data.get(CompositeDataConstants.REDELIVERED));
|
rc.put(JMSCompositeDataConstants.JMS_REDELIVERED, data.get(CompositeDataConstants.REDELIVERED));
|
||||||
putStringProperty(rc, data, JMSCompositeDataConstants.JMSXGROUP_ID, Message.HDR_GROUP_ID.toString());
|
putStringProperty(rc, data, JMSCompositeDataConstants.JMSXGROUP_ID, Message.HDR_GROUP_ID.toString());
|
||||||
putIntProperty(rc, data, JMSCompositeDataConstants.JMSXGROUP_SEQ, JMSCompositeDataConstants.JMSXGROUP_SEQ);
|
putIntProperty(rc, data, JMSCompositeDataConstants.JMSXGROUP_SEQ, JMSCompositeDataConstants.JMSXGROUP_SEQ);
|
||||||
putStringProperty(rc, data, JMSCompositeDataConstants.JMSXUSER_ID, JMSCompositeDataConstants.JMSXUSER_ID);
|
putStringProperty(rc, data, JMSCompositeDataConstants.JMSXUSER_ID, Message.HDR_VALIDATED_USER.toString());
|
||||||
putStringProperty(rc, data, JMSCompositeDataConstants.ORIGINAL_DESTINATION, Message.HDR_ORIGINAL_ADDRESS.toString());
|
putStringProperty(rc, data, JMSCompositeDataConstants.ORIGINAL_DESTINATION, Message.HDR_ORIGINAL_ADDRESS.toString());
|
||||||
|
|
||||||
rc.put(CompositeDataConstants.PROPERTIES, "" + data.get(CompositeDataConstants.PROPERTIES));
|
rc.put(CompositeDataConstants.PROPERTIES, "" + data.get(CompositeDataConstants.PROPERTIES));
|
||||||
|
|
|
@ -50,6 +50,7 @@ import org.apache.activemq.artemis.spi.core.protocol.RemotingConnection;
|
||||||
import org.apache.activemq.artemis.spi.core.remoting.Acceptor;
|
import org.apache.activemq.artemis.spi.core.remoting.Acceptor;
|
||||||
import org.apache.activemq.artemis.spi.core.remoting.Connection;
|
import org.apache.activemq.artemis.spi.core.remoting.Connection;
|
||||||
import org.apache.activemq.artemis.spi.core.security.ActiveMQSecurityManager;
|
import org.apache.activemq.artemis.spi.core.security.ActiveMQSecurityManager;
|
||||||
|
import org.apache.activemq.artemis.spi.core.security.ActiveMQSecurityManager3;
|
||||||
import org.apache.activemq.artemis.utils.DataConstants;
|
import org.apache.activemq.artemis.utils.DataConstants;
|
||||||
import org.apache.activemq.command.ActiveMQMessage;
|
import org.apache.activemq.command.ActiveMQMessage;
|
||||||
import org.apache.activemq.command.ActiveMQTopic;
|
import org.apache.activemq.command.ActiveMQTopic;
|
||||||
|
@ -442,7 +443,12 @@ public class OpenWireProtocolManager implements ProtocolManager<Interceptor>, Cl
|
||||||
ActiveMQSecurityManager sm = server.getSecurityManager();
|
ActiveMQSecurityManager sm = server.getSecurityManager();
|
||||||
|
|
||||||
if (sm != null && server.getConfiguration().isSecurityEnabled()) {
|
if (sm != null && server.getConfiguration().isSecurityEnabled()) {
|
||||||
validated = sm.validateUser(login, passcode);
|
if (sm instanceof ActiveMQSecurityManager3) {
|
||||||
|
validated = ((ActiveMQSecurityManager3) sm).validateUser(login, passcode, null) != null;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
validated = sm.validateUser(login, passcode);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return validated;
|
return validated;
|
||||||
|
|
|
@ -125,6 +125,8 @@ public interface Stomp {
|
||||||
String ACK = "ack";
|
String ACK = "ack";
|
||||||
|
|
||||||
String PERSISTENT = "persistent";
|
String PERSISTENT = "persistent";
|
||||||
|
|
||||||
|
String VALIDATED_USER = "JMSXUserID";
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface Subscribe {
|
public interface Subscribe {
|
||||||
|
|
|
@ -45,6 +45,7 @@ import org.apache.activemq.artemis.spi.core.protocol.RemotingConnection;
|
||||||
import org.apache.activemq.artemis.spi.core.remoting.Acceptor;
|
import org.apache.activemq.artemis.spi.core.remoting.Acceptor;
|
||||||
import org.apache.activemq.artemis.spi.core.remoting.Connection;
|
import org.apache.activemq.artemis.spi.core.remoting.Connection;
|
||||||
import org.apache.activemq.artemis.spi.core.security.ActiveMQSecurityManager;
|
import org.apache.activemq.artemis.spi.core.security.ActiveMQSecurityManager;
|
||||||
|
import org.apache.activemq.artemis.spi.core.security.ActiveMQSecurityManager3;
|
||||||
import org.apache.activemq.artemis.utils.UUIDGenerator;
|
import org.apache.activemq.artemis.utils.UUIDGenerator;
|
||||||
|
|
||||||
import static org.apache.activemq.artemis.core.protocol.stomp.ActiveMQStompProtocolMessageBundle.BUNDLE;
|
import static org.apache.activemq.artemis.core.protocol.stomp.ActiveMQStompProtocolMessageBundle.BUNDLE;
|
||||||
|
@ -331,7 +332,12 @@ class StompProtocolManager extends AbstractProtocolManager<StompFrame,StompFrame
|
||||||
ActiveMQSecurityManager sm = server.getSecurityManager();
|
ActiveMQSecurityManager sm = server.getSecurityManager();
|
||||||
|
|
||||||
if (sm != null && server.getConfiguration().isSecurityEnabled()) {
|
if (sm != null && server.getConfiguration().isSecurityEnabled()) {
|
||||||
validated = sm.validateUser(login, passcode);
|
if (sm instanceof ActiveMQSecurityManager3) {
|
||||||
|
validated = ((ActiveMQSecurityManager3) sm).validateUser(login, passcode, null) != null;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
validated = sm.validateUser(login, passcode);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return validated;
|
return validated;
|
||||||
|
|
|
@ -26,6 +26,7 @@ import org.apache.activemq.artemis.api.core.SimpleString;
|
||||||
import org.apache.activemq.artemis.core.client.impl.ClientMessageImpl;
|
import org.apache.activemq.artemis.core.client.impl.ClientMessageImpl;
|
||||||
import org.apache.activemq.artemis.core.message.impl.MessageInternal;
|
import org.apache.activemq.artemis.core.message.impl.MessageInternal;
|
||||||
import org.apache.activemq.artemis.core.server.impl.ServerMessageImpl;
|
import org.apache.activemq.artemis.core.server.impl.ServerMessageImpl;
|
||||||
|
import org.apache.activemq.artemis.reader.MessageUtil;
|
||||||
|
|
||||||
public class StompUtils {
|
public class StompUtils {
|
||||||
|
|
||||||
|
@ -51,11 +52,10 @@ public class StompUtils {
|
||||||
msg.setDurable(Boolean.parseBoolean(persistent));
|
msg.setDurable(Boolean.parseBoolean(persistent));
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME should use a proper constant
|
msg.putObjectProperty(MessageUtil.CORRELATIONID_HEADER_NAME, headers.remove(Stomp.Headers.Send.CORRELATION_ID));
|
||||||
msg.putObjectProperty("JMSCorrelationID", headers.remove(Stomp.Headers.Send.CORRELATION_ID));
|
msg.putObjectProperty(MessageUtil.TYPE_HEADER_NAME, headers.remove(Stomp.Headers.Send.TYPE));
|
||||||
msg.putObjectProperty("JMSType", headers.remove(Stomp.Headers.Send.TYPE));
|
|
||||||
|
|
||||||
String groupID = headers.remove("JMSXGroupID");
|
String groupID = headers.remove(MessageUtil.JMSXGROUPID);
|
||||||
if (groupID != null) {
|
if (groupID != null) {
|
||||||
msg.putStringProperty(Message.HDR_GROUP_ID, SimpleString.toSimpleString(groupID));
|
msg.putStringProperty(Message.HDR_GROUP_ID, SimpleString.toSimpleString(groupID));
|
||||||
}
|
}
|
||||||
|
@ -86,8 +86,8 @@ public class StompUtils {
|
||||||
command.addHeader(Stomp.Headers.Message.MESSAGE_ID, String.valueOf(message.getMessageID()));
|
command.addHeader(Stomp.Headers.Message.MESSAGE_ID, String.valueOf(message.getMessageID()));
|
||||||
command.addHeader(Stomp.Headers.Message.DESTINATION, message.getAddress().toString());
|
command.addHeader(Stomp.Headers.Message.DESTINATION, message.getAddress().toString());
|
||||||
|
|
||||||
if (message.getObjectProperty("JMSCorrelationID") != null) {
|
if (message.getObjectProperty(MessageUtil.CORRELATIONID_HEADER_NAME) != null) {
|
||||||
command.addHeader(Stomp.Headers.Message.CORRELATION_ID, message.getObjectProperty("JMSCorrelationID").toString());
|
command.addHeader(Stomp.Headers.Message.CORRELATION_ID, message.getObjectProperty(MessageUtil.CORRELATIONID_HEADER_NAME).toString());
|
||||||
}
|
}
|
||||||
command.addHeader(Stomp.Headers.Message.EXPIRATION_TIME, "" + message.getExpiration());
|
command.addHeader(Stomp.Headers.Message.EXPIRATION_TIME, "" + message.getExpiration());
|
||||||
command.addHeader(Stomp.Headers.Message.REDELIVERED, String.valueOf(deliveryCount > 1));
|
command.addHeader(Stomp.Headers.Message.REDELIVERED, String.valueOf(deliveryCount > 1));
|
||||||
|
@ -98,22 +98,25 @@ public class StompUtils {
|
||||||
}
|
}
|
||||||
command.addHeader(Stomp.Headers.Message.TIMESTAMP, "" + message.getTimestamp());
|
command.addHeader(Stomp.Headers.Message.TIMESTAMP, "" + message.getTimestamp());
|
||||||
|
|
||||||
if (message.getObjectProperty("JMSType") != null) {
|
if (message.getObjectProperty(MessageUtil.TYPE_HEADER_NAME) != null) {
|
||||||
command.addHeader(Stomp.Headers.Message.TYPE, message.getObjectProperty("JMSType").toString());
|
command.addHeader(Stomp.Headers.Message.TYPE, message.getObjectProperty(MessageUtil.TYPE_HEADER_NAME).toString());
|
||||||
}
|
}
|
||||||
if (message.getStringProperty(Message.HDR_CONTENT_TYPE.toString()) != null) {
|
if (message.getStringProperty(Message.HDR_CONTENT_TYPE.toString()) != null) {
|
||||||
command.addHeader(Stomp.Headers.CONTENT_TYPE, message.getStringProperty(Message.HDR_CONTENT_TYPE.toString()));
|
command.addHeader(Stomp.Headers.CONTENT_TYPE, message.getStringProperty(Message.HDR_CONTENT_TYPE.toString()));
|
||||||
}
|
}
|
||||||
|
if (message.getStringProperty(Message.HDR_VALIDATED_USER.toString()) != null) {
|
||||||
|
command.addHeader(Stomp.Headers.Message.VALIDATED_USER, message.getStringProperty(Message.HDR_VALIDATED_USER.toString()));
|
||||||
|
}
|
||||||
|
|
||||||
// now let's add all the message headers
|
// now let's add all the rest of the message headers
|
||||||
Set<SimpleString> names = message.getPropertyNames();
|
Set<SimpleString> names = message.getPropertyNames();
|
||||||
for (SimpleString name : names) {
|
for (SimpleString name : names) {
|
||||||
String value = name.toString();
|
|
||||||
if (name.equals(ClientMessageImpl.REPLYTO_HEADER_NAME) ||
|
if (name.equals(ClientMessageImpl.REPLYTO_HEADER_NAME) ||
|
||||||
name.equals(Message.HDR_CONTENT_TYPE) ||
|
name.equals(Message.HDR_CONTENT_TYPE) ||
|
||||||
value.equals("JMSType") ||
|
name.equals(Message.HDR_VALIDATED_USER) ||
|
||||||
value.equals("JMSCorrelationID") ||
|
name.equals(MessageUtil.TYPE_HEADER_NAME) ||
|
||||||
value.equals(Stomp.Headers.Message.DESTINATION)) {
|
name.equals(MessageUtil.CORRELATIONID_HEADER_NAME) ||
|
||||||
|
name.toString().equals(Stomp.Headers.Message.DESTINATION)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -948,6 +948,10 @@ public interface Configuration {
|
||||||
|
|
||||||
Configuration setStoreConfiguration(StoreConfiguration storeConfiguration);
|
Configuration setStoreConfiguration(StoreConfiguration storeConfiguration);
|
||||||
|
|
||||||
|
boolean isPopulateValidatedUser();
|
||||||
|
|
||||||
|
Configuration setPopulateValidatedUser(boolean populateValidatedUser);
|
||||||
|
|
||||||
/** It will return all the connectors in a toString manner for debug purposes. */
|
/** It will return all the connectors in a toString manner for debug purposes. */
|
||||||
String debugConnectors();
|
String debugConnectors();
|
||||||
|
|
||||||
|
|
|
@ -237,6 +237,8 @@ public class ConfigurationImpl implements Configuration, Serializable {
|
||||||
|
|
||||||
private StoreConfiguration storeConfiguration;
|
private StoreConfiguration storeConfiguration;
|
||||||
|
|
||||||
|
protected boolean populateValidatedUser = ActiveMQDefaultConfiguration.isDefaultPopulateValidatedUser();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parent folder for all data folders.
|
* Parent folder for all data folders.
|
||||||
*/
|
*/
|
||||||
|
@ -1352,6 +1354,17 @@ public class ConfigurationImpl implements Configuration, Serializable {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isPopulateValidatedUser() {
|
||||||
|
return populateValidatedUser;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ConfigurationImpl setPopulateValidatedUser(boolean populateValidatedUser) {
|
||||||
|
this.populateValidatedUser = populateValidatedUser;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
final int prime = 31;
|
final int prime = 31;
|
||||||
|
@ -1417,6 +1430,7 @@ public class ConfigurationImpl implements Configuration, Serializable {
|
||||||
result = prime * result + (runSyncSpeedTest ? 1231 : 1237);
|
result = prime * result + (runSyncSpeedTest ? 1231 : 1237);
|
||||||
result = prime * result + scheduledThreadPoolMaxSize;
|
result = prime * result + scheduledThreadPoolMaxSize;
|
||||||
result = prime * result + (securityEnabled ? 1231 : 1237);
|
result = prime * result + (securityEnabled ? 1231 : 1237);
|
||||||
|
result = prime * result + (populateValidatedUser ? 1231 : 1237);
|
||||||
result = prime * result + (int) (securityInvalidationInterval ^ (securityInvalidationInterval >>> 32));
|
result = prime * result + (int) (securityInvalidationInterval ^ (securityInvalidationInterval >>> 32));
|
||||||
result = prime * result + ((securitySettings == null) ? 0 : securitySettings.hashCode());
|
result = prime * result + ((securitySettings == null) ? 0 : securitySettings.hashCode());
|
||||||
result = prime * result + (int) (serverDumpInterval ^ (serverDumpInterval >>> 32));
|
result = prime * result + (int) (serverDumpInterval ^ (serverDumpInterval >>> 32));
|
||||||
|
@ -1654,6 +1668,8 @@ public class ConfigurationImpl implements Configuration, Serializable {
|
||||||
return false;
|
return false;
|
||||||
if (securityEnabled != other.securityEnabled)
|
if (securityEnabled != other.securityEnabled)
|
||||||
return false;
|
return false;
|
||||||
|
if (populateValidatedUser != other.populateValidatedUser)
|
||||||
|
return false;
|
||||||
if (securityInvalidationInterval != other.securityInvalidationInterval)
|
if (securityInvalidationInterval != other.securityInvalidationInterval)
|
||||||
return false;
|
return false;
|
||||||
if (securitySettings == null) {
|
if (securitySettings == null) {
|
||||||
|
|
|
@ -274,6 +274,8 @@ public final class FileConfigurationParser extends XMLConfigurationUtil {
|
||||||
|
|
||||||
config.setPasswordCodec(getString(e, "password-codec", DefaultSensitiveStringCodec.class.getName(), Validators.NOT_NULL_OR_EMPTY));
|
config.setPasswordCodec(getString(e, "password-codec", DefaultSensitiveStringCodec.class.getName(), Validators.NOT_NULL_OR_EMPTY));
|
||||||
|
|
||||||
|
config.setPopulateValidatedUser(getBoolean(e, "populate-validated-user", config.isPopulateValidatedUser()));
|
||||||
|
|
||||||
// parsing cluster password
|
// parsing cluster password
|
||||||
String passwordText = getString(e, "cluster-password", null, Validators.NO_CHECK);
|
String passwordText = getString(e, "cluster-password", null, Validators.NO_CHECK);
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,7 @@ import org.apache.activemq.artemis.api.core.SimpleString;
|
||||||
|
|
||||||
public interface SecurityStore {
|
public interface SecurityStore {
|
||||||
|
|
||||||
void authenticate(String user, String password, X509Certificate[] certificates) throws Exception;
|
String authenticate(String user, String password, X509Certificate[] certificates) throws Exception;
|
||||||
|
|
||||||
void check(SimpleString address, CheckType checkType, SecurityAuth session) throws Exception;
|
void check(SimpleString address, CheckType checkType, SecurityAuth session) throws Exception;
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,7 @@ import org.apache.activemq.artemis.core.settings.HierarchicalRepository;
|
||||||
import org.apache.activemq.artemis.core.settings.HierarchicalRepositoryChangeListener;
|
import org.apache.activemq.artemis.core.settings.HierarchicalRepositoryChangeListener;
|
||||||
import org.apache.activemq.artemis.spi.core.security.ActiveMQSecurityManager;
|
import org.apache.activemq.artemis.spi.core.security.ActiveMQSecurityManager;
|
||||||
import org.apache.activemq.artemis.spi.core.security.ActiveMQSecurityManager2;
|
import org.apache.activemq.artemis.spi.core.security.ActiveMQSecurityManager2;
|
||||||
|
import org.apache.activemq.artemis.spi.core.security.ActiveMQSecurityManager3;
|
||||||
import org.apache.activemq.artemis.utils.ConcurrentHashSet;
|
import org.apache.activemq.artemis.utils.ConcurrentHashSet;
|
||||||
import org.apache.activemq.artemis.utils.TypedProperties;
|
import org.apache.activemq.artemis.utils.TypedProperties;
|
||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
|
@ -99,7 +100,7 @@ public class SecurityStoreImpl implements SecurityStore, HierarchicalRepositoryC
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void authenticate(final String user, final String password, X509Certificate[] certificates) throws Exception {
|
public String authenticate(final String user, final String password, X509Certificate[] certificates) throws Exception {
|
||||||
if (securityEnabled) {
|
if (securityEnabled) {
|
||||||
|
|
||||||
if (managementClusterUser.equals(user)) {
|
if (managementClusterUser.equals(user)) {
|
||||||
|
@ -115,20 +116,24 @@ public class SecurityStoreImpl implements SecurityStore, HierarchicalRepositoryC
|
||||||
throw ActiveMQMessageBundle.BUNDLE.unableToValidateClusterUser(user);
|
throw ActiveMQMessageBundle.BUNDLE.unableToValidateClusterUser(user);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return;
|
return managementClusterUser;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String validatedUser = null;
|
||||||
boolean userIsValid = false;
|
boolean userIsValid = false;
|
||||||
|
|
||||||
if (securityManager instanceof ActiveMQSecurityManager2) {
|
if (securityManager instanceof ActiveMQSecurityManager3) {
|
||||||
|
validatedUser = ((ActiveMQSecurityManager3)securityManager).validateUser(user, password, certificates);
|
||||||
|
}
|
||||||
|
else if (securityManager instanceof ActiveMQSecurityManager2) {
|
||||||
userIsValid = ((ActiveMQSecurityManager2)securityManager).validateUser(user, password, certificates);
|
userIsValid = ((ActiveMQSecurityManager2)securityManager).validateUser(user, password, certificates);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
userIsValid = securityManager.validateUser(user, password);
|
userIsValid = securityManager.validateUser(user, password);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!userIsValid) {
|
if (!userIsValid && validatedUser == null) {
|
||||||
if (notificationService != null) {
|
if (notificationService != null) {
|
||||||
TypedProperties props = new TypedProperties();
|
TypedProperties props = new TypedProperties();
|
||||||
|
|
||||||
|
@ -139,7 +144,11 @@ public class SecurityStoreImpl implements SecurityStore, HierarchicalRepositoryC
|
||||||
|
|
||||||
throw ActiveMQMessageBundle.BUNDLE.unableToValidateUser();
|
throw ActiveMQMessageBundle.BUNDLE.unableToValidateUser();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return validatedUser;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -167,7 +176,11 @@ public class SecurityStoreImpl implements SecurityStore, HierarchicalRepositoryC
|
||||||
}
|
}
|
||||||
|
|
||||||
final boolean validated;
|
final boolean validated;
|
||||||
if (securityManager instanceof ActiveMQSecurityManager2) {
|
if (securityManager instanceof ActiveMQSecurityManager3) {
|
||||||
|
final ActiveMQSecurityManager3 securityManager3 = (ActiveMQSecurityManager3) securityManager;
|
||||||
|
validated = securityManager3.validateUserAndRole(user, session.getPassword(), roles, checkType, saddress, session.getRemotingConnection()) != null;
|
||||||
|
}
|
||||||
|
else if (securityManager instanceof ActiveMQSecurityManager2) {
|
||||||
final ActiveMQSecurityManager2 securityManager2 = (ActiveMQSecurityManager2) securityManager;
|
final ActiveMQSecurityManager2 securityManager2 = (ActiveMQSecurityManager2) securityManager;
|
||||||
validated = securityManager2.validateUserAndRole(user, session.getPassword(), roles, checkType, saddress, session.getRemotingConnection());
|
validated = securityManager2.validateUserAndRole(user, session.getPassword(), roles, checkType, saddress, session.getRemotingConnection());
|
||||||
}
|
}
|
||||||
|
|
|
@ -1161,19 +1161,20 @@ public class ActiveMQServerImpl implements ActiveMQServer {
|
||||||
final String defaultAddress,
|
final String defaultAddress,
|
||||||
final SessionCallback callback,
|
final SessionCallback callback,
|
||||||
final boolean autoCreateQueues) throws Exception {
|
final boolean autoCreateQueues) throws Exception {
|
||||||
|
String validatedUser = "";
|
||||||
|
|
||||||
if (securityStore != null) {
|
if (securityStore != null) {
|
||||||
X509Certificate[] certificates = null;
|
X509Certificate[] certificates = null;
|
||||||
if (connection.getTransportConnection() instanceof NettyConnection) {
|
if (connection.getTransportConnection() instanceof NettyConnection) {
|
||||||
certificates = CertificateUtil.getCertsFromChannel(((NettyConnection) connection.getTransportConnection()).getChannel());
|
certificates = CertificateUtil.getCertsFromChannel(((NettyConnection) connection.getTransportConnection()).getChannel());
|
||||||
}
|
}
|
||||||
securityStore.authenticate(username, password, certificates);
|
validatedUser = securityStore.authenticate(username, password, certificates);
|
||||||
}
|
}
|
||||||
|
|
||||||
checkSessionLimit(username);
|
checkSessionLimit(validatedUser);
|
||||||
|
|
||||||
final OperationContext context = storageManager.newContext(getExecutorFactory().getExecutor());
|
final OperationContext context = storageManager.newContext(getExecutorFactory().getExecutor());
|
||||||
final ServerSessionImpl session = internalCreateSession(name, username, password, minLargeMessageSize, connection, autoCommitSends, autoCommitAcks, preAcknowledge, xa, defaultAddress, callback, context, autoCreateQueues);
|
final ServerSessionImpl session = internalCreateSession(name, username, password, validatedUser, minLargeMessageSize, connection, autoCommitSends, autoCommitAcks, preAcknowledge, xa, defaultAddress, callback, context, autoCreateQueues);
|
||||||
|
|
||||||
sessions.put(name, session);
|
sessions.put(name, session);
|
||||||
|
|
||||||
|
@ -1237,6 +1238,7 @@ public class ActiveMQServerImpl implements ActiveMQServer {
|
||||||
protected ServerSessionImpl internalCreateSession(String name,
|
protected ServerSessionImpl internalCreateSession(String name,
|
||||||
String username,
|
String username,
|
||||||
String password,
|
String password,
|
||||||
|
String validatedUser,
|
||||||
int minLargeMessageSize,
|
int minLargeMessageSize,
|
||||||
RemotingConnection connection,
|
RemotingConnection connection,
|
||||||
boolean autoCommitSends,
|
boolean autoCommitSends,
|
||||||
|
@ -1247,7 +1249,7 @@ public class ActiveMQServerImpl implements ActiveMQServer {
|
||||||
SessionCallback callback,
|
SessionCallback callback,
|
||||||
OperationContext context,
|
OperationContext context,
|
||||||
boolean autoCreateJMSQueues) throws Exception {
|
boolean autoCreateJMSQueues) throws Exception {
|
||||||
return new ServerSessionImpl(name, username, password, minLargeMessageSize, autoCommitSends, autoCommitAcks, preAcknowledge, configuration.isPersistDeliveryCountBeforeDelivery(), xa, connection, storageManager, postOffice, resourceManager, securityStore, managementService, this, configuration.getManagementAddress(), defaultAddress == null ? null : new SimpleString(defaultAddress), callback, context, autoCreateJMSQueues ? jmsQueueCreator : null);
|
return new ServerSessionImpl(name, username, password, validatedUser, minLargeMessageSize, autoCommitSends, autoCommitAcks, preAcknowledge, configuration.isPersistDeliveryCountBeforeDelivery(), xa, connection, storageManager, postOffice, resourceManager, securityStore, managementService, this, configuration.getManagementAddress(), defaultAddress == null ? null : new SimpleString(defaultAddress), callback, context, autoCreateJMSQueues ? jmsQueueCreator : null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -105,6 +105,8 @@ public class ServerSessionImpl implements ServerSession, FailureListener {
|
||||||
|
|
||||||
protected final String password;
|
protected final String password;
|
||||||
|
|
||||||
|
protected final String validatedUser;
|
||||||
|
|
||||||
private final int minLargeMessageSize;
|
private final int minLargeMessageSize;
|
||||||
|
|
||||||
protected boolean autoCommitSends;
|
protected boolean autoCommitSends;
|
||||||
|
@ -176,6 +178,7 @@ public class ServerSessionImpl implements ServerSession, FailureListener {
|
||||||
public ServerSessionImpl(final String name,
|
public ServerSessionImpl(final String name,
|
||||||
final String username,
|
final String username,
|
||||||
final String password,
|
final String password,
|
||||||
|
final String validatedUser,
|
||||||
final int minLargeMessageSize,
|
final int minLargeMessageSize,
|
||||||
final boolean autoCommitSends,
|
final boolean autoCommitSends,
|
||||||
final boolean autoCommitAcks,
|
final boolean autoCommitAcks,
|
||||||
|
@ -198,6 +201,8 @@ public class ServerSessionImpl implements ServerSession, FailureListener {
|
||||||
|
|
||||||
this.password = password;
|
this.password = password;
|
||||||
|
|
||||||
|
this.validatedUser = validatedUser;
|
||||||
|
|
||||||
this.minLargeMessageSize = minLargeMessageSize;
|
this.minLargeMessageSize = minLargeMessageSize;
|
||||||
|
|
||||||
this.autoCommitSends = autoCommitSends;
|
this.autoCommitSends = autoCommitSends;
|
||||||
|
@ -1230,6 +1235,10 @@ public class ServerSessionImpl implements ServerSession, FailureListener {
|
||||||
message.encodeMessageIDToBuffer();
|
message.encodeMessageIDToBuffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (server.getConfiguration().isPopulateValidatedUser() && validatedUser != null) {
|
||||||
|
message.putStringProperty(Message.HDR_VALIDATED_USER, SimpleString.toSimpleString(validatedUser));
|
||||||
|
}
|
||||||
|
|
||||||
SimpleString address = message.getAddress();
|
SimpleString address = message.getAddress();
|
||||||
|
|
||||||
if (defaultAddress == null && address != null) {
|
if (defaultAddress == null && address != null) {
|
||||||
|
|
|
@ -34,6 +34,7 @@ import org.apache.activemq.artemis.core.security.Role;
|
||||||
import org.apache.activemq.artemis.spi.core.protocol.RemotingConnection;
|
import org.apache.activemq.artemis.spi.core.protocol.RemotingConnection;
|
||||||
import org.apache.activemq.artemis.spi.core.security.jaas.JaasCallbackHandler;
|
import org.apache.activemq.artemis.spi.core.security.jaas.JaasCallbackHandler;
|
||||||
import org.apache.activemq.artemis.spi.core.security.jaas.RolePrincipal;
|
import org.apache.activemq.artemis.spi.core.security.jaas.RolePrincipal;
|
||||||
|
import org.apache.activemq.artemis.spi.core.security.jaas.UserPrincipal;
|
||||||
import org.apache.activemq.artemis.utils.CertificateUtil;
|
import org.apache.activemq.artemis.utils.CertificateUtil;
|
||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
|
|
||||||
|
@ -43,7 +44,7 @@ import org.jboss.logging.Logger;
|
||||||
* The {@link Subject} returned by the login context is expecting to have a set of {@link RolePrincipal} for each
|
* The {@link Subject} returned by the login context is expecting to have a set of {@link RolePrincipal} for each
|
||||||
* role of the user.
|
* role of the user.
|
||||||
*/
|
*/
|
||||||
public class ActiveMQJAASSecurityManager implements ActiveMQSecurityManager2 {
|
public class ActiveMQJAASSecurityManager implements ActiveMQSecurityManager3 {
|
||||||
|
|
||||||
private static final Logger logger = Logger.getLogger(ActiveMQJAASSecurityManager.class);
|
private static final Logger logger = Logger.getLogger(ActiveMQJAASSecurityManager.class);
|
||||||
|
|
||||||
|
@ -81,30 +82,40 @@ public class ActiveMQJAASSecurityManager implements ActiveMQSecurityManager2 {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean validateUser(String user, String password) {
|
public boolean validateUser(String user, String password) {
|
||||||
return validateUser(user, password, null);
|
throw new UnsupportedOperationException("Invoke validateUser(String, String, X509Certificate[]) instead");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean validateUser(final String user, final String password, X509Certificate[] certificates) {
|
public String validateUser(final String user, final String password, X509Certificate[] certificates) {
|
||||||
try {
|
try {
|
||||||
getAuthenticatedSubject(user, password, certificates);
|
return getUserFromSubject(getAuthenticatedSubject(user, password, certificates));
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
catch (LoginException e) {
|
catch (LoginException e) {
|
||||||
if (logger.isDebugEnabled()) {
|
if (logger.isDebugEnabled()) {
|
||||||
logger.debug("Couldn't validate user", e);
|
logger.debug("Couldn't validate user", e);
|
||||||
}
|
}
|
||||||
return false;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getUserFromSubject(Subject subject) {
|
||||||
|
String validatedUser = "";
|
||||||
|
Set<UserPrincipal> users = subject.getPrincipals(UserPrincipal.class);
|
||||||
|
|
||||||
|
// should only ever be 1 UserPrincipal
|
||||||
|
for (UserPrincipal userPrincipal : users) {
|
||||||
|
validatedUser = userPrincipal.getName();
|
||||||
|
}
|
||||||
|
return validatedUser;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean validateUserAndRole(String user, String password, Set<Role> roles, CheckType checkType) {
|
public boolean validateUserAndRole(String user, String password, Set<Role> roles, CheckType checkType) {
|
||||||
throw new UnsupportedOperationException("Invoke validateUserAndRole(String, String, Set<Role>, CheckType, String, RemotingConnection) instead");
|
throw new UnsupportedOperationException("Invoke validateUserAndRole(String, String, Set<Role>, CheckType, String, RemotingConnection) instead");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean validateUserAndRole(final String user,
|
public String validateUserAndRole(final String user,
|
||||||
final String password,
|
final String password,
|
||||||
final Set<Role> roles,
|
final Set<Role> roles,
|
||||||
final CheckType checkType,
|
final CheckType checkType,
|
||||||
|
@ -122,7 +133,7 @@ public class ActiveMQJAASSecurityManager implements ActiveMQSecurityManager2 {
|
||||||
if (logger.isDebugEnabled()) {
|
if (logger.isDebugEnabled()) {
|
||||||
logger.debug("Couldn't validate user", e);
|
logger.debug("Couldn't validate user", e);
|
||||||
}
|
}
|
||||||
return false;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean authorized = false;
|
boolean authorized = false;
|
||||||
|
@ -155,7 +166,12 @@ public class ActiveMQJAASSecurityManager implements ActiveMQSecurityManager2 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return authorized;
|
if (authorized) {
|
||||||
|
return getUserFromSubject(localSubject);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Subject getAuthenticatedSubject(final String user, final String password, final X509Certificate[] certificates) throws LoginException {
|
private Subject getAuthenticatedSubject(final String user, final String password, final X509Certificate[] certificates) throws LoginException {
|
||||||
|
|
|
@ -0,0 +1,64 @@
|
||||||
|
/*
|
||||||
|
* 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.spi.core.security;
|
||||||
|
|
||||||
|
import javax.security.cert.X509Certificate;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.apache.activemq.artemis.core.security.CheckType;
|
||||||
|
import org.apache.activemq.artemis.core.security.Role;
|
||||||
|
import org.apache.activemq.artemis.spi.core.protocol.RemotingConnection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to validate whether a user is authorized to connect to the
|
||||||
|
* server and perform certain functions on certain destinations.
|
||||||
|
*
|
||||||
|
* This is an evolution of {@link ActiveMQSecurityManager} and
|
||||||
|
* {@link ActiveMQSecurityManager2} that adds the ability to determine
|
||||||
|
* the identity of the validated user.
|
||||||
|
*/
|
||||||
|
public interface ActiveMQSecurityManager3 extends ActiveMQSecurityManager {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* is this a valid user.
|
||||||
|
*
|
||||||
|
* This method is called instead of
|
||||||
|
* {@link ActiveMQSecurityManager#validateUser(String, String)}.
|
||||||
|
*
|
||||||
|
* @param user the user
|
||||||
|
* @param password the users password
|
||||||
|
* @return the name of the validated user or null if the user isn't validated
|
||||||
|
*/
|
||||||
|
String validateUser(String user, String password, X509Certificate[] certificates);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine whether the given user is valid and whether they have
|
||||||
|
* the correct role for the given destination address.
|
||||||
|
*
|
||||||
|
* This method is called instead of
|
||||||
|
* {@link ActiveMQSecurityManager#validateUserAndRole(String, String, Set, CheckType)}.
|
||||||
|
*
|
||||||
|
* @param user the user
|
||||||
|
* @param password the user's password
|
||||||
|
* @param roles the user's roles
|
||||||
|
* @param checkType which permission to validate
|
||||||
|
* @param address the address for which to perform authorization
|
||||||
|
* @param connection the user's connection
|
||||||
|
* @return the name of the validated user or null if the user isn't validated
|
||||||
|
*/
|
||||||
|
String validateUserAndRole(String user, String password, Set<Role> roles, CheckType checkType, String address, RemotingConnection connection);
|
||||||
|
}
|
|
@ -324,6 +324,14 @@
|
||||||
</xsd:annotation>
|
</xsd:annotation>
|
||||||
</xsd:element>
|
</xsd:element>
|
||||||
|
|
||||||
|
<xsd:element name="populate-validated-user" type="xsd:boolean" default="false" maxOccurs="1" minOccurs="0">
|
||||||
|
<xsd:annotation>
|
||||||
|
<xsd:documentation>
|
||||||
|
true means that the server will add the name of the validated user to messages it sends
|
||||||
|
</xsd:documentation>
|
||||||
|
</xsd:annotation>
|
||||||
|
</xsd:element>
|
||||||
|
|
||||||
<xsd:element name="connectors" maxOccurs="1" minOccurs="0">
|
<xsd:element name="connectors" maxOccurs="1" minOccurs="0">
|
||||||
<xsd:annotation>
|
<xsd:annotation>
|
||||||
<xsd:documentation>
|
<xsd:documentation>
|
||||||
|
|
|
@ -102,6 +102,7 @@ public class FileConfigurationTest extends ConfigurationImplTest {
|
||||||
Assert.assertEquals(33, conf.getJournalCompactPercentage());
|
Assert.assertEquals(33, conf.getJournalCompactPercentage());
|
||||||
Assert.assertEquals(true, conf.isGracefulShutdownEnabled());
|
Assert.assertEquals(true, conf.isGracefulShutdownEnabled());
|
||||||
Assert.assertEquals(12345, conf.getGracefulShutdownTimeout());
|
Assert.assertEquals(12345, conf.getGracefulShutdownTimeout());
|
||||||
|
Assert.assertEquals(true, conf.isPopulateValidatedUser());
|
||||||
|
|
||||||
Assert.assertEquals("largemessagesdir", conf.getLargeMessagesDirectory());
|
Assert.assertEquals("largemessagesdir", conf.getLargeMessagesDirectory());
|
||||||
Assert.assertEquals(95, conf.getMemoryWarningThreshold());
|
Assert.assertEquals(95, conf.getMemoryWarningThreshold());
|
||||||
|
|
|
@ -50,6 +50,7 @@
|
||||||
<message-expiry-thread-priority>8</message-expiry-thread-priority>
|
<message-expiry-thread-priority>8</message-expiry-thread-priority>
|
||||||
<id-cache-size>127</id-cache-size>
|
<id-cache-size>127</id-cache-size>
|
||||||
<persist-id-cache>true</persist-id-cache>
|
<persist-id-cache>true</persist-id-cache>
|
||||||
|
<populate-validated-user>true</populate-validated-user>
|
||||||
<remoting-incoming-interceptors>
|
<remoting-incoming-interceptors>
|
||||||
<class-name>org.apache.activemq.artemis.tests.unit.core.config.impl.TestInterceptor1</class-name>
|
<class-name>org.apache.activemq.artemis.tests.unit.core.config.impl.TestInterceptor1</class-name>
|
||||||
<class-name>org.apache.activemq.artemis.tests.unit.core.config.impl.TestInterceptor2</class-name>
|
<class-name>org.apache.activemq.artemis.tests.unit.core.config.impl.TestInterceptor2</class-name>
|
||||||
|
|
|
@ -81,6 +81,7 @@ Name | Description
|
||||||
[scheduled-thread-pool-max-size](thread-pooling.md#server.scheduled.thread.pool "Server Scheduled Thread Pool")| Maximum number of threads to use for the scheduled thread pool. Default=5
|
[scheduled-thread-pool-max-size](thread-pooling.md#server.scheduled.thread.pool "Server Scheduled Thread Pool")| Maximum number of threads to use for the scheduled thread pool. Default=5
|
||||||
[security-enabled](security.md "Security") | true means that security is enabled. Default=true
|
[security-enabled](security.md "Security") | true means that security is enabled. Default=true
|
||||||
[security-invalidation-interval](security.md "Security") | how long (in ms) to wait before invalidating the security cache. Default=10000
|
[security-invalidation-interval](security.md "Security") | how long (in ms) to wait before invalidating the security cache. Default=10000
|
||||||
|
[populate-validated-user](security.md "Security") | whether or not to add the name of the validated user to the messages that user sends. Default=false
|
||||||
[security-settings](security.md "Role based security for addresses") | [a list of security-setting](#security-setting-type)
|
[security-settings](security.md "Role based security for addresses") | [a list of security-setting](#security-setting-type)
|
||||||
[thread-pool-max-size](thread-pooling.md "Server Scheduled Thread Pool") | Maximum number of threads to use for the thread pool. -1 means 'no limits'.. Default=30
|
[thread-pool-max-size](thread-pooling.md "Server Scheduled Thread Pool") | Maximum number of threads to use for the thread pool. -1 means 'no limits'.. Default=30
|
||||||
[transaction-timeout](transaction-config.md "Resource Manager Configuration") | how long (in ms) before a transaction can be removed from the resource manager after create time. Default=300000
|
[transaction-timeout](transaction-config.md "Resource Manager Configuration") | how long (in ms) before a transaction can be removed from the resource manager after create time. Default=300000
|
||||||
|
|
|
@ -10,6 +10,13 @@ long. To change this period set the property
|
||||||
`security-invalidation-interval`, which is in milliseconds. The default
|
`security-invalidation-interval`, which is in milliseconds. The default
|
||||||
is `10000` ms.
|
is `10000` ms.
|
||||||
|
|
||||||
|
To assist in security auditing the `populate-validated-user` option exists. If this is `true` then
|
||||||
|
the server will add the name of the validated user to the message using the key `_AMQ_VALIDATED_USER`.
|
||||||
|
For JMS and Stomp clients this is mapped to the key `JMSXUserID`. For users authenticated based on
|
||||||
|
their SSL certificate this name is the name to which their certificate's DN maps. If `security-enabled`
|
||||||
|
is `false` and `populate-validated-user` is `true` then the server will simply use whatever user name
|
||||||
|
(if any) the client provides. This option is `false` by default.
|
||||||
|
|
||||||
## Role based security for addresses
|
## Role based security for addresses
|
||||||
|
|
||||||
Apache ActiveMQ Artemis contains a flexible role-based security model for applying
|
Apache ActiveMQ Artemis contains a flexible role-based security model for applying
|
||||||
|
|
|
@ -577,6 +577,7 @@ public class HangConsumerTest extends ActiveMQTestBase {
|
||||||
protected ServerSessionImpl internalCreateSession(String name,
|
protected ServerSessionImpl internalCreateSession(String name,
|
||||||
String username,
|
String username,
|
||||||
String password,
|
String password,
|
||||||
|
String validatedUser,
|
||||||
int minLargeMessageSize,
|
int minLargeMessageSize,
|
||||||
RemotingConnection connection,
|
RemotingConnection connection,
|
||||||
boolean autoCommitSends,
|
boolean autoCommitSends,
|
||||||
|
@ -587,7 +588,7 @@ public class HangConsumerTest extends ActiveMQTestBase {
|
||||||
SessionCallback callback,
|
SessionCallback callback,
|
||||||
OperationContext context,
|
OperationContext context,
|
||||||
boolean autoCreateQueue) throws Exception {
|
boolean autoCreateQueue) throws Exception {
|
||||||
return new ServerSessionImpl(name, username, password, minLargeMessageSize, autoCommitSends, autoCommitAcks, preAcknowledge, getConfiguration().isPersistDeliveryCountBeforeDelivery(), xa, connection, getStorageManager(), getPostOffice(), getResourceManager(), getSecurityStore(), getManagementService(), this, getConfiguration().getManagementAddress(), defaultAddress == null ? null : new SimpleString(defaultAddress), new MyCallback(callback), context, null);
|
return new ServerSessionImpl(name, username, password, validatedUser, minLargeMessageSize, autoCommitSends, autoCommitAcks, preAcknowledge, getConfiguration().isPersistDeliveryCountBeforeDelivery(), xa, connection, getStorageManager(), getPostOffice(), getResourceManager(), getSecurityStore(), getManagementService(), this, getConfiguration().getManagementAddress(), defaultAddress == null ? null : new SimpleString(defaultAddress), new MyCallback(callback), context, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -236,8 +236,8 @@ public class JMSQueueControlTest extends ManagementTestBase {
|
||||||
|
|
||||||
CompositeData[] data = queueControl.browse();
|
CompositeData[] data = queueControl.browse();
|
||||||
Assert.assertEquals(1, data.length);
|
Assert.assertEquals(1, data.length);
|
||||||
Assert.assertNotNull(data[0].get("JMSCorrelationID"));
|
Assert.assertNotNull(data[0].get(MessageUtil.CORRELATIONID_HEADER_NAME.toString()));
|
||||||
Assert.assertEquals("foo", data[0].get("JMSCorrelationID"));
|
Assert.assertEquals("foo", data[0].get(MessageUtil.CORRELATIONID_HEADER_NAME.toString()));
|
||||||
System.out.println(data[0]);
|
System.out.println(data[0]);
|
||||||
|
|
||||||
JMSUtil.consumeMessages(1, queue);
|
JMSUtil.consumeMessages(1, queue);
|
||||||
|
@ -248,8 +248,8 @@ public class JMSQueueControlTest extends ManagementTestBase {
|
||||||
|
|
||||||
data = queueControl.browse();
|
data = queueControl.browse();
|
||||||
Assert.assertEquals(1, data.length);
|
Assert.assertEquals(1, data.length);
|
||||||
Assert.assertNotNull(data[0].get("JMSXGroupID"));
|
Assert.assertNotNull(data[0].get(MessageUtil.JMSXGROUPID.toString()));
|
||||||
Assert.assertEquals("myGroupID", data[0].get("JMSXGroupID"));
|
Assert.assertEquals("myGroupID", data[0].get(MessageUtil.JMSXGROUPID.toString()));
|
||||||
System.out.println(data[0]);
|
System.out.println(data[0]);
|
||||||
|
|
||||||
JMSUtil.consumeMessages(1, queue);
|
JMSUtil.consumeMessages(1, queue);
|
||||||
|
@ -266,14 +266,14 @@ public class JMSQueueControlTest extends ManagementTestBase {
|
||||||
|
|
||||||
JMSUtil.consumeMessages(1, queue);
|
JMSUtil.consumeMessages(1, queue);
|
||||||
|
|
||||||
JMSUtil.sendMessageWithProperty(session, queue, "JMSXUserID", "theheadhonch");
|
JMSUtil.sendMessageWithProperty(session, queue, MessageUtil.JMSXUSERID.toString(), "theheadhonch");
|
||||||
|
|
||||||
Assert.assertEquals(1, getMessageCount(queueControl));
|
Assert.assertEquals(1, getMessageCount(queueControl));
|
||||||
|
|
||||||
data = queueControl.browse();
|
data = queueControl.browse();
|
||||||
Assert.assertEquals(1, data.length);
|
Assert.assertEquals(1, data.length);
|
||||||
Assert.assertNotNull(data[0].get("JMSXUserID"));
|
Assert.assertNotNull(data[0].get(MessageUtil.JMSXUSERID.toString()));
|
||||||
Assert.assertEquals("theheadhonch", data[0].get("JMSXUserID"));
|
Assert.assertEquals("theheadhonch", data[0].get(MessageUtil.JMSXUSERID.toString()));
|
||||||
System.out.println(data[0]);
|
System.out.println(data[0]);
|
||||||
|
|
||||||
JMSUtil.consumeMessages(1, queue);
|
JMSUtil.consumeMessages(1, queue);
|
||||||
|
|
|
@ -52,6 +52,7 @@ import org.apache.activemq.artemis.spi.core.protocol.RemotingConnection;
|
||||||
import org.apache.activemq.artemis.spi.core.security.ActiveMQJAASSecurityManager;
|
import org.apache.activemq.artemis.spi.core.security.ActiveMQJAASSecurityManager;
|
||||||
import org.apache.activemq.artemis.spi.core.security.ActiveMQSecurityManager;
|
import org.apache.activemq.artemis.spi.core.security.ActiveMQSecurityManager;
|
||||||
import org.apache.activemq.artemis.spi.core.security.ActiveMQSecurityManager2;
|
import org.apache.activemq.artemis.spi.core.security.ActiveMQSecurityManager2;
|
||||||
|
import org.apache.activemq.artemis.spi.core.security.ActiveMQSecurityManager3;
|
||||||
import org.apache.activemq.artemis.tests.util.ActiveMQTestBase;
|
import org.apache.activemq.artemis.tests.util.ActiveMQTestBase;
|
||||||
import org.apache.activemq.artemis.tests.util.CreateMessage;
|
import org.apache.activemq.artemis.tests.util.CreateMessage;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
|
@ -1648,39 +1649,39 @@ public class SecurityTest extends ActiveMQTestBase {
|
||||||
public void testCustomSecurityManager() throws Exception {
|
public void testCustomSecurityManager() throws Exception {
|
||||||
final Configuration configuration = createDefaultInVMConfig().setSecurityEnabled(true);
|
final Configuration configuration = createDefaultInVMConfig().setSecurityEnabled(true);
|
||||||
final ActiveMQSecurityManager customSecurityManager = new ActiveMQSecurityManager() {
|
final ActiveMQSecurityManager customSecurityManager = new ActiveMQSecurityManager() {
|
||||||
@Override
|
@Override
|
||||||
public boolean validateUser(final String username, final String password) {
|
public boolean validateUser(final String username, final String password) {
|
||||||
return (username.equals("foo") || username.equals("bar") || username.equals("all")) &&
|
return (username.equals("foo") || username.equals("bar") || username.equals("all")) &&
|
||||||
password.equals("frobnicate");
|
password.equals("frobnicate");
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public boolean validateUserAndRole(
|
public boolean validateUserAndRole(
|
||||||
final String username,
|
final String username,
|
||||||
final String password,
|
final String password,
|
||||||
final Set<Role> requiredRoles,
|
final Set<Role> requiredRoles,
|
||||||
final CheckType checkType) {
|
final CheckType checkType) {
|
||||||
|
|
||||||
if ((username.equals("foo") || username.equals("bar") || username.equals("all")) &&
|
if ((username.equals("foo") || username.equals("bar") || username.equals("all")) &&
|
||||||
password.equals("frobnicate")) {
|
password.equals("frobnicate")) {
|
||||||
|
|
||||||
if (username.equals("all")) {
|
if (username.equals("all")) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else if (username.equals("foo")) {
|
else if (username.equals("foo")) {
|
||||||
return checkType == CheckType.CONSUME || checkType == CheckType.CREATE_NON_DURABLE_QUEUE;
|
return checkType == CheckType.CONSUME || checkType == CheckType.CREATE_NON_DURABLE_QUEUE;
|
||||||
}
|
}
|
||||||
else if (username.equals("bar")) {
|
else if (username.equals("bar")) {
|
||||||
return checkType == CheckType.SEND || checkType == CheckType.CREATE_NON_DURABLE_QUEUE;
|
return checkType == CheckType.SEND || checkType == CheckType.CREATE_NON_DURABLE_QUEUE;
|
||||||
}
|
|
||||||
else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
final ActiveMQServer server = addServer(new ActiveMQServerImpl(configuration, customSecurityManager));
|
final ActiveMQServer server = addServer(new ActiveMQServerImpl(configuration, customSecurityManager));
|
||||||
server.start();
|
server.start();
|
||||||
|
|
||||||
|
@ -1734,61 +1735,207 @@ public class SecurityTest extends ActiveMQTestBase {
|
||||||
public void testCustomSecurityManager2() throws Exception {
|
public void testCustomSecurityManager2() throws Exception {
|
||||||
final Configuration configuration = createDefaultInVMConfig().setSecurityEnabled(true);
|
final Configuration configuration = createDefaultInVMConfig().setSecurityEnabled(true);
|
||||||
final ActiveMQSecurityManager customSecurityManager = new ActiveMQSecurityManager2() {
|
final ActiveMQSecurityManager customSecurityManager = new ActiveMQSecurityManager2() {
|
||||||
@Override
|
@Override
|
||||||
public boolean validateUser(final String username, final String password) {
|
public boolean validateUser(final String username, final String password) {
|
||||||
fail("Unexpected call to overridden method");
|
fail("Unexpected call to overridden method");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public boolean validateUser(final String username, final String password, final X509Certificate[] certificates) {
|
public boolean validateUser(final String username, final String password, final X509Certificate[] certificates) {
|
||||||
return (username.equals("foo") || username.equals("bar") || username.equals("all")) &&
|
return (username.equals("foo") || username.equals("bar") || username.equals("all")) &&
|
||||||
password.equals("frobnicate");
|
password.equals("frobnicate");
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public boolean validateUserAndRole(
|
public boolean validateUserAndRole(
|
||||||
final String username,
|
final String username,
|
||||||
final String password,
|
final String password,
|
||||||
final Set<Role> requiredRoles,
|
final Set<Role> requiredRoles,
|
||||||
final CheckType checkType) {
|
final CheckType checkType) {
|
||||||
|
|
||||||
fail("Unexpected call to overridden method");
|
fail("Unexpected call to overridden method");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean validateUserAndRole(
|
||||||
|
final String username,
|
||||||
|
final String password,
|
||||||
|
final Set<Role> requiredRoles,
|
||||||
|
final CheckType checkType,
|
||||||
|
final String address,
|
||||||
|
final RemotingConnection connection) {
|
||||||
|
|
||||||
|
if (!(connection.getTransportConnection() instanceof InVMConnection)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
if ((username.equals("foo") || username.equals("bar") || username.equals("all")) &&
|
||||||
public boolean validateUserAndRole(
|
password.equals("frobnicate")) {
|
||||||
final String username,
|
|
||||||
final String password,
|
|
||||||
final Set<Role> requiredRoles,
|
|
||||||
final CheckType checkType,
|
|
||||||
final String address,
|
|
||||||
final RemotingConnection connection) {
|
|
||||||
|
|
||||||
if (!(connection.getTransportConnection() instanceof InVMConnection)) {
|
if (username.equals("all")) {
|
||||||
return false;
|
return true;
|
||||||
}
|
}
|
||||||
|
else if (username.equals("foo")) {
|
||||||
if ((username.equals("foo") || username.equals("bar") || username.equals("all")) &&
|
return address.equals("test.queue") && checkType == CheckType.CONSUME;
|
||||||
password.equals("frobnicate")) {
|
}
|
||||||
|
else if (username.equals("bar")) {
|
||||||
if (username.equals("all")) {
|
return address.equals("test.queue") && checkType == CheckType.SEND;
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else if (username.equals("foo")) {
|
|
||||||
return address.equals("test.queue") && checkType == CheckType.CONSUME;
|
|
||||||
}
|
|
||||||
else if (username.equals("bar")) {
|
|
||||||
return address.equals("test.queue") && checkType == CheckType.SEND;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
final ActiveMQServer server = addServer(new ActiveMQServerImpl(configuration, customSecurityManager));
|
||||||
|
server.start();
|
||||||
|
|
||||||
|
final ServerLocator locator = createInVMNonHALocator();
|
||||||
|
locator.setBlockOnNonDurableSend(true).setBlockOnDurableSend(true);
|
||||||
|
final ClientSessionFactory factory = createSessionFactory(locator);
|
||||||
|
ClientSession adminSession = factory.createSession("all", "frobnicate", false, true, true, false, -1);
|
||||||
|
|
||||||
|
final String queueName = "test.queue";
|
||||||
|
adminSession.createQueue(queueName, queueName, false);
|
||||||
|
|
||||||
|
final String otherQueueName = "other.queue";
|
||||||
|
adminSession.createQueue(otherQueueName, otherQueueName, false);
|
||||||
|
|
||||||
|
// Wrong user name
|
||||||
|
try {
|
||||||
|
factory.createSession("baz", "frobnicate", false, true, true, false, -1);
|
||||||
|
Assert.fail("should throw exception");
|
||||||
|
}
|
||||||
|
catch (ActiveMQSecurityException se) {
|
||||||
|
//ok
|
||||||
|
}
|
||||||
|
catch (ActiveMQException e) {
|
||||||
|
fail("Invalid Exception type:" + e.getType());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wrong password
|
||||||
|
try {
|
||||||
|
factory.createSession("foo", "xxx", false, true, true, false, -1);
|
||||||
|
Assert.fail("should throw exception");
|
||||||
|
}
|
||||||
|
catch (ActiveMQSecurityException se) {
|
||||||
|
//ok
|
||||||
|
}
|
||||||
|
catch (ActiveMQException e) {
|
||||||
|
fail("Invalid Exception type:" + e.getType());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Correct user and password, wrong queue for sending
|
||||||
|
try {
|
||||||
|
final ClientSession session = factory.createSession("foo", "frobnicate", false, true, true, false, -1);
|
||||||
|
checkUserReceiveNoSend(otherQueueName, session, adminSession);
|
||||||
|
Assert.fail("should throw exception");
|
||||||
|
}
|
||||||
|
catch (ActiveMQSecurityException se) {
|
||||||
|
//ok
|
||||||
|
}
|
||||||
|
catch (ActiveMQException e) {
|
||||||
|
fail("Invalid Exception type:" + e.getType());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Correct user and password, wrong queue for receiving
|
||||||
|
try {
|
||||||
|
final ClientSession session = factory.createSession("foo", "frobnicate", false, true, true, false, -1);
|
||||||
|
checkUserReceiveNoSend(otherQueueName, session, adminSession);
|
||||||
|
Assert.fail("should throw exception");
|
||||||
|
}
|
||||||
|
catch (ActiveMQSecurityException se) {
|
||||||
|
//ok
|
||||||
|
}
|
||||||
|
catch (ActiveMQException e) {
|
||||||
|
fail("Invalid Exception type:" + e.getType());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Correct user and password, allowed to send but not receive
|
||||||
|
{
|
||||||
|
final ClientSession session = factory.createSession("foo", "frobnicate", false, true, true, false, -1);
|
||||||
|
checkUserReceiveNoSend(queueName, session, adminSession);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Correct user and password, allowed to receive but not send
|
||||||
|
{
|
||||||
|
final ClientSession session = factory.createSession("bar", "frobnicate", false, true, true, false, -1);
|
||||||
|
checkUserSendNoReceive(queueName, session);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCustomSecurityManager3() throws Exception {
|
||||||
|
final Configuration configuration = createDefaultInVMConfig().setSecurityEnabled(true);
|
||||||
|
final ActiveMQSecurityManager customSecurityManager = new ActiveMQSecurityManager3() {
|
||||||
|
@Override
|
||||||
|
public boolean validateUser(final String username, final String password) {
|
||||||
|
fail("Unexpected call to overridden method");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public String validateUser(final String username, final String password, final X509Certificate[] certificates) {
|
||||||
|
if ((username.equals("foo") || username.equals("bar") || username.equals("all")) && password.equals("frobnicate")) {
|
||||||
|
return username;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public boolean validateUserAndRole(
|
||||||
|
final String username,
|
||||||
|
final String password,
|
||||||
|
final Set<Role> requiredRoles,
|
||||||
|
final CheckType checkType) {
|
||||||
|
|
||||||
|
fail("Unexpected call to overridden method");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String validateUserAndRole(
|
||||||
|
final String username,
|
||||||
|
final String password,
|
||||||
|
final Set<Role> requiredRoles,
|
||||||
|
final CheckType checkType,
|
||||||
|
final String address,
|
||||||
|
final RemotingConnection connection) {
|
||||||
|
|
||||||
|
if (!(connection.getTransportConnection() instanceof InVMConnection)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((username.equals("foo") || username.equals("bar") || username.equals("all")) &&
|
||||||
|
password.equals("frobnicate")) {
|
||||||
|
|
||||||
|
if (username.equals("all")) {
|
||||||
|
return username;
|
||||||
|
}
|
||||||
|
else if (username.equals("foo")) {
|
||||||
|
if (address.equals("test.queue") && checkType == CheckType.CONSUME)
|
||||||
|
return username;
|
||||||
|
else
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
else if (username.equals("bar")) {
|
||||||
|
if (address.equals("test.queue") && checkType == CheckType.SEND)
|
||||||
|
return username;
|
||||||
|
else
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
final ActiveMQServer server = addServer(new ActiveMQServerImpl(configuration, customSecurityManager));
|
final ActiveMQServer server = addServer(new ActiveMQServerImpl(configuration, customSecurityManager));
|
||||||
server.start();
|
server.start();
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,7 @@ import java.net.Socket;
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.ArrayBlockingQueue;
|
import java.util.concurrent.ArrayBlockingQueue;
|
||||||
import java.util.concurrent.BlockingQueue;
|
import java.util.concurrent.BlockingQueue;
|
||||||
|
@ -50,8 +51,6 @@ import io.netty.channel.socket.nio.NioSocketChannel;
|
||||||
import io.netty.handler.codec.string.StringDecoder;
|
import io.netty.handler.codec.string.StringDecoder;
|
||||||
import io.netty.handler.codec.string.StringEncoder;
|
import io.netty.handler.codec.string.StringEncoder;
|
||||||
import org.apache.activemq.artemis.api.core.TransportConfiguration;
|
import org.apache.activemq.artemis.api.core.TransportConfiguration;
|
||||||
import org.apache.activemq.artemis.tests.unit.util.InVMNamingContext;
|
|
||||||
import org.apache.activemq.artemis.tests.util.ActiveMQTestBase;
|
|
||||||
import org.apache.activemq.artemis.core.config.Configuration;
|
import org.apache.activemq.artemis.core.config.Configuration;
|
||||||
import org.apache.activemq.artemis.core.protocol.stomp.StompProtocolManagerFactory;
|
import org.apache.activemq.artemis.core.protocol.stomp.StompProtocolManagerFactory;
|
||||||
import org.apache.activemq.artemis.core.registry.JndiBindingRegistry;
|
import org.apache.activemq.artemis.core.registry.JndiBindingRegistry;
|
||||||
|
@ -59,6 +58,7 @@ import org.apache.activemq.artemis.core.remoting.impl.invm.InVMAcceptorFactory;
|
||||||
import org.apache.activemq.artemis.core.remoting.impl.invm.InVMConnectorFactory;
|
import org.apache.activemq.artemis.core.remoting.impl.invm.InVMConnectorFactory;
|
||||||
import org.apache.activemq.artemis.core.remoting.impl.netty.NettyAcceptorFactory;
|
import org.apache.activemq.artemis.core.remoting.impl.netty.NettyAcceptorFactory;
|
||||||
import org.apache.activemq.artemis.core.remoting.impl.netty.TransportConstants;
|
import org.apache.activemq.artemis.core.remoting.impl.netty.TransportConstants;
|
||||||
|
import org.apache.activemq.artemis.core.security.Role;
|
||||||
import org.apache.activemq.artemis.core.server.ActiveMQServer;
|
import org.apache.activemq.artemis.core.server.ActiveMQServer;
|
||||||
import org.apache.activemq.artemis.core.server.ActiveMQServers;
|
import org.apache.activemq.artemis.core.server.ActiveMQServers;
|
||||||
import org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory;
|
import org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory;
|
||||||
|
@ -69,6 +69,9 @@ import org.apache.activemq.artemis.jms.server.config.impl.JMSConfigurationImpl;
|
||||||
import org.apache.activemq.artemis.jms.server.config.impl.JMSQueueConfigurationImpl;
|
import org.apache.activemq.artemis.jms.server.config.impl.JMSQueueConfigurationImpl;
|
||||||
import org.apache.activemq.artemis.jms.server.config.impl.TopicConfigurationImpl;
|
import org.apache.activemq.artemis.jms.server.config.impl.TopicConfigurationImpl;
|
||||||
import org.apache.activemq.artemis.jms.server.impl.JMSServerManagerImpl;
|
import org.apache.activemq.artemis.jms.server.impl.JMSServerManagerImpl;
|
||||||
|
import org.apache.activemq.artemis.spi.core.security.ActiveMQJAASSecurityManager;
|
||||||
|
import org.apache.activemq.artemis.tests.unit.util.InVMNamingContext;
|
||||||
|
import org.apache.activemq.artemis.tests.util.ActiveMQTestBase;
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
|
|
||||||
|
@ -116,7 +119,12 @@ public abstract class StompTestBase extends ActiveMQTestBase {
|
||||||
connectionFactory = createConnectionFactory();
|
connectionFactory = createConnectionFactory();
|
||||||
createBootstrap();
|
createBootstrap();
|
||||||
|
|
||||||
connection = connectionFactory.createConnection();
|
if (isSecurityEnabled()) {
|
||||||
|
connection = connectionFactory.createConnection("brianm", "wombats");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
connection = connectionFactory.createConnection();
|
||||||
|
}
|
||||||
session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
|
session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
|
||||||
queue = session.createQueue(getQueueName());
|
queue = session.createQueue(getQueueName());
|
||||||
topic = session.createTopic(getTopicName());
|
topic = session.createTopic(getTopicName());
|
||||||
|
@ -185,11 +193,23 @@ public abstract class StompTestBase extends ActiveMQTestBase {
|
||||||
TransportConfiguration stompTransport = new TransportConfiguration(NettyAcceptorFactory.class.getName(), params);
|
TransportConfiguration stompTransport = new TransportConfiguration(NettyAcceptorFactory.class.getName(), params);
|
||||||
TransportConfiguration allTransport = new TransportConfiguration(NettyAcceptorFactory.class.getName());
|
TransportConfiguration allTransport = new TransportConfiguration(NettyAcceptorFactory.class.getName());
|
||||||
|
|
||||||
Configuration config = createBasicConfig().setPersistenceEnabled(false).addAcceptorConfiguration(stompTransport).addAcceptorConfiguration(new TransportConfiguration(InVMAcceptorFactory.class.getName()));
|
Configuration config = createBasicConfig().setSecurityEnabled(isSecurityEnabled()).setPersistenceEnabled(false).addAcceptorConfiguration(stompTransport).addAcceptorConfiguration(new TransportConfiguration(InVMAcceptorFactory.class.getName()));
|
||||||
config.addAcceptorConfiguration(allTransport);
|
config.addAcceptorConfiguration(allTransport);
|
||||||
|
|
||||||
ActiveMQServer activeMQServer = addServer(ActiveMQServers.newActiveMQServer(config, defUser, defPass));
|
ActiveMQServer activeMQServer = addServer(ActiveMQServers.newActiveMQServer(config, defUser, defPass));
|
||||||
|
|
||||||
|
if (isSecurityEnabled()) {
|
||||||
|
ActiveMQJAASSecurityManager securityManager = (ActiveMQJAASSecurityManager) activeMQServer.getSecurityManager();
|
||||||
|
|
||||||
|
final String role = "testRole";
|
||||||
|
securityManager.getConfiguration().addRole(defUser, role);
|
||||||
|
config.getSecurityRoles().put("#", new HashSet<Role>() {
|
||||||
|
{
|
||||||
|
add(new Role(role, true, true, true, true, true, true, true));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
JMSConfiguration jmsConfig = new JMSConfigurationImpl();
|
JMSConfiguration jmsConfig = new JMSConfigurationImpl();
|
||||||
jmsConfig.getQueueConfigurations().add(new JMSQueueConfigurationImpl().setName(getQueueName()).setDurable(false).setBindings(getQueueName()));
|
jmsConfig.getQueueConfigurations().add(new JMSQueueConfigurationImpl().setName(getQueueName()).setDurable(false).setBindings(getQueueName()));
|
||||||
jmsConfig.getTopicConfigurations().add(new TopicConfigurationImpl().setName(getTopicName()).setBindings(getTopicName()));
|
jmsConfig.getTopicConfigurations().add(new TopicConfigurationImpl().setName(getTopicName()).setBindings(getTopicName()));
|
||||||
|
@ -319,6 +339,10 @@ public abstract class StompTestBase extends ActiveMQTestBase {
|
||||||
Thread.sleep(500);
|
Thread.sleep(500);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isSecurityEnabled() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
class StompClientHandler extends SimpleChannelInboundHandler<String> {
|
class StompClientHandler extends SimpleChannelInboundHandler<String> {
|
||||||
|
|
||||||
StringBuffer currentMessage = new StringBuffer("");
|
StringBuffer currentMessage = new StringBuffer("");
|
||||||
|
|
|
@ -0,0 +1,61 @@
|
||||||
|
/*
|
||||||
|
* 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.tests.integration.stomp;
|
||||||
|
|
||||||
|
import javax.jms.MessageConsumer;
|
||||||
|
import javax.jms.TextMessage;
|
||||||
|
|
||||||
|
import org.apache.activemq.artemis.core.protocol.stomp.Stomp;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
public class StompTestWithSecurity extends StompTestBase {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testJMSXUserID() throws Exception {
|
||||||
|
server.getActiveMQServer().getConfiguration().setPopulateValidatedUser(true);
|
||||||
|
|
||||||
|
MessageConsumer consumer = session.createConsumer(queue);
|
||||||
|
|
||||||
|
String frame = "CONNECT\n" + "login: brianm\n" + "passcode: wombats\n\n" + Stomp.NULL;
|
||||||
|
sendFrame(frame);
|
||||||
|
|
||||||
|
frame = receiveFrame(10000);
|
||||||
|
Assert.assertTrue(frame.startsWith("CONNECTED"));
|
||||||
|
|
||||||
|
frame = "SEND\n" + "destination:" + getQueuePrefix() + getQueueName() + "\n\n" + "Hello World" + Stomp.NULL;
|
||||||
|
|
||||||
|
sendFrame(frame);
|
||||||
|
|
||||||
|
TextMessage message = (TextMessage) consumer.receive(1000);
|
||||||
|
Assert.assertNotNull(message);
|
||||||
|
Assert.assertEquals("Hello World", message.getText());
|
||||||
|
// Assert default priority 4 is used when priority header is not set
|
||||||
|
Assert.assertEquals("getJMSPriority", 4, message.getJMSPriority());
|
||||||
|
Assert.assertEquals("JMSXUserID", "brianm", message.getStringProperty("JMSXUserID"));
|
||||||
|
|
||||||
|
// Make sure that the timestamp is valid - should
|
||||||
|
// be very close to the current time.
|
||||||
|
long tnow = System.currentTimeMillis();
|
||||||
|
long tmsg = message.getJMSTimestamp();
|
||||||
|
Assert.assertTrue(Math.abs(tnow - tmsg) < 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isSecurityEnabled() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue