diff --git a/dd-java-agent/appsec/src/main/java/com/datadog/appsec/config/AppSecConfigServiceImpl.java b/dd-java-agent/appsec/src/main/java/com/datadog/appsec/config/AppSecConfigServiceImpl.java index 1539000bf88..069733a03fd 100644 --- a/dd-java-agent/appsec/src/main/java/com/datadog/appsec/config/AppSecConfigServiceImpl.java +++ b/dd-java-agent/appsec/src/main/java/com/datadog/appsec/config/AppSecConfigServiceImpl.java @@ -115,9 +115,13 @@ private void subscribeConfigurationPoller() { if (tracerConfig.isAppSecRaspEnabled()) { capabilities |= CAPABILITY_ASM_RASP_SQLI; capabilities |= CAPABILITY_ASM_RASP_SSRF; - capabilities |= CAPABILITY_ASM_RASP_LFI; capabilities |= CAPABILITY_ASM_RASP_CMDI; capabilities |= CAPABILITY_ASM_RASP_SHI; + // RASP LFI is only available in fully enabled mode as it's implemented using callsite + // instrumentation + if (tracerConfig.getAppSecActivation() == ProductActivation.FULLY_ENABLED) { + capabilities |= CAPABILITY_ASM_RASP_LFI; + } } this.configurationPoller.addCapabilities(capabilities); } diff --git a/dd-java-agent/appsec/src/test/groovy/com/datadog/appsec/config/AppSecConfigServiceImplSpecification.groovy b/dd-java-agent/appsec/src/test/groovy/com/datadog/appsec/config/AppSecConfigServiceImplSpecification.groovy index 2978bc27fed..33f07f611b5 100644 --- a/dd-java-agent/appsec/src/test/groovy/com/datadog/appsec/config/AppSecConfigServiceImplSpecification.groovy +++ b/dd-java-agent/appsec/src/test/groovy/com/datadog/appsec/config/AppSecConfigServiceImplSpecification.groovy @@ -202,7 +202,7 @@ class AppSecConfigServiceImplSpecification extends DDSpecification { then: 1 * config.isAppSecRaspEnabled() >> true 1 * config.getAppSecRulesFile() >> null - 1 * config.getAppSecActivation() >> ProductActivation.ENABLED_INACTIVE + 2 * config.getAppSecActivation() >> ProductActivation.ENABLED_INACTIVE 1 * poller.addListener(Product.ASM_FEATURES, _, _) >> { listeners.savedFeaturesDeserializer = it[1] listeners.savedFeaturesListener = it[2] @@ -239,7 +239,7 @@ class AppSecConfigServiceImplSpecification extends DDSpecification { then: 1 * config.isAppSecRaspEnabled() >> true 1 * config.getAppSecRulesFile() >> null - 1 * config.getAppSecActivation() >> ProductActivation.ENABLED_INACTIVE + 2 * config.getAppSecActivation() >> ProductActivation.ENABLED_INACTIVE 1 * poller.addListener(Product.ASM_DD, _, _) >> { listeners.savedConfDeserializer = it[1] listeners.savedConfChangesListener = it[2] @@ -273,7 +273,6 @@ class AppSecConfigServiceImplSpecification extends DDSpecification { | CAPABILITY_ASM_RASP_SSRF | CAPABILITY_ASM_RASP_CMDI | CAPABILITY_ASM_RASP_SHI - | CAPABILITY_ASM_RASP_LFI | CAPABILITY_ENDPOINT_FINGERPRINT | CAPABILITY_ASM_SESSION_FINGERPRINT | CAPABILITY_ASM_NETWORK_FINGERPRINT @@ -393,7 +392,7 @@ class AppSecConfigServiceImplSpecification extends DDSpecification { then: 1 * config.isAppSecRaspEnabled() >> true 1 * config.getAppSecRulesFile() >> null - 1 * config.getAppSecActivation() >> ProductActivation.ENABLED_INACTIVE + 2 * config.getAppSecActivation() >> ProductActivation.ENABLED_INACTIVE 1 * poller.addListener(Product.ASM_DD, _, _) >> { listeners.savedConfDeserializer = it[1] listeners.savedConfChangesListener = it[2] @@ -427,7 +426,6 @@ class AppSecConfigServiceImplSpecification extends DDSpecification { | CAPABILITY_ASM_RASP_SSRF | CAPABILITY_ASM_RASP_CMDI | CAPABILITY_ASM_RASP_SHI - | CAPABILITY_ASM_RASP_LFI | CAPABILITY_ENDPOINT_FINGERPRINT | CAPABILITY_ASM_SESSION_FINGERPRINT | CAPABILITY_ASM_NETWORK_FINGERPRINT @@ -564,6 +562,67 @@ class AppSecConfigServiceImplSpecification extends DDSpecification { autoUserInstrum('yolo') | DISABLED } + void 'RASP capabilities for LFI is not sent when RASP is not fully enabled '() { + AppSecModuleConfigurer.SubconfigListener subconfigListener = Mock() + SavedListeners listeners = new SavedListeners() + Optional initialWafConfig + + when: + AppSecSystem.active = false + appSecConfigService.init() + appSecConfigService.maybeSubscribeConfigPolling() + def configurer = appSecConfigService.createAppSecModuleConfigurer() + initialWafConfig = configurer.addSubConfigListener("waf", subconfigListener) + configurer.commit() + + then: + 1 * config.isAppSecRaspEnabled() >> true + 1 * config.getAppSecRulesFile() >> null + 2 * config.getAppSecActivation() >> ProductActivation.FULLY_ENABLED + 1 * poller.addListener(Product.ASM_DD, _, _) >> { + listeners.savedConfDeserializer = it[1] + listeners.savedConfChangesListener = it[2] + } + 1 * poller.addListener(Product.ASM_DATA, _, _) >> { + listeners.savedWafDataDeserializer = it[1] + listeners.savedWafDataChangesListener = it[2] + } + 1 * poller.addListener(Product.ASM, _, _) >> { + listeners.savedWafRulesOverrideDeserializer = it[1] + listeners.savedWafRulesOverrideListener = it[2] + } + 1 * poller.addListener(Product.ASM_FEATURES, _, _) >> { + listeners.savedFeaturesDeserializer = it[1] + listeners.savedFeaturesListener = it[2] + } + 1 * poller.addConfigurationEndListener(_) >> { listeners.savedConfEndListener = it[0] } + 1 * poller.addCapabilities(CAPABILITY_ASM_API_SECURITY_SAMPLE_RATE) + 1 * poller.addCapabilities(CAPABILITY_ASM_AUTO_USER_INSTRUM_MODE) + 1 * poller.addCapabilities(CAPABILITY_ASM_DD_RULES + | CAPABILITY_ASM_IP_BLOCKING + | CAPABILITY_ASM_EXCLUSIONS + | CAPABILITY_ASM_EXCLUSION_DATA + | CAPABILITY_ASM_REQUEST_BLOCKING + | CAPABILITY_ASM_USER_BLOCKING + | CAPABILITY_ASM_CUSTOM_RULES + | CAPABILITY_ASM_CUSTOM_BLOCKING_RESPONSE + | CAPABILITY_ASM_TRUSTED_IPS + | CAPABILITY_ASM_RASP_SQLI + | CAPABILITY_ASM_RASP_SSRF + | CAPABILITY_ASM_RASP_CMDI + | CAPABILITY_ASM_RASP_SHI + | CAPABILITY_ASM_RASP_LFI + | CAPABILITY_ENDPOINT_FINGERPRINT + | CAPABILITY_ASM_SESSION_FINGERPRINT + | CAPABILITY_ASM_NETWORK_FINGERPRINT + | CAPABILITY_ASM_HEADER_FINGERPRINT) + 0 * _._ + initialWafConfig.get() != null + + cleanup: + AppSecSystem.active = true + } + private static AppSecFeatures autoUserInstrum(String mode) { return new AppSecFeatures().tap { features -> features.autoUserInstrum = new AppSecFeatures.AutoUserInstrum().tap { instrum ->