Explorar o código

cef extension length limits

Jason Rivard %!s(int64=6) %!d(string=hai) anos
pai
achega
f2cc3b0143

+ 87 - 46
server/src/main/java/password/pwm/svc/event/CEFAuditFormatter.java

@@ -22,6 +22,8 @@
 
 package password.pwm.svc.event;
 
+import lombok.Builder;
+import lombok.Value;
 import password.pwm.AppProperty;
 import password.pwm.PwmApplication;
 import password.pwm.PwmConstants;
@@ -32,6 +34,7 @@ import password.pwm.util.i18n.LocaleHelper;
 import password.pwm.util.java.JavaHelper;
 import password.pwm.util.java.JsonUtil;
 import password.pwm.util.java.StringUtil;
+import password.pwm.util.logging.PwmLogger;
 import password.pwm.util.macro.MacroMachine;
 
 import java.util.Collections;
@@ -41,6 +44,8 @@ import java.util.Optional;
 
 public class CEFAuditFormatter implements AuditFormatter
 {
+    private static final PwmLogger LOGGER = PwmLogger.forClass( CEFAuditFormatter.class );
+
     private static final String CEF_EXTENSION_SEPARATOR = "|";
     private static final Map<String, String> CEF_VALUE_ESCAPES;
 
@@ -91,62 +96,24 @@ public class CEFAuditFormatter implements AuditFormatter
             throws PwmUnrecoverableException
     {
         final Configuration configuration = pwmApplication.getConfig();
-        final String cefTimezone = configuration.readAppProperty( AppProperty.AUDIT_SYSLOG_CEF_TIMEZONE );
-
+        final Settings settings = Settings.fromConfiguration( configuration );
         final Map<String, Object> auditRecordMap = JsonUtil.deserializeMap( JsonUtil.serialize( auditRecord ) );
 
-        final String headerSeverity = configuration.readAppProperty( AppProperty.AUDIT_SYSLOG_CEF_HEADER_SEVERITY );
-        final String headerProduct = configuration.readAppProperty( AppProperty.AUDIT_SYSLOG_CEF_HEADER_PRODUCT );
-        final String headerVendor = configuration.readAppProperty( AppProperty.AUDIT_SYSLOG_CEF_HEADER_VENDOR );
         final Optional<String> srcHost = JavaHelper.deriveLocalServerHostname( configuration );
 
-        final MacroMachine macroMachine = MacroMachine.forNonUserSpecific( pwmApplication, SessionLabel.SYSTEM_LABEL );
-
-        final String cefFieldName = LocaleHelper.getLocalizedMessage(
-                PwmConstants.DEFAULT_LOCALE,
-                auditRecord.getEventCode().getMessage(),
-                configuration
-        );
-
         final StringBuilder cefOutput = new StringBuilder(  );
 
         // cef header
-        {
-            // cef declaration:version prefix
-            cefOutput.append( "CEF:0" );
-
-            // Device Vendor
-            cefOutput.append( CEFAuditFormatter.CEF_EXTENSION_SEPARATOR );
-            cefOutput.append( macroMachine.expandMacros( headerVendor ) );
-
-            // Device Product
-            cefOutput.append( CEFAuditFormatter.CEF_EXTENSION_SEPARATOR );
-            cefOutput.append( macroMachine.expandMacros( headerProduct ) );
-
-            // Device Version
-            cefOutput.append( CEFAuditFormatter.CEF_EXTENSION_SEPARATOR );
-            cefOutput.append( PwmConstants.SERVLET_VERSION );
-
-            // Device Event Class ID
-            cefOutput.append( CEFAuditFormatter.CEF_EXTENSION_SEPARATOR );
-            cefOutput.append( auditRecord.getEventCode() );
+        cefOutput.append( makeCefHeader( pwmApplication, settings, auditRecord ) );
 
-            // field name
-            cefOutput.append( CEFAuditFormatter.CEF_EXTENSION_SEPARATOR );
-            cefOutput.append( cefFieldName );
-
-            // severity
-            cefOutput.append( CEFAuditFormatter.CEF_EXTENSION_SEPARATOR );
-            cefOutput.append( macroMachine.expandMacros( headerSeverity ) );
-        }
 
         cefOutput.append( CEFAuditFormatter.CEF_EXTENSION_SEPARATOR );
 
-        srcHost.ifPresent( s -> appendCefValue( CEFAuditField.dvchost.name(), s, cefOutput ) );
+        srcHost.ifPresent( s -> appendCefValue( CEFAuditField.dvchost.name(), s, cefOutput, settings ) );
 
-        if ( StringUtil.isEmpty( cefTimezone ) )
+        if ( StringUtil.isEmpty( settings.getCefTimezone() ) )
         {
-            appendCefValue( CEFAuditField.dtz.name(), cefTimezone, cefOutput );
+            appendCefValue( CEFAuditField.dtz.name(), settings.getCefTimezone(), cefOutput, settings );
         }
 
         for ( final CEFAuditField cefAuditField : CEFAuditField.values() )
@@ -158,7 +125,7 @@ public class CEFAuditFormatter implements AuditFormatter
                 if ( value != null )
                 {
                     final String valueString = value.toString();
-                    appendCefValue( auditFieldName, valueString, cefOutput );
+                    appendCefValue( auditFieldName, valueString, cefOutput, settings );
                 }
             }
         }
@@ -172,17 +139,69 @@ public class CEFAuditFormatter implements AuditFormatter
         return cefOutput.toString();
     }
 
-    private static void appendCefValue( final String name, final String value, final StringBuilder cefOutput )
+    private String makeCefHeader( final PwmApplication pwmApplication, final Settings settings, final AuditRecord auditRecord )
+            throws PwmUnrecoverableException
+    {
+        final StringBuilder cefOutput = new StringBuilder(  );
+
+        // cef declaration:version prefix
+        cefOutput.append( "CEF:0" );
+
+        // Device Vendor
+        appendCefHeader( pwmApplication, cefOutput, settings.getHeaderVendor() );
+
+        // Device Product
+        appendCefHeader( pwmApplication, cefOutput, settings.getHeaderProduct() );
+
+        // Device Version
+        appendCefHeader( pwmApplication, cefOutput, PwmConstants.SERVLET_VERSION );
+
+        // Device Event Class ID
+        appendCefHeader( pwmApplication, cefOutput, String.valueOf( auditRecord.getEventCode() ) );
+
+        // field name
+        appendCefHeader( pwmApplication, cefOutput, LocaleHelper.getLocalizedMessage(
+                PwmConstants.DEFAULT_LOCALE,
+                auditRecord.getEventCode().getMessage(),
+                pwmApplication.getConfig()
+        ) );
+
+        // severity
+        appendCefHeader( pwmApplication, cefOutput, settings.getHeaderSeverity() );
+
+        return cefOutput.toString();
+    }
+
+    private void appendCefHeader( final PwmApplication pwmApplication, final StringBuilder cefOutput, final String value )
+            throws PwmUnrecoverableException
+    {
+        final MacroMachine macroMachine = MacroMachine.forNonUserSpecific( pwmApplication, SessionLabel.SYSTEM_LABEL );
+        cefOutput.append( CEFAuditFormatter.CEF_EXTENSION_SEPARATOR );
+        cefOutput.append( macroMachine.expandMacros( value ) );
+    }
+
+    private void appendCefValue( final String name, final String value, final StringBuilder cefOutput, final Settings settings )
     {
         if ( !StringUtil.isEmpty( value ) && !StringUtil.isEmpty( name ) )
         {
+            final String outputValue = trimCEFValue( name, escapeCEFValue( value ), settings );
             cefOutput.append( " " );
             cefOutput.append( name );
             cefOutput.append( "=" );
-            cefOutput.append( escapeCEFValue( value ) );
+            cefOutput.append( outputValue );
         }
     }
 
+    private String trimCEFValue ( final String name, final String value, final Settings settings )
+    {
+        final int cefMaxExtensionChars = settings.getCefMaxExtensionChars();
+        if ( value != null && value.length() > cefMaxExtensionChars )
+        {
+            LOGGER.trace( () -> "truncating cef value for field '" + name + "' from " + value.length() + " to max cef length " + cefMaxExtensionChars );
+        }
+        return StringUtil.truncate( value, cefMaxExtensionChars );
+    }
+
     private static String escapeCEFValue( final String value )
     {
         String replacedValue = value;
@@ -194,4 +213,26 @@ public class CEFAuditFormatter implements AuditFormatter
         }
         return replacedValue;
     }
+
+    @Value
+    @Builder
+    private static class Settings
+    {
+        private int cefMaxExtensionChars;
+        private String cefTimezone;
+        private String headerSeverity;
+        private String headerProduct;
+        private String headerVendor;
+
+        static Settings fromConfiguration( final Configuration configuration )
+        {
+            return Settings.builder()
+                    .cefMaxExtensionChars( JavaHelper.silentParseInt( configuration.readAppProperty( AppProperty.AUDIT_SYSLOG_CEF_MAX_EXTENSION_CHARS ), 1023 ) )
+                    .cefTimezone( configuration.readAppProperty( AppProperty.AUDIT_SYSLOG_CEF_TIMEZONE ) )
+                    .headerSeverity( configuration.readAppProperty( AppProperty.AUDIT_SYSLOG_CEF_HEADER_SEVERITY ) )
+                    .headerProduct( configuration.readAppProperty( AppProperty.AUDIT_SYSLOG_CEF_HEADER_PRODUCT ) )
+                    .headerVendor( configuration.readAppProperty( AppProperty.AUDIT_SYSLOG_CEF_HEADER_VENDOR ) )
+                    .build();
+        }
+    }
 }