Skip to content

Commit d858d53

Browse files
Only report ASM_DD, ASM_DATA and ASM capabilities when AppSec is enabled (#9260)
Only report ASM_DD, ASM_DATA and ASM capabilities when AppSec is enabled
1 parent 1b40197 commit d858d53

File tree

7 files changed

+270
-224
lines changed

7 files changed

+270
-224
lines changed

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

Lines changed: 74 additions & 31 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;
@@ -99,7 +99,11 @@ public class AppSecConfigServiceImpl implements AppSecConfigService {
9999

100100
private boolean hasUserWafConfig;
101101
private boolean defaultConfigActivated;
102-
private final Set<String> usedDDWafConfigKeys = new HashSet<>();
102+
private final AtomicBoolean subscribedToRulesAndData = new AtomicBoolean();
103+
private final Set<String> usedDDWafConfigKeys =
104+
Collections.newSetFromMap(new ConcurrentHashMap<>());
105+
private final Set<String> ignoredConfigKeys =
106+
Collections.newSetFromMap(new ConcurrentHashMap<>());
103107
private final String DEFAULT_WAF_CONFIG_RULE = "DEFAULT_WAF_CONFIG";
104108
private String currentRuleVersion;
105109
private List<AppSecModule> modulesToUpdateVersionIn;
@@ -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 getRulesAndDataCapabilities() {
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(getRulesAndDataCapabilities());
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(getRulesAndDataCapabilities());
192+
}
164193
}
165194

166195
public void modulesToUpdateVersionIn(List<AppSecModule> modules) {
@@ -175,19 +204,21 @@ private class AppSecConfigChangesListener implements ProductListener {
175204
@Override
176205
public void accept(ConfigKey configKey, byte[] content, PollingRateHinter pollingRateHinter)
177206
throws IOException {
178-
maybeInitializeDefaultConfig();
179-
180207
if (content == null) {
181-
try {
182-
wafBuilder.removeConfig(configKey.toString());
183-
} catch (UnclassifiedWafException e) {
184-
throw new RuntimeException(e);
185-
}
208+
remove(configKey, pollingRateHinter);
209+
return;
210+
}
211+
final String key = configKey.toString();
212+
Map<String, Object> contentMap =
213+
ADAPTER.fromJson(Okio.buffer(Okio.source(new ByteArrayInputStream(content))));
214+
if (contentMap == null || contentMap.isEmpty()) {
215+
ignoredConfigKeys.add(key);
186216
} else {
187-
Map<String, Object> contentMap =
188-
ADAPTER.fromJson(Okio.buffer(Okio.source(new ByteArrayInputStream(content))));
217+
ignoredConfigKeys.remove(key);
189218
try {
190-
handleWafUpdateResultReport(configKey.toString(), contentMap);
219+
beforeApply(key, contentMap);
220+
maybeInitializeDefaultConfig();
221+
handleWafUpdateResultReport(key, contentMap);
191222
} catch (AppSecModule.AppSecModuleActivationException e) {
192223
throw new RuntimeException(e);
193224
}
@@ -197,19 +228,32 @@ public void accept(ConfigKey configKey, byte[] content, PollingRateHinter pollin
197228
@Override
198229
public void remove(ConfigKey configKey, PollingRateHinter pollingRateHinter)
199230
throws IOException {
200-
accept(configKey, null, pollingRateHinter);
231+
final String key = configKey.toString();
232+
if (ignoredConfigKeys.remove(key)) {
233+
return;
234+
}
235+
try {
236+
maybeInitializeDefaultConfig();
237+
wafBuilder.removeConfig(key);
238+
afterRemove(key);
239+
} catch (UnclassifiedWafException e) {
240+
throw new RuntimeException(e);
241+
}
201242
}
202243

203244
@Override
204245
public void commit(PollingRateHinter pollingRateHinter) {
205246
// no action needed
206247
}
248+
249+
protected void beforeApply(final String key, final Map<String, Object> contentMap) {}
250+
251+
protected void afterRemove(final String key) {}
207252
}
208253

209254
private class AppSecConfigChangesDDListener extends AppSecConfigChangesListener {
210255
@Override
211-
public void accept(ConfigKey configKey, byte[] content, PollingRateHinter pollingRateHinter)
212-
throws IOException {
256+
protected void beforeApply(final String key, final Map<String, Object> config) {
213257
if (defaultConfigActivated) { // if we get any config, remove the default one
214258
log.debug("Removing default config");
215259
try {
@@ -219,15 +263,12 @@ public void accept(ConfigKey configKey, byte[] content, PollingRateHinter pollin
219263
}
220264
defaultConfigActivated = false;
221265
}
222-
usedDDWafConfigKeys.add(configKey.toString());
223-
super.accept(configKey, content, pollingRateHinter);
266+
usedDDWafConfigKeys.add(key);
224267
}
225268

226269
@Override
227-
public void remove(ConfigKey configKey, PollingRateHinter pollingRateHinter)
228-
throws IOException {
229-
super.remove(configKey, pollingRateHinter);
230-
usedDDWafConfigKeys.remove(configKey.toString());
270+
protected void afterRemove(final String key) {
271+
usedDDWafConfigKeys.remove(key);
231272
}
232273
}
233274

@@ -282,7 +323,6 @@ private void subscribeAsmFeatures() {
282323
Product.ASM_FEATURES,
283324
AppSecFeaturesDeserializer.INSTANCE,
284325
(configKey, newConfig, hinter) -> {
285-
maybeInitializeDefaultConfig();
286326
if (newConfig == null) {
287327
mergedAsmFeatures.removeConfig(configKey);
288328
} else {
@@ -339,8 +379,6 @@ public void init() {
339379
} else {
340380
hasUserWafConfig = true;
341381
}
342-
this.mergedAsmFeatures.clear();
343-
this.usedDDWafConfigKeys.clear();
344382

345383
if (wafConfig.isEmpty()) {
346384
throw new IllegalStateException("Expected default waf config to be available");
@@ -353,9 +391,12 @@ public void init() {
353391
}
354392

355393
public void maybeSubscribeConfigPolling() {
394+
final ProductActivation appSecActivation = tracerConfig.getAppSecActivation();
395+
if (appSecActivation == ProductActivation.FULLY_DISABLED) {
396+
return; // shouldn't happen but just in case.
397+
}
356398
if (this.configurationPoller != null) {
357-
if (hasUserWafConfig
358-
&& tracerConfig.getAppSecActivation() == ProductActivation.FULLY_ENABLED) {
399+
if (hasUserWafConfig && appSecActivation == ProductActivation.FULLY_ENABLED) {
359400
log.info(
360401
"AppSec will not use remote config because "
361402
+ "there is a custom user configuration and AppSec is explicitly enabled");
@@ -494,6 +535,7 @@ public void close() {
494535
this.configurationPoller.removeListeners(Product.ASM);
495536
this.configurationPoller.removeListeners(Product.ASM_FEATURES);
496537
this.configurationPoller.removeConfigurationEndListener(applyRemoteConfigListener);
538+
this.subscribedToRulesAndData.set(false);
497539
this.configurationPoller.stop();
498540
if (this.wafBuilder != null) {
499541
this.wafBuilder.close();
@@ -526,6 +568,7 @@ private void setAppSecActivation(final AppSecFeatures.Asm asm) {
526568
if (AppSecSystem.isActive() != newState) {
527569
log.info("AppSec {} (runtime)", newState ? "enabled" : "disabled");
528570
AppSecSystem.setActive(newState);
571+
updateRulesAndDataSubscription();
529572
}
530573
}
531574

dd-java-agent/appsec/src/main/java/com/datadog/appsec/ddwaf/WafInitialization.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ private static boolean initWAF() {
1515
try {
1616
boolean simpleLoad = System.getProperty("POWERWAF_SIMPLE_LOAD") != null;
1717
Waf.initialize(simpleLoad);
18-
} catch (Exception e) {
18+
} catch (Throwable e) {
1919
Logger logger = LoggerFactory.getLogger(WafInitialization.class);
2020
logger.warn("Error initializing WAF library", e);
2121
StandardizedLogging.libddwafCannotBeLoaded(logger, getLibc());

0 commit comments

Comments
 (0)