This closes #3107
This commit is contained in:
commit
0fe11c7562
|
@ -17,7 +17,7 @@
|
|||
|
||||
# Additional logger names to configure (root logger is always configured)
|
||||
# Root logger option
|
||||
loggers=org.eclipse.jetty,org.jboss.logging,org.apache.activemq.artemis.core.server,org.apache.activemq.artemis.utils,org.apache.activemq.artemis.journal,org.apache.activemq.artemis.jms.server,org.apache.activemq.artemis.integration.bootstrap,org.apache.activemq.audit.base,org.apache.activemq.audit.message
|
||||
loggers=org.eclipse.jetty,org.jboss.logging,org.apache.activemq.artemis.core.server,org.apache.activemq.artemis.utils,org.apache.activemq.artemis.journal,org.apache.activemq.artemis.jms.server,org.apache.activemq.artemis.integration.bootstrap,org.apache.activemq.audit.base,org.apache.activemq.audit.message,org.apache.activemq.audit.resource
|
||||
|
||||
# Root logger level
|
||||
logger.level=INFO
|
||||
|
@ -36,6 +36,10 @@ logger.org.apache.activemq.audit.base.level=ERROR
|
|||
logger.org.apache.activemq.audit.base.handlers=AUDIT_FILE
|
||||
logger.org.apache.activemq.audit.base.useParentHandlers=false
|
||||
|
||||
logger.org.apache.activemq.audit.resource.level=ERROR
|
||||
logger.org.apache.activemq.audit.resource.handlers=AUDIT_FILE
|
||||
logger.org.apache.activemq.audit.resource.useParentHandlers=false
|
||||
|
||||
logger.org.apache.activemq.audit.message.level=ERROR
|
||||
logger.org.apache.activemq.audit.message.handlers=AUDIT_FILE
|
||||
logger.org.apache.activemq.audit.message.useParentHandlers=false
|
||||
|
|
|
@ -23,10 +23,12 @@ import org.jboss.logging.annotations.LogMessage;
|
|||
import org.jboss.logging.annotations.Message;
|
||||
import org.jboss.logging.annotations.MessageLogger;
|
||||
|
||||
import javax.management.ObjectName;
|
||||
import javax.security.auth.Subject;
|
||||
import java.security.AccessController;
|
||||
import java.security.Principal;
|
||||
import java.util.Arrays;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Logger Code 60
|
||||
|
@ -46,26 +48,81 @@ import java.util.Arrays;
|
|||
public interface AuditLogger extends BasicLogger {
|
||||
|
||||
AuditLogger LOGGER = Logger.getMessageLogger(AuditLogger.class, "org.apache.activemq.audit.base");
|
||||
AuditLogger RESOURCE_LOGGER = Logger.getMessageLogger(AuditLogger.class, "org.apache.activemq.audit.resource");
|
||||
AuditLogger MESSAGE_LOGGER = Logger.getMessageLogger(AuditLogger.class, "org.apache.activemq.audit.message");
|
||||
|
||||
ThreadLocal<String> remoteUrl = new ThreadLocal<>();
|
||||
|
||||
ThreadLocal<Subject> currentCaller = new ThreadLocal<>();
|
||||
|
||||
static boolean isAnyLoggingEnabled() {
|
||||
return isEnabled() || isMessageEnabled() || isResourceLoggingEnabled();
|
||||
}
|
||||
|
||||
static boolean isEnabled() {
|
||||
return LOGGER.isEnabled(Logger.Level.INFO);
|
||||
}
|
||||
|
||||
static boolean isResourceLoggingEnabled() {
|
||||
return RESOURCE_LOGGER.isEnabled(Logger.Level.INFO);
|
||||
}
|
||||
|
||||
static boolean isMessageEnabled() {
|
||||
return MESSAGE_LOGGER.isEnabled(Logger.Level.INFO);
|
||||
}
|
||||
|
||||
static String getCaller() {
|
||||
Subject subject = Subject.getSubject(AccessController.getContext());
|
||||
String caller = "anonymous";
|
||||
if (subject == null) {
|
||||
subject = currentCaller.get();
|
||||
}
|
||||
return getCaller(subject);
|
||||
}
|
||||
|
||||
static String getCaller(String user) {
|
||||
Subject subject = Subject.getSubject(AccessController.getContext());
|
||||
if (subject == null) {
|
||||
subject = currentCaller.get();
|
||||
}
|
||||
if (subject == null) {
|
||||
return user + (remoteUrl.get() == null ? "@unknown" : remoteUrl.get());
|
||||
}
|
||||
return getCaller(subject);
|
||||
}
|
||||
|
||||
static String getCaller(Subject subject) {
|
||||
String user = "anonymous";
|
||||
String roles = "";
|
||||
String url = remoteUrl.get() == null ? "@unknown" : remoteUrl.get();
|
||||
if (subject != null) {
|
||||
caller = "";
|
||||
for (Principal principal : subject.getPrincipals()) {
|
||||
caller += principal.getName() + "|";
|
||||
Set<Principal> principals = subject.getPrincipals();
|
||||
for (Principal principal : principals) {
|
||||
if (principal.getClass().getName().endsWith("UserPrincipal")) {
|
||||
user = principal.getName();
|
||||
} else if (principal.getClass().getName().endsWith("RolePrincipal")) {
|
||||
roles = "(" + principal.getName() + ")";
|
||||
}
|
||||
}
|
||||
return caller;
|
||||
}
|
||||
return user + roles + url;
|
||||
}
|
||||
|
||||
static void setCurrentCaller(Subject caller) {
|
||||
currentCaller.set(caller);
|
||||
}
|
||||
|
||||
static void setRemoteAddress(String remoteAddress) {
|
||||
String actualAddress;
|
||||
if (remoteAddress.startsWith("/")) {
|
||||
actualAddress = "@" + remoteAddress.substring(1);
|
||||
} else {
|
||||
actualAddress = "@" + remoteAddress;
|
||||
}
|
||||
remoteUrl.set(actualAddress);
|
||||
}
|
||||
|
||||
static String getRemoteAddress() {
|
||||
return remoteUrl.get();
|
||||
}
|
||||
|
||||
static String arrayToString(Object value) {
|
||||
|
@ -201,7 +258,7 @@ public interface AuditLogger extends BasicLogger {
|
|||
void getUnRoutedMessageCount(String user, Object source, Object... args);
|
||||
|
||||
static void sendMessage(Object source, String user, Object... args) {
|
||||
LOGGER.sendMessage(user == null ? getCaller() : user, source, arrayToString(args));
|
||||
LOGGER.sendMessage(getCaller(user), source, arrayToString(args));
|
||||
}
|
||||
|
||||
@LogMessage(level = Logger.Level.INFO)
|
||||
|
@ -617,7 +674,7 @@ public interface AuditLogger extends BasicLogger {
|
|||
void deployQueue(String user, Object source, Object... args);
|
||||
|
||||
static void createQueue(Object source, String user, Object... args) {
|
||||
LOGGER.createQueue(user == null ? getCaller() : user, source, arrayToString(args));
|
||||
RESOURCE_LOGGER.createQueue(getCaller(user), source, arrayToString(args));
|
||||
}
|
||||
|
||||
@LogMessage(level = Logger.Level.INFO)
|
||||
|
@ -673,7 +730,7 @@ public interface AuditLogger extends BasicLogger {
|
|||
void getAddressNames(String user, Object source, Object... args);
|
||||
|
||||
static void destroyQueue(Object source, String user, Object... args) {
|
||||
LOGGER.destroyQueue(user == null ? getCaller() : user, source, arrayToString(args));
|
||||
LOGGER.destroyQueue(getCaller(user), source, arrayToString(args));
|
||||
}
|
||||
|
||||
@LogMessage(level = Logger.Level.INFO)
|
||||
|
@ -2193,7 +2250,7 @@ public interface AuditLogger extends BasicLogger {
|
|||
void getUniqueName(String user, Object source, Object... args);
|
||||
|
||||
static void serverSessionCreateAddress(Object source, String user, Object... args) {
|
||||
LOGGER.serverSessionCreateAddress2(user == null ? getCaller() : user, source, arrayToString(args));
|
||||
LOGGER.serverSessionCreateAddress2(getCaller(user), source, arrayToString(args));
|
||||
}
|
||||
|
||||
@LogMessage(level = Logger.Level.INFO)
|
||||
|
@ -2201,7 +2258,7 @@ public interface AuditLogger extends BasicLogger {
|
|||
void serverSessionCreateAddress2(String user, Object source, Object... args);
|
||||
|
||||
static void handleManagementMessage(Object source, String user, Object... args) {
|
||||
LOGGER.handleManagementMessage2(user == null ? getCaller() : user, source, arrayToString(args));
|
||||
LOGGER.handleManagementMessage2(getCaller(user), source, arrayToString(args));
|
||||
}
|
||||
|
||||
@LogMessage(level = Logger.Level.INFO)
|
||||
|
@ -2219,7 +2276,7 @@ public interface AuditLogger extends BasicLogger {
|
|||
|
||||
|
||||
static void createCoreConsumer(Object source, String user, Object... args) {
|
||||
LOGGER.createCoreConsumer(user == null ? getCaller() : user, source, arrayToString(args));
|
||||
LOGGER.createCoreConsumer(getCaller(user), source, arrayToString(args));
|
||||
}
|
||||
|
||||
@LogMessage(level = Logger.Level.INFO)
|
||||
|
@ -2227,7 +2284,7 @@ public interface AuditLogger extends BasicLogger {
|
|||
void createCoreConsumer(String user, Object source, Object... args);
|
||||
|
||||
static void createSharedQueue(Object source, String user, Object... args) {
|
||||
LOGGER.createSharedQueue(user == null ? getCaller() : user, source, arrayToString(args));
|
||||
LOGGER.createSharedQueue(getCaller(user), source, arrayToString(args));
|
||||
}
|
||||
|
||||
@LogMessage(level = Logger.Level.INFO)
|
||||
|
@ -2250,22 +2307,12 @@ public interface AuditLogger extends BasicLogger {
|
|||
@Message(id = 601268, value = "User {0} is getting produced message rate on target resource: {1} {2}", format = Message.Format.MESSAGE_FORMAT)
|
||||
void getProducedRate(String user, Object source, Object... args);
|
||||
|
||||
//hot path log using a different logger
|
||||
static void coreSendMessage(Object source, String user, Object... args) {
|
||||
MESSAGE_LOGGER.coreSendMessage(user == null ? getCaller() : user, source, arrayToString(args));
|
||||
}
|
||||
|
||||
@LogMessage(level = Logger.Level.INFO)
|
||||
@Message(id = 601500, value = "User {0} is sending a core message on target resource: {1} {2}", format = Message.Format.MESSAGE_FORMAT)
|
||||
void coreSendMessage(String user, Object source, Object... args);
|
||||
|
||||
|
||||
static void getAcknowledgeAttempts(Object source) {
|
||||
LOGGER.getMessagesAcknowledged(getCaller(), source);
|
||||
}
|
||||
|
||||
@LogMessage(level = Logger.Level.INFO)
|
||||
@Message(id = 601501, value = "User {0} is getting messages acknowledged attempts on target resource: {1} {2}", format = Message.Format.MESSAGE_FORMAT)
|
||||
@Message(id = 601269, value = "User {0} is getting messages acknowledged attempts on target resource: {1} {2}", format = Message.Format.MESSAGE_FORMAT)
|
||||
void getAcknowledgeAttempts(String user, Object source, Object... args);
|
||||
|
||||
static void getRingSize(Object source, Object... args) {
|
||||
|
@ -2273,7 +2320,7 @@ public interface AuditLogger extends BasicLogger {
|
|||
}
|
||||
|
||||
@LogMessage(level = Logger.Level.INFO)
|
||||
@Message(id = 601502, value = "User {0} is getting ring size on target resource: {1} {2}", format = Message.Format.MESSAGE_FORMAT)
|
||||
@Message(id = 601270, value = "User {0} is getting ring size on target resource: {1} {2}", format = Message.Format.MESSAGE_FORMAT)
|
||||
void getRingSize(String user, Object source, Object... args);
|
||||
|
||||
|
||||
|
@ -2282,7 +2329,7 @@ public interface AuditLogger extends BasicLogger {
|
|||
}
|
||||
|
||||
@LogMessage(level = Logger.Level.INFO)
|
||||
@Message(id = 601503, value = "User {0} is getting retroactiveResource property on target resource: {1} {2}", format = Message.Format.MESSAGE_FORMAT)
|
||||
@Message(id = 601271, value = "User {0} is getting retroactiveResource property on target resource: {1} {2}", format = Message.Format.MESSAGE_FORMAT)
|
||||
void isRetroactiveResource(String user, Object source, Object... args);
|
||||
|
||||
static void getDiskStoreUsage(Object source) {
|
||||
|
@ -2290,7 +2337,7 @@ public interface AuditLogger extends BasicLogger {
|
|||
}
|
||||
|
||||
@LogMessage(level = Logger.Level.INFO)
|
||||
@Message(id = 601504, value = "User {0} is getting disk store usage on target resource: {1} {2}", format = Message.Format.MESSAGE_FORMAT)
|
||||
@Message(id = 601272, value = "User {0} is getting disk store usage on target resource: {1} {2}", format = Message.Format.MESSAGE_FORMAT)
|
||||
void getDiskStoreUsage(String user, Object source, Object... args);
|
||||
|
||||
static void getDiskStoreUsagePercentage(Object source) {
|
||||
|
@ -2298,7 +2345,7 @@ public interface AuditLogger extends BasicLogger {
|
|||
}
|
||||
|
||||
@LogMessage(level = Logger.Level.INFO)
|
||||
@Message(id = 601505, value = "User {0} is getting disk store usage percentage on target resource: {1} {2}", format = Message.Format.MESSAGE_FORMAT)
|
||||
@Message(id = 601273, value = "User {0} is getting disk store usage percentage on target resource: {1} {2}", format = Message.Format.MESSAGE_FORMAT)
|
||||
void getDiskStoreUsagePercentage(String user, Object source, Object... args);
|
||||
|
||||
static void isGroupRebalance(Object source) {
|
||||
|
@ -2306,7 +2353,7 @@ public interface AuditLogger extends BasicLogger {
|
|||
}
|
||||
|
||||
@LogMessage(level = Logger.Level.INFO)
|
||||
@Message(id = 601506, value = "User {0} is getting group rebalance property on target resource: {1} {2}", format = Message.Format.MESSAGE_FORMAT)
|
||||
@Message(id = 601274, value = "User {0} is getting group rebalance property on target resource: {1} {2}", format = Message.Format.MESSAGE_FORMAT)
|
||||
void isGroupRebalance(String user, Object source, Object... args);
|
||||
|
||||
static void getGroupBuckets(Object source) {
|
||||
|
@ -2314,7 +2361,7 @@ public interface AuditLogger extends BasicLogger {
|
|||
}
|
||||
|
||||
@LogMessage(level = Logger.Level.INFO)
|
||||
@Message(id = 601507, value = "User {0} is getting group buckets on target resource: {1} {2}", format = Message.Format.MESSAGE_FORMAT)
|
||||
@Message(id = 601275, value = "User {0} is getting group buckets on target resource: {1} {2}", format = Message.Format.MESSAGE_FORMAT)
|
||||
void getGroupBuckets(String user, Object source, Object... args);
|
||||
|
||||
static void getGroupFirstKey(Object source) {
|
||||
|
@ -2322,7 +2369,7 @@ public interface AuditLogger extends BasicLogger {
|
|||
}
|
||||
|
||||
@LogMessage(level = Logger.Level.INFO)
|
||||
@Message(id = 601508, value = "User {0} is getting group first key on target resource: {1} {2}", format = Message.Format.MESSAGE_FORMAT)
|
||||
@Message(id = 601276, value = "User {0} is getting group first key on target resource: {1} {2}", format = Message.Format.MESSAGE_FORMAT)
|
||||
void getGroupFirstKey(String user, Object source, Object... args);
|
||||
|
||||
static void getCurrentDuplicateIdCacheSize(Object source) {
|
||||
|
@ -2341,4 +2388,254 @@ public interface AuditLogger extends BasicLogger {
|
|||
@LogMessage(level = Logger.Level.INFO)
|
||||
@Message(id = 601510, value = "User {0} is clearing duplicate ID cache on target resource: {1} {2}", format = Message.Format.MESSAGE_FORMAT)
|
||||
void clearDuplicateIdCache(String user, Object source, Object... args);
|
||||
|
||||
|
||||
/*
|
||||
* This logger is for message production and consumption and is on the hot path so enabled independently
|
||||
*
|
||||
* */
|
||||
//hot path log using a different logger
|
||||
static void coreSendMessage(String user, Object context) {
|
||||
MESSAGE_LOGGER.sendMessage(getCaller(user), context);
|
||||
}
|
||||
|
||||
@LogMessage(level = Logger.Level.INFO)
|
||||
@Message(id = 601500, value = "User {0} is sending a core message with Context: {1}", format = Message.Format.MESSAGE_FORMAT)
|
||||
void sendMessage(String user, Object context);
|
||||
|
||||
//hot path log using a different logger
|
||||
static void coreConsumeMessage(String queue) {
|
||||
MESSAGE_LOGGER.consumeMessage(getCaller(), queue);
|
||||
}
|
||||
|
||||
@LogMessage(level = Logger.Level.INFO)
|
||||
@Message(id = 601501, value = "User {0} is consuming a message from {1}", format = Message.Format.MESSAGE_FORMAT)
|
||||
void consumeMessage(String user, String address);
|
||||
|
||||
/*
|
||||
* This logger is focused on user interaction from the console or thru resource specific functions in the management layer/JMX
|
||||
* */
|
||||
|
||||
static void createAddressSuccess(String name, String routingTypes) {
|
||||
RESOURCE_LOGGER.createAddressSuccess(getCaller(), name, routingTypes);
|
||||
}
|
||||
|
||||
@LogMessage(level = Logger.Level.INFO)
|
||||
@Message(id = 601701, value = "User {0} successfully created Address: {1} with routing types {2}", format = Message.Format.MESSAGE_FORMAT)
|
||||
void createAddressSuccess(String user, String name, String routingTypes);
|
||||
|
||||
static void createAddressFailure(String name, String routingTypes) {
|
||||
RESOURCE_LOGGER.createAddressFailure(getCaller(), name, routingTypes);
|
||||
}
|
||||
|
||||
@LogMessage(level = Logger.Level.INFO)
|
||||
@Message(id = 601702, value = "User {0} failed to created Address: {1} with routing types {2}", format = Message.Format.MESSAGE_FORMAT)
|
||||
void createAddressFailure(String user, String name, String routingTypes);
|
||||
|
||||
static void updateAddressSuccess(String name, String routingTypes) {
|
||||
RESOURCE_LOGGER.updateAddressSuccess(getCaller(), name, routingTypes);
|
||||
}
|
||||
|
||||
@LogMessage(level = Logger.Level.INFO)
|
||||
@Message(id = 601703, value = "User {0} successfully updated Address: {1} with routing types {2}", format = Message.Format.MESSAGE_FORMAT)
|
||||
void updateAddressSuccess(String user, String name, String routingTypes);
|
||||
|
||||
static void updateAddressFailure(String name, String routingTypes) {
|
||||
RESOURCE_LOGGER.updateAddressFailure(getCaller(), name, routingTypes);
|
||||
}
|
||||
|
||||
@LogMessage(level = Logger.Level.INFO)
|
||||
@Message(id = 601704, value = "User {0} successfully updated Address: {1} with routing types {2}", format = Message.Format.MESSAGE_FORMAT)
|
||||
void updateAddressFailure(String user, String name, String routingTypes);
|
||||
|
||||
static void deleteAddressSuccess(String name) {
|
||||
RESOURCE_LOGGER.deleteAddressSuccess(getCaller(), name);
|
||||
}
|
||||
|
||||
@LogMessage(level = Logger.Level.INFO)
|
||||
@Message(id = 601705, value = "User {0} successfully deleted Address: {1}", format = Message.Format.MESSAGE_FORMAT)
|
||||
void deleteAddressSuccess(String user, String name);
|
||||
|
||||
|
||||
static void deleteAddressFailure(String name) {
|
||||
RESOURCE_LOGGER.deleteAddressFailure(getCaller(), name);
|
||||
}
|
||||
|
||||
@LogMessage(level = Logger.Level.INFO)
|
||||
@Message(id = 601706, value = "User {0} failed to deleted Address: {1}", format = Message.Format.MESSAGE_FORMAT)
|
||||
void deleteAddressFailure(String user, String name);
|
||||
|
||||
static void createQueueSuccess(String name, String address, String routingType) {
|
||||
RESOURCE_LOGGER.createQueueSuccess(getCaller(), name, address, routingType);
|
||||
}
|
||||
|
||||
@LogMessage(level = Logger.Level.INFO)
|
||||
@Message(id = 601707, value = "User {0} successfully created Queue: {1} on Address: {2} with routing type {3}", format = Message.Format.MESSAGE_FORMAT)
|
||||
void createQueueSuccess(String user, String name, String address, String routingType);
|
||||
|
||||
static void createQueueFailure(String name, String address, String routingType) {
|
||||
RESOURCE_LOGGER.createQueueFailure(getCaller(), name, address, routingType);
|
||||
}
|
||||
|
||||
@LogMessage(level = Logger.Level.INFO)
|
||||
@Message(id = 601708, value = "User {0} failed to create Queue: {1} on Address: {2} with routing type {3}", format = Message.Format.MESSAGE_FORMAT)
|
||||
void createQueueFailure(String user, String name, String address, String routingType);
|
||||
|
||||
static void updateQueueSuccess(String name, String routingType) {
|
||||
RESOURCE_LOGGER.updateQueueSuccess(getCaller(), name, routingType);
|
||||
}
|
||||
|
||||
@LogMessage(level = Logger.Level.INFO)
|
||||
@Message(id = 601709, value = "User {0} successfully updated Queue: {1} with routing type {2}", format = Message.Format.MESSAGE_FORMAT)
|
||||
void updateQueueSuccess(String user, String name, String routingType);
|
||||
|
||||
static void updateQueueFailure(String name, String routingType) {
|
||||
RESOURCE_LOGGER.updateQueueFailure(getCaller(), name, routingType);
|
||||
}
|
||||
|
||||
@LogMessage(level = Logger.Level.INFO)
|
||||
@Message(id = 601710, value = "User {0} failed to update Queue: {1} with routing type {2}", format = Message.Format.MESSAGE_FORMAT)
|
||||
void updateQueueFailure(String user, String name, String routingType);
|
||||
|
||||
|
||||
static void destroyQueueSuccess(String name) {
|
||||
RESOURCE_LOGGER.destroyQueueSuccess(getCaller(), name);
|
||||
}
|
||||
|
||||
@LogMessage(level = Logger.Level.INFO)
|
||||
@Message(id = 601711, value = "User {0} successfully deleted Queue: {1}", format = Message.Format.MESSAGE_FORMAT)
|
||||
void destroyQueueSuccess(String user, String name);
|
||||
|
||||
static void destroyQueueFailure(String name) {
|
||||
RESOURCE_LOGGER.destroyQueueFailure(getCaller(), name);
|
||||
}
|
||||
|
||||
@LogMessage(level = Logger.Level.INFO)
|
||||
@Message(id = 601712, value = "User {0} failed to delete Queue: {1}", format = Message.Format.MESSAGE_FORMAT)
|
||||
void destroyQueueFailure(String user, String name);
|
||||
|
||||
static void removeMessagesSuccess(int removed, String queue) {
|
||||
RESOURCE_LOGGER.removeMessagesSuccess(getCaller(), removed, queue);
|
||||
}
|
||||
|
||||
@LogMessage(level = Logger.Level.INFO)
|
||||
@Message(id = 601713, value = "User {0} has removed {1} messages from Queue: {2}", format = Message.Format.MESSAGE_FORMAT)
|
||||
void removeMessagesSuccess(String user, int removed, String queue);
|
||||
|
||||
static void removeMessagesFailure(String queue) {
|
||||
RESOURCE_LOGGER.removeMessagesFailure(getCaller(), queue);
|
||||
}
|
||||
|
||||
@LogMessage(level = Logger.Level.INFO)
|
||||
@Message(id = 601714, value = "User {0} failed to remove messages from Queue: {1}", format = Message.Format.MESSAGE_FORMAT)
|
||||
void removeMessagesFailure(String user, String queue);
|
||||
|
||||
static void userSuccesfullyLoggedInAudit(Subject subject) {
|
||||
RESOURCE_LOGGER.userSuccesfullyLoggedIn(getCaller(subject));
|
||||
}
|
||||
|
||||
static void userSuccesfullyLoggedInAudit() {
|
||||
RESOURCE_LOGGER.userSuccesfullyLoggedIn(getCaller());
|
||||
}
|
||||
|
||||
@LogMessage(level = Logger.Level.INFO)
|
||||
@Message(id = 601715, value = "User {0} successfully authorized", format = Message.Format.MESSAGE_FORMAT)
|
||||
void userSuccesfullyLoggedIn(String caller);
|
||||
|
||||
|
||||
static void userFailedLoggedInAudit(String reason) {
|
||||
RESOURCE_LOGGER.userFailedLoggedIn(getCaller(), reason);
|
||||
}
|
||||
|
||||
static void userFailedLoggedInAudit(Subject subject, String reason) {
|
||||
RESOURCE_LOGGER.userFailedLoggedIn(getCaller(subject), reason);
|
||||
}
|
||||
|
||||
@LogMessage(level = Logger.Level.INFO)
|
||||
@Message(id = 601716, value = "User {0} failed authorization, reason: {1}", format = Message.Format.MESSAGE_FORMAT)
|
||||
void userFailedLoggedIn(String user, String reason);
|
||||
|
||||
static void objectInvokedSuccessfully(ObjectName objectName, String operationName) {
|
||||
RESOURCE_LOGGER.objectInvokedSuccessfully(getCaller(), objectName, operationName);
|
||||
}
|
||||
|
||||
@LogMessage(level = Logger.Level.INFO)
|
||||
@Message(id = 601717, value = "User {0} accessed {2} on management object {1}", format = Message.Format.MESSAGE_FORMAT)
|
||||
void objectInvokedSuccessfully(String caller, ObjectName objectName, String operationName);
|
||||
|
||||
|
||||
static void objectInvokedFailure(ObjectName objectName, String operationName) {
|
||||
RESOURCE_LOGGER.objectInvokedFailure(getCaller(), objectName, operationName);
|
||||
}
|
||||
|
||||
@LogMessage(level = Logger.Level.INFO)
|
||||
@Message(id = 601718, value = "User {0} does not have correct role to access {2} on management object {1}", format = Message.Format.MESSAGE_FORMAT)
|
||||
void objectInvokedFailure(String caller, ObjectName objectName, String operationName);
|
||||
|
||||
static void pauseQueueSuccess(String queueName) {
|
||||
RESOURCE_LOGGER.pauseQueueSuccess(getCaller(), queueName);
|
||||
}
|
||||
|
||||
@LogMessage(level = Logger.Level.INFO)
|
||||
@Message(id = 601719, value = "User {0} has paused queue {1}", format = Message.Format.MESSAGE_FORMAT)
|
||||
void pauseQueueSuccess(String user, String queueName);
|
||||
|
||||
|
||||
static void pauseQueueFailure(String queueName) {
|
||||
RESOURCE_LOGGER.pauseQueueFailure(getCaller(), queueName);
|
||||
}
|
||||
|
||||
@LogMessage(level = Logger.Level.INFO)
|
||||
@Message(id = 601720, value = "User {0} failed to pause queue {1}", format = Message.Format.MESSAGE_FORMAT)
|
||||
void pauseQueueFailure(String user, String queueName);
|
||||
|
||||
|
||||
static void resumeQueueSuccess(String queueName) {
|
||||
RESOURCE_LOGGER.resumeQueueSuccess(getCaller(), queueName);
|
||||
}
|
||||
|
||||
@LogMessage(level = Logger.Level.INFO)
|
||||
@Message(id = 601721, value = "User {0} has paused queue {1}", format = Message.Format.MESSAGE_FORMAT)
|
||||
void resumeQueueSuccess(String user, String queueName);
|
||||
|
||||
|
||||
static void resumeQueueFailure(String queueName) {
|
||||
RESOURCE_LOGGER.pauseQueueFailure(getCaller(), queueName);
|
||||
}
|
||||
|
||||
@LogMessage(level = Logger.Level.INFO)
|
||||
@Message(id = 601722, value = "User {0} failed to resume queue {1}", format = Message.Format.MESSAGE_FORMAT)
|
||||
void resumeQueueFailure(String user, String queueName);
|
||||
|
||||
static void sendMessageSuccess(String queueName, String user) {
|
||||
RESOURCE_LOGGER.sendMessageSuccess(getCaller(), queueName, user);
|
||||
}
|
||||
|
||||
@LogMessage(level = Logger.Level.INFO)
|
||||
@Message(id = 601723, value = "User {0} sent message to {1} as user {2}", format = Message.Format.MESSAGE_FORMAT)
|
||||
void sendMessageSuccess(String user, String queueName, String sendUser);
|
||||
|
||||
static void sendMessageFailure(String queueName, String user) {
|
||||
RESOURCE_LOGGER.sendMessageFailure(getCaller(), queueName, user);
|
||||
}
|
||||
|
||||
@LogMessage(level = Logger.Level.INFO)
|
||||
@Message(id = 601724, value = "User {0} failed to send message to {1} as user {2}", format = Message.Format.MESSAGE_FORMAT)
|
||||
void sendMessageFailure(String user, String queueName, String sendUser);
|
||||
|
||||
static void browseMessagesSuccess(String queueName, int numMessages) {
|
||||
RESOURCE_LOGGER.browseMessagesSuccess(getCaller(), queueName, numMessages);
|
||||
}
|
||||
|
||||
@LogMessage(level = Logger.Level.INFO)
|
||||
@Message(id = 601725, value = "User {0} browsed {2} messages from queue {1}", format = Message.Format.MESSAGE_FORMAT)
|
||||
void browseMessagesSuccess(String user, String queueName, int numMessages);
|
||||
|
||||
static void browseMessagesFailure(String queueName) {
|
||||
RESOURCE_LOGGER.browseMessagesFailure(getCaller(), queueName);
|
||||
}
|
||||
|
||||
@LogMessage(level = Logger.Level.INFO)
|
||||
@Message(id = 601726, value = "User {0} failed to browse messages from queue {1}", format = Message.Format.MESSAGE_FORMAT)
|
||||
void browseMessagesFailure(String user, String queueName);
|
||||
}
|
||||
|
|
|
@ -47,6 +47,7 @@ public abstract class AbstractRemotingConnection implements RemotingConnection {
|
|||
protected final long creationTime;
|
||||
protected volatile boolean dataReceived;
|
||||
private String clientId;
|
||||
private Subject subject;
|
||||
|
||||
public AbstractRemotingConnection(final Connection transportConnection, final Executor executor) {
|
||||
this.transportConnection = transportConnection;
|
||||
|
@ -247,6 +248,16 @@ public abstract class AbstractRemotingConnection implements RemotingConnection {
|
|||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAuditSubject(Subject subject) {
|
||||
this.subject = subject;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Subject getAuditSubject() {
|
||||
return subject;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Subject getSubject() {
|
||||
return null;
|
||||
|
|
|
@ -219,6 +219,13 @@ public interface RemotingConnection extends BufferHandler {
|
|||
*/
|
||||
boolean isSupportsFlowControl();
|
||||
|
||||
/*
|
||||
* sets the currently associated subject for this connection
|
||||
* */
|
||||
void setAuditSubject(Subject subject);
|
||||
|
||||
Subject getAuditSubject();
|
||||
|
||||
/**
|
||||
* the possibly null identity associated with this connection
|
||||
* @return
|
||||
|
|
|
@ -494,6 +494,16 @@ public class ChannelImplTest {
|
|||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAuditSubject(Subject subject) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Subject getAuditSubject() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Subject getSubject() {
|
||||
return null;
|
||||
|
|
|
@ -107,7 +107,7 @@ public class AMQPConnectionCallback implements FailureListener, CloseListener {
|
|||
if (isPermittedMechanism(mechanism)) {
|
||||
switch (mechanism) {
|
||||
case PlainSASL.NAME:
|
||||
result = new PlainSASL(server.getSecurityStore(), manager.getSecurityDomain());
|
||||
result = new PlainSASL(server.getSecurityStore(), manager.getSecurityDomain(), connection.getProtocolConnection());
|
||||
break;
|
||||
|
||||
case AnonymousServerSASL.NAME:
|
||||
|
|
|
@ -392,6 +392,11 @@ public class AMQPConnectionContext extends ProtonInitializable implements EventH
|
|||
return connectionCallback.isWritable(readyListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRemoteAddress() {
|
||||
return connectionCallback.getTransportConnection().getRemoteAddress();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRemoteOpen(Connection connection) throws Exception {
|
||||
handler.requireHandler();
|
||||
|
|
|
@ -91,4 +91,7 @@ public interface EventHandler {
|
|||
return true;
|
||||
}
|
||||
|
||||
default String getRemoteAddress() {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ import io.netty.buffer.ByteBuf;
|
|||
import io.netty.buffer.PooledByteBufAllocator;
|
||||
import io.netty.channel.EventLoop;
|
||||
import org.apache.activemq.artemis.api.core.ActiveMQSecurityException;
|
||||
import org.apache.activemq.artemis.logs.AuditLogger;
|
||||
import org.apache.activemq.artemis.protocol.amqp.proton.AMQPConnectionContext;
|
||||
import org.apache.activemq.artemis.protocol.amqp.proton.ProtonInitializable;
|
||||
import org.apache.activemq.artemis.protocol.amqp.sasl.ClientSASL;
|
||||
|
@ -492,6 +493,11 @@ public class ProtonHandler extends ProtonInitializable implements SaslListener {
|
|||
}
|
||||
try {
|
||||
inDispatch = true;
|
||||
if (AuditLogger.isAnyLoggingEnabled()) {
|
||||
for (EventHandler h : handlers) {
|
||||
AuditLogger.setRemoteAddress(h.getRemoteAddress());
|
||||
}
|
||||
}
|
||||
while ((ev = collector.peek()) != null) {
|
||||
for (EventHandler h : handlers) {
|
||||
if (log.isTraceEnabled()) {
|
||||
|
|
|
@ -17,22 +17,25 @@
|
|||
package org.apache.activemq.artemis.protocol.amqp.sasl;
|
||||
|
||||
import org.apache.activemq.artemis.core.security.SecurityStore;
|
||||
import org.apache.activemq.artemis.spi.core.protocol.RemotingConnection;
|
||||
|
||||
public class PlainSASL extends ServerSASLPlain {
|
||||
|
||||
private final SecurityStore securityStore;
|
||||
private final String securityDomain;
|
||||
private RemotingConnection remotingConnection;
|
||||
|
||||
public PlainSASL(SecurityStore securityStore, String securityDomain) {
|
||||
public PlainSASL(SecurityStore securityStore, String securityDomain, RemotingConnection remotingConnection) {
|
||||
this.securityStore = securityStore;
|
||||
this.securityDomain = securityDomain;
|
||||
this.remotingConnection = remotingConnection;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean authenticate(String user, String password) {
|
||||
if (securityStore.isSecurityEnabled()) {
|
||||
try {
|
||||
securityStore.authenticate(user, password, null, securityDomain);
|
||||
securityStore.authenticate(user, password, remotingConnection, securityDomain);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
*/
|
||||
package org.apache.activemq.artemis.protocol.amqp.broker;
|
||||
|
||||
import org.apache.activemq.artemis.core.remoting.impl.invm.InVMConnection;
|
||||
import org.apache.activemq.artemis.core.server.impl.ActiveMQServerImpl;
|
||||
import org.apache.activemq.artemis.protocol.amqp.sasl.AnonymousServerSASL;
|
||||
import org.apache.activemq.artemis.protocol.amqp.sasl.GSSAPIServerSASL;
|
||||
|
@ -32,7 +33,7 @@ public class AMQPConnectionCallbackTest {
|
|||
public void getServerSASLOnlyAllowedMechs() throws Exception {
|
||||
ProtonProtocolManager protonProtocolManager = new ProtonProtocolManager(new ProtonProtocolManagerFactory(), null, null, null);
|
||||
protonProtocolManager.setSaslMechanisms(new String[]{PlainSASL.NAME});
|
||||
AMQPConnectionCallback connectionCallback = new AMQPConnectionCallback(protonProtocolManager, null, null, new ActiveMQServerImpl());
|
||||
AMQPConnectionCallback connectionCallback = new AMQPConnectionCallback(protonProtocolManager, new InVMConnection(1, null, null, null), null, new ActiveMQServerImpl());
|
||||
assertEquals(1, connectionCallback.getSaslMechanisms().length);
|
||||
for (String mech: connectionCallback.getSaslMechanisms()) {
|
||||
assertNotNull(connectionCallback.getServerSASL(mech));
|
||||
|
|
|
@ -52,6 +52,7 @@ public class MQTTConnection implements RemotingConnection {
|
|||
private final List<FailureListener> failureListeners = new CopyOnWriteArrayList<>();
|
||||
|
||||
private final List<CloseListener> closeListeners = new CopyOnWriteArrayList<>();
|
||||
private Subject subject;
|
||||
|
||||
public MQTTConnection(Connection transportConnection) throws Exception {
|
||||
this.transportConnection = transportConnection;
|
||||
|
@ -258,6 +259,16 @@ public class MQTTConnection implements RemotingConnection {
|
|||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAuditSubject(Subject subject) {
|
||||
this.subject = subject;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Subject getAuditSubject() {
|
||||
return subject;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Subject getSubject() {
|
||||
return null;
|
||||
|
|
|
@ -39,6 +39,7 @@ import io.netty.handler.codec.mqtt.MqttUnsubAckMessage;
|
|||
import io.netty.handler.codec.mqtt.MqttUnsubscribeMessage;
|
||||
import io.netty.util.ReferenceCountUtil;
|
||||
import org.apache.activemq.artemis.core.server.ActiveMQServer;
|
||||
import org.apache.activemq.artemis.logs.AuditLogger;
|
||||
import org.apache.activemq.artemis.spi.core.protocol.ConnectionEntry;
|
||||
|
||||
/**
|
||||
|
@ -98,6 +99,10 @@ public class MQTTProtocolHandler extends ChannelInboundHandlerAdapter {
|
|||
|
||||
connection.dataReceived();
|
||||
|
||||
if (AuditLogger.isAnyLoggingEnabled()) {
|
||||
AuditLogger.setRemoteAddress(connection.getRemoteAddress());
|
||||
}
|
||||
|
||||
MQTTUtil.logMessage(session.getState(), message, true);
|
||||
|
||||
if (this.protocolManager.invokeIncoming(message, this.connection) != null) {
|
||||
|
|
|
@ -80,6 +80,7 @@ import org.apache.activemq.artemis.core.transaction.ResourceManager;
|
|||
import org.apache.activemq.artemis.core.transaction.Transaction;
|
||||
import org.apache.activemq.artemis.core.transaction.TransactionOperationAbstract;
|
||||
import org.apache.activemq.artemis.core.transaction.TransactionPropertyIndexes;
|
||||
import org.apache.activemq.artemis.logs.AuditLogger;
|
||||
import org.apache.activemq.artemis.spi.core.protocol.AbstractRemotingConnection;
|
||||
import org.apache.activemq.artemis.spi.core.protocol.ConnectionEntry;
|
||||
import org.apache.activemq.artemis.spi.core.remoting.Connection;
|
||||
|
@ -305,6 +306,10 @@ public class OpenWireConnection extends AbstractRemotingConnection implements Se
|
|||
try {
|
||||
recoverOperationContext();
|
||||
|
||||
if (AuditLogger.isAnyLoggingEnabled()) {
|
||||
AuditLogger.setRemoteAddress(getRemoteAddress());
|
||||
}
|
||||
|
||||
boolean responseRequired = command.isResponseRequired();
|
||||
int commandId = command.getCommandId();
|
||||
|
||||
|
|
|
@ -115,6 +115,7 @@ public final class StompConnection implements RemotingConnection {
|
|||
private final ScheduledExecutorService scheduledExecutorService;
|
||||
|
||||
private final ExecutorFactory executorFactory;
|
||||
private Subject subject;
|
||||
|
||||
@Override
|
||||
public boolean isSupportReconnect() {
|
||||
|
@ -855,6 +856,16 @@ public final class StompConnection implements RemotingConnection {
|
|||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAuditSubject(Subject subject) {
|
||||
this.subject = subject;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Subject getAuditSubject() {
|
||||
return subject;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Subject getSubject() {
|
||||
return null;
|
||||
|
|
|
@ -38,6 +38,7 @@ import org.apache.activemq.artemis.core.remoting.impl.netty.TransportConstants;
|
|||
import org.apache.activemq.artemis.core.server.ActiveMQServer;
|
||||
import org.apache.activemq.artemis.core.server.ActiveMQServerLogger;
|
||||
import org.apache.activemq.artemis.core.server.ServerSession;
|
||||
import org.apache.activemq.artemis.logs.AuditLogger;
|
||||
import org.apache.activemq.artemis.spi.core.protocol.AbstractProtocolManager;
|
||||
import org.apache.activemq.artemis.spi.core.protocol.ConnectionEntry;
|
||||
import org.apache.activemq.artemis.spi.core.protocol.ProtocolManagerFactory;
|
||||
|
@ -154,6 +155,9 @@ public class StompProtocolManager extends AbstractProtocolManager<StompFrame, St
|
|||
}
|
||||
|
||||
try {
|
||||
if (AuditLogger.isAnyLoggingEnabled()) {
|
||||
AuditLogger.setRemoteAddress(connection.getRemoteAddress());
|
||||
}
|
||||
conn.logFrame(request, true);
|
||||
if (invokeInterceptors(this.incomingInterceptors, request, conn) != null) {
|
||||
return;
|
||||
|
|
|
@ -846,9 +846,7 @@ public class ActiveMQServerControlImpl extends AbstractControl implements Active
|
|||
|
||||
@Override
|
||||
public String createAddress(String name, String routingTypes) throws Exception {
|
||||
if (AuditLogger.isEnabled()) {
|
||||
AuditLogger.createAddress(this.server, name, routingTypes);
|
||||
}
|
||||
|
||||
checkStarted();
|
||||
|
||||
clearIO();
|
||||
|
@ -859,8 +857,15 @@ public class ActiveMQServerControlImpl extends AbstractControl implements Active
|
|||
}
|
||||
final AddressInfo addressInfo = new AddressInfo(new SimpleString(name), set);
|
||||
if (server.addAddressInfo(addressInfo)) {
|
||||
return AddressInfoTextFormatter.Long.format(addressInfo, new StringBuilder()).toString();
|
||||
String result = AddressInfoTextFormatter.Long.format(addressInfo, new StringBuilder()).toString();
|
||||
if (AuditLogger.isResourceLoggingEnabled()) {
|
||||
AuditLogger.createAddressSuccess(name, routingTypes);
|
||||
}
|
||||
return result;
|
||||
} else {
|
||||
if (AuditLogger.isResourceLoggingEnabled()) {
|
||||
AuditLogger.createAddressFailure(name, routingTypes);
|
||||
}
|
||||
throw ActiveMQMessageBundle.BUNDLE.addressAlreadyExists(addressInfo.getName());
|
||||
}
|
||||
} finally {
|
||||
|
@ -870,9 +875,7 @@ public class ActiveMQServerControlImpl extends AbstractControl implements Active
|
|||
|
||||
@Override
|
||||
public String updateAddress(String name, String routingTypes) throws Exception {
|
||||
if (AuditLogger.isEnabled()) {
|
||||
AuditLogger.updateAddress(this.server, name, routingTypes);
|
||||
}
|
||||
|
||||
checkStarted();
|
||||
|
||||
clearIO();
|
||||
|
@ -888,8 +891,14 @@ public class ActiveMQServerControlImpl extends AbstractControl implements Active
|
|||
}
|
||||
}
|
||||
if (!server.updateAddressInfo(SimpleString.toSimpleString(name), routingTypeSet)) {
|
||||
if (AuditLogger.isResourceLoggingEnabled()) {
|
||||
AuditLogger.updateAddressFailure(name, routingTypes);
|
||||
}
|
||||
throw ActiveMQMessageBundle.BUNDLE.addressDoesNotExist(SimpleString.toSimpleString(name));
|
||||
}
|
||||
if (AuditLogger.isResourceLoggingEnabled()) {
|
||||
AuditLogger.updateAddressSuccess(name, routingTypes);
|
||||
}
|
||||
return AddressInfoTextFormatter.Long.format(server.getAddressInfo(SimpleString.toSimpleString(name)), new StringBuilder()).toString();
|
||||
} finally {
|
||||
blockOnIO();
|
||||
|
@ -904,15 +913,18 @@ public class ActiveMQServerControlImpl extends AbstractControl implements Active
|
|||
|
||||
@Override
|
||||
public void deleteAddress(String name, boolean force) throws Exception {
|
||||
if (AuditLogger.isEnabled()) {
|
||||
AuditLogger.deleteAddress(this.server, name, force);
|
||||
}
|
||||
checkStarted();
|
||||
|
||||
clearIO();
|
||||
try {
|
||||
server.removeAddressInfo(new SimpleString(name), null, force);
|
||||
if (AuditLogger.isResourceLoggingEnabled()) {
|
||||
AuditLogger.deleteAddressSuccess(name);
|
||||
}
|
||||
} catch (ActiveMQException e) {
|
||||
if (AuditLogger.isResourceLoggingEnabled()) {
|
||||
AuditLogger.deleteAddressFailure(name);
|
||||
}
|
||||
throw new IllegalStateException(e.getMessage());
|
||||
} finally {
|
||||
blockOnIO();
|
||||
|
@ -1203,8 +1215,14 @@ public class ActiveMQServerControlImpl extends AbstractControl implements Active
|
|||
.setAutoDeleteMessageCount(autoDeleteMessageCount)
|
||||
.setAutoCreateAddress(autoCreateAddress)
|
||||
.setRingSize(ringSize));
|
||||
if (AuditLogger.isResourceLoggingEnabled()) {
|
||||
AuditLogger.createQueueSuccess( name, address, routingType);
|
||||
}
|
||||
return QueueTextFormatter.Long.format(queue, new StringBuilder()).toString();
|
||||
} catch (ActiveMQException e) {
|
||||
if (AuditLogger.isResourceLoggingEnabled()) {
|
||||
AuditLogger.createQueueFailure( name, address, routingType);
|
||||
}
|
||||
throw new IllegalStateException(e.getMessage());
|
||||
} finally {
|
||||
blockOnIO();
|
||||
|
@ -1353,8 +1371,15 @@ public class ActiveMQServerControlImpl extends AbstractControl implements Active
|
|||
try {
|
||||
final Queue queue = server.updateQueue(name, routingType != null ? RoutingType.valueOf(routingType) : null, filter, maxConsumers, purgeOnNoConsumers, exclusive, groupRebalance, groupBuckets, groupFirstKey, nonDestructive, consumersBeforeDispatch, delayBeforeDispatch, user);
|
||||
if (queue == null) {
|
||||
if (AuditLogger.isResourceLoggingEnabled()) {
|
||||
AuditLogger.updateQueueFailure(name, routingType);
|
||||
}
|
||||
throw ActiveMQMessageBundle.BUNDLE.noSuchQueue(new SimpleString(name));
|
||||
}
|
||||
if (AuditLogger.isResourceLoggingEnabled()) {
|
||||
AuditLogger.updateQueueSuccess(name, routingType);
|
||||
}
|
||||
|
||||
return QueueTextFormatter.Long.format(queue, new StringBuilder()).toString();
|
||||
} finally {
|
||||
blockOnIO();
|
||||
|
@ -1490,7 +1515,17 @@ public class ActiveMQServerControlImpl extends AbstractControl implements Active
|
|||
clearIO();
|
||||
try {
|
||||
SimpleString queueName = new SimpleString(name);
|
||||
try {
|
||||
server.destroyQueue(queueName, null, !removeConsumers, removeConsumers, autoDeleteAddress);
|
||||
} catch (Exception e) {
|
||||
if (AuditLogger.isResourceLoggingEnabled()) {
|
||||
AuditLogger.destroyQueueFailure(name);
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
if (AuditLogger.isResourceLoggingEnabled()) {
|
||||
AuditLogger.destroyQueueSuccess(name);
|
||||
}
|
||||
} finally {
|
||||
blockOnIO();
|
||||
}
|
||||
|
|
|
@ -181,6 +181,16 @@ public class ManagementRemotingConnection implements RemotingConnection {
|
|||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAuditSubject(Subject subject) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Subject getAuditSubject() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Subject getSubject() {
|
||||
return null;
|
||||
|
|
|
@ -1000,7 +1000,19 @@ public class QueueControlImpl extends AbstractControl implements QueueControl {
|
|||
try {
|
||||
Filter filter = FilterImpl.createFilter(filterStr);
|
||||
|
||||
return queue.deleteMatchingReferences(flushLimit, filter);
|
||||
int removed = 0;
|
||||
try {
|
||||
removed = queue.deleteMatchingReferences(flushLimit, filter);
|
||||
if (AuditLogger.isResourceLoggingEnabled()) {
|
||||
AuditLogger.removeMessagesSuccess(removed, queue.getName().toString());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
if (AuditLogger.isResourceLoggingEnabled()) {
|
||||
AuditLogger.removeMessagesFailure(queue.getName().toString());
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
return removed;
|
||||
} finally {
|
||||
blockOnIO();
|
||||
}
|
||||
|
@ -1194,8 +1206,15 @@ public class QueueControlImpl extends AbstractControl implements QueueControl {
|
|||
AuditLogger.sendMessage(queue, null, headers, type, body, durable, user, "****");
|
||||
}
|
||||
try {
|
||||
return sendMessage(queue.getAddress(), server, headers, type, body, durable, user, password, queue.getID());
|
||||
String s = sendMessage(queue.getAddress(), server, headers, type, body, durable, user, password, queue.getID());
|
||||
if (AuditLogger.isResourceLoggingEnabled()) {
|
||||
AuditLogger.sendMessageSuccess(queue.getName().toString(), user);
|
||||
}
|
||||
return s;
|
||||
} catch (Exception e) {
|
||||
if (AuditLogger.isResourceLoggingEnabled()) {
|
||||
AuditLogger.sendMessageFailure(queue.getName().toString(), user);
|
||||
}
|
||||
throw new IllegalStateException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
@ -1338,8 +1357,17 @@ public class QueueControlImpl extends AbstractControl implements QueueControl {
|
|||
checkStarted();
|
||||
|
||||
clearIO();
|
||||
try {
|
||||
try {
|
||||
queue.pause();
|
||||
if (AuditLogger.isResourceLoggingEnabled()) {
|
||||
AuditLogger.pauseQueueSuccess(queue.getName().toString());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
if (AuditLogger.isResourceLoggingEnabled()) {
|
||||
AuditLogger.pauseQueueFailure(queue.getName().toString());
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
blockOnIO();
|
||||
}
|
||||
|
@ -1354,8 +1382,17 @@ public class QueueControlImpl extends AbstractControl implements QueueControl {
|
|||
checkStarted();
|
||||
|
||||
clearIO();
|
||||
try {
|
||||
try {
|
||||
queue.pause(persist);
|
||||
if (AuditLogger.isResourceLoggingEnabled()) {
|
||||
AuditLogger.pauseQueueSuccess(queue.getName().toString());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
if (AuditLogger.isResourceLoggingEnabled()) {
|
||||
AuditLogger.pauseQueueFailure(queue.getName().toString());
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
blockOnIO();
|
||||
}
|
||||
|
@ -1368,8 +1405,18 @@ public class QueueControlImpl extends AbstractControl implements QueueControl {
|
|||
checkStarted();
|
||||
|
||||
clearIO();
|
||||
try {
|
||||
try {
|
||||
queue.resume();
|
||||
if (AuditLogger.isResourceLoggingEnabled()) {
|
||||
AuditLogger.resumeQueueSuccess(queue.getName().toString());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
if (AuditLogger.isResourceLoggingEnabled()) {
|
||||
AuditLogger.resumeQueueFailure(queue.getName().toString());
|
||||
}
|
||||
e.printStackTrace();
|
||||
}
|
||||
} finally {
|
||||
blockOnIO();
|
||||
}
|
||||
|
@ -1425,9 +1472,15 @@ public class QueueControlImpl extends AbstractControl implements QueueControl {
|
|||
|
||||
CompositeData[] rc = new CompositeData[c.size()];
|
||||
c.toArray(rc);
|
||||
if (AuditLogger.isResourceLoggingEnabled()) {
|
||||
AuditLogger.browseMessagesSuccess(queue.getName().toString(), c.size());
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
} catch (ActiveMQException e) {
|
||||
if (AuditLogger.isResourceLoggingEnabled()) {
|
||||
AuditLogger.browseMessagesFailure(queue.getName().toString());
|
||||
}
|
||||
throw new IllegalStateException(e.getMessage());
|
||||
} finally {
|
||||
blockOnIO();
|
||||
|
@ -1467,9 +1520,15 @@ public class QueueControlImpl extends AbstractControl implements QueueControl {
|
|||
|
||||
CompositeData[] rc = new CompositeData[c.size()];
|
||||
c.toArray(rc);
|
||||
if (AuditLogger.isResourceLoggingEnabled()) {
|
||||
AuditLogger.browseMessagesSuccess(queue.getName().toString(), currentPageSize);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
} catch (ActiveMQException e) {
|
||||
if (AuditLogger.isResourceLoggingEnabled()) {
|
||||
AuditLogger.browseMessagesFailure(queue.getName().toString());
|
||||
}
|
||||
throw new IllegalStateException(e.getMessage());
|
||||
} finally {
|
||||
blockOnIO();
|
||||
|
|
|
@ -95,6 +95,7 @@ import org.apache.activemq.artemis.core.server.BindingQueryResult;
|
|||
import org.apache.activemq.artemis.core.server.LargeServerMessage;
|
||||
import org.apache.activemq.artemis.core.server.QueueQueryResult;
|
||||
import org.apache.activemq.artemis.core.server.ServerSession;
|
||||
import org.apache.activemq.artemis.logs.AuditLogger;
|
||||
import org.apache.activemq.artemis.spi.core.protocol.EmbedMessageUtil;
|
||||
import org.apache.activemq.artemis.spi.core.remoting.Connection;
|
||||
import org.apache.activemq.artemis.utils.SimpleFuture;
|
||||
|
@ -264,6 +265,10 @@ public class ServerSessionPacketHandler implements ChannelHandler {
|
|||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("ServerSessionPacketHandler::handlePacket," + packet);
|
||||
}
|
||||
if (AuditLogger.isAnyLoggingEnabled()) {
|
||||
AuditLogger.setRemoteAddress(remotingConnection.getRemoteAddress());
|
||||
AuditLogger.setCurrentCaller(remotingConnection.getAuditSubject());
|
||||
}
|
||||
final byte type = packet.getType();
|
||||
switch (type) {
|
||||
case SESS_SEND: {
|
||||
|
|
|
@ -48,6 +48,7 @@ import org.apache.activemq.artemis.core.server.ServerProducer;
|
|||
import org.apache.activemq.artemis.core.server.ServerSession;
|
||||
import org.apache.activemq.artemis.core.server.impl.ServerProducerImpl;
|
||||
import org.apache.activemq.artemis.core.version.Version;
|
||||
import org.apache.activemq.artemis.logs.AuditLogger;
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
/**
|
||||
|
@ -82,6 +83,11 @@ public class ActiveMQPacketHandler implements ChannelHandler {
|
|||
public void handlePacket(final Packet packet) {
|
||||
byte type = packet.getType();
|
||||
|
||||
if (AuditLogger.isAnyLoggingEnabled()) {
|
||||
AuditLogger.setRemoteAddress(connection.getRemoteAddress());
|
||||
AuditLogger.setCurrentCaller(connection.getAuditSubject());
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case PacketImpl.CREATESESSION: {
|
||||
CreateSessionMessage request = (CreateSessionMessage) packet;
|
||||
|
|
|
@ -61,6 +61,7 @@ import org.apache.activemq.artemis.core.server.management.ManagementService;
|
|||
import org.apache.activemq.artemis.core.server.management.Notification;
|
||||
import org.apache.activemq.artemis.core.transaction.Transaction;
|
||||
import org.apache.activemq.artemis.core.transaction.impl.TransactionImpl;
|
||||
import org.apache.activemq.artemis.logs.AuditLogger;
|
||||
import org.apache.activemq.artemis.spi.core.protocol.SessionCallback;
|
||||
import org.apache.activemq.artemis.spi.core.remoting.ReadyListener;
|
||||
import org.apache.activemq.artemis.utils.FutureLatch;
|
||||
|
@ -489,6 +490,9 @@ public class ServerConsumerImpl implements ServerConsumer, ReadyListener {
|
|||
try {
|
||||
Message message = reference.getMessage();
|
||||
|
||||
if (AuditLogger.isMessageEnabled()) {
|
||||
AuditLogger.coreConsumeMessage(getQueueName().toString());
|
||||
}
|
||||
if (server.hasBrokerMessagePlugins()) {
|
||||
server.callBrokerMessagePlugins(plugin -> plugin.beforeDeliver(this, reference));
|
||||
}
|
||||
|
|
|
@ -1749,7 +1749,7 @@ public class ServerSessionImpl implements ServerSession, FailureListener {
|
|||
boolean noAutoCreateQueue,
|
||||
RoutingContext routingContext) throws Exception {
|
||||
if (AuditLogger.isMessageEnabled()) {
|
||||
AuditLogger.coreSendMessage(this, getUsername(), tx, messageParameter, direct, noAutoCreateQueue, routingContext);
|
||||
AuditLogger.coreSendMessage(getUsername(), routingContext);
|
||||
}
|
||||
|
||||
final Message message = LargeServerMessageImpl.checkLargeMessage(messageParameter, storageManager);
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
*/
|
||||
package org.apache.activemq.artemis.core.server.management;
|
||||
|
||||
import org.apache.activemq.artemis.logs.AuditLogger;
|
||||
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
|
@ -57,6 +59,16 @@ public class ArtemisMBeanServerBuilder extends MBeanServerBuilder {
|
|||
|
||||
@Override
|
||||
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
|
||||
//if this is invoked via jolokia the address will be set by the filter
|
||||
//if not we can deduct it from RMI or it must be internal
|
||||
if (AuditLogger.isAnyLoggingEnabled() && AuditLogger.getRemoteAddress() == null) {
|
||||
String name = Thread.currentThread().getName();
|
||||
String url = "internal";
|
||||
if (name.startsWith("RMI TCP Connection")) {
|
||||
url = name.substring(name.indexOf('-') + 1);
|
||||
}
|
||||
AuditLogger.setRemoteAddress(url);
|
||||
}
|
||||
if (guarded.contains(method.getName())) {
|
||||
if (ArtemisMBeanServerBuilder.guard == null) {
|
||||
throw new IllegalStateException("ArtemisMBeanServerBuilder not initialized");
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
package org.apache.activemq.artemis.core.server.management;
|
||||
|
||||
|
||||
import org.apache.activemq.artemis.logs.AuditLogger;
|
||||
|
||||
import javax.management.Attribute;
|
||||
import javax.management.AttributeList;
|
||||
import javax.management.JMException;
|
||||
|
@ -121,6 +123,9 @@ public class ArtemisMBeanServerGuard implements InvocationHandler {
|
|||
if (currentUserHasRole(role))
|
||||
return;
|
||||
}
|
||||
if (AuditLogger.isResourceLoggingEnabled()) {
|
||||
AuditLogger.objectInvokedFailure(objectName, operationName);
|
||||
}
|
||||
throw new SecurityException("Insufficient roles/credentials for operation");
|
||||
}
|
||||
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
*/
|
||||
package org.apache.activemq.artemis.core.server.management;
|
||||
|
||||
import org.apache.activemq.artemis.logs.AuditLogger;
|
||||
|
||||
import javax.management.remote.JMXAuthenticator;
|
||||
import javax.security.auth.Subject;
|
||||
import javax.security.auth.callback.Callback;
|
||||
|
@ -41,8 +43,9 @@ public class JaasAuthenticator implements JMXAuthenticator {
|
|||
|
||||
@Override
|
||||
public Subject authenticate(final Object credentials) throws SecurityException {
|
||||
try {
|
||||
|
||||
Subject subject = new Subject();
|
||||
try {
|
||||
|
||||
LoginContext loginContext = new LoginContext(realm, subject, new CallbackHandler() {
|
||||
@Override
|
||||
|
@ -70,8 +73,14 @@ public class JaasAuthenticator implements JMXAuthenticator {
|
|||
}
|
||||
});
|
||||
loginContext.login();
|
||||
if (AuditLogger.isResourceLoggingEnabled()) {
|
||||
AuditLogger.userSuccesfullyLoggedInAudit(subject);
|
||||
}
|
||||
return subject;
|
||||
} catch (LoginException e) {
|
||||
if (AuditLogger.isResourceLoggingEnabled()) {
|
||||
AuditLogger.userFailedLoggedInAudit(subject, e.getMessage());
|
||||
}
|
||||
throw new SecurityException("Authentication failed", e);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@ import org.apache.activemq.artemis.core.config.impl.SecurityConfiguration;
|
|||
import org.apache.activemq.artemis.core.security.CheckType;
|
||||
import org.apache.activemq.artemis.core.security.Role;
|
||||
import org.apache.activemq.artemis.core.server.ActiveMQServerLogger;
|
||||
import org.apache.activemq.artemis.logs.AuditLogger;
|
||||
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.RolePrincipal;
|
||||
|
@ -193,7 +194,20 @@ public class ActiveMQJAASSecurityManager implements ActiveMQSecurityManager4 {
|
|||
} else {
|
||||
lc = new LoginContext(configurationName, null, new JaasCallbackHandler(user, password, remotingConnection), configuration);
|
||||
}
|
||||
try {
|
||||
lc.login();
|
||||
if (AuditLogger.isAnyLoggingEnabled() && remotingConnection != null) {
|
||||
remotingConnection.setAuditSubject(lc.getSubject());
|
||||
}
|
||||
if (AuditLogger.isResourceLoggingEnabled()) {
|
||||
AuditLogger.userSuccesfullyLoggedInAudit(lc.getSubject());
|
||||
}
|
||||
} catch (LoginException e) {
|
||||
if (AuditLogger.isResourceLoggingEnabled()) {
|
||||
AuditLogger.userFailedLoggedInAudit(lc.getSubject(), e.getMessage());
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
return lc.getSubject();
|
||||
} finally {
|
||||
if (thisLoader != currentLoader) {
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* 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.jaas;
|
||||
|
||||
import org.apache.activemq.artemis.logs.AuditLogger;
|
||||
|
||||
import javax.security.auth.Subject;
|
||||
import javax.security.auth.spi.LoginModule;
|
||||
|
||||
/*
|
||||
* This is only to support auditlogging
|
||||
* */
|
||||
public interface AuditLoginModule extends LoginModule {
|
||||
|
||||
/*
|
||||
* We need this because if authentication fails at the web layer then there is no way to access the unauthenticated
|
||||
* subject as it is removed and the session destroyed and never gets as far as the broker
|
||||
* */
|
||||
default void registerFailureForAudit(String name) {
|
||||
Subject subject = new Subject();
|
||||
subject.getPrincipals().add(new UserPrincipal(name));
|
||||
AuditLogger.setCurrentCaller(subject);
|
||||
}
|
||||
}
|
|
@ -22,7 +22,6 @@ import javax.security.auth.callback.CallbackHandler;
|
|||
import javax.security.auth.callback.UnsupportedCallbackException;
|
||||
import javax.security.auth.login.FailedLoginException;
|
||||
import javax.security.auth.login.LoginException;
|
||||
import javax.security.auth.spi.LoginModule;
|
||||
import javax.security.cert.X509Certificate;
|
||||
import java.io.IOException;
|
||||
import java.security.Principal;
|
||||
|
@ -37,7 +36,7 @@ import org.jboss.logging.Logger;
|
|||
* Allows for subclasses to define methods used to verify user certificates and
|
||||
* find user roles. Uses CertificateCallbacks to retrieve certificates.
|
||||
*/
|
||||
public abstract class CertificateLoginModule extends PropertiesLoader implements LoginModule {
|
||||
public abstract class CertificateLoginModule extends PropertiesLoader implements AuditLoginModule {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(CertificateLoginModule.class);
|
||||
|
||||
|
@ -116,6 +115,7 @@ public abstract class CertificateLoginModule extends PropertiesLoader implements
|
|||
*/
|
||||
@Override
|
||||
public boolean abort() throws LoginException {
|
||||
registerFailureForAudit(username);
|
||||
clear();
|
||||
|
||||
if (debug) {
|
||||
|
|
|
@ -21,7 +21,6 @@ import javax.security.auth.callback.Callback;
|
|||
import javax.security.auth.callback.CallbackHandler;
|
||||
import javax.security.auth.callback.UnsupportedCallbackException;
|
||||
import javax.security.auth.login.LoginException;
|
||||
import javax.security.auth.spi.LoginModule;
|
||||
import javax.security.cert.X509Certificate;
|
||||
import java.io.IOException;
|
||||
import java.security.Principal;
|
||||
|
@ -35,7 +34,7 @@ import org.jboss.logging.Logger;
|
|||
/**
|
||||
* A LoginModule that propagates TLS certificates subject DN as a UserPrincipal.
|
||||
*/
|
||||
public class ExternalCertificateLoginModule implements LoginModule {
|
||||
public class ExternalCertificateLoginModule implements AuditLoginModule {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(ExternalCertificateLoginModule.class);
|
||||
|
||||
|
@ -90,6 +89,7 @@ public class ExternalCertificateLoginModule implements LoginModule {
|
|||
|
||||
@Override
|
||||
public boolean abort() throws LoginException {
|
||||
registerFailureForAudit(userName);
|
||||
clear();
|
||||
logger.debug("abort");
|
||||
return true;
|
||||
|
|
|
@ -22,7 +22,6 @@ import javax.security.auth.callback.CallbackHandler;
|
|||
import javax.security.auth.callback.PasswordCallback;
|
||||
import javax.security.auth.callback.UnsupportedCallbackException;
|
||||
import javax.security.auth.login.LoginException;
|
||||
import javax.security.auth.spi.LoginModule;
|
||||
import java.io.IOException;
|
||||
import java.security.Principal;
|
||||
import java.util.HashSet;
|
||||
|
@ -37,7 +36,7 @@ import org.jboss.logging.Logger;
|
|||
* Useful for unauthenticated communication channels being used in the
|
||||
* same broker as authenticated ones.
|
||||
*/
|
||||
public class GuestLoginModule implements LoginModule {
|
||||
public class GuestLoginModule implements AuditLoginModule {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(GuestLoginModule.class);
|
||||
|
||||
|
@ -114,7 +113,7 @@ public class GuestLoginModule implements LoginModule {
|
|||
|
||||
@Override
|
||||
public boolean abort() throws LoginException {
|
||||
|
||||
registerFailureForAudit(GUEST_USER);
|
||||
if (debug) {
|
||||
logger.debug("abort");
|
||||
}
|
||||
|
|
|
@ -24,7 +24,6 @@ import javax.security.auth.callback.PasswordCallback;
|
|||
import javax.security.auth.callback.UnsupportedCallbackException;
|
||||
import javax.security.auth.login.FailedLoginException;
|
||||
import javax.security.auth.login.LoginException;
|
||||
import javax.security.auth.spi.LoginModule;
|
||||
import java.io.IOException;
|
||||
import java.security.Principal;
|
||||
import java.util.HashSet;
|
||||
|
@ -35,7 +34,7 @@ import java.util.Set;
|
|||
import org.apache.activemq.artemis.core.config.impl.SecurityConfiguration;
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
public class InVMLoginModule implements LoginModule {
|
||||
public class InVMLoginModule implements AuditLoginModule {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(InVMLoginModule.class);
|
||||
|
||||
|
@ -126,6 +125,7 @@ public class InVMLoginModule implements LoginModule {
|
|||
|
||||
@Override
|
||||
public boolean abort() throws LoginException {
|
||||
registerFailureForAudit(user);
|
||||
clear();
|
||||
|
||||
logger.debug("abort");
|
||||
|
|
|
@ -23,7 +23,6 @@ import javax.security.auth.callback.Callback;
|
|||
import javax.security.auth.callback.CallbackHandler;
|
||||
import javax.security.auth.callback.UnsupportedCallbackException;
|
||||
import javax.security.auth.login.LoginException;
|
||||
import javax.security.auth.spi.LoginModule;
|
||||
import java.io.IOException;
|
||||
import java.security.Principal;
|
||||
import java.util.LinkedList;
|
||||
|
@ -33,7 +32,7 @@ import java.util.Map;
|
|||
/**
|
||||
* populate a subject with kerberos credential from the handler
|
||||
*/
|
||||
public class Krb5LoginModule implements LoginModule {
|
||||
public class Krb5LoginModule implements AuditLoginModule {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(Krb5LoginModule.class);
|
||||
|
||||
|
@ -41,6 +40,7 @@ public class Krb5LoginModule implements LoginModule {
|
|||
private final List<Principal> principals = new LinkedList<>();
|
||||
private CallbackHandler callbackHandler;
|
||||
private boolean loginSucceeded;
|
||||
private Principal principal;
|
||||
|
||||
@Override
|
||||
public void initialize(Subject subject,
|
||||
|
@ -58,7 +58,7 @@ public class Krb5LoginModule implements LoginModule {
|
|||
callbacks[0] = new Krb5Callback();
|
||||
try {
|
||||
callbackHandler.handle(callbacks);
|
||||
Principal principal = ((Krb5Callback)callbacks[0]).getPeerPrincipal();
|
||||
principal = ((Krb5Callback)callbacks[0]).getPeerPrincipal();
|
||||
if (principal != null) {
|
||||
principals.add(principal);
|
||||
}
|
||||
|
@ -91,6 +91,7 @@ public class Krb5LoginModule implements LoginModule {
|
|||
|
||||
@Override
|
||||
public boolean abort() throws LoginException {
|
||||
registerFailureForAudit(principal != null ? principal.getName() : null);
|
||||
clear();
|
||||
|
||||
logger.debug("abort");
|
||||
|
@ -99,6 +100,7 @@ public class Krb5LoginModule implements LoginModule {
|
|||
}
|
||||
|
||||
private void clear() {
|
||||
principal = null;
|
||||
loginSucceeded = false;
|
||||
}
|
||||
|
||||
|
|
|
@ -41,7 +41,6 @@ import javax.security.auth.callback.UnsupportedCallbackException;
|
|||
import javax.security.auth.login.FailedLoginException;
|
||||
import javax.security.auth.login.LoginContext;
|
||||
import javax.security.auth.login.LoginException;
|
||||
import javax.security.auth.spi.LoginModule;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
|
@ -62,7 +61,7 @@ import org.apache.activemq.artemis.core.server.ActiveMQServerLogger;
|
|||
import org.apache.activemq.artemis.utils.PasswordMaskingUtil;
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
public class LDAPLoginModule implements LoginModule {
|
||||
public class LDAPLoginModule implements AuditLoginModule {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(LDAPLoginModule.class);
|
||||
|
||||
|
@ -243,6 +242,7 @@ public class LDAPLoginModule implements LoginModule {
|
|||
|
||||
@Override
|
||||
public boolean abort() throws LoginException {
|
||||
registerFailureForAudit(username);
|
||||
clear();
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -24,7 +24,6 @@ import javax.security.auth.callback.PasswordCallback;
|
|||
import javax.security.auth.callback.UnsupportedCallbackException;
|
||||
import javax.security.auth.login.FailedLoginException;
|
||||
import javax.security.auth.login.LoginException;
|
||||
import javax.security.auth.spi.LoginModule;
|
||||
import java.io.IOException;
|
||||
import java.security.Principal;
|
||||
import java.util.HashSet;
|
||||
|
@ -36,7 +35,7 @@ import org.apache.activemq.artemis.utils.HashProcessor;
|
|||
import org.apache.activemq.artemis.utils.PasswordMaskingUtil;
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
public class PropertiesLoginModule extends PropertiesLoader implements LoginModule {
|
||||
public class PropertiesLoginModule extends PropertiesLoader implements AuditLoginModule {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(PropertiesLoginModule.class);
|
||||
|
||||
|
@ -144,6 +143,7 @@ public class PropertiesLoginModule extends PropertiesLoader implements LoginModu
|
|||
|
||||
@Override
|
||||
public boolean abort() throws LoginException {
|
||||
registerFailureForAudit(user);
|
||||
clear();
|
||||
|
||||
if (debug) {
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* 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.component;
|
||||
|
||||
import org.apache.activemq.artemis.logs.AuditLogger;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.Response;
|
||||
|
||||
import javax.security.auth.Subject;
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.FilterConfig;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpSession;
|
||||
import java.io.IOException;
|
||||
|
||||
/*
|
||||
* This filter intercepts the login and audits its results
|
||||
* */
|
||||
public class AuthenticationFilter implements Filter {
|
||||
@Override
|
||||
public void init(FilterConfig filterConfig) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
|
||||
filterChain.doFilter(servletRequest, servletResponse);
|
||||
if (AuditLogger.isAnyLoggingEnabled()) {
|
||||
int status = ((Response) servletResponse).getStatus();
|
||||
//status 200 means that the user has been authenticated, anything else must be a failure
|
||||
if (status == 200) {
|
||||
HttpSession session = ((Request) servletRequest).getSession();
|
||||
AuditLogger.userSuccesfullyLoggedInAudit(session != null ? (Subject) session.getAttribute("subject") : null);
|
||||
} else {
|
||||
AuditLogger.userFailedLoggedInAudit("" + status);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
}
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* 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.component;
|
||||
|
||||
import org.apache.activemq.artemis.logs.AuditLogger;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
|
||||
import javax.security.auth.Subject;
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.FilterConfig;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpSession;
|
||||
import java.io.IOException;
|
||||
|
||||
/*
|
||||
* This intercepts all calls made via jolokia
|
||||
* */
|
||||
public class JolokiaFilter implements Filter {
|
||||
@Override
|
||||
public void init(FilterConfig filterConfig) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
|
||||
/*
|
||||
* this is the only place we can catch the remote address of the calling console client thru Jolokia.
|
||||
* We set the address on the calling thread which will end up in JMX audit logging
|
||||
* */
|
||||
if (AuditLogger.isAnyLoggingEnabled() && servletRequest != null) {
|
||||
String remoteHost = servletRequest.getRemoteHost();
|
||||
AuditLogger.setRemoteAddress(remoteHost + ":" + servletRequest.getRemotePort());
|
||||
}
|
||||
filterChain.doFilter(servletRequest, servletResponse);
|
||||
/*
|
||||
* This is the only place we can get access to the authenticated subject on invocations after the login has happened.
|
||||
* we set the subject for audit logging
|
||||
* */
|
||||
if (AuditLogger.isAnyLoggingEnabled()) {
|
||||
try {
|
||||
HttpSession session = ((Request) servletRequest).getSession();
|
||||
Subject subject = (Subject) session.getAttribute("subject");
|
||||
AuditLogger.setCurrentCaller(subject);
|
||||
} catch (Throwable e) {
|
||||
//best effort
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
}
|
||||
}
|
|
@ -22,6 +22,7 @@ import java.net.URI;
|
|||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
|
@ -44,10 +45,13 @@ import org.eclipse.jetty.server.handler.DefaultHandler;
|
|||
import org.eclipse.jetty.server.handler.HandlerList;
|
||||
import org.eclipse.jetty.server.handler.RequestLogHandler;
|
||||
import org.eclipse.jetty.server.handler.ResourceHandler;
|
||||
import org.eclipse.jetty.servlet.FilterHolder;
|
||||
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||
import org.eclipse.jetty.webapp.WebAppContext;
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
import javax.servlet.DispatcherType;
|
||||
|
||||
public class WebServerComponent implements ExternalComponent {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(WebServerComponent.class);
|
||||
|
@ -303,6 +307,9 @@ public class WebServerComponent implements ExternalComponent {
|
|||
} else {
|
||||
webapp.setContextPath("/" + url);
|
||||
}
|
||||
//add the filters needed for audit logging
|
||||
webapp.addFilter(new FilterHolder(JolokiaFilter.class), "/*", EnumSet.of(DispatcherType.INCLUDE, DispatcherType.REQUEST));
|
||||
webapp.addFilter(new FilterHolder(AuthenticationFilter.class), "/auth/login/*", EnumSet.of(DispatcherType.REQUEST));
|
||||
|
||||
webapp.setWar(warDirectory.resolve(warFile).toString());
|
||||
handlers.addHandler(webapp);
|
||||
|
|
|
@ -5,7 +5,7 @@ configurable via the `logging.properties` file found in the
|
|||
configuration directories. This is configured by Default to log to both
|
||||
the console and to a file.
|
||||
|
||||
There are 8 loggers available which are as follows:
|
||||
There are 9 loggers available which are as follows:
|
||||
|
||||
Logger | Description
|
||||
---|---
|
||||
|
@ -16,6 +16,7 @@ org.apache.activemq.artemis.journal|Logs Journal calls
|
|||
org.apache.activemq.artemis.jms|Logs JMS calls
|
||||
org.apache.activemq.artemis.integration.bootstrap|Logs bootstrap calls
|
||||
org.apache.activemq.audit.base|audit log. Disabled by default
|
||||
org.apache.activemq.audit.resource|resource audit log. Disabled by default
|
||||
org.apache.activemq.audit.message|message audit log. Disabled by default
|
||||
|
||||
|
||||
|
@ -88,17 +89,25 @@ formatter.PATTERN.properties=pattern
|
|||
formatter.PATTERN.pattern=%d{HH:mm:ss,SSS} %-5p [%c] %s%E%n
|
||||
```
|
||||
|
||||
## Configuring Audit Log
|
||||
## Configuring Audit Logging
|
||||
|
||||
The 2 audit loggers can be enabled to record some important operations like
|
||||
create/delete queues. By default this logger is disabled. The configuration
|
||||
(logging.properties) for audit log is like this by default:
|
||||
There are 3 audit loggers that can be enabled separately and audit sifferent types of events, these are:
|
||||
|
||||
1. Base logger: This is a highly verbose logger that will capture most events that occur on JMX beans
|
||||
2. Resource logger: This logs creation, updates and deletion of resources such as Addresses and Queues and also authentication, the main purpose of this is to track console activity and access to broker.
|
||||
3. Message logger: this logs message production and consumption of messages and will have a potentially negatibve affect on performance
|
||||
|
||||
These are disabled by default in the logging.properties configuration file:
|
||||
|
||||
```$xslt
|
||||
logger.org.apache.activemq.audit.base.level=ERROR
|
||||
logger.org.apache.activemq.audit.base.handlers=AUDIT_FILE
|
||||
logger.org.apache.activemq.audit.base.useParentHandlers=false
|
||||
|
||||
logger.org.apache.activemq.audit.resource.level=ERROR
|
||||
logger.org.apache.activemq.audit.resource.handlers=AUDIT_FILE
|
||||
logger.org.apache.activemq.audit.resource.useParentHandlers=false
|
||||
|
||||
logger.org.apache.activemq.audit.message.level=ERROR
|
||||
logger.org.apache.activemq.audit.message.handlers=AUDIT_FILE
|
||||
logger.org.apache.activemq.audit.message.useParentHandlers=false
|
||||
|
@ -110,21 +119,33 @@ To enable the audit log change the above level to INFO, like this:
|
|||
logger.org.apache.activemq.audit.base.level=INFO
|
||||
logger.org.apache.activemq.audit.base.handlers=AUDIT_FILE
|
||||
logger.org.apache.activemq.audit.base.useParentHandlers=false
|
||||
|
||||
logger.org.apache.activemq.audit.message.level=INFO
|
||||
logger.org.apache.activemq.audit.message.handlers=AUDIT_FILE
|
||||
logger.org.apache.activemq.audit.message.useParentHandlers=false
|
||||
...
|
||||
```
|
||||
|
||||
The 2 audit loggers can be disable/enable separately. The second logger
|
||||
(org.apache.activemq.audit.message) audits messages in 'hot path'
|
||||
(code path that is very sensitive to performance, e.g. sending messages).
|
||||
Turn on this audit logger may affect the performance.
|
||||
The 3 audit loggers can be disable/enabled separately.
|
||||
|
||||
Once enabled, all audit records are written into a separate log
|
||||
file (by default audit.log).
|
||||
|
||||
### Logging the clients remote address
|
||||
|
||||
It is possible to configure the audit loggers to log the remote address of any calling clients either through normal
|
||||
clients or through the console and JMX. This is configured by enabling a specific login module in the login config file.
|
||||
```$xslt
|
||||
org.apache.activemq.artemis.spi.core.security.jaas.AuditLoginModule optional
|
||||
debug=false;
|
||||
```
|
||||
|
||||
|
||||
> **Note:**
|
||||
>
|
||||
> This needs to be the first entry in the login.config file
|
||||
|
||||
> **Note:**
|
||||
>
|
||||
> This login module does no authentication, it is used only to catch client information through which ever path a client takes
|
||||
|
||||
|
||||
## Use Custom Handlers
|
||||
|
||||
To use a different handler than the built-in ones, you either pick one from
|
||||
|
|
|
@ -0,0 +1,81 @@
|
|||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
# Additional logger names to configure (root logger is always configured)
|
||||
# Root logger option
|
||||
loggers=org.eclipse.jetty,org.jboss.logging,org.apache.activemq.artemis.core.server,org.apache.activemq.artemis.utils,org.apache.activemq.artemis.journal,org.apache.activemq.artemis.jms.server,org.apache.activemq.artemis.integration.bootstrap,org.apache.activemq.audit.base,org.apache.activemq.audit.message,org.apache.activemq.audit.resource
|
||||
|
||||
# Root logger level
|
||||
logger.level=INFO
|
||||
# ActiveMQ Artemis logger levels
|
||||
logger.org.apache.activemq.artemis.core.server.level=INFO
|
||||
logger.org.apache.activemq.artemis.journal.level=INFO
|
||||
logger.org.apache.activemq.artemis.utils.level=INFO
|
||||
logger.org.apache.activemq.artemis.jms.level=INFO
|
||||
logger.org.apache.activemq.artemis.integration.bootstrap.level=INFO
|
||||
logger.org.eclipse.jetty.level=WARN
|
||||
# Root logger handlers
|
||||
logger.handlers=FILE,CONSOLE
|
||||
|
||||
# to enable audit change the level to INFO
|
||||
logger.org.apache.activemq.audit.base.level=INFO
|
||||
logger.org.apache.activemq.audit.base.handlers=AUDIT_FILE
|
||||
logger.org.apache.activemq.audit.base.useParentHandlers=false
|
||||
|
||||
logger.org.apache.activemq.audit.resource.level=INFO
|
||||
logger.org.apache.activemq.audit.resource.handlers=AUDIT_FILE
|
||||
logger.org.apache.activemq.audit.resource.useParentHandlers=false
|
||||
|
||||
logger.org.apache.activemq.audit.message.level=INFO
|
||||
logger.org.apache.activemq.audit.message.handlers=AUDIT_FILE
|
||||
logger.org.apache.activemq.audit.message.useParentHandlers=false
|
||||
|
||||
# Console handler configuration
|
||||
handler.CONSOLE=org.jboss.logmanager.handlers.ConsoleHandler
|
||||
handler.CONSOLE.properties=autoFlush
|
||||
handler.CONSOLE.level=DEBUG
|
||||
handler.CONSOLE.autoFlush=true
|
||||
handler.CONSOLE.formatter=PATTERN
|
||||
|
||||
# File handler configuration
|
||||
handler.FILE=org.jboss.logmanager.handlers.PeriodicRotatingFileHandler
|
||||
handler.FILE.level=DEBUG
|
||||
handler.FILE.properties=suffix,append,autoFlush,fileName
|
||||
handler.FILE.suffix=.yyyy-MM-dd
|
||||
handler.FILE.append=true
|
||||
handler.FILE.autoFlush=true
|
||||
handler.FILE.fileName=${artemis.instance}/log/artemis.log
|
||||
handler.FILE.formatter=PATTERN
|
||||
|
||||
# Formatter pattern configuration
|
||||
formatter.PATTERN=org.jboss.logmanager.formatters.PatternFormatter
|
||||
formatter.PATTERN.properties=pattern
|
||||
formatter.PATTERN.pattern=%d %-5p [%c] %s%E%n
|
||||
|
||||
#Audit logger
|
||||
handler.AUDIT_FILE=org.jboss.logmanager.handlers.PeriodicRotatingFileHandler
|
||||
handler.AUDIT_FILE.level=INFO
|
||||
handler.AUDIT_FILE.properties=suffix,append,autoFlush,fileName
|
||||
handler.AUDIT_FILE.suffix=.yyyy-MM-dd
|
||||
handler.AUDIT_FILE.append=true
|
||||
handler.AUDIT_FILE.autoFlush=true
|
||||
handler.AUDIT_FILE.fileName=${artemis.instance}/log/audit.log
|
||||
handler.AUDIT_FILE.formatter=AUDIT_PATTERN
|
||||
|
||||
formatter.AUDIT_PATTERN=org.jboss.logmanager.formatters.PatternFormatter
|
||||
formatter.AUDIT_PATTERN.properties=pattern
|
||||
formatter.AUDIT_PATTERN.pattern=%d [AUDIT](%t) %s%E%n
|
|
@ -267,6 +267,48 @@
|
|||
</args>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<phase>test-compile</phase>
|
||||
<id>create-createAuditLogging</id>
|
||||
<goals>
|
||||
<goal>create</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<configuration>${basedir}/target/classes/servers/audit-logging</configuration>
|
||||
<noWeb>false</noWeb>
|
||||
<allowAnonymous>true</allowAnonymous>
|
||||
<user>admin</user>
|
||||
<password>admin</password>
|
||||
<instance>${basedir}/target/audit-logging</instance>
|
||||
<args>
|
||||
<!-- this is needed to run the server remotely -->
|
||||
<arg>--java-options</arg>
|
||||
<arg>-Djava.rmi.server.hostname=localhost</arg>
|
||||
<!--<arg>-Djava.rmi.server.hostname=localhost -agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5005</arg>-->
|
||||
</args>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<phase>test-compile</phase>
|
||||
<id>create-createAuditLogging2</id>
|
||||
<goals>
|
||||
<goal>create</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<configuration>${basedir}/target/classes/servers/audit-logging2</configuration>
|
||||
<noWeb>false</noWeb>
|
||||
<allowAnonymous>true</allowAnonymous>
|
||||
<user>admin</user>
|
||||
<password>admin</password>
|
||||
<instance>${basedir}/target/audit-logging2</instance>
|
||||
<args>
|
||||
<!-- this is needed to run the server remotely -->
|
||||
<arg>--java-options</arg>
|
||||
<arg>-Djava.rmi.server.hostname=localhost</arg>
|
||||
<!--<arg>-Djava.rmi.server.hostname=localhost -agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5005</arg>-->
|
||||
</args>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<phase>test-compile</phase>
|
||||
<id>create-jmx-failback</id>
|
||||
|
|
|
@ -0,0 +1,190 @@
|
|||
<?xml version='1.0'?>
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
|
||||
<configuration xmlns="urn:activemq"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="urn:activemq /schema/artemis-configuration.xsd">
|
||||
|
||||
<core xmlns="urn:activemq:core" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="urn:activemq:core ">
|
||||
|
||||
<name>0.0.0.0</name>
|
||||
|
||||
<persistence-enabled>true</persistence-enabled>
|
||||
|
||||
<!-- this could be ASYNCIO or NIO
|
||||
-->
|
||||
<journal-type>NIO</journal-type>
|
||||
|
||||
<paging-directory>./data/paging</paging-directory>
|
||||
|
||||
<bindings-directory>./data/bindings</bindings-directory>
|
||||
|
||||
<journal-directory>./data/journal</journal-directory>
|
||||
|
||||
<large-messages-directory>./data/large-messages</large-messages-directory>
|
||||
|
||||
<journal-datasync>true</journal-datasync>
|
||||
|
||||
<journal-min-files>2</journal-min-files>
|
||||
|
||||
<journal-pool-files>-1</journal-pool-files>
|
||||
|
||||
<message-expiry-scan-period>1000</message-expiry-scan-period>
|
||||
|
||||
<!--
|
||||
You can verify the network health of a particular NIC by specifying the <network-check-NIC> element.
|
||||
<network-check-NIC>theNicName</network-check-NIC>
|
||||
-->
|
||||
|
||||
<!--
|
||||
Use this to use an HTTP server to validate the network
|
||||
<network-check-URL-list>http://www.apache.org</network-check-URL-list> -->
|
||||
|
||||
<!-- <network-check-period>10000</network-check-period> -->
|
||||
<!-- <network-check-timeout>1000</network-check-timeout> -->
|
||||
|
||||
<!-- this is a comma separated list, no spaces, just DNS or IPs
|
||||
it should accept IPV6
|
||||
|
||||
Warning: Make sure you understand your network topology as this is meant to validate if your network is valid.
|
||||
Using IPs that could eventually disappear or be partially visible may defeat the purpose.
|
||||
You can use a list of multiple IPs, and if any successful ping will make the server OK to continue running -->
|
||||
<!-- <network-check-list>10.0.0.1</network-check-list> -->
|
||||
|
||||
<!-- use this to customize the ping used for ipv4 addresses -->
|
||||
<!-- <network-check-ping-command>ping -c 1 -t %d %s</network-check-ping-command> -->
|
||||
|
||||
<!-- use this to customize the ping used for ipv6 addresses -->
|
||||
<!-- <network-check-ping6-command>ping6 -c 1 %2$s</network-check-ping6-command> -->
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- how often we are looking for how many bytes are being used on the disk in ms -->
|
||||
<disk-scan-period>5000</disk-scan-period>
|
||||
|
||||
<!-- once the disk hits this limit the system will block, or close the connection in certain protocols
|
||||
that won't support flow control. -->
|
||||
<max-disk-usage>90</max-disk-usage>
|
||||
|
||||
<!-- the system will enter into page mode once you hit this limit.
|
||||
This is an estimate in bytes of how much the messages are using in memory
|
||||
|
||||
The system will use half of the available memory (-Xmx) by default for the global-max-size.
|
||||
You may specify a different value here if you need to customize it to your needs.
|
||||
|
||||
<global-max-size>100Mb</global-max-size>
|
||||
|
||||
-->
|
||||
|
||||
<acceptors>
|
||||
|
||||
<!-- useEpoll means: it will use Netty epoll if you are on a system (Linux) that supports it -->
|
||||
<!-- useKQueue means: it will use Netty kqueue if you are on a system (MacOS) that supports it -->
|
||||
<!-- amqpCredits: The number of credits sent to AMQP producers -->
|
||||
<!-- amqpLowCredits: The server will send the # credits specified at amqpCredits at this low mark -->
|
||||
|
||||
<!-- Acceptor for every supported protocol -->
|
||||
<acceptor name="artemis">tcp://localhost:61616?tcpSendBufferSize=1048576;tcpReceiveBufferSize=1048576;protocols=CORE,AMQP,STOMP,HORNETQ,MQTT,OPENWIRE;useEpoll=true;useKQueue;amqpCredits=1000;amqpLowCredits=300</acceptor>
|
||||
|
||||
<!-- AMQP Acceptor. Listens on default AMQP port for AMQP traffic.-->
|
||||
<acceptor name="amqp">tcp://localhost:5672?tcpSendBufferSize=1048576;tcpReceiveBufferSize=1048576;protocols=AMQP;useEpoll=true;useKQueue=true;amqpCredits=1000;amqpLowCredits=300</acceptor>
|
||||
|
||||
<!-- STOMP Acceptor. -->
|
||||
<acceptor name="stomp">tcp://localhost:61613?tcpSendBufferSize=1048576;tcpReceiveBufferSize=1048576;protocols=STOMP;useEpoll=true;useKQueue=true</acceptor>
|
||||
|
||||
<!-- HornetQ Compatibility Acceptor. Enables HornetQ Core and STOMP for legacy HornetQ clients. -->
|
||||
<acceptor name="hornetq">tcp://localhost:5445?protocols=HORNETQ,STOMP;useEpoll=true;useKQueue=true</acceptor>
|
||||
|
||||
<!-- MQTT Acceptor -->
|
||||
<acceptor name="mqtt">tcp://localhost:1883?tcpSendBufferSize=1048576;tcpReceiveBufferSize=1048576;protocols=MQTT;useEpoll=true;useKQueue=true</acceptor>
|
||||
|
||||
</acceptors>
|
||||
|
||||
|
||||
<security-settings>
|
||||
<security-setting match="#">
|
||||
<permission type="createNonDurableQueue" roles="guest"/>
|
||||
<permission type="deleteNonDurableQueue" roles="guest"/>
|
||||
<permission type="createDurableQueue" roles="guest"/>
|
||||
<permission type="deleteDurableQueue" roles="guest"/>
|
||||
<permission type="createAddress" roles="guest"/>
|
||||
<permission type="deleteAddress" roles="guest"/>
|
||||
<permission type="consume" roles="guest"/>
|
||||
<permission type="browse" roles="guest"/>
|
||||
<permission type="send" roles="guest"/>
|
||||
<!-- we need this otherwise ./artemis data imp wouldn't work -->
|
||||
<permission type="manage" roles="guest"/>
|
||||
</security-setting>
|
||||
</security-settings>
|
||||
|
||||
<address-settings>
|
||||
<!-- if you define auto-create on certain queues, management has to be auto-create -->
|
||||
<address-setting match="activemq.management#">
|
||||
<dead-letter-address>DLQ</dead-letter-address>
|
||||
<expiry-address>ExpiryQueue</expiry-address>
|
||||
<redelivery-delay>0</redelivery-delay>
|
||||
<!-- with -1 only the global-max-size is in use for limiting -->
|
||||
<max-size-bytes>-1</max-size-bytes>
|
||||
<message-counter-history-day-limit>10</message-counter-history-day-limit>
|
||||
<address-full-policy>PAGE</address-full-policy>
|
||||
<auto-create-queues>true</auto-create-queues>
|
||||
<auto-create-addresses>true</auto-create-addresses>
|
||||
<auto-create-jms-queues>true</auto-create-jms-queues>
|
||||
<auto-create-jms-topics>true</auto-create-jms-topics>
|
||||
</address-setting>
|
||||
<!--default for catch all-->
|
||||
<address-setting match="#">
|
||||
<dead-letter-address>DLQ</dead-letter-address>
|
||||
<expiry-address>ExpiryQueue</expiry-address>
|
||||
<redelivery-delay>0</redelivery-delay>
|
||||
<!-- with -1 only the global-max-size is in use for limiting -->
|
||||
<max-size-bytes>-1</max-size-bytes>
|
||||
<message-counter-history-day-limit>10</message-counter-history-day-limit>
|
||||
<address-full-policy>PAGE</address-full-policy>
|
||||
<auto-create-queues>true</auto-create-queues>
|
||||
<auto-create-addresses>true</auto-create-addresses>
|
||||
<auto-create-jms-queues>true</auto-create-jms-queues>
|
||||
<auto-create-jms-topics>true</auto-create-jms-topics>
|
||||
</address-setting>
|
||||
</address-settings>
|
||||
|
||||
<addresses>
|
||||
<address name="myQ">
|
||||
<anycast>
|
||||
<queue name="myQ"/>
|
||||
</anycast>
|
||||
</address>
|
||||
<address name="DLQ">
|
||||
<anycast>
|
||||
<queue name="DLQ" />
|
||||
</anycast>
|
||||
</address>
|
||||
<address name="ExpiryQueue">
|
||||
<anycast>
|
||||
<queue name="ExpiryQueue" />
|
||||
</anycast>
|
||||
</address>
|
||||
|
||||
</addresses>
|
||||
|
||||
</core>
|
||||
</configuration>
|
|
@ -17,7 +17,7 @@
|
|||
|
||||
# Additional logger names to configure (root logger is always configured)
|
||||
# Root logger option
|
||||
loggers=org.eclipse.jetty,org.jboss.logging,org.apache.activemq.artemis.core.server,org.apache.activemq.artemis.utils,org.apache.activemq.artemis.journal,org.apache.activemq.artemis.jms.server,org.apache.activemq.artemis.integration.bootstrap,org.apache.activemq.audit.base,org.apache.activemq.audit.message
|
||||
loggers=org.eclipse.jetty,org.jboss.logging,org.apache.activemq.artemis.core.server,org.apache.activemq.artemis.utils,org.apache.activemq.artemis.journal,org.apache.activemq.artemis.jms.server,org.apache.activemq.artemis.integration.bootstrap,org.apache.activemq.audit.base,org.apache.activemq.audit.message,org.apache.activemq.audit.resource
|
||||
|
||||
# Root logger level
|
||||
logger.level=INFO
|
||||
|
@ -31,13 +31,17 @@ logger.org.eclipse.jetty.level=WARN
|
|||
# Root logger handlers
|
||||
logger.handlers=FILE,CONSOLE
|
||||
|
||||
logger.org.apache.activemq.audit.base.level=INFO
|
||||
logger.org.apache.activemq.audit.base.level=ERROR
|
||||
logger.org.apache.activemq.audit.base.handlers=AUDIT_FILE
|
||||
logger.org.apache.activemq.audit.base.useParentHandlers=false
|
||||
|
||||
logger.org.apache.activemq.audit.message.level=ERROR
|
||||
logger.org.apache.activemq.audit.message.handlers=AUDIT_FILE
|
||||
logger.org.apache.activemq.audit.message.useParentHandlers=false
|
||||
logger.org.apache.activemq.audit.message.useParentHandlers=
|
||||
|
||||
logger.org.apache.activemq.audit.resource.level=INFO
|
||||
logger.org.apache.activemq.audit.resource.handlers=AUDIT_FILE
|
||||
logger.org.apache.activemq.audit.resource.useParentHandlers=false
|
||||
|
||||
# Console handler configuration
|
||||
handler.CONSOLE=org.jboss.logmanager.handlers.ConsoleHandler
|
||||
|
@ -53,7 +57,7 @@ handler.FILE.properties=suffix,append,autoFlush,fileName
|
|||
handler.FILE.suffix=.yyyy-MM-dd
|
||||
handler.FILE.append=true
|
||||
handler.FILE.autoFlush=true
|
||||
handler.FILE.fileName=target/artemis.log
|
||||
handler.FILE.fileName=../log/artemis.log
|
||||
handler.FILE.formatter=PATTERN
|
||||
|
||||
# Formatter pattern configuration
|
||||
|
@ -68,7 +72,7 @@ handler.AUDIT_FILE.properties=suffix,append,autoFlush,fileName
|
|||
handler.AUDIT_FILE.suffix=.yyyy-MM-dd
|
||||
handler.AUDIT_FILE.append=true
|
||||
handler.AUDIT_FILE.autoFlush=true
|
||||
handler.AUDIT_FILE.fileName=target/audit.log
|
||||
handler.AUDIT_FILE.fileName=../log/audit.log
|
||||
handler.AUDIT_FILE.formatter=AUDIT_PATTERN
|
||||
|
||||
formatter.AUDIT_PATTERN=org.jboss.logmanager.formatters.PatternFormatter
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
activemq {
|
||||
org.apache.activemq.artemis.spi.core.security.jaas.PropertiesLoginModule sufficient
|
||||
debug=false
|
||||
reload=true
|
||||
org.apache.activemq.jaas.properties.user="artemis-users.properties"
|
||||
org.apache.activemq.jaas.properties.role="artemis-roles.properties";
|
||||
|
||||
org.apache.activemq.artemis.spi.core.security.jaas.GuestLoginModule sufficient
|
||||
debug=false
|
||||
org.apache.activemq.jaas.guest.user="guest"
|
||||
org.apache.activemq.jaas.guest.role="guest";
|
||||
};
|
|
@ -0,0 +1,49 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<!--
|
||||
~ Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
~ contributor license agreements. See the NOTICE file distributed with
|
||||
~ this work for additional information regarding copyright ownership.
|
||||
~ The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
~ (the "License"); you may not use this file except in compliance with
|
||||
~ the License. You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
<management-context xmlns="http://activemq.org/schema">
|
||||
<connector connector-port="10099" connector-host="localhost"/>
|
||||
<authorisation>
|
||||
<whitelist>
|
||||
<entry domain="hawtio"/>
|
||||
</whitelist>
|
||||
<default-access>
|
||||
<access method="list*" roles="guest"/>
|
||||
<access method="get*" roles="guest"/>
|
||||
<access method="is*" roles="guest"/>
|
||||
<access method="set*" roles="guest"/>
|
||||
<access method="*" roles="guest"/>
|
||||
</default-access>
|
||||
<role-access>
|
||||
<match domain="org.apache.activemq.artemis">
|
||||
<access method="list*" roles="guest"/>
|
||||
<access method="get*" roles="guest"/>
|
||||
<access method="is*" roles="guest"/>
|
||||
<access method="set*" roles="guest"/>
|
||||
<access method="*" roles="guest"/>
|
||||
</match>
|
||||
<!--example of how to configure a specific object-->
|
||||
<!--<match domain="org.apache.activemq.artemis" key="subcomponent=queues">
|
||||
<access method="list*" roles="view,update,amq"/>
|
||||
<access method="get*" roles="view,update,amq"/>
|
||||
<access method="is*" roles="view,update,amq"/>
|
||||
<access method="set*" roles="update,amq"/>
|
||||
<access method="*" roles="amq"/>
|
||||
</match>-->
|
||||
</role-access>
|
||||
</authorisation>
|
||||
</management-context>
|
|
@ -0,0 +1,190 @@
|
|||
<?xml version='1.0'?>
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
|
||||
<configuration xmlns="urn:activemq"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="urn:activemq /schema/artemis-configuration.xsd">
|
||||
|
||||
<core xmlns="urn:activemq:core" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="urn:activemq:core ">
|
||||
|
||||
<name>0.0.0.0</name>
|
||||
|
||||
<persistence-enabled>true</persistence-enabled>
|
||||
|
||||
<!-- this could be ASYNCIO or NIO
|
||||
-->
|
||||
<journal-type>NIO</journal-type>
|
||||
|
||||
<paging-directory>./data/paging</paging-directory>
|
||||
|
||||
<bindings-directory>./data/bindings</bindings-directory>
|
||||
|
||||
<journal-directory>./data/journal</journal-directory>
|
||||
|
||||
<large-messages-directory>./data/large-messages</large-messages-directory>
|
||||
|
||||
<journal-datasync>true</journal-datasync>
|
||||
|
||||
<journal-min-files>2</journal-min-files>
|
||||
|
||||
<journal-pool-files>-1</journal-pool-files>
|
||||
|
||||
<message-expiry-scan-period>1000</message-expiry-scan-period>
|
||||
|
||||
<!--
|
||||
You can verify the network health of a particular NIC by specifying the <network-check-NIC> element.
|
||||
<network-check-NIC>theNicName</network-check-NIC>
|
||||
-->
|
||||
|
||||
<!--
|
||||
Use this to use an HTTP server to validate the network
|
||||
<network-check-URL-list>http://www.apache.org</network-check-URL-list> -->
|
||||
|
||||
<!-- <network-check-period>10000</network-check-period> -->
|
||||
<!-- <network-check-timeout>1000</network-check-timeout> -->
|
||||
|
||||
<!-- this is a comma separated list, no spaces, just DNS or IPs
|
||||
it should accept IPV6
|
||||
|
||||
Warning: Make sure you understand your network topology as this is meant to validate if your network is valid.
|
||||
Using IPs that could eventually disappear or be partially visible may defeat the purpose.
|
||||
You can use a list of multiple IPs, and if any successful ping will make the server OK to continue running -->
|
||||
<!-- <network-check-list>10.0.0.1</network-check-list> -->
|
||||
|
||||
<!-- use this to customize the ping used for ipv4 addresses -->
|
||||
<!-- <network-check-ping-command>ping -c 1 -t %d %s</network-check-ping-command> -->
|
||||
|
||||
<!-- use this to customize the ping used for ipv6 addresses -->
|
||||
<!-- <network-check-ping6-command>ping6 -c 1 %2$s</network-check-ping6-command> -->
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- how often we are looking for how many bytes are being used on the disk in ms -->
|
||||
<disk-scan-period>5000</disk-scan-period>
|
||||
|
||||
<!-- once the disk hits this limit the system will block, or close the connection in certain protocols
|
||||
that won't support flow control. -->
|
||||
<max-disk-usage>90</max-disk-usage>
|
||||
|
||||
<!-- the system will enter into page mode once you hit this limit.
|
||||
This is an estimate in bytes of how much the messages are using in memory
|
||||
|
||||
The system will use half of the available memory (-Xmx) by default for the global-max-size.
|
||||
You may specify a different value here if you need to customize it to your needs.
|
||||
|
||||
<global-max-size>100Mb</global-max-size>
|
||||
|
||||
-->
|
||||
|
||||
<acceptors>
|
||||
|
||||
<!-- useEpoll means: it will use Netty epoll if you are on a system (Linux) that supports it -->
|
||||
<!-- useKQueue means: it will use Netty kqueue if you are on a system (MacOS) that supports it -->
|
||||
<!-- amqpCredits: The number of credits sent to AMQP producers -->
|
||||
<!-- amqpLowCredits: The server will send the # credits specified at amqpCredits at this low mark -->
|
||||
|
||||
<!-- Acceptor for every supported protocol -->
|
||||
<acceptor name="artemis">tcp://localhost:61616?tcpSendBufferSize=1048576;tcpReceiveBufferSize=1048576;protocols=CORE,AMQP,STOMP,HORNETQ,MQTT,OPENWIRE;useEpoll=true;useKQueue;amqpCredits=1000;amqpLowCredits=300</acceptor>
|
||||
|
||||
<!-- AMQP Acceptor. Listens on default AMQP port for AMQP traffic.-->
|
||||
<acceptor name="amqp">tcp://localhost:5672?tcpSendBufferSize=1048576;tcpReceiveBufferSize=1048576;protocols=AMQP;useEpoll=true;useKQueue=true;amqpCredits=1000;amqpLowCredits=300</acceptor>
|
||||
|
||||
<!-- STOMP Acceptor. -->
|
||||
<acceptor name="stomp">tcp://localhost:61613?tcpSendBufferSize=1048576;tcpReceiveBufferSize=1048576;protocols=STOMP;useEpoll=true;useKQueue=true</acceptor>
|
||||
|
||||
<!-- HornetQ Compatibility Acceptor. Enables HornetQ Core and STOMP for legacy HornetQ clients. -->
|
||||
<acceptor name="hornetq">tcp://localhost:5445?protocols=HORNETQ,STOMP;useEpoll=true;useKQueue=true</acceptor>
|
||||
|
||||
<!-- MQTT Acceptor -->
|
||||
<acceptor name="mqtt">tcp://localhost:1883?tcpSendBufferSize=1048576;tcpReceiveBufferSize=1048576;protocols=MQTT;useEpoll=true;useKQueue=true</acceptor>
|
||||
|
||||
</acceptors>
|
||||
|
||||
|
||||
<security-settings>
|
||||
<security-setting match="#">
|
||||
<permission type="createNonDurableQueue" roles="guest"/>
|
||||
<permission type="deleteNonDurableQueue" roles=""/>
|
||||
<permission type="createDurableQueue" roles="guest"/>
|
||||
<permission type="deleteDurableQueue" roles="guest"/>
|
||||
<permission type="createAddress" roles="guest"/>
|
||||
<permission type="deleteAddress" roles="guest"/>
|
||||
<permission type="consume" roles="guest"/>
|
||||
<permission type="browse" roles="guest"/>
|
||||
<permission type="send" roles="guest"/>
|
||||
<!-- we need this otherwise ./artemis data imp wouldn't work -->
|
||||
<permission type="manage" roles="guest"/>
|
||||
</security-setting>
|
||||
</security-settings>
|
||||
|
||||
<address-settings>
|
||||
<!-- if you define auto-create on certain queues, management has to be auto-create -->
|
||||
<address-setting match="activemq.management#">
|
||||
<dead-letter-address>DLQ</dead-letter-address>
|
||||
<expiry-address>ExpiryQueue</expiry-address>
|
||||
<redelivery-delay>0</redelivery-delay>
|
||||
<!-- with -1 only the global-max-size is in use for limiting -->
|
||||
<max-size-bytes>-1</max-size-bytes>
|
||||
<message-counter-history-day-limit>10</message-counter-history-day-limit>
|
||||
<address-full-policy>PAGE</address-full-policy>
|
||||
<auto-create-queues>true</auto-create-queues>
|
||||
<auto-create-addresses>true</auto-create-addresses>
|
||||
<auto-create-jms-queues>true</auto-create-jms-queues>
|
||||
<auto-create-jms-topics>true</auto-create-jms-topics>
|
||||
</address-setting>
|
||||
<!--default for catch all-->
|
||||
<address-setting match="#">
|
||||
<dead-letter-address>DLQ</dead-letter-address>
|
||||
<expiry-address>ExpiryQueue</expiry-address>
|
||||
<redelivery-delay>0</redelivery-delay>
|
||||
<!-- with -1 only the global-max-size is in use for limiting -->
|
||||
<max-size-bytes>-1</max-size-bytes>
|
||||
<message-counter-history-day-limit>10</message-counter-history-day-limit>
|
||||
<address-full-policy>PAGE</address-full-policy>
|
||||
<auto-create-queues>true</auto-create-queues>
|
||||
<auto-create-addresses>true</auto-create-addresses>
|
||||
<auto-create-jms-queues>true</auto-create-jms-queues>
|
||||
<auto-create-jms-topics>true</auto-create-jms-topics>
|
||||
</address-setting>
|
||||
</address-settings>
|
||||
|
||||
<addresses>
|
||||
<address name="myQ">
|
||||
<anycast>
|
||||
<queue name="myQ"/>
|
||||
</anycast>
|
||||
</address>
|
||||
<address name="DLQ">
|
||||
<anycast>
|
||||
<queue name="DLQ" />
|
||||
</anycast>
|
||||
</address>
|
||||
<address name="ExpiryQueue">
|
||||
<anycast>
|
||||
<queue name="ExpiryQueue" />
|
||||
</anycast>
|
||||
</address>
|
||||
|
||||
</addresses>
|
||||
|
||||
</core>
|
||||
</configuration>
|
|
@ -17,7 +17,7 @@
|
|||
|
||||
# Additional logger names to configure (root logger is always configured)
|
||||
# Root logger option
|
||||
loggers=org.eclipse.jetty,org.jboss.logging,org.apache.activemq.artemis.core.server,org.apache.activemq.artemis.utils,org.apache.activemq.artemis.journal,org.apache.activemq.artemis.jms.server,org.apache.activemq.artemis.integration.bootstrap,org.apache.activemq.audit.base,org.apache.activemq.audit.message
|
||||
loggers=org.eclipse.jetty,org.jboss.logging,org.apache.activemq.artemis.core.server,org.apache.activemq.artemis.utils,org.apache.activemq.artemis.journal,org.apache.activemq.artemis.jms.server,org.apache.activemq.artemis.integration.bootstrap,org.apache.activemq.audit.base,org.apache.activemq.audit.message,org.apache.activemq.audit.resource
|
||||
|
||||
# Root logger level
|
||||
logger.level=INFO
|
||||
|
@ -37,7 +37,11 @@ logger.org.apache.activemq.audit.base.useParentHandlers=false
|
|||
|
||||
logger.org.apache.activemq.audit.message.level=INFO
|
||||
logger.org.apache.activemq.audit.message.handlers=AUDIT_FILE
|
||||
logger.org.apache.activemq.audit.message.useParentHandlers=false
|
||||
logger.org.apache.activemq.audit.message.useParentHandlers=
|
||||
|
||||
logger.org.apache.activemq.audit.resource.level=ERROR
|
||||
logger.org.apache.activemq.audit.resource.handlers=AUDIT_FILE
|
||||
logger.org.apache.activemq.audit.resource.useParentHandlers=false
|
||||
|
||||
# Console handler configuration
|
||||
handler.CONSOLE=org.jboss.logmanager.handlers.ConsoleHandler
|
||||
|
@ -53,7 +57,7 @@ handler.FILE.properties=suffix,append,autoFlush,fileName
|
|||
handler.FILE.suffix=.yyyy-MM-dd
|
||||
handler.FILE.append=true
|
||||
handler.FILE.autoFlush=true
|
||||
handler.FILE.fileName=target/artemis.log
|
||||
handler.FILE.fileName=../log/artemis.log
|
||||
handler.FILE.formatter=PATTERN
|
||||
|
||||
# Formatter pattern configuration
|
||||
|
@ -62,13 +66,13 @@ formatter.PATTERN.properties=pattern
|
|||
formatter.PATTERN.pattern=%d %-5p [%c] %s%E%n
|
||||
|
||||
#Audit logger
|
||||
handler.AUDIT_FILE.level=DEBUG
|
||||
handler.AUDIT_FILE.level=INFO
|
||||
handler.AUDIT_FILE=org.jboss.logmanager.handlers.PeriodicRotatingFileHandler
|
||||
handler.AUDIT_FILE.properties=suffix,append,autoFlush,fileName
|
||||
handler.AUDIT_FILE.suffix=.yyyy-MM-dd
|
||||
handler.AUDIT_FILE.append=true
|
||||
handler.AUDIT_FILE.autoFlush=true
|
||||
handler.AUDIT_FILE.fileName=target/audit.log
|
||||
handler.AUDIT_FILE.fileName=../log/audit.log
|
||||
handler.AUDIT_FILE.formatter=AUDIT_PATTERN
|
||||
|
||||
formatter.AUDIT_PATTERN=org.jboss.logmanager.formatters.PatternFormatter
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
activemq {
|
||||
org.apache.activemq.artemis.spi.core.security.jaas.PropertiesLoginModule sufficient
|
||||
debug=false
|
||||
reload=true
|
||||
org.apache.activemq.jaas.properties.user="artemis-users.properties"
|
||||
org.apache.activemq.jaas.properties.role="artemis-roles.properties";
|
||||
|
||||
org.apache.activemq.artemis.spi.core.security.jaas.GuestLoginModule sufficient
|
||||
debug=false
|
||||
org.apache.activemq.jaas.guest.user="guest"
|
||||
org.apache.activemq.jaas.guest.role="guest";
|
||||
};
|
|
@ -0,0 +1,49 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<!--
|
||||
~ Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
~ contributor license agreements. See the NOTICE file distributed with
|
||||
~ this work for additional information regarding copyright ownership.
|
||||
~ The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
~ (the "License"); you may not use this file except in compliance with
|
||||
~ the License. You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
<management-context xmlns="http://activemq.org/schema">
|
||||
<connector connector-port="10099" connector-host="localhost"/>
|
||||
<authorisation>
|
||||
<whitelist>
|
||||
<entry domain="hawtio"/>
|
||||
</whitelist>
|
||||
<default-access>
|
||||
<access method="list*" roles="guest"/>
|
||||
<access method="get*" roles="guest"/>
|
||||
<access method="is*" roles="guest"/>
|
||||
<access method="set*" roles="guest"/>
|
||||
<access method="*" roles="guest"/>
|
||||
</default-access>
|
||||
<role-access>
|
||||
<match domain="org.apache.activemq.artemis">
|
||||
<access method="list*" roles="guest"/>
|
||||
<access method="get*" roles="guest"/>
|
||||
<access method="is*" roles="guest"/>
|
||||
<access method="set*" roles="guest"/>
|
||||
<access method="*" roles="guest"/>
|
||||
</match>
|
||||
<!--example of how to configure a specific object-->
|
||||
<!--<match domain="org.apache.activemq.artemis" key="subcomponent=queues">
|
||||
<access method="list*" roles="view,update,amq"/>
|
||||
<access method="get*" roles="view,update,amq"/>
|
||||
<access method="is*" roles="view,update,amq"/>
|
||||
<access method="set*" roles="update,amq"/>
|
||||
<access method="*" roles="amq"/>
|
||||
</match>-->
|
||||
</role-access>
|
||||
</authorisation>
|
||||
</management-context>
|
|
@ -0,0 +1,166 @@
|
|||
/*
|
||||
* 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.smoke.logging;
|
||||
|
||||
import org.apache.activemq.artemis.api.config.ActiveMQDefaultConfiguration;
|
||||
import org.apache.activemq.artemis.api.core.RoutingType;
|
||||
import org.apache.activemq.artemis.api.core.SimpleString;
|
||||
import org.apache.activemq.artemis.api.core.client.ClientProducer;
|
||||
import org.apache.activemq.artemis.api.core.client.ClientSession;
|
||||
import org.apache.activemq.artemis.api.core.client.ClientSessionFactory;
|
||||
import org.apache.activemq.artemis.api.core.client.ServerLocator;
|
||||
import org.apache.activemq.artemis.api.core.management.ActiveMQServerControl;
|
||||
import org.apache.activemq.artemis.api.core.management.ObjectNameBuilder;
|
||||
import org.apache.activemq.artemis.api.core.management.QueueControl;
|
||||
import org.apache.activemq.artemis.tests.smoke.common.SmokeTestBase;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import javax.management.MBeanServerConnection;
|
||||
import javax.management.MBeanServerInvocationHandler;
|
||||
import javax.management.openmbean.CompositeData;
|
||||
import javax.management.remote.JMXConnector;
|
||||
import javax.management.remote.JMXConnectorFactory;
|
||||
import javax.management.remote.JMXServiceURL;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.FileWriter;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.HashMap;
|
||||
|
||||
public class AuditLoggerResourceTest extends SmokeTestBase {
|
||||
|
||||
private static final File auditLog = new File("target/audit-logging/log/audit.log");
|
||||
|
||||
private static final String JMX_SERVER_HOSTNAME = "localhost";
|
||||
private static final int JMX_SERVER_PORT = 10099;
|
||||
|
||||
public static final String SERVER_NAME = "audit-logging";
|
||||
|
||||
@Before
|
||||
public void before() throws Exception {
|
||||
cleanupData(SERVER_NAME);
|
||||
disableCheckThread();
|
||||
startServer(SERVER_NAME, 0, 30000);
|
||||
emptyLogFile();
|
||||
}
|
||||
|
||||
private void emptyLogFile() throws Exception {
|
||||
if (auditLog.exists()) {
|
||||
try (PrintWriter writer = new PrintWriter(new FileWriter(auditLog))) {
|
||||
writer.print("");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAuditResourceLog() throws Exception {
|
||||
HashMap environment = new HashMap();
|
||||
String[] credentials = new String[] {"admin", "admin"};
|
||||
environment.put(JMXConnector.CREDENTIALS, credentials);
|
||||
// Without this, the RMI server would bind to the default interface IP (the user's local IP mostly)
|
||||
System.setProperty("java.rmi.server.hostname", JMX_SERVER_HOSTNAME);
|
||||
|
||||
// I don't specify both ports here manually on purpose. See actual RMI registry connection port extraction below.
|
||||
String urlString = "service:jmx:rmi:///jndi/rmi://" + JMX_SERVER_HOSTNAME + ":" + JMX_SERVER_PORT + "/jmxrmi";
|
||||
|
||||
JMXServiceURL url = new JMXServiceURL(urlString);
|
||||
JMXConnector jmxConnector = null;
|
||||
|
||||
try {
|
||||
jmxConnector = JMXConnectorFactory.connect(url, environment);
|
||||
System.out.println("Successfully connected to: " + urlString);
|
||||
} catch (Exception e) {
|
||||
jmxConnector = null;
|
||||
e.printStackTrace();
|
||||
Assert.fail(e.getMessage());
|
||||
}
|
||||
|
||||
try {
|
||||
MBeanServerConnection mBeanServerConnection = jmxConnector.getMBeanServerConnection();
|
||||
String brokerName = "0.0.0.0"; // configured e.g. in broker.xml <broker-name> element
|
||||
ObjectNameBuilder objectNameBuilder = ObjectNameBuilder.create(ActiveMQDefaultConfiguration.getDefaultJmxDomain(), brokerName, true);
|
||||
ActiveMQServerControl serverControl = MBeanServerInvocationHandler.newProxyInstance(mBeanServerConnection, objectNameBuilder.getActiveMQServerObjectName(), ActiveMQServerControl.class, false);
|
||||
|
||||
serverControl.createAddress("auditAddress", "ANYCAST,MULTICAST");
|
||||
checkAuditLogRecord(true, "successfully created Address:");
|
||||
serverControl.updateAddress("auditAddress", "ANYCAST");
|
||||
checkAuditLogRecord(true, "successfully updated Address:");
|
||||
serverControl.deleteAddress("auditAddress");
|
||||
checkAuditLogRecord(true, "successfully deleted Address:");
|
||||
serverControl.createQueue("auditAddress", "auditQueue", "ANYCAST");
|
||||
checkAuditLogRecord(true, "successfully created Queue:");
|
||||
serverControl.updateQueue("auditQueue", "ANYCAST", -1, false);
|
||||
final QueueControl queueControl = MBeanServerInvocationHandler.newProxyInstance(mBeanServerConnection,
|
||||
objectNameBuilder.getQueueObjectName(new SimpleString( "auditAddress"), new SimpleString("auditQueue"), RoutingType.ANYCAST),
|
||||
QueueControl.class,
|
||||
false);
|
||||
checkAuditLogRecord(true, "successfully updated Queue:");
|
||||
queueControl.removeAllMessages();
|
||||
checkAuditLogRecord(true, "has removed 0 messages");
|
||||
queueControl.sendMessage(new HashMap<>(), 0, "foo", true, "admin", "admin");
|
||||
checkAuditLogRecord(true, "sent message to");
|
||||
CompositeData[] browse = queueControl.browse();
|
||||
checkAuditLogRecord(true, "browsed " + browse.length + " messages");
|
||||
serverControl.destroyQueue("auditQueue");
|
||||
checkAuditLogRecord(true, "successfully deleted Queue:");
|
||||
|
||||
ServerLocator locator = createNettyNonHALocator();
|
||||
ClientSessionFactory sessionFactory = locator.createSessionFactory();
|
||||
ClientSession session = sessionFactory.createSession("admin", "admin", false, false, true, false, 0);
|
||||
ClientProducer producer = session.createProducer("myQ");
|
||||
producer.send(session.createMessage(true));
|
||||
locator.close();
|
||||
|
||||
} finally {
|
||||
jmxConnector.close();
|
||||
}
|
||||
}
|
||||
|
||||
//check the audit log has a line that contains all the values
|
||||
private void checkAuditLogRecord(boolean exist, String... values) throws Exception {
|
||||
Assert.assertTrue(auditLog.exists());
|
||||
boolean hasRecord = false;
|
||||
try (BufferedReader reader = new BufferedReader(new FileReader(auditLog))) {
|
||||
String line = reader.readLine();
|
||||
while (line != null) {
|
||||
if (line.contains(values[0])) {
|
||||
boolean hasAll = true;
|
||||
for (int i = 1; i < values.length; i++) {
|
||||
if (!line.contains(values[i])) {
|
||||
hasAll = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (hasAll) {
|
||||
hasRecord = true;
|
||||
System.out.println("audit has it: " + line);
|
||||
break;
|
||||
}
|
||||
}
|
||||
line = reader.readLine();
|
||||
}
|
||||
if (exist) {
|
||||
Assert.assertTrue(hasRecord);
|
||||
} else {
|
||||
Assert.assertFalse(hasRecord);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -14,114 +14,69 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.activemq.artemis.tests.integration.management;
|
||||
package org.apache.activemq.artemis.tests.smoke.logging;
|
||||
|
||||
import org.apache.activemq.artemis.api.config.ActiveMQDefaultConfiguration;
|
||||
import org.apache.activemq.artemis.api.core.Message;
|
||||
import org.apache.activemq.artemis.api.core.QueueConfiguration;
|
||||
import org.apache.activemq.artemis.api.core.RoutingType;
|
||||
import org.apache.activemq.artemis.api.core.SimpleString;
|
||||
import org.apache.activemq.artemis.api.core.TransportConfiguration;
|
||||
import org.apache.activemq.artemis.api.core.client.ClientConsumer;
|
||||
import org.apache.activemq.artemis.api.core.client.ClientMessage;
|
||||
import org.apache.activemq.artemis.api.core.client.ClientProducer;
|
||||
import org.apache.activemq.artemis.api.core.client.ClientSession;
|
||||
import org.apache.activemq.artemis.api.core.client.ClientSessionFactory;
|
||||
import org.apache.activemq.artemis.api.core.client.ServerLocator;
|
||||
import org.apache.activemq.artemis.api.core.management.AddressControl;
|
||||
import org.apache.activemq.artemis.core.config.Configuration;
|
||||
import org.apache.activemq.artemis.core.config.impl.SecurityConfiguration;
|
||||
import org.apache.activemq.artemis.core.security.Role;
|
||||
import org.apache.activemq.artemis.core.server.ActiveMQServer;
|
||||
import org.apache.activemq.artemis.core.server.ActiveMQServers;
|
||||
import org.apache.activemq.artemis.spi.core.security.ActiveMQJAASSecurityManager;
|
||||
import org.apache.activemq.artemis.spi.core.security.jaas.InVMLoginModule;
|
||||
import org.apache.activemq.artemis.tests.util.Wait;
|
||||
import org.apache.activemq.artemis.api.core.management.ObjectNameBuilder;
|
||||
import org.apache.activemq.artemis.tests.smoke.common.SmokeTestBase;
|
||||
import org.apache.activemq.artemis.utils.Base64;
|
||||
import org.apache.activemq.artemis.utils.RandomUtil;
|
||||
import org.junit.After;
|
||||
import org.apache.activemq.artemis.utils.Wait;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
import javax.management.MBeanServerConnection;
|
||||
import javax.management.MBeanServerInvocationHandler;
|
||||
import javax.management.remote.JMXConnector;
|
||||
import javax.management.remote.JMXConnectorFactory;
|
||||
import javax.management.remote.JMXServiceURL;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileReader;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.net.URI;
|
||||
import java.util.HashSet;
|
||||
import java.net.MalformedURLException;
|
||||
import java.util.HashMap;
|
||||
import java.util.UUID;
|
||||
import java.util.logging.LogManager;
|
||||
|
||||
// https://issues.apache.org/jira/browse/ARTEMIS-2730 this test needs to be moved as a SmokeTest
|
||||
// as it's messing up with logging configurations
|
||||
@Ignore
|
||||
public class AuditLoggerTest extends ManagementTestBase {
|
||||
public class AuditLoggerTest extends SmokeTestBase {
|
||||
|
||||
private static final File auditLog = new File("target/audit.log");
|
||||
private static final File auditLog = new File("target/audit-logging2/log/audit.log");
|
||||
|
||||
private static final String JMX_SERVER_HOSTNAME = "localhost";
|
||||
private static final int JMX_SERVER_PORT = 10099;
|
||||
|
||||
public static final String SERVER_NAME = "audit-logging2";
|
||||
|
||||
private ActiveMQServer server;
|
||||
private Configuration conf;
|
||||
protected ClientSession session;
|
||||
private ServerLocator locator;
|
||||
private ClientSessionFactory sf;
|
||||
|
||||
@Override
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
public void before() throws Exception {
|
||||
cleanupData(SERVER_NAME);
|
||||
disableCheckThread();
|
||||
startServer(SERVER_NAME, 0, 30000);
|
||||
emptyLogFile();
|
||||
|
||||
TransportConfiguration connectorConfig = new TransportConfiguration(INVM_CONNECTOR_FACTORY);
|
||||
|
||||
conf = createDefaultNettyConfig().setJMXManagementEnabled(true).addConnectorConfiguration(connectorConfig.getName(), connectorConfig);
|
||||
conf.setSecurityEnabled(true);
|
||||
SecurityConfiguration securityConfiguration = new SecurityConfiguration();
|
||||
securityConfiguration.addUser("guest", "guest");
|
||||
securityConfiguration.addUser("myUser", "myPass");
|
||||
securityConfiguration.addRole("guest", "guest");
|
||||
securityConfiguration.addRole("myUser", "guest");
|
||||
securityConfiguration.setDefaultUser("guest");
|
||||
ActiveMQJAASSecurityManager securityManager = new ActiveMQJAASSecurityManager(InVMLoginModule.class.getName(), securityConfiguration);
|
||||
server = addServer(ActiveMQServers.newActiveMQServer(conf, mbeanServer, securityManager, true));
|
||||
server.start();
|
||||
|
||||
HashSet<Role> role = new HashSet<>();
|
||||
//role guest cannot delete queues
|
||||
role.add(new Role("guest", true, true, true, false, true, false, true, true, true, true));
|
||||
server.getSecurityRepository().addMatch("#", role);
|
||||
|
||||
locator = createInVMNonHALocator().setBlockOnNonDurableSend(true);
|
||||
locator = createNonHALocator(true).setBlockOnNonDurableSend(true);
|
||||
sf = createSessionFactory(locator);
|
||||
session = sf.createSession("guest", "guest", false, true, false, false, 100);
|
||||
session.start();
|
||||
addClientSession(session);
|
||||
}
|
||||
|
||||
@After
|
||||
@Override
|
||||
public void tearDown() throws Exception {
|
||||
super.tearDown();
|
||||
|
||||
String originalLoggingConfig = System.getProperty("logging.configuration");
|
||||
|
||||
if (originalLoggingConfig != null) {
|
||||
File file = new File(new URI(originalLoggingConfig));
|
||||
InputStream inputStream = new FileInputStream(file);
|
||||
|
||||
LogManager logManager = LogManager.getLogManager();
|
||||
try {
|
||||
logManager.readConfiguration(inputStream);
|
||||
} catch (IOException e) {
|
||||
System.out.println("error loading logging conifg");
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
inputStream.close();
|
||||
}
|
||||
}
|
||||
|
||||
private void emptyLogFile() throws Exception {
|
||||
if (auditLog.exists()) {
|
||||
try (PrintWriter writer = new PrintWriter(new FileWriter(auditLog))) {
|
||||
|
@ -132,11 +87,15 @@ public class AuditLoggerTest extends ManagementTestBase {
|
|||
|
||||
@Test
|
||||
public void testAuditLog() throws Exception {
|
||||
reloadLoggingConfig("audit.logging.properties");
|
||||
JMXConnector jmxConnector = getJmxConnector();
|
||||
|
||||
MBeanServerConnection mBeanServerConnection = jmxConnector.getMBeanServerConnection();
|
||||
String brokerName = "0.0.0.0"; // configured e.g. in broker.xml <broker-name> element
|
||||
ObjectNameBuilder objectNameBuilder = ObjectNameBuilder.create(ActiveMQDefaultConfiguration.getDefaultJmxDomain(), brokerName, true);
|
||||
SimpleString address = RandomUtil.randomSimpleString();
|
||||
session.createAddress(address, RoutingType.ANYCAST, false);
|
||||
|
||||
final AddressControl addressControl = ManagementControlHelper.createAddressControl(address, mbeanServer);
|
||||
final AddressControl addressControl = MBeanServerInvocationHandler.newProxyInstance(mBeanServerConnection, objectNameBuilder.getAddressObjectName(address), AddressControl.class, false);
|
||||
|
||||
Assert.assertEquals(0, addressControl.getQueueNames().length);
|
||||
session.createQueue(new QueueConfiguration(address).setRoutingType(RoutingType.ANYCAST));
|
||||
|
@ -153,62 +112,90 @@ public class AuditLoggerTest extends ManagementTestBase {
|
|||
address = RandomUtil.randomSimpleString();
|
||||
session.createAddress(address, RoutingType.ANYCAST, false);
|
||||
|
||||
final AddressControl addressControl2 = ManagementControlHelper.createAddressControl(address, mbeanServer);
|
||||
final AddressControl addressControl2 = MBeanServerInvocationHandler.newProxyInstance(mBeanServerConnection, objectNameBuilder.getAddressObjectName(address), AddressControl.class, false);
|
||||
|
||||
Assert.assertEquals(1, addressControl.getQueueNames().length);
|
||||
|
||||
session.createQueue(new QueueConfiguration(address).setRoutingType(RoutingType.ANYCAST).setDurable(false));
|
||||
Wait.waitFor(() -> addressControl2.getQueueNames().length == 1);
|
||||
|
||||
ClientProducer producer = session.createProducer(address);
|
||||
producer.send(session.createMessage(true));
|
||||
Wait.waitFor(() -> addressControl.getMessageCount() == 1);
|
||||
try {
|
||||
session.deleteQueue(address);
|
||||
fail("Deleting queue should get exception");
|
||||
Assert.fail("Deleting queue should get exception");
|
||||
} catch (Exception e) {
|
||||
//ignore
|
||||
}
|
||||
|
||||
checkAuditLogRecord(true, "gets security check failure:", "guest does not have permission='DELETE_NON_DURABLE_QUEUE'");
|
||||
//hot patch not in log
|
||||
checkAuditLogRecord(false, "is sending a core message");
|
||||
checkAuditLogRecord(true, "is sending a core message");
|
||||
}
|
||||
|
||||
private void reloadLoggingConfig(String logFile) {
|
||||
ClassLoader cl = AuditLoggerTest.class.getClassLoader();
|
||||
InputStream inputStream = cl.getResourceAsStream(logFile);
|
||||
LogManager logManager = LogManager.getLogManager();
|
||||
protected JMXConnector getJmxConnector() throws MalformedURLException {
|
||||
HashMap environment = new HashMap();
|
||||
String[] credentials = new String[] {"admin", "admin"};
|
||||
environment.put(JMXConnector.CREDENTIALS, credentials);
|
||||
// Without this, the RMI server would bind to the default interface IP (the user's local IP mostly)
|
||||
System.setProperty("java.rmi.server.hostname", JMX_SERVER_HOSTNAME);
|
||||
|
||||
// I don't specify both ports here manually on purpose. See actual RMI registry connection port extraction below.
|
||||
String urlString = "service:jmx:rmi:///jndi/rmi://" + JMX_SERVER_HOSTNAME + ":" + JMX_SERVER_PORT + "/jmxrmi";
|
||||
|
||||
JMXServiceURL url = new JMXServiceURL(urlString);
|
||||
JMXConnector jmxConnector = null;
|
||||
|
||||
try {
|
||||
logManager.readConfiguration(inputStream);
|
||||
inputStream.close();
|
||||
} catch (IOException e) {
|
||||
System.out.println("error loading logging conifg");
|
||||
jmxConnector = JMXConnectorFactory.connect(url, environment);
|
||||
System.out.println("Successfully connected to: " + urlString);
|
||||
} catch (Exception e) {
|
||||
jmxConnector = null;
|
||||
e.printStackTrace();
|
||||
Assert.fail(e.getMessage());
|
||||
}
|
||||
|
||||
return jmxConnector;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAuditHotLog() throws Exception {
|
||||
reloadLoggingConfig("audit.logging.hot.properties");
|
||||
JMXConnector jmxConnector = getJmxConnector();
|
||||
MBeanServerConnection mBeanServerConnection = jmxConnector.getMBeanServerConnection();
|
||||
String brokerName = "0.0.0.0"; // configured e.g. in broker.xml <broker-name> element
|
||||
ObjectNameBuilder objectNameBuilder = ObjectNameBuilder.create(ActiveMQDefaultConfiguration.getDefaultJmxDomain(), brokerName, true);
|
||||
SimpleString address = RandomUtil.randomSimpleString();
|
||||
session.createAddress(address, RoutingType.ANYCAST, false);
|
||||
|
||||
final AddressControl addressControl = ManagementControlHelper.createAddressControl(address, mbeanServer);
|
||||
final AddressControl addressControl = MBeanServerInvocationHandler.newProxyInstance(mBeanServerConnection, objectNameBuilder.getAddressObjectName(address), AddressControl.class, false);
|
||||
|
||||
Assert.assertEquals(0, addressControl.getQueueNames().length);
|
||||
session.createQueue(new QueueConfiguration(address).setRoutingType(RoutingType.ANYCAST));
|
||||
Assert.assertEquals(1, addressControl.getQueueNames().length);
|
||||
String uniqueStr = Base64.encodeBytes(UUID.randomUUID().toString().getBytes());
|
||||
addressControl.sendMessage(null, Message.BYTES_TYPE, uniqueStr, false, null, null);
|
||||
|
||||
Wait.waitFor(() -> addressControl.getMessageCount() == 1);
|
||||
Assert.assertEquals(1, addressControl.getMessageCount());
|
||||
ClientProducer producer = session.createProducer(address);
|
||||
producer.send(session.createMessage(true));
|
||||
producer.send(session.createMessage(true));
|
||||
// addressControl.sendMessage(null, Message.BYTES_TYPE, uniqueStr, false, null, null);
|
||||
|
||||
Wait.waitFor(() -> addressControl.getMessageCount() == 2);
|
||||
Assert.assertEquals(2, addressControl.getMessageCount());
|
||||
|
||||
checkAuditLogRecord(true, "sending a core message");
|
||||
|
||||
ClientConsumer consumer = session.createConsumer(address);
|
||||
session.start();
|
||||
ClientMessage clientMessage = consumer.receiveImmediate();
|
||||
Assert.assertNotNull(clientMessage);
|
||||
clientMessage = consumer.receiveImmediate();
|
||||
Assert.assertNotNull(clientMessage);
|
||||
checkAuditLogRecord(true, "is consuming a message from");
|
||||
}
|
||||
|
||||
//check the audit log has a line that contains all the values
|
||||
private void checkAuditLogRecord(boolean exist, String... values) throws Exception {
|
||||
assertTrue(auditLog.exists());
|
||||
Assert.assertTrue(auditLog.exists());
|
||||
boolean hasRecord = false;
|
||||
try (BufferedReader reader = new BufferedReader(new FileReader(auditLog))) {
|
||||
String line = reader.readLine();
|
||||
|
@ -230,9 +217,9 @@ public class AuditLoggerTest extends ManagementTestBase {
|
|||
line = reader.readLine();
|
||||
}
|
||||
if (exist) {
|
||||
assertTrue(hasRecord);
|
||||
Assert.assertTrue(hasRecord);
|
||||
} else {
|
||||
assertFalse(hasRecord);
|
||||
Assert.assertFalse(hasRecord);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue