瀏覽代碼

syslog max length

Jason Rivard 9 年之前
父節點
當前提交
d7575429f3

+ 2 - 0
src/main/java/password/pwm/AppProperty.java

@@ -36,6 +36,8 @@ public enum AppProperty {
     APPLICATION_WORDLIST_RETRY_SECONDS              ("application.wordlistRetryImportSeconds"),
     AUDIT_EVENTS_EMAILFROM                          ("audit.events.emailFrom"),
     AUDIT_EVENTS_EMAILSUBJECT                       ("audit.events.emailSubject"),
+    AUDIT_SYSLOG_MAX_MESSAGE_LENGTH                 ("audit.syslog.message.length"),
+    AUDIT_SYSLOG_TRUNCATE_MESSAGE                   ("audit.syslog.message.truncateMsg"),
     BACKUP_LOCATION                                 ("backup.path"),
     BACKUP_CONFIG_COUNT                             ("backup.config.count"),
     BACKUP_LOCALDB_COUNT                            ("backup.localdb.count"),

+ 1 - 7
src/main/java/password/pwm/svc/event/AuditEvent.java

@@ -33,13 +33,7 @@ import java.util.*;
 public enum AuditEvent {
 
     // system events
-    STARTUP(
-            Message.EventLog_Startup,
-            Admin.EventLog_Narrative_Startup,
-            Type.SYSTEM
-    ),
-
-
+    STARTUP(                        Message.EventLog_Startup,                           Admin.EventLog_Narrative_Startup,                          Type.SYSTEM),
     SHUTDOWN(                       Message.EventLog_Shutdown,                          Admin.EventLog_Narrative_Shutdown,                         Type.SYSTEM),
     FATAL_EVENT(                    Message.EventLog_FatalEvent,                        Admin.EventLog_Narrative_FatalEvent,                       Type.SYSTEM),
     INTRUDER_LOCK(                  Message.EventLog_IntruderLockout,                   Admin.EventLog_Narrative_IntruderLockout,                  Type.SYSTEM),

+ 4 - 4
src/main/java/password/pwm/svc/event/AuditRecord.java

@@ -34,8 +34,8 @@ public abstract class AuditRecord implements Serializable {
     protected Date timestamp = new Date();
     protected String message;
     protected String narrative;
-    protected String xdasTaxonomy;
-    protected String xdasOutcome;
+    protected final String xdasTaxonomy;
+    protected final String xdasOutcome;
 
 
     protected AuditRecord(
@@ -49,13 +49,13 @@ public abstract class AuditRecord implements Serializable {
 
         this.timestamp = timestamp;
         this.guid = PwmRandom.getInstance().randomUUID().toString();
+        this.xdasOutcome = eventCode.getXdasOutcome();
+        this.xdasTaxonomy = eventCode.getXdasTaxonomy();
     }
 
 
     protected AuditRecord(final AuditEvent eventCode, final String message) {
         this(new Date(), eventCode, message);
-        this.xdasOutcome = eventCode.getXdasOutcome();
-        this.xdasTaxonomy = eventCode.getXdasTaxonomy();
     }
 
     public AuditEvent.Type getType() {

+ 78 - 16
src/main/java/password/pwm/svc/event/SyslogAuditService.java

@@ -44,8 +44,10 @@ import password.pwm.error.PwmError;
 import password.pwm.error.PwmOperationalException;
 import password.pwm.health.HealthRecord;
 import password.pwm.health.HealthStatus;
-import password.pwm.health.HealthTopic;
-import password.pwm.util.*;
+import password.pwm.util.JsonUtil;
+import password.pwm.util.TimeDuration;
+import password.pwm.util.WorkQueueProcessor;
+import password.pwm.util.X509Utils;
 import password.pwm.util.localdb.LocalDB;
 import password.pwm.util.localdb.LocalDBException;
 import password.pwm.util.localdb.LocalDBStoredQueue;
@@ -58,7 +60,11 @@ import java.io.Serializable;
 import java.security.KeyManagementException;
 import java.security.NoSuchAlgorithmException;
 import java.security.cert.X509Certificate;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import static password.pwm.health.HealthTopic.Audit;
 
 public class SyslogAuditService {
     private static final PwmLogger LOGGER = PwmLogger.forClass(SyslogAuditService.class);
@@ -70,7 +76,7 @@ public class SyslogAuditService {
     private ErrorInformation lastError = null;
     private X509Certificate[] certificates = null;
 
-    private WorkQueueProcessor<AuditRecord> workQueueProcessor;
+    private WorkQueueProcessor<String> workQueueProcessor;
 
 
     private final Configuration configuration;
@@ -92,23 +98,23 @@ public class SyslogAuditService {
         }
 
         final WorkQueueProcessor.Settings settings = new WorkQueueProcessor.Settings();
-        settings.setMaxEvents(Integer.parseInt(pwmApplication.getConfig().readAppProperty(AppProperty.QUEUE_SYSLOG_MAX_COUNT)));
-        settings.setRetryDiscardAge(new TimeDuration(Long.parseLong(pwmApplication.getConfig().readAppProperty(AppProperty.QUEUE_SYSLOG_MAX_AGE_MS))));
-        settings.setRetryInterval(new TimeDuration(Long.parseLong(pwmApplication.getConfig().readAppProperty(AppProperty.QUEUE_SYSLOG_RETRY_TIMEOUT_MS))));
+        settings.setMaxEvents(Integer.parseInt(configuration.readAppProperty(AppProperty.QUEUE_SYSLOG_MAX_COUNT)));
+        settings.setRetryDiscardAge(new TimeDuration(Long.parseLong(configuration.readAppProperty(AppProperty.QUEUE_SYSLOG_MAX_AGE_MS))));
+        settings.setRetryInterval(new TimeDuration(Long.parseLong(configuration.readAppProperty(AppProperty.QUEUE_SYSLOG_RETRY_TIMEOUT_MS))));
 
         final LocalDBStoredQueue localDBStoredQueue = LocalDBStoredQueue.createLocalDBStoredQueue(pwmApplication, pwmApplication.getLocalDB(), LocalDB.DB.SYSLOG_QUEUE);
 
         workQueueProcessor = new WorkQueueProcessor<>(pwmApplication, localDBStoredQueue, settings, new SyslogItemProcessor(), this.getClass());
     }
 
-    private class SyslogItemProcessor implements WorkQueueProcessor.ItemProcessor<AuditRecord> {
+    private class SyslogItemProcessor implements WorkQueueProcessor.ItemProcessor<String> {
         @Override
-        public WorkQueueProcessor.ProcessResult process(AuditRecord workItem) {
+        public WorkQueueProcessor.ProcessResult process(String workItem) {
             return processEvent(workItem);
         }
 
         @Override
-        public String convertToDebugString(AuditRecord workItem) {
+        public String convertToDebugString(String workItem) {
             return JsonUtil.serialize(workItem);
         }
     }
@@ -144,8 +150,11 @@ public class SyslogAuditService {
                 throw new IllegalArgumentException("unknown protocol type");
         }
 
+        final int maxLength = Integer.parseInt(configuration.readAppProperty(AppProperty.AUDIT_SYSLOG_MAX_MESSAGE_LENGTH));
+
         syslogConfigIF.setThreaded(false);
         syslogConfigIF.setMaxQueueSize(0);
+        syslogConfigIF.setMaxMessageLength(maxLength);
         syslogConfigIF.setThrowExceptionOnWrite(true);
         syslogConfigIF.setHost(syslogConfig.getHost());
         syslogConfigIF.setPort(syslogConfig.getPort());
@@ -155,7 +164,8 @@ public class SyslogAuditService {
 
     public void add(AuditRecord event) throws PwmOperationalException {
         try {
-            workQueueProcessor.submit(event);
+            final String syslogMsg = convertAuditRecordToSyslogMessage(event, configuration);
+            workQueueProcessor.submit(syslogMsg);
         } catch (PwmOperationalException e) {
             LOGGER.warn("unable to add email to queue: " + e.getMessage());
         }
@@ -166,20 +176,19 @@ public class SyslogAuditService {
         if (lastError != null) {
             final ErrorInformation errorInformation = lastError;
             if (TimeDuration.fromCurrent(errorInformation.getDate()).isShorterThan(WARNING_WINDOW_MS)) {
-                healthRecords.add(new HealthRecord(HealthStatus.WARN, HealthTopic.Audit,
+                healthRecords.add(new HealthRecord(HealthStatus.WARN, Audit,
                         errorInformation.toUserStr(PwmConstants.DEFAULT_LOCALE, configuration)));
             }
         }
         return healthRecords;
     }
 
-    private WorkQueueProcessor.ProcessResult processEvent(final AuditRecord auditRecord) {
-        final String syslogEventString = PwmConstants.PWM_APP_NAME + " " + JsonUtil.serialize(auditRecord);
+    private WorkQueueProcessor.ProcessResult processEvent(final String auditRecord) {
 
         final SyslogIF syslogIF = syslogInstance;
         try {
-            syslogIF.info(syslogEventString);
-            LOGGER.trace("delivered syslog audit event: " + syslogEventString);
+            syslogIF.info(auditRecord);
+            LOGGER.trace("delivered syslog audit event: " + auditRecord);
             lastError = null;
             return WorkQueueProcessor.ProcessResult.SUCCESS;
         } catch (Exception e) {
@@ -199,6 +208,59 @@ public class SyslogAuditService {
         syslogInstance = null;
     }
 
+    private static String convertAuditRecordToSyslogMessage(
+            final AuditRecord auditRecord,
+            final Configuration configuration
+    )
+    {
+        final int maxLength = Integer.parseInt(configuration.readAppProperty(AppProperty.AUDIT_SYSLOG_MAX_MESSAGE_LENGTH));
+        final StringBuilder message = new StringBuilder();
+        message.append(PwmConstants.PWM_APP_NAME);
+        message.append(" ");
+
+        final String jsonValue = JsonUtil.serialize(auditRecord);
+
+        if (message.length() + jsonValue.length() <= maxLength) {
+            message.append(jsonValue);
+        } else {
+            final AuditRecord inputRecord = JsonUtil.cloneUsingJson(auditRecord, auditRecord.getClass());
+            inputRecord.message = inputRecord.message == null ? "" : inputRecord.message;
+            inputRecord.narrative= inputRecord.narrative == null ? "" : inputRecord.narrative;
+
+            final String truncateMessage = configuration.readAppProperty(AppProperty.AUDIT_SYSLOG_TRUNCATE_MESSAGE);
+            final AuditRecord copiedRecord = JsonUtil.cloneUsingJson(auditRecord, auditRecord.getClass());
+            copiedRecord.message = "";
+            copiedRecord.narrative = "";
+            final int shortenedMessageLength = message.length()
+                    + JsonUtil.serialize(copiedRecord).length()
+                    + truncateMessage.length();
+            final int maxMessageAndNarrativeLength = maxLength - (shortenedMessageLength + (truncateMessage.length() * 2));
+            int maxMessageLength = inputRecord.getMessage().length();
+            int maxNarrativeLength = inputRecord.getNarrative().length();
+
+            {
+                int top = maxMessageAndNarrativeLength;
+                while (maxMessageLength + maxNarrativeLength > maxMessageAndNarrativeLength) {
+                    top--;
+                    maxMessageLength = Math.min(maxMessageLength, top);
+                    maxNarrativeLength = Math.min(maxNarrativeLength, top);
+                }
+            }
+
+            copiedRecord.message = inputRecord.getMessage().length() > maxMessageLength
+                    ? inputRecord.message.substring(0, maxMessageLength) + truncateMessage
+                    : inputRecord.message;
+
+            copiedRecord.narrative = inputRecord.getNarrative().length() > maxNarrativeLength
+                    ? inputRecord.narrative.substring(0, maxNarrativeLength) + truncateMessage
+                    : inputRecord.narrative;
+
+            message.append(JsonUtil.serialize(copiedRecord));
+        }
+
+        return message.toString();
+    }
+
     public static class SyslogConfig implements Serializable {
         public enum Protocol { sslTcp, tcp, udp, tls }
 

+ 2 - 0
src/main/resources/password/pwm/AppProperty.properties

@@ -28,6 +28,8 @@ application.fileLock.waitSeconds=120
 application.wordlistRetryImportSeconds=600
 audit.events.emailFrom=Audit Event Notification <@DefaultEmailFromAddress@>
 audit.events.emailSubject=@PwmAppName@ - Audit Event - %EVENT%
+audit.syslog.message.length=1024
+audit.syslog.message.truncateMsg=[truncated]
 backup.path=backup
 backup.config.count=20
 backup.localdb.count=10