Skip to content

Commit c442de6

Browse files
authored
Opt-out API Security endpoint discovery (#9623)
We were keeping this feature disabled for now because the backend does not support it yet. However, we’re actively working on adding support, and in the meantime, we need to measure the volume of data we’d need to handle once the feature is enabled. As a result, this PR sets the default config flag to true: ConfigDefaults.java#L120 Enabling the feature by default surfaced an issue during test execution: an exception was thrown due to multiple beans of type RequestMappingHandlerMapping being present in the Spring context, which caused a NoUniqueBeanDefinitionException. Error: No qualifying bean of type 'RequestMappingHandlerMapping' available: expected single matching bean but found 2: requestMappingHandlerMapping,controllerEndpointHandlerMapping To resolve this, the instrumentations were updated to: Use getBeansOfType(...) instead of getBean(...) Iterate over all available RequestMappingHandlerMapping beans Collect and merge their handler methods safely. This avoids the error and ensures compatibility with Spring setups that register multiple handler mappings.
1 parent 730565b commit c442de6

File tree

3 files changed

+19
-12
lines changed

3 files changed

+19
-12
lines changed

dd-java-agent/instrumentation/spring/spring-webmvc/spring-webmvc-3.1/src/main/java/datadog/trace/instrumentation/springweb/AppSecDispatcherServletInstrumentation.java

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import datadog.trace.agent.tooling.InstrumenterModule;
1414
import datadog.trace.api.Config;
1515
import datadog.trace.api.telemetry.EndpointCollector;
16+
import java.util.HashMap;
1617
import java.util.Map;
1718
import net.bytebuddy.asm.Advice;
1819
import net.bytebuddy.matcher.ElementMatcher;
@@ -71,13 +72,16 @@ public static class AppSecHandlerMappingAdvice {
7172

7273
@Advice.OnMethodExit(suppress = Throwable.class)
7374
public static void afterRefresh(@Advice.Argument(0) final ApplicationContext springCtx) {
74-
final RequestMappingHandlerMapping handler =
75-
springCtx.getBean(RequestMappingHandlerMapping.class);
76-
if (handler == null) {
75+
final Map<String, RequestMappingHandlerMapping> handlers =
76+
springCtx.getBeansOfType(RequestMappingHandlerMapping.class);
77+
if (handlers == null || handlers.isEmpty()) {
7778
return;
7879
}
79-
final Map<RequestMappingInfo, HandlerMethod> mappings = handler.getHandlerMethods();
80-
if (mappings == null || mappings.isEmpty()) {
80+
final Map<RequestMappingInfo, HandlerMethod> mappings = new HashMap<>();
81+
for (RequestMappingHandlerMapping mapping : handlers.values()) {
82+
mappings.putAll(mapping.getHandlerMethods());
83+
}
84+
if (mappings.isEmpty()) {
8185
return;
8286
}
8387
EndpointCollector.get().supplier(new RequestMappingInfoIterator(mappings));

dd-java-agent/instrumentation/spring/spring-webmvc/spring-webmvc-5.3/src/main/java/datadog/trace/instrumentation/springweb/AppSecDispatcherServletWithPathPatternsInstrumentation.java

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import datadog.trace.agent.tooling.InstrumenterModule;
1313
import datadog.trace.api.Config;
1414
import datadog.trace.api.telemetry.EndpointCollector;
15+
import java.util.HashMap;
1516
import java.util.Map;
1617
import net.bytebuddy.asm.Advice;
1718
import net.bytebuddy.matcher.ElementMatcher;
@@ -66,13 +67,16 @@ public static class AppSecHandlerMappingAdvice {
6667

6768
@Advice.OnMethodExit(suppress = Throwable.class)
6869
public static void afterRefresh(@Advice.Argument(0) final ApplicationContext springCtx) {
69-
final RequestMappingHandlerMapping handler =
70-
springCtx.getBean(RequestMappingHandlerMapping.class);
71-
if (handler == null) {
70+
final Map<String, RequestMappingHandlerMapping> handlers =
71+
springCtx.getBeansOfType(RequestMappingHandlerMapping.class);
72+
if (handlers == null || handlers.isEmpty()) {
7273
return;
7374
}
74-
final Map<RequestMappingInfo, HandlerMethod> mappings = handler.getHandlerMethods();
75-
if (mappings == null || mappings.isEmpty()) {
75+
final Map<RequestMappingInfo, HandlerMethod> mappings = new HashMap<>();
76+
for (RequestMappingHandlerMapping mapping : handlers.values()) {
77+
mappings.putAll(mapping.getHandlerMethods());
78+
}
79+
if (mappings.isEmpty()) {
7680
return;
7781
}
7882
EndpointCollector.get().supplier(new RequestMappingInfoWithPathPatternsIterator(mappings));

dd-trace-api/src/main/java/datadog/trace/api/ConfigDefaults.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,8 +117,7 @@ public final class ConfigDefaults {
117117
static final int DEFAULT_APPSEC_WAF_TIMEOUT = 100000; // 0.1 s
118118
static final boolean DEFAULT_API_SECURITY_ENABLED = true;
119119
static final float DEFAULT_API_SECURITY_SAMPLE_DELAY = 30.0f;
120-
// TODO: change to true once the RFC is approved
121-
static final boolean DEFAULT_API_SECURITY_ENDPOINT_COLLECTION_ENABLED = false;
120+
static final boolean DEFAULT_API_SECURITY_ENDPOINT_COLLECTION_ENABLED = true;
122121
static final int DEFAULT_API_SECURITY_ENDPOINT_COLLECTION_MESSAGE_LIMIT = 300;
123122
static final double DEFAULT_API_SECURITY_DOWNSTREAM_REQUEST_ANALYSIS_SAMPLE_RATE = 0.5D;
124123
static final int DEFAULT_API_SECURITY_MAX_DOWNSTREAM_REQUEST_BODY_ANALYSIS = 1;

0 commit comments

Comments
 (0)