5
5
import static datadog .remoteconfig .Capabilities .CAPABILITY_ASM_AUTO_USER_INSTRUM_MODE ;
6
6
import static datadog .remoteconfig .Capabilities .CAPABILITY_ASM_CUSTOM_BLOCKING_RESPONSE ;
7
7
import static datadog .remoteconfig .Capabilities .CAPABILITY_ASM_CUSTOM_RULES ;
8
+ import static datadog .remoteconfig .Capabilities .CAPABILITY_ASM_DD_MULTICONFIG ;
8
9
import static datadog .remoteconfig .Capabilities .CAPABILITY_ASM_DD_RULES ;
9
10
import static datadog .remoteconfig .Capabilities .CAPABILITY_ASM_EXCLUSIONS ;
10
11
import static datadog .remoteconfig .Capabilities .CAPABILITY_ASM_EXCLUSION_DATA ;
18
19
import static datadog .remoteconfig .Capabilities .CAPABILITY_ASM_RASP_SSRF ;
19
20
import static datadog .remoteconfig .Capabilities .CAPABILITY_ASM_REQUEST_BLOCKING ;
20
21
import static datadog .remoteconfig .Capabilities .CAPABILITY_ASM_SESSION_FINGERPRINT ;
22
+ import static datadog .remoteconfig .Capabilities .CAPABILITY_ASM_TRACE_TAGGING_RULES ;
21
23
import static datadog .remoteconfig .Capabilities .CAPABILITY_ASM_TRUSTED_IPS ;
22
24
import static datadog .remoteconfig .Capabilities .CAPABILITY_ASM_USER_BLOCKING ;
23
25
import static datadog .remoteconfig .Capabilities .CAPABILITY_ENDPOINT_FINGERPRINT ;
36
38
import com .datadog .ddwaf .exception .InvalidRuleSetException ;
37
39
import com .datadog .ddwaf .exception .UnclassifiedWafException ;
38
40
import com .squareup .moshi .JsonAdapter ;
39
- import com .squareup .moshi .Moshi ;
40
- import com .squareup .moshi .Types ;
41
+ import com .squareup .moshi .JsonReader ;
42
+ import com .squareup .moshi .JsonWriter ;
41
43
import datadog .remoteconfig .ConfigurationEndListener ;
42
44
import datadog .remoteconfig .ConfigurationPoller ;
43
45
import datadog .remoteconfig .PollingRateHinter ;
58
60
import java .util .Collections ;
59
61
import java .util .HashMap ;
60
62
import java .util .HashSet ;
63
+ import java .util .LinkedHashMap ;
61
64
import java .util .List ;
62
65
import java .util .Map ;
63
66
import java .util .Set ;
@@ -90,15 +93,12 @@ public class AppSecConfigServiceImpl implements AppSecConfigService {
90
93
new WAFInitializationResultReporter ();
91
94
private final WAFStatsReporter statsReporter = new WAFStatsReporter ();
92
95
93
- private static final JsonAdapter <Map <String , Object >> ADAPTER =
94
- new Moshi .Builder ()
95
- .build ()
96
- .adapter (Types .newParameterizedType (Map .class , String .class , Object .class ));
96
+ private static final JsonAdapter <Object > ADAPTER = new SafeMapAdapter ();
97
97
98
98
private boolean hasUserWafConfig ;
99
99
private boolean defaultConfigActivated ;
100
100
private final Set <String > usedDDWafConfigKeys = new HashSet <>();
101
- private final String DEFAULT_WAF_CONFIG_RULE = "DEFAULT_WAF_CONFIG " ;
101
+ private final String DEFAULT_WAF_CONFIG_RULE = "ASM_DD/default " ;
102
102
private String currentRuleVersion ;
103
103
private List <AppSecModule > modulesToUpdateVersionIn ;
104
104
@@ -129,6 +129,7 @@ private void subscribeConfigurationPoller() {
129
129
130
130
long capabilities =
131
131
CAPABILITY_ASM_DD_RULES
132
+ | CAPABILITY_ASM_DD_MULTICONFIG
132
133
| CAPABILITY_ASM_IP_BLOCKING
133
134
| CAPABILITY_ASM_EXCLUSIONS
134
135
| CAPABILITY_ASM_EXCLUSION_DATA
@@ -140,7 +141,8 @@ private void subscribeConfigurationPoller() {
140
141
| CAPABILITY_ENDPOINT_FINGERPRINT
141
142
| CAPABILITY_ASM_SESSION_FINGERPRINT
142
143
| CAPABILITY_ASM_NETWORK_FINGERPRINT
143
- | CAPABILITY_ASM_HEADER_FINGERPRINT ;
144
+ | CAPABILITY_ASM_HEADER_FINGERPRINT
145
+ | CAPABILITY_ASM_TRACE_TAGGING_RULES ;
144
146
if (tracerConfig .isAppSecRaspEnabled ()) {
145
147
capabilities |= CAPABILITY_ASM_RASP_SQLI ;
146
148
capabilities |= CAPABILITY_ASM_RASP_SSRF ;
@@ -185,7 +187,8 @@ public void accept(ConfigKey configKey, byte[] content, PollingRateHinter pollin
185
187
}
186
188
} else {
187
189
Map <String , Object > contentMap =
188
- ADAPTER .fromJson (Okio .buffer (Okio .source (new ByteArrayInputStream (content ))));
190
+ (Map <String , Object >)
191
+ ADAPTER .fromJson (Okio .buffer (Okio .source (new ByteArrayInputStream (content ))));
189
192
try {
190
193
handleWafUpdateResultReport (configKey .toString (), contentMap );
191
194
} catch (AppSecModule .AppSecModuleActivationException e ) {
@@ -211,7 +214,7 @@ private class AppSecConfigChangesDDListener extends AppSecConfigChangesListener
211
214
public void accept (ConfigKey configKey , byte [] content , PollingRateHinter pollingRateHinter )
212
215
throws IOException {
213
216
if (defaultConfigActivated ) { // if we get any config, remove the default one
214
- log .debug ("Removing default config" );
217
+ log .debug ("Removing default config ASM_DD/default " );
215
218
try {
216
219
wafBuilder .removeConfig (DEFAULT_WAF_CONFIG_RULE );
217
220
} catch (UnclassifiedWafException e ) {
@@ -306,7 +309,10 @@ private void subscribeAsmFeatures() {
306
309
private void distributeSubConfigurations (
307
310
String key , AppSecModuleConfigurer .Reconfiguration reconfiguration ) {
308
311
if (usedDDWafConfigKeys .isEmpty () && !defaultConfigActivated && !hasUserWafConfig ) {
309
- // no config left in the WAF builder, add the default config
312
+ // ASM_DD Failure Fallback: If none of the configurations obtained through ASM_DD were loaded
313
+ // successfully,
314
+ // libraries must revert back to the default configuration
315
+ log .debug ("No ASM_DD configurations loaded, falling back to default configuration" );
310
316
init ();
311
317
}
312
318
for (Map .Entry <String , SubconfigListener > entry : subconfigListeners .entrySet ()) {
@@ -427,7 +433,8 @@ private static Map<String, Object> loadDefaultWafConfig() throws IOException {
427
433
throw new IOException ("Resource " + DEFAULT_CONFIG_LOCATION + " not found" );
428
434
}
429
435
430
- Map <String , Object > ret = ADAPTER .fromJson (Okio .buffer (Okio .source (is )));
436
+ Map <String , Object > ret =
437
+ (Map <String , Object >) ADAPTER .fromJson (Okio .buffer (Okio .source (is )));
431
438
432
439
StandardizedLogging ._initialConfigSourceAndLibddwafVersion (log , "<bundled config>" );
433
440
if (log .isInfoEnabled ()) {
@@ -444,7 +451,8 @@ private static Map<String, Object> loadUserWafConfig(Config tracerConfig) throws
444
451
return null ;
445
452
}
446
453
try (InputStream is = new FileInputStream (filename )) {
447
- Map <String , Object > ret = ADAPTER .fromJson (Okio .buffer (Okio .source (is )));
454
+ Map <String , Object > ret =
455
+ (Map <String , Object >) ADAPTER .fromJson (Okio .buffer (Okio .source (is )));
448
456
449
457
StandardizedLogging ._initialConfigSourceAndLibddwafVersion (log , filename );
450
458
if (log .isInfoEnabled ()) {
@@ -473,6 +481,7 @@ public void close() {
473
481
this .configurationPoller .removeCapabilities (
474
482
CAPABILITY_ASM_ACTIVATION
475
483
| CAPABILITY_ASM_DD_RULES
484
+ | CAPABILITY_ASM_DD_MULTICONFIG
476
485
| CAPABILITY_ASM_IP_BLOCKING
477
486
| CAPABILITY_ASM_EXCLUSIONS
478
487
| CAPABILITY_ASM_EXCLUSION_DATA
@@ -490,7 +499,8 @@ public void close() {
490
499
| CAPABILITY_ENDPOINT_FINGERPRINT
491
500
| CAPABILITY_ASM_SESSION_FINGERPRINT
492
501
| CAPABILITY_ASM_NETWORK_FINGERPRINT
493
- | CAPABILITY_ASM_HEADER_FINGERPRINT );
502
+ | CAPABILITY_ASM_HEADER_FINGERPRINT
503
+ | CAPABILITY_ASM_TRACE_TAGGING_RULES );
494
504
this .configurationPoller .removeListeners (Product .ASM_DD );
495
505
this .configurationPoller .removeListeners (Product .ASM_DATA );
496
506
this .configurationPoller .removeListeners (Product .ASM );
@@ -558,4 +568,59 @@ private static WafConfig createWafConfig(Config config) {
558
568
}
559
569
return wafConfig ;
560
570
}
571
+
572
+ private static class SafeMapAdapter extends JsonAdapter <Object > {
573
+ @ Override
574
+ public Object fromJson (JsonReader reader ) throws IOException {
575
+ switch (reader .peek ()) {
576
+ case BEGIN_OBJECT :
577
+ Map <String , Object > map = new LinkedHashMap <>();
578
+ reader .beginObject ();
579
+ while (reader .hasNext ()) {
580
+ map .put (reader .nextName (), fromJson (reader ));
581
+ }
582
+ reader .endObject ();
583
+ return map ;
584
+
585
+ case BEGIN_ARRAY :
586
+ List <Object > list = new ArrayList <>();
587
+ reader .beginArray ();
588
+ while (reader .hasNext ()) {
589
+ list .add (fromJson (reader ));
590
+ }
591
+ reader .endArray ();
592
+ return list ;
593
+
594
+ case STRING :
595
+ return reader .nextString ();
596
+ case NUMBER :
597
+ String numberStr = reader .nextString ();
598
+ try {
599
+ if (numberStr .contains ("." )) {
600
+ return Double .parseDouble (numberStr );
601
+ } else {
602
+ return Long .parseLong (numberStr );
603
+ }
604
+ } catch (NumberFormatException e ) {
605
+ // Fallback to string if parsing fails
606
+ return numberStr ;
607
+ }
608
+
609
+ case BOOLEAN :
610
+ return reader .nextBoolean ();
611
+
612
+ case NULL :
613
+ reader .nextNull ();
614
+ return null ;
615
+
616
+ default :
617
+ throw new IllegalStateException ("Unexpected token: " + reader .peek ());
618
+ }
619
+ }
620
+
621
+ @ Override
622
+ public void toJson (JsonWriter writer , Object value ) throws IOException {
623
+ throw new UnsupportedOperationException ("Serialization not supported" );
624
+ }
625
+ }
561
626
}
0 commit comments