|
@@ -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();
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|