22
22
23
23
package password .pwm .svc .event ;
24
24
25
+ import lombok .Builder ;
26
+ import lombok .Value ;
25
27
import password .pwm .AppProperty ;
26
28
import password .pwm .PwmApplication ;
27
29
import password .pwm .PwmConstants ;
32
34
import password .pwm .util .java .JavaHelper ;
33
35
import password .pwm .util .java .JsonUtil ;
34
36
import password .pwm .util .java .StringUtil ;
37
+ import password .pwm .util .logging .PwmLogger ;
35
38
import password .pwm .util .macro .MacroMachine ;
36
39
37
40
import java .util .Collections ;
41
44
42
45
public class CEFAuditFormatter implements AuditFormatter
43
46
{
47
+ private static final PwmLogger LOGGER = PwmLogger .forClass ( CEFAuditFormatter .class );
48
+
44
49
private static final String CEF_EXTENSION_SEPARATOR = "|" ;
45
50
private static final Map <String , String > CEF_VALUE_ESCAPES ;
46
51
@@ -91,62 +96,24 @@ public String convertAuditRecordToMessage(
91
96
throws PwmUnrecoverableException
92
97
{
93
98
final Configuration configuration = pwmApplication .getConfig ();
94
- final String cefTimezone = configuration .readAppProperty ( AppProperty .AUDIT_SYSLOG_CEF_TIMEZONE );
95
-
99
+ final Settings settings = Settings .fromConfiguration ( configuration );
96
100
final Map <String , Object > auditRecordMap = JsonUtil .deserializeMap ( JsonUtil .serialize ( auditRecord ) );
97
101
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 );
101
102
final Optional <String > srcHost = JavaHelper .deriveLocalServerHostname ( configuration );
102
103
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
-
111
104
final StringBuilder cefOutput = new StringBuilder ( );
112
105
113
106
// 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 ) );
133
108
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
- }
142
109
143
110
cefOutput .append ( CEFAuditFormatter .CEF_EXTENSION_SEPARATOR );
144
111
145
- srcHost .ifPresent ( s -> appendCefValue ( CEFAuditField .dvchost .name (), s , cefOutput ) );
112
+ srcHost .ifPresent ( s -> appendCefValue ( CEFAuditField .dvchost .name (), s , cefOutput , settings ) );
146
113
147
- if ( StringUtil .isEmpty ( cefTimezone ) )
114
+ if ( StringUtil .isEmpty ( settings . getCefTimezone () ) )
148
115
{
149
- appendCefValue ( CEFAuditField .dtz .name (), cefTimezone , cefOutput );
116
+ appendCefValue ( CEFAuditField .dtz .name (), settings . getCefTimezone () , cefOutput , settings );
150
117
}
151
118
152
119
for ( final CEFAuditField cefAuditField : CEFAuditField .values () )
@@ -158,7 +125,7 @@ public String convertAuditRecordToMessage(
158
125
if ( value != null )
159
126
{
160
127
final String valueString = value .toString ();
161
- appendCefValue ( auditFieldName , valueString , cefOutput );
128
+ appendCefValue ( auditFieldName , valueString , cefOutput , settings );
162
129
}
163
130
}
164
131
}
@@ -172,17 +139,69 @@ public String convertAuditRecordToMessage(
172
139
return cefOutput .toString ();
173
140
}
174
141
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 )
176
184
{
177
185
if ( !StringUtil .isEmpty ( value ) && !StringUtil .isEmpty ( name ) )
178
186
{
187
+ final String outputValue = trimCEFValue ( name , escapeCEFValue ( value ), settings );
179
188
cefOutput .append ( " " );
180
189
cefOutput .append ( name );
181
190
cefOutput .append ( "=" );
182
- cefOutput .append ( escapeCEFValue ( value ) );
191
+ cefOutput .append ( outputValue );
183
192
}
184
193
}
185
194
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
+
186
205
private static String escapeCEFValue ( final String value )
187
206
{
188
207
String replacedValue = value ;
@@ -194,4 +213,26 @@ private static String escapeCEFValue( final String value )
194
213
}
195
214
return replacedValue ;
196
215
}
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
+ }
197
238
}
0 commit comments