Skip to content

Commit f84294e

Browse files
Only report ASM_DD, ASM_DATA and ASM capabilities when AppSec is enabled
1 parent 05a10a5 commit f84294e

File tree

2 files changed

+135
-199
lines changed

2 files changed

+135
-199
lines changed

dd-java-agent/appsec/src/main/java/com/datadog/appsec/config/AppSecConfigServiceImpl.java

Lines changed: 62 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -60,11 +60,11 @@
6060
import java.util.ArrayList;
6161
import java.util.Collections;
6262
import java.util.HashMap;
63-
import java.util.HashSet;
6463
import java.util.List;
6564
import java.util.Map;
6665
import java.util.Set;
6766
import java.util.concurrent.ConcurrentHashMap;
67+
import java.util.concurrent.atomic.AtomicBoolean;
6868
import okio.Okio;
6969
import org.slf4j.Logger;
7070
import org.slf4j.LoggerFactory;
@@ -97,12 +97,16 @@ public class AppSecConfigServiceImpl implements AppSecConfigService {
9797
.build()
9898
.adapter(Types.newParameterizedType(Map.class, String.class, Object.class));
9999

100-
private boolean hasUserWafConfig;
101-
private boolean defaultConfigActivated;
102-
private final Set<String> usedDDWafConfigKeys = new HashSet<>();
100+
private volatile boolean hasUserWafConfig;
101+
private volatile boolean defaultConfigActivated;
102+
private final AtomicBoolean subscribedToRulesAndData = new AtomicBoolean();
103+
private final Set<String> usedDDWafConfigKeys =
104+
Collections.newSetFromMap(new ConcurrentHashMap<>());
105+
private final Set<String> emptyConfigKeys = Collections.newSetFromMap(new ConcurrentHashMap<>());
103106
private final String DEFAULT_WAF_CONFIG_RULE = "DEFAULT_WAF_CONFIG";
104107
private String currentRuleVersion;
105108
private List<AppSecModule> modulesToUpdateVersionIn;
109+
private long rulesAndDataCapabilities;
106110

107111
public AppSecConfigServiceImpl(
108112
Config tracerConfig,
@@ -122,13 +126,15 @@ private void subscribeConfigurationPoller() {
122126
subscribeAsmFeatures();
123127

124128
if (!hasUserWafConfig) {
125-
subscribeRulesAndData();
129+
updateRulesAndDataSubscription();
126130
} else {
127131
log.debug("Will not subscribe to ASM, ASM_DD and ASM_DATA (AppSec custom rules in use)");
128132
}
129133

130134
this.configurationPoller.addConfigurationEndListener(applyRemoteConfigListener);
135+
}
131136

137+
private long buildRulesAndDataCapabilities() {
132138
long capabilities =
133139
CAPABILITY_ASM_DD_RULES
134140
| CAPABILITY_ASM_IP_BLOCKING
@@ -154,13 +160,36 @@ private void subscribeConfigurationPoller() {
154160
capabilities |= CAPABILITY_ASM_RASP_LFI;
155161
}
156162
}
157-
this.configurationPoller.addCapabilities(capabilities);
163+
return capabilities;
164+
}
165+
166+
private void updateRulesAndDataSubscription() {
167+
if (hasUserWafConfig) {
168+
return; // do nothing if the customer has custom rules
169+
}
170+
if (AppSecSystem.isActive()) {
171+
subscribeRulesAndData();
172+
} else {
173+
unsubscribeRulesAndData();
174+
}
158175
}
159176

160177
private void subscribeRulesAndData() {
161-
this.configurationPoller.addListener(Product.ASM_DD, new AppSecConfigChangesDDListener());
162-
this.configurationPoller.addListener(Product.ASM_DATA, new AppSecConfigChangesListener());
163-
this.configurationPoller.addListener(Product.ASM, new AppSecConfigChangesListener());
178+
if (subscribedToRulesAndData.compareAndSet(false, true)) {
179+
this.configurationPoller.addListener(Product.ASM_DD, new AppSecConfigChangesDDListener());
180+
this.configurationPoller.addListener(Product.ASM_DATA, new AppSecConfigChangesListener());
181+
this.configurationPoller.addListener(Product.ASM, new AppSecConfigChangesListener());
182+
this.configurationPoller.addCapabilities(rulesAndDataCapabilities);
183+
}
184+
}
185+
186+
private void unsubscribeRulesAndData() {
187+
if (subscribedToRulesAndData.compareAndSet(true, false)) {
188+
this.configurationPoller.removeListeners(Product.ASM_DD);
189+
this.configurationPoller.removeListeners(Product.ASM_DATA);
190+
this.configurationPoller.removeListeners(Product.ASM);
191+
this.configurationPoller.removeCapabilities(rulesAndDataCapabilities);
192+
}
164193
}
165194

166195
public void modulesToUpdateVersionIn(List<AppSecModule> modules) {
@@ -176,20 +205,26 @@ private class AppSecConfigChangesListener implements ProductListener {
176205
public void accept(ConfigKey configKey, byte[] content, PollingRateHinter pollingRateHinter)
177206
throws IOException {
178207
maybeInitializeDefaultConfig();
179-
208+
final String key = configKey.toString();
180209
if (content == null) {
181-
try {
182-
wafBuilder.removeConfig(configKey.toString());
183-
} catch (UnclassifiedWafException e) {
184-
throw new RuntimeException(e);
210+
if (!emptyConfigKeys.remove(key)) {
211+
try {
212+
wafBuilder.removeConfig(key);
213+
} catch (UnclassifiedWafException e) {
214+
throw new RuntimeException(e);
215+
}
185216
}
186217
} else {
187218
Map<String, Object> contentMap =
188219
ADAPTER.fromJson(Okio.buffer(Okio.source(new ByteArrayInputStream(content))));
189-
try {
190-
handleWafUpdateResultReport(configKey.toString(), contentMap);
191-
} catch (AppSecModule.AppSecModuleActivationException e) {
192-
throw new RuntimeException(e);
220+
if (contentMap == null || contentMap.isEmpty()) {
221+
emptyConfigKeys.add(key);
222+
} else {
223+
try {
224+
handleWafUpdateResultReport(key, contentMap);
225+
} catch (AppSecModule.AppSecModuleActivationException e) {
226+
throw new RuntimeException(e);
227+
}
193228
}
194229
}
195230
}
@@ -282,7 +317,6 @@ private void subscribeAsmFeatures() {
282317
Product.ASM_FEATURES,
283318
AppSecFeaturesDeserializer.INSTANCE,
284319
(configKey, newConfig, hinter) -> {
285-
maybeInitializeDefaultConfig();
286320
if (newConfig == null) {
287321
mergedAsmFeatures.removeConfig(configKey);
288322
} else {
@@ -341,6 +375,8 @@ public void init() {
341375
}
342376
this.mergedAsmFeatures.clear();
343377
this.usedDDWafConfigKeys.clear();
378+
this.emptyConfigKeys.clear();
379+
this.rulesAndDataCapabilities = buildRulesAndDataCapabilities();
344380

345381
if (wafConfig.isEmpty()) {
346382
throw new IllegalStateException("Expected default waf config to be available");
@@ -353,9 +389,12 @@ public void init() {
353389
}
354390

355391
public void maybeSubscribeConfigPolling() {
392+
final ProductActivation appSecActivation = tracerConfig.getAppSecActivation();
393+
if (appSecActivation == ProductActivation.FULLY_DISABLED) {
394+
return; // shouldn't happen but just in case.
395+
}
356396
if (this.configurationPoller != null) {
357-
if (hasUserWafConfig
358-
&& tracerConfig.getAppSecActivation() == ProductActivation.FULLY_ENABLED) {
397+
if (hasUserWafConfig && appSecActivation == ProductActivation.FULLY_ENABLED) {
359398
log.info(
360399
"AppSec will not use remote config because "
361400
+ "there is a custom user configuration and AppSec is explicitly enabled");
@@ -494,6 +533,7 @@ public void close() {
494533
this.configurationPoller.removeListeners(Product.ASM);
495534
this.configurationPoller.removeListeners(Product.ASM_FEATURES);
496535
this.configurationPoller.removeConfigurationEndListener(applyRemoteConfigListener);
536+
this.subscribedToRulesAndData.set(false);
497537
this.configurationPoller.stop();
498538
if (this.wafBuilder != null) {
499539
this.wafBuilder.close();
@@ -526,6 +566,7 @@ private void setAppSecActivation(final AppSecFeatures.Asm asm) {
526566
if (AppSecSystem.isActive() != newState) {
527567
log.info("AppSec {} (runtime)", newState ? "enabled" : "disabled");
528568
AppSecSystem.setActive(newState);
569+
updateRulesAndDataSubscription();
529570
}
530571
}
531572

0 commit comments

Comments
 (0)