Skip to content

Commit f2cc3b0

Browse files
committed
cef extension length limits
1 parent e503852 commit f2cc3b0

File tree

1 file changed

+87
-46
lines changed

1 file changed

+87
-46
lines changed

server/src/main/java/password/pwm/svc/event/CEFAuditFormatter.java

Lines changed: 87 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222

2323
package password.pwm.svc.event;
2424

25+
import lombok.Builder;
26+
import lombok.Value;
2527
import password.pwm.AppProperty;
2628
import password.pwm.PwmApplication;
2729
import password.pwm.PwmConstants;
@@ -32,6 +34,7 @@
3234
import password.pwm.util.java.JavaHelper;
3335
import password.pwm.util.java.JsonUtil;
3436
import password.pwm.util.java.StringUtil;
37+
import password.pwm.util.logging.PwmLogger;
3538
import password.pwm.util.macro.MacroMachine;
3639

3740
import java.util.Collections;
@@ -41,6 +44,8 @@
4144

4245
public class CEFAuditFormatter implements AuditFormatter
4346
{
47+
private static final PwmLogger LOGGER = PwmLogger.forClass( CEFAuditFormatter.class );
48+
4449
private static final String CEF_EXTENSION_SEPARATOR = "|";
4550
private static final Map<String, String> CEF_VALUE_ESCAPES;
4651

@@ -91,62 +96,24 @@ public String convertAuditRecordToMessage(
9196
throws PwmUnrecoverableException
9297
{
9398
final Configuration configuration = pwmApplication.getConfig();
94-
final String cefTimezone = configuration.readAppProperty( AppProperty.AUDIT_SYSLOG_CEF_TIMEZONE );
95-
99+
final Settings settings = Settings.fromConfiguration( configuration );
96100
final Map<String, Object> auditRecordMap = JsonUtil.deserializeMap( JsonUtil.serialize( auditRecord ) );
97101

98-
final String headerSeverity = configuration.readAppProperty( AppProperty.AUDIT_SYSLOG_CEF_HEADER_SEVERITY );
99-
final String headerProduct = configuration.readAppProperty( AppProperty.AUDIT_SYSLOG_CEF_HEADER_PRODUCT );
100-
final String headerVendor = configuration.readAppProperty( AppProperty.AUDIT_SYSLOG_CEF_HEADER_VENDOR );
101102
final Optional<String> srcHost = JavaHelper.deriveLocalServerHostname( configuration );
102103

103-
final MacroMachine macroMachine = MacroMachine.forNonUserSpecific( pwmApplication, SessionLabel.SYSTEM_LABEL );
104-
105-
final String cefFieldName = LocaleHelper.getLocalizedMessage(
106-
PwmConstants.DEFAULT_LOCALE,
107-
auditRecord.getEventCode().getMessage(),
108-
configuration
109-
);
110-
111104
final StringBuilder cefOutput = new StringBuilder( );
112105

113106
// cef header
114-
{
115-
// cef declaration:version prefix
116-
cefOutput.append( "CEF:0" );
117-
118-
// Device Vendor
119-
cefOutput.append( CEFAuditFormatter.CEF_EXTENSION_SEPARATOR );
120-
cefOutput.append( macroMachine.expandMacros( headerVendor ) );
121-
122-
// Device Product
123-
cefOutput.append( CEFAuditFormatter.CEF_EXTENSION_SEPARATOR );
124-
cefOutput.append( macroMachine.expandMacros( headerProduct ) );
125-
126-
// Device Version
127-
cefOutput.append( CEFAuditFormatter.CEF_EXTENSION_SEPARATOR );
128-
cefOutput.append( PwmConstants.SERVLET_VERSION );
129-
130-
// Device Event Class ID
131-
cefOutput.append( CEFAuditFormatter.CEF_EXTENSION_SEPARATOR );
132-
cefOutput.append( auditRecord.getEventCode() );
107+
cefOutput.append( makeCefHeader( pwmApplication, settings, auditRecord ) );
133108

134-
// field name
135-
cefOutput.append( CEFAuditFormatter.CEF_EXTENSION_SEPARATOR );
136-
cefOutput.append( cefFieldName );
137-
138-
// severity
139-
cefOutput.append( CEFAuditFormatter.CEF_EXTENSION_SEPARATOR );
140-
cefOutput.append( macroMachine.expandMacros( headerSeverity ) );
141-
}
142109

143110
cefOutput.append( CEFAuditFormatter.CEF_EXTENSION_SEPARATOR );
144111

145-
srcHost.ifPresent( s -> appendCefValue( CEFAuditField.dvchost.name(), s, cefOutput ) );
112+
srcHost.ifPresent( s -> appendCefValue( CEFAuditField.dvchost.name(), s, cefOutput, settings ) );
146113

147-
if ( StringUtil.isEmpty( cefTimezone ) )
114+
if ( StringUtil.isEmpty( settings.getCefTimezone() ) )
148115
{
149-
appendCefValue( CEFAuditField.dtz.name(), cefTimezone, cefOutput );
116+
appendCefValue( CEFAuditField.dtz.name(), settings.getCefTimezone(), cefOutput, settings );
150117
}
151118

152119
for ( final CEFAuditField cefAuditField : CEFAuditField.values() )
@@ -158,7 +125,7 @@ public String convertAuditRecordToMessage(
158125
if ( value != null )
159126
{
160127
final String valueString = value.toString();
161-
appendCefValue( auditFieldName, valueString, cefOutput );
128+
appendCefValue( auditFieldName, valueString, cefOutput, settings );
162129
}
163130
}
164131
}
@@ -172,17 +139,69 @@ public String convertAuditRecordToMessage(
172139
return cefOutput.toString();
173140
}
174141

175-
private static void appendCefValue( final String name, final String value, final StringBuilder cefOutput )
142+
private String makeCefHeader( final PwmApplication pwmApplication, final Settings settings, final AuditRecord auditRecord )
143+
throws PwmUnrecoverableException
144+
{
145+
final StringBuilder cefOutput = new StringBuilder( );
146+
147+
// cef declaration:version prefix
148+
cefOutput.append( "CEF:0" );
149+
150+
// Device Vendor
151+
appendCefHeader( pwmApplication, cefOutput, settings.getHeaderVendor() );
152+
153+
// Device Product
154+
appendCefHeader( pwmApplication, cefOutput, settings.getHeaderProduct() );
155+
156+
// Device Version
157+
appendCefHeader( pwmApplication, cefOutput, PwmConstants.SERVLET_VERSION );
158+
159+
// Device Event Class ID
160+
appendCefHeader( pwmApplication, cefOutput, String.valueOf( auditRecord.getEventCode() ) );
161+
162+
// field name
163+
appendCefHeader( pwmApplication, cefOutput, LocaleHelper.getLocalizedMessage(
164+
PwmConstants.DEFAULT_LOCALE,
165+
auditRecord.getEventCode().getMessage(),
166+
pwmApplication.getConfig()
167+
) );
168+
169+
// severity
170+
appendCefHeader( pwmApplication, cefOutput, settings.getHeaderSeverity() );
171+
172+
return cefOutput.toString();
173+
}
174+
175+
private void appendCefHeader( final PwmApplication pwmApplication, final StringBuilder cefOutput, final String value )
176+
throws PwmUnrecoverableException
177+
{
178+
final MacroMachine macroMachine = MacroMachine.forNonUserSpecific( pwmApplication, SessionLabel.SYSTEM_LABEL );
179+
cefOutput.append( CEFAuditFormatter.CEF_EXTENSION_SEPARATOR );
180+
cefOutput.append( macroMachine.expandMacros( value ) );
181+
}
182+
183+
private void appendCefValue( final String name, final String value, final StringBuilder cefOutput, final Settings settings )
176184
{
177185
if ( !StringUtil.isEmpty( value ) && !StringUtil.isEmpty( name ) )
178186
{
187+
final String outputValue = trimCEFValue( name, escapeCEFValue( value ), settings );
179188
cefOutput.append( " " );
180189
cefOutput.append( name );
181190
cefOutput.append( "=" );
182-
cefOutput.append( escapeCEFValue( value ) );
191+
cefOutput.append( outputValue );
183192
}
184193
}
185194

195+
private String trimCEFValue ( final String name, final String value, final Settings settings )
196+
{
197+
final int cefMaxExtensionChars = settings.getCefMaxExtensionChars();
198+
if ( value != null && value.length() > cefMaxExtensionChars )
199+
{
200+
LOGGER.trace( () -> "truncating cef value for field '" + name + "' from " + value.length() + " to max cef length " + cefMaxExtensionChars );
201+
}
202+
return StringUtil.truncate( value, cefMaxExtensionChars );
203+
}
204+
186205
private static String escapeCEFValue( final String value )
187206
{
188207
String replacedValue = value;
@@ -194,4 +213,26 @@ private static String escapeCEFValue( final String value )
194213
}
195214
return replacedValue;
196215
}
216+
217+
@Value
218+
@Builder
219+
private static class Settings
220+
{
221+
private int cefMaxExtensionChars;
222+
private String cefTimezone;
223+
private String headerSeverity;
224+
private String headerProduct;
225+
private String headerVendor;
226+
227+
static Settings fromConfiguration( final Configuration configuration )
228+
{
229+
return Settings.builder()
230+
.cefMaxExtensionChars( JavaHelper.silentParseInt( configuration.readAppProperty( AppProperty.AUDIT_SYSLOG_CEF_MAX_EXTENSION_CHARS ), 1023 ) )
231+
.cefTimezone( configuration.readAppProperty( AppProperty.AUDIT_SYSLOG_CEF_TIMEZONE ) )
232+
.headerSeverity( configuration.readAppProperty( AppProperty.AUDIT_SYSLOG_CEF_HEADER_SEVERITY ) )
233+
.headerProduct( configuration.readAppProperty( AppProperty.AUDIT_SYSLOG_CEF_HEADER_PRODUCT ) )
234+
.headerVendor( configuration.readAppProperty( AppProperty.AUDIT_SYSLOG_CEF_HEADER_VENDOR ) )
235+
.build();
236+
}
237+
}
197238
}

0 commit comments

Comments
 (0)