ARTEMIS-4210 audit connection creation & destruction

This commit is contained in:
Justin Bertram 2023-03-17 11:42:59 -05:00
parent 57321e8fec
commit d2e5ddfe86
7 changed files with 57 additions and 20 deletions

View File

@ -50,6 +50,10 @@ logger.audit_message = OFF, audit_log_file
logger.audit_message.name = org.apache.activemq.audit.message
logger.audit_message.additivity = false
logger.audit_connection = OFF, audit_log_file
logger.audit_connection.name = org.apache.activemq.audit.connection
logger.audit_connection.additivity = false
# Jetty logger levels
logger.jetty.name=org.eclipse.jetty
logger.jetty.level=WARN

View File

@ -37,18 +37,19 @@ public interface AuditLogger {
AuditLogger BASE_LOGGER = BundleFactory.newBundle(AuditLogger.class, "org.apache.activemq.audit.base");
AuditLogger RESOURCE_LOGGER = BundleFactory.newBundle(AuditLogger.class, "org.apache.activemq.audit.resource");
AuditLogger MESSAGE_LOGGER = BundleFactory.newBundle(AuditLogger.class, "org.apache.activemq.audit.message");
AuditLogger CONNECTION_LOGGER = BundleFactory.newBundle(AuditLogger.class, "org.apache.activemq.audit.connection");
ThreadLocal<String> remoteAddress = new ThreadLocal<>();
ThreadLocal<Subject> currentCaller = new ThreadLocal<>();
static boolean isAnyLoggingEnabled() {
return isBaseLoggingEnabled() || isMessageLoggingEnabled() || isResourceLoggingEnabled();
}
@GetLogger
Logger getLogger();
static boolean isAnyLoggingEnabled() {
return isBaseLoggingEnabled() || isMessageLoggingEnabled() || isResourceLoggingEnabled() || isConnectionLoggingEnabled();
}
static boolean isBaseLoggingEnabled() {
return BASE_LOGGER.getLogger().isInfoEnabled();
}
@ -61,6 +62,10 @@ public interface AuditLogger {
return MESSAGE_LOGGER.getLogger().isInfoEnabled();
}
static boolean isConnectionLoggingEnabled() {
return CONNECTION_LOGGER.getLogger().isInfoEnabled();
}
/**
* @return a String representing the "caller" in the format "user(role)@remoteAddress" using ThreadLocal values (if set)
*/
@ -2255,28 +2260,28 @@ public interface AuditLogger {
@LogMessage(id = 601714, value = "User {} failed to remove messages from queue: {}", level = LogMessage.Level.INFO)
void removeMessagesFailure(String user, String queue);
static void userSuccesfullyAuthenticatedInAudit(Subject subject, String remoteAddress) {
RESOURCE_LOGGER.userSuccesfullyAuthenticated(getCaller(subject, remoteAddress));
static void userSuccesfullyAuthenticatedInAudit(Subject subject, String remoteAddress, String connectionID) {
RESOURCE_LOGGER.userSuccesfullyAuthenticated(getCaller(subject, remoteAddress), connectionID);
}
static void userSuccesfullyAuthenticatedInAudit(Subject subject) {
userSuccesfullyAuthenticatedInAudit(subject, null);
userSuccesfullyAuthenticatedInAudit(subject, null, null);
}
@LogMessage(id = 601715, value = "User {} successfully authenticated", level = LogMessage.Level.INFO)
void userSuccesfullyAuthenticated(String caller);
@LogMessage(id = 601715, value = "User {} successfully authenticated on connection {}", level = LogMessage.Level.INFO)
void userSuccesfullyAuthenticated(String caller, String connectionID);
static void userFailedAuthenticationInAudit(String reason) {
RESOURCE_LOGGER.userFailedAuthentication(getCaller(), reason);
RESOURCE_LOGGER.userFailedAuthentication(getCaller(), null, reason);
}
static void userFailedAuthenticationInAudit(Subject subject, String reason) {
RESOURCE_LOGGER.userFailedAuthentication(getCaller(subject, null), reason);
static void userFailedAuthenticationInAudit(Subject subject, String reason, String connectionID) {
RESOURCE_LOGGER.userFailedAuthentication(getCaller(subject, null), connectionID, reason);
}
@LogMessage(id = 601716, value = "User {} failed authentication, reason: {}", level = LogMessage.Level.INFO)
void userFailedAuthentication(String user, String reason);
@LogMessage(id = 601716, value = "User {} failed authentication on connection {}, reason: {}", level = LogMessage.Level.INFO)
void userFailedAuthentication(String user, String connectionID, String reason);
static void objectInvokedSuccessfully(ObjectName objectName, String operationName) {
RESOURCE_LOGGER.objectInvokedSuccessfully(getCaller(), objectName, operationName);
@ -2639,4 +2644,18 @@ public interface AuditLogger {
@LogMessage(id = 601766, value = "User {} is getting auto-delete property on target resource: {}", level = LogMessage.Level.INFO)
void isAutoDelete(String user, Object source);
static void createdConnection(String protocol, Object connectionID, String remoteAddress) {
CONNECTION_LOGGER.createdConnection(protocol, connectionID.toString(), String.format("unknown%s", formatRemoteAddress(remoteAddress)));
}
@LogMessage(id = 601767, value = "{} connection {} for user {} created", level = LogMessage.Level.INFO)
void createdConnection(String protocol, String connectionID, String user);
static void destroyedConnection(String protocol, Object connectionID, Subject subject, String remoteAddress) {
CONNECTION_LOGGER.destroyedConnection(protocol, connectionID.toString(), getCaller(subject, remoteAddress));
}
@LogMessage(id = 601768, value = "{} connection {} for user {} destroyed", level = LogMessage.Level.INFO)
void destroyedConnection(String protocol, String connectionID, String user);
}

View File

@ -61,6 +61,7 @@ import org.apache.activemq.artemis.core.server.ServiceRegistry;
import org.apache.activemq.artemis.core.server.cluster.ClusterConnection;
import org.apache.activemq.artemis.core.server.cluster.ClusterManager;
import org.apache.activemq.artemis.core.server.management.ManagementService;
import org.apache.activemq.artemis.logs.AuditLogger;
import org.apache.activemq.artemis.spi.core.protocol.ConnectionEntry;
import org.apache.activemq.artemis.spi.core.protocol.MessagePersister;
import org.apache.activemq.artemis.spi.core.protocol.ProtocolManager;
@ -486,6 +487,9 @@ public class RemotingServiceImpl implements RemotingService, ServerConnectionLif
ConnectionEntry entry = connections.remove(remotingConnectionID);
if (entry != null) {
if (AuditLogger.isConnectionLoggingEnabled()) {
AuditLogger.destroyedConnection(entry.connection.getProtocolName(), entry.connection.getID().toString(), entry.connection.getSubject(), entry.connection.getRemoteAddress());
}
if (logger.isDebugEnabled()) {
logger.debug("RemotingServiceImpl::removing succeeded connection ID {}, we now have {} connections", remotingConnectionID, connections.size());
}
@ -577,6 +581,9 @@ public class RemotingServiceImpl implements RemotingService, ServerConnectionLif
@Override
public void addConnectionEntry(Connection connection, ConnectionEntry entry) {
connections.put(connection.getID(), entry);
if (AuditLogger.isConnectionLoggingEnabled()) {
AuditLogger.createdConnection(connection.getProtocolConnection().getProtocolName(), connection.getID(), connection.getRemoteAddress());
}
if (logger.isDebugEnabled()) {
logger.debug("Adding connection {}, we now have {}", connection.getID(), connections.size());
}

View File

@ -211,7 +211,7 @@ public class SecurityStoreImpl implements SecurityStore, HierarchicalRepositoryC
connection.setSubject(subject);
}
if (AuditLogger.isResourceLoggingEnabled()) {
AuditLogger.userSuccesfullyAuthenticatedInAudit(subject, connection.getRemoteAddress());
AuditLogger.userSuccesfullyAuthenticatedInAudit(subject, connection.getRemoteAddress(), connection.getID().toString());
}
return validatedUser;
@ -380,7 +380,7 @@ public class SecurityStoreImpl implements SecurityStore, HierarchicalRepositoryC
ActiveMQServerLogger.LOGGER.securityProblemWhileAuthenticating(e.getMessage());
if (AuditLogger.isResourceLoggingEnabled()) {
AuditLogger.userFailedAuthenticationInAudit(null, e.getMessage());
AuditLogger.userFailedAuthenticationInAudit(null, e.getMessage(), connection.getID().toString());
}
throw e;

View File

@ -48,7 +48,7 @@ public class BasicAuthenticator implements JMXAuthenticator {
return result;
} else {
if (AuditLogger.isResourceLoggingEnabled()) {
AuditLogger.userFailedAuthenticationInAudit(result, null);
AuditLogger.userFailedAuthenticationInAudit(result, null, null);
}
throw new SecurityException("Authentication failed");
}

View File

@ -79,7 +79,7 @@ public class JaasAuthenticator implements JMXAuthenticator {
return subject;
} catch (LoginException e) {
if (AuditLogger.isResourceLoggingEnabled()) {
AuditLogger.userFailedAuthenticationInAudit(subject, e.getMessage());
AuditLogger.userFailedAuthenticationInAudit(subject, e.getMessage(), null);
}
throw new SecurityException("Authentication failed", e);
}

View File

@ -121,6 +121,7 @@ different types of broker events, these are:
The main purpose of this is to track console activity and access
to the broker.
3. **message**: This logs the production and consumption of messages.
3. **connection**: This logs the creation and destruction of connections.
> **Note:**
>
@ -144,6 +145,10 @@ logger.audit_resource.additivity = false
logger.audit_message = OFF, audit_log_file
logger.audit_message.name = org.apache.activemq.audit.message
logger.audit_message.additivity = false
logger.audit_connection = OFF, audit_log_file
logger.audit_connection.name = org.apache.activemq.audit.connection
logger.audit_connection.additivity = false
...
```
@ -155,12 +160,14 @@ logger.audit_base = INFO, audit_log_file
logger.audit_resource = INFO, audit_log_file
...
logger.audit_message = INFO, audit_log_file
...
logger.audit_connection = INFO, audit_log_file
```
The 3 audit loggers can be disable/enabled separately.
The 4 audit loggers can be disable/enabled separately.
Once enabled, all audit records are written into a separate log
file (by default audit.log).
file (by default `audit.log`).
## More on Log4J2 configuration: