diff --git a/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/blocking/BlockingActionHelper.java b/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/blocking/BlockingActionHelper.java
index fbcb1062eb1..056d8381b26 100644
--- a/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/blocking/BlockingActionHelper.java
+++ b/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/blocking/BlockingActionHelper.java
@@ -118,12 +118,26 @@ public static TemplateType determineTemplateType(
}
public static byte[] getTemplate(TemplateType type) {
+ return getTemplate(type, null);
+ }
+
+ public static byte[] getTemplate(TemplateType type, String securityResponseId) {
+ byte[] template;
if (type == TemplateType.JSON) {
- return TEMPLATE_JSON;
+ template = TEMPLATE_JSON;
} else if (type == TemplateType.HTML) {
- return TEMPLATE_HTML;
+ template = TEMPLATE_HTML;
+ } else {
+ return null;
}
- return null;
+
+ // Use empty string when securityResponseId is not present
+ String replacementValue =
+ (securityResponseId == null || securityResponseId.isEmpty()) ? "" : securityResponseId;
+
+ String templateString = new String(template, java.nio.charset.StandardCharsets.UTF_8);
+ String replacedTemplate = templateString.replace("[security_response_id]", replacementValue);
+ return replacedTemplate.getBytes(java.nio.charset.StandardCharsets.UTF_8);
}
public static String getContentType(TemplateType type) {
diff --git a/dd-java-agent/agent-bootstrap/src/main/resources/datadog/trace/bootstrap/blocking/template.html b/dd-java-agent/agent-bootstrap/src/main/resources/datadog/trace/bootstrap/blocking/template.html
index b43edd96dd5..1c3bf791a6b 100644
--- a/dd-java-agent/agent-bootstrap/src/main/resources/datadog/trace/bootstrap/blocking/template.html
+++ b/dd-java-agent/agent-bootstrap/src/main/resources/datadog/trace/bootstrap/blocking/template.html
@@ -1 +1 @@
-
You've been blockedSorry, you cannot access this page. Please contact the customer service team.
\ No newline at end of file
+You've been blockedSorry, you cannot access this page. Please contact the customer service team.
Security Response ID: [security_response_id]
diff --git a/dd-java-agent/agent-bootstrap/src/main/resources/datadog/trace/bootstrap/blocking/template.json b/dd-java-agent/agent-bootstrap/src/main/resources/datadog/trace/bootstrap/blocking/template.json
index 885d766c18f..8e8a49e6a81 100644
--- a/dd-java-agent/agent-bootstrap/src/main/resources/datadog/trace/bootstrap/blocking/template.json
+++ b/dd-java-agent/agent-bootstrap/src/main/resources/datadog/trace/bootstrap/blocking/template.json
@@ -1 +1 @@
-{"errors":[{"title":"You've been blocked","detail":"Sorry, you cannot access this page. Please contact the customer service team. Security provided by Datadog."}]}
+{"errors":[{"title":"You've been blocked","detail":"Sorry, you cannot access this page. Please contact the customer service team. Security provided by Datadog."}],"security_response_id":"[security_response_id]"}
diff --git a/dd-java-agent/agent-bootstrap/src/test/groovy/datadog/trace/bootstrap/blocking/BlockingActionHelperSpecification.groovy b/dd-java-agent/agent-bootstrap/src/test/groovy/datadog/trace/bootstrap/blocking/BlockingActionHelperSpecification.groovy
index 25cea31e886..d80313fd3f0 100644
--- a/dd-java-agent/agent-bootstrap/src/test/groovy/datadog/trace/bootstrap/blocking/BlockingActionHelperSpecification.groovy
+++ b/dd-java-agent/agent-bootstrap/src/test/groovy/datadog/trace/bootstrap/blocking/BlockingActionHelperSpecification.groovy
@@ -167,4 +167,112 @@ class BlockingActionHelperSpecification extends DDSpecification {
BlockingActionHelper.reset(Config.get())
tempDir.deleteDir()
}
+
+
+ void 'getTemplate with security_response_id replaces placeholder in HTML template'() {
+ given:
+ def securityResponseId = '12345678-1234-1234-1234-123456789abc'
+
+ when:
+ def template = BlockingActionHelper.getTemplate(HTML, securityResponseId)
+ def templateStr = new String(template, StandardCharsets.UTF_8)
+
+ then:
+ templateStr.contains("Security Response ID: ${securityResponseId}")
+ !templateStr.contains('[security_response_id]')
+ }
+
+ void 'getTemplate with security_response_id replaces placeholder in JSON template'() {
+ given:
+ def securityResponseId = '12345678-1234-1234-1234-123456789abc'
+
+ when:
+ def template = BlockingActionHelper.getTemplate(JSON, securityResponseId)
+ def templateStr = new String(template, StandardCharsets.UTF_8)
+
+ then:
+ templateStr.contains("\"security_response_id\":\"${securityResponseId}\"")
+ !templateStr.contains('[security_response_id]')
+ }
+
+ void 'getTemplate without security_response_id uses empty string in HTML template'() {
+ when:
+ def template = BlockingActionHelper.getTemplate(HTML, null)
+ def templateStr = new String(template, StandardCharsets.UTF_8)
+
+ then:
+ !templateStr.contains('[security_response_id]')
+ templateStr.contains('Security Response ID:')
+ // The placeholder is replaced with empty string
+ }
+
+ void 'getTemplate without security_response_id uses empty string in JSON template'() {
+ when:
+ def template = BlockingActionHelper.getTemplate(JSON, null)
+ def templateStr = new String(template, StandardCharsets.UTF_8)
+
+ then:
+ !templateStr.contains('[security_response_id]')
+ templateStr.contains('"security_response_id"')
+ templateStr.contains('""') // Empty string value
+ }
+
+ void 'getTemplate with empty security_response_id uses empty string'() {
+ when:
+ def htmlTemplate = BlockingActionHelper.getTemplate(HTML, '')
+ def jsonTemplate = BlockingActionHelper.getTemplate(JSON, '')
+
+ then:
+ !new String(htmlTemplate, StandardCharsets.UTF_8).contains('[security_response_id]')
+ !new String(jsonTemplate, StandardCharsets.UTF_8).contains('[security_response_id]')
+ // Both templates have placeholders replaced with empty string
+ }
+
+ void 'getTemplate with security_response_id works with custom HTML template'() {
+ setup:
+ File tempDir = File.createTempDir('testTempDir-', '')
+ Config config = Mock(Config)
+ File tempFile = new File(tempDir, 'template.html')
+ tempFile << 'Custom template with security_response_id: [security_response_id]'
+ def securityResponseId = 'test-block-id-123'
+
+ when:
+ BlockingActionHelper.reset(config)
+ def template = BlockingActionHelper.getTemplate(HTML, securityResponseId)
+ def templateStr = new String(template, StandardCharsets.UTF_8)
+
+ then:
+ 1 * config.getAppSecHttpBlockedTemplateHtml() >> tempFile.toString()
+ 1 * config.getAppSecHttpBlockedTemplateJson() >> null
+ templateStr.contains("Custom template with security_response_id: ${securityResponseId}")
+ !templateStr.contains('[security_response_id]')
+
+ cleanup:
+ BlockingActionHelper.reset(Config.get())
+ tempDir.deleteDir()
+ }
+
+ void 'getTemplate with security_response_id works with custom JSON template'() {
+ setup:
+ File tempDir = File.createTempDir('testTempDir-', '')
+ Config config = Mock(Config)
+ File tempFile = new File(tempDir, 'template.json')
+ tempFile << '{"error":"blocked","id":"[security_response_id]"}'
+ def securityResponseId = 'test-block-id-456'
+
+ when:
+ BlockingActionHelper.reset(config)
+ def template = BlockingActionHelper.getTemplate(JSON, securityResponseId)
+ def templateStr = new String(template, StandardCharsets.UTF_8)
+
+ then:
+ 1 * config.getAppSecHttpBlockedTemplateHtml() >> null
+ 1 * config.getAppSecHttpBlockedTemplateJson() >> tempFile.toString()
+ templateStr.contains("\"error\":\"blocked\",\"id\":\"${securityResponseId}\"")
+ !templateStr.contains('[security_response_id]')
+
+ cleanup:
+ BlockingActionHelper.reset(Config.get())
+ tempDir.deleteDir()
+ }
}
diff --git a/dd-java-agent/appsec/build.gradle b/dd-java-agent/appsec/build.gradle
index 559ae10eebe..a9bb2b1b001 100644
--- a/dd-java-agent/appsec/build.gradle
+++ b/dd-java-agent/appsec/build.gradle
@@ -15,7 +15,7 @@ dependencies {
implementation project(':internal-api')
implementation project(':communication')
implementation project(':telemetry')
- implementation group: 'io.sqreen', name: 'libsqreen', version: '17.2.0'
+ implementation group: 'io.sqreen', name: 'libsqreen', version: '17.3.0'
implementation libs.moshi
testImplementation libs.bytebuddy
diff --git a/dd-java-agent/appsec/src/main/java/com/datadog/appsec/blocking/BlockingServiceImpl.java b/dd-java-agent/appsec/src/main/java/com/datadog/appsec/blocking/BlockingServiceImpl.java
index ea67812ecbd..827e436b6c8 100644
--- a/dd-java-agent/appsec/src/main/java/com/datadog/appsec/blocking/BlockingServiceImpl.java
+++ b/dd-java-agent/appsec/src/main/java/com/datadog/appsec/blocking/BlockingServiceImpl.java
@@ -89,7 +89,7 @@ public boolean tryCommitBlockingResponse(
log.debug("About to call block response function: {}", blockResponseFunction);
boolean res =
blockResponseFunction.tryCommitBlockingResponse(
- reqCtx.getTraceSegment(), statusCode, templateType, extraHeaders);
+ reqCtx.getTraceSegment(), statusCode, templateType, extraHeaders, null);
if (res) {
TraceSegment traceSegment = reqCtx.getTraceSegment();
if (traceSegment != null) {
diff --git a/dd-java-agent/appsec/src/main/java/com/datadog/appsec/ddwaf/WAFModule.java b/dd-java-agent/appsec/src/main/java/com/datadog/appsec/ddwaf/WAFModule.java
index e00ddecc9a3..63d3f69fdd0 100644
--- a/dd-java-agent/appsec/src/main/java/com/datadog/appsec/ddwaf/WAFModule.java
+++ b/dd-java-agent/appsec/src/main/java/com/datadog/appsec/ddwaf/WAFModule.java
@@ -363,6 +363,7 @@ public void onDataAvailable(
WafMetricCollector.get().raspRuleMatch(gwCtx.raspRuleType);
}
+ String securityResponseId = null;
for (Map.Entry> action : resultWithData.actions.entrySet()) {
String actionType = action.getKey();
Map actionParams = action.getValue();
@@ -370,12 +371,16 @@ public void onDataAvailable(
ActionInfo actionInfo = new ActionInfo(actionType, actionParams);
if ("block_request".equals(actionInfo.type)) {
+ // Extract security_response_id from action parameters for use in triggers
+ securityResponseId = (String) actionInfo.parameters.get("security_response_id");
Flow.Action.RequestBlockingAction rba =
- createBlockRequestAction(actionInfo, reqCtx, gwCtx.isRasp);
+ createBlockRequestAction(actionInfo, reqCtx, gwCtx.isRasp, securityResponseId);
flow.setAction(rba);
} else if ("redirect_request".equals(actionInfo.type)) {
+ // Extract security_response_id from action parameters for use in triggers
+ securityResponseId = (String) actionInfo.parameters.get("security_response_id");
Flow.Action.RequestBlockingAction rba =
- createRedirectRequestAction(actionInfo, reqCtx, gwCtx.isRasp);
+ createRedirectRequestAction(actionInfo, reqCtx, gwCtx.isRasp, securityResponseId);
flow.setAction(rba);
} else if ("generate_stack".equals(actionInfo.type)) {
if (Config.get().isAppSecStackTraceEnabled()) {
@@ -412,7 +417,7 @@ public void onDataAvailable(
}
}
}
- Collection events = buildEvents(resultWithData);
+ Collection events = buildEvents(resultWithData, securityResponseId);
boolean isThrottled = reqCtx.isThrottled(rateLimiter);
if (!isThrottled) {
@@ -459,7 +464,10 @@ public void onDataAvailable(
}
private Flow.Action.RequestBlockingAction createBlockRequestAction(
- final ActionInfo actionInfo, final AppSecRequestContext reqCtx, final boolean isRasp) {
+ final ActionInfo actionInfo,
+ final AppSecRequestContext reqCtx,
+ final boolean isRasp,
+ final String securityResponseId) {
try {
int statusCode;
Object statusCodeObj = actionInfo.parameters.get("status_code");
@@ -477,7 +485,8 @@ private Flow.Action.RequestBlockingAction createBlockRequestAction(
} catch (IllegalArgumentException iae) {
log.warn("Unknown content type: {}; using auto", contentType);
}
- return new Flow.Action.RequestBlockingAction(statusCode, blockingContentType);
+ return new Flow.Action.RequestBlockingAction(
+ statusCode, blockingContentType, Collections.emptyMap(), securityResponseId);
} catch (RuntimeException cce) {
log.warn("Invalid blocking action data", cce);
if (!isRasp) {
@@ -488,7 +497,10 @@ private Flow.Action.RequestBlockingAction createBlockRequestAction(
}
private Flow.Action.RequestBlockingAction createRedirectRequestAction(
- final ActionInfo actionInfo, final AppSecRequestContext reqCtx, final boolean isRasp) {
+ final ActionInfo actionInfo,
+ final AppSecRequestContext reqCtx,
+ final boolean isRasp,
+ final String securityResponseId) {
try {
int statusCode;
Object statusCodeObj = actionInfo.parameters.get("status_code");
@@ -506,6 +518,15 @@ private Flow.Action.RequestBlockingAction createRedirectRequestAction(
if (location == null) {
throw new RuntimeException("redirect_request action has no location");
}
+ if (securityResponseId != null && !securityResponseId.isEmpty()) {
+ // For custom redirects, only replace [security_response_id] placeholder if present in the
+ // URL.
+ // The client decides whether to include security_response_id by adding the placeholder.
+ // We don't automatically append security_response_id as a URL parameter.
+ if (location.contains("[security_response_id]")) {
+ location = location.replace("[security_response_id]", securityResponseId);
+ }
+ }
return Flow.Action.RequestBlockingAction.forRedirect(statusCode, location);
} catch (RuntimeException cce) {
log.warn("Invalid blocking action data", cce);
@@ -572,7 +593,8 @@ private Waf.ResultWithData runWafTransient(
new DataBundleMapWrapper(ctxAndAddr.addressesOfInterest, newData), LIMITS, metrics);
}
- private Collection buildEvents(Waf.ResultWithData actionWithData) {
+ private Collection buildEvents(
+ Waf.ResultWithData actionWithData, String securityResponseId) {
if (actionWithData.data == null) {
log.debug(SEND_TELEMETRY, "WAF result data is null");
return Collections.emptyList();
@@ -590,14 +612,14 @@ private Collection buildEvents(Waf.ResultWithData actionWithData) {
if (listResults != null && !listResults.isEmpty()) {
return listResults.stream()
- .map(this::buildEvent)
+ .map(wafResult -> buildEvent(wafResult, securityResponseId))
.filter(Objects::nonNull)
.collect(Collectors.toList());
}
return emptyList();
}
- private AppSecEvent buildEvent(WAFResultData wafResult) {
+ private AppSecEvent buildEvent(WAFResultData wafResult, String securityResponseId) {
if (wafResult == null || wafResult.rule == null || wafResult.rule_matches == null) {
log.warn("WAF result is empty: {}", wafResult);
@@ -615,6 +637,7 @@ private AppSecEvent buildEvent(WAFResultData wafResult) {
.withRuleMatches(wafResult.rule_matches)
.withSpanId(spanId)
.withStackId(wafResult.stack_id)
+ .withSecurityResponseId(securityResponseId)
.build();
}
diff --git a/dd-java-agent/appsec/src/main/java/com/datadog/appsec/report/AppSecEvent.java b/dd-java-agent/appsec/src/main/java/com/datadog/appsec/report/AppSecEvent.java
index 9c68aff77ad..51e36d2d191 100644
--- a/dd-java-agent/appsec/src/main/java/com/datadog/appsec/report/AppSecEvent.java
+++ b/dd-java-agent/appsec/src/main/java/com/datadog/appsec/report/AppSecEvent.java
@@ -21,6 +21,9 @@ public class AppSecEvent {
@com.squareup.moshi.Json(name = "stack_id")
private String stackId;
+ @com.squareup.moshi.Json(name = "security_response_id")
+ private String securityResponseId;
+
public Rule getRule() {
return rule;
}
@@ -37,6 +40,10 @@ public String getStackId() {
return stackId;
}
+ public String getSecurityResponseId() {
+ return securityResponseId;
+ }
+
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
@@ -58,6 +65,10 @@ public String toString() {
sb.append("stackId");
sb.append('=');
sb.append(((this.stackId == null) ? "" : this.stackId));
+ sb.append(',');
+ sb.append("securityResponseId");
+ sb.append('=');
+ sb.append(((this.securityResponseId == null) ? "" : this.securityResponseId));
if (sb.charAt((sb.length() - 1)) == ',') {
sb.setCharAt((sb.length() - 1), ']');
} else {
@@ -73,6 +84,9 @@ public int hashCode() {
result = ((result * 31) + ((this.ruleMatches == null) ? 0 : this.ruleMatches.hashCode()));
result = ((result * 31) + ((this.spanId == null) ? 0 : this.spanId.hashCode()));
result = ((result * 31) + ((this.stackId == null) ? 0 : this.stackId.hashCode()));
+ result =
+ ((result * 31)
+ + ((this.securityResponseId == null) ? 0 : this.securityResponseId.hashCode()));
return result;
}
@@ -88,7 +102,8 @@ public boolean equals(Object other) {
return ((Objects.equals(this.rule, rhs.rule))
&& (Objects.equals(this.ruleMatches, rhs.ruleMatches))
&& (Objects.equals(this.spanId, rhs.spanId))
- && (Objects.equals(this.stackId, rhs.stackId)));
+ && (Objects.equals(this.stackId, rhs.stackId))
+ && (Objects.equals(this.securityResponseId, rhs.securityResponseId)));
}
public static class Builder {
@@ -125,5 +140,10 @@ public Builder withStackId(String stackId) {
this.instance.stackId = stackId;
return this;
}
+
+ public Builder withSecurityResponseId(String securityResponseId) {
+ this.instance.securityResponseId = securityResponseId;
+ return this;
+ }
}
}
diff --git a/dd-java-agent/appsec/src/test/groovy/com/datadog/appsec/blocking/BlockingServiceImplSpecification.groovy b/dd-java-agent/appsec/src/test/groovy/com/datadog/appsec/blocking/BlockingServiceImplSpecification.groovy
index a151f4917ae..d1a68cf7c13 100644
--- a/dd-java-agent/appsec/src/test/groovy/com/datadog/appsec/blocking/BlockingServiceImplSpecification.groovy
+++ b/dd-java-agent/appsec/src/test/groovy/com/datadog/appsec/blocking/BlockingServiceImplSpecification.groovy
@@ -108,7 +108,7 @@ class BlockingServiceImplSpecification extends DDSpecification {
then:
res == true
- 1 * brf.tryCommitBlockingResponse(mts, 405, BlockingContentType.HTML, [:],) >> true
+ 1 * brf.tryCommitBlockingResponse(mts, 405, BlockingContentType.HTML, [:], null) >> true
1 * mts.effectivelyBlocked()
}
diff --git a/dd-java-agent/appsec/src/test/groovy/com/datadog/appsec/ddwaf/WAFModuleSpecification.groovy b/dd-java-agent/appsec/src/test/groovy/com/datadog/appsec/ddwaf/WAFModuleSpecification.groovy
index d683006de7e..2483d5af410 100644
--- a/dd-java-agent/appsec/src/test/groovy/com/datadog/appsec/ddwaf/WAFModuleSpecification.groovy
+++ b/dd-java-agent/appsec/src/test/groovy/com/datadog/appsec/ddwaf/WAFModuleSpecification.groovy
@@ -608,7 +608,13 @@ class WAFModuleSpecification extends DDSpecification {
flow.action instanceof Flow.Action.RequestBlockingAction
with(flow.action as Flow.Action.RequestBlockingAction) {
assert it.statusCode == statusCode
- assert it.extraHeaders == [Location: "https://example${variant}.com/"]
+ // Location header may include security_response_id parameter from libddwaf
+ def location = it.extraHeaders['Location']
+ assert location.startsWith("https://example${variant}.com/")
+ // If security_response_id is present, it should be a valid UUID
+ if (location.contains('security_response_id=')) {
+ assert location.matches(".*security_response_id=[0-9a-f-]{36}.*")
+ }
}
where:
@@ -1357,7 +1363,7 @@ class WAFModuleSpecification extends DDSpecification {
Collection ret
when:
- ret = waf.buildEvents(rwd)
+ ret = waf.buildEvents(rwd, null)
then:
ret.isEmpty()
@@ -1369,7 +1375,7 @@ class WAFModuleSpecification extends DDSpecification {
Collection ret
when:
- ret = waf.buildEvents(rwd)
+ ret = waf.buildEvents(rwd, null)
then:
ret.isEmpty()
@@ -1714,7 +1720,7 @@ class WAFModuleSpecification extends DDSpecification {
Collection ret
when:
- ret = waf.buildEvents(rwd)
+ ret = waf.buildEvents(rwd, null)
then:
noExceptionThrown()
@@ -2051,6 +2057,298 @@ class WAFModuleSpecification extends DDSpecification {
!flow.blocking // Should not block since keep: false
}
+ void 'security_response_id is extracted from blocking action and included in RequestBlockingAction'() {
+ setup:
+ def rulesConfig = [
+ version: '2.1',
+ metadata: [
+ rules_version: '1.0.0'
+ ],
+ actions: [
+ [
+ id: 'block',
+ type: 'block_request',
+ parameters: [
+ status_code: 403,
+ type: 'json'
+ ]
+ ]
+ ],
+ rules: [
+ [
+ id: 'test-rule',
+ name: 'Test blocking rule',
+ tags: [
+ type: 'security_scanner',
+ category: 'attack_attempt'
+ ],
+ conditions: [
+ [
+ parameters: [
+ inputs: [
+ [
+ address: 'server.request.headers.no_cookies',
+ key_path: ['user-agent']
+ ]
+ ],
+ regex: '^BlockTest'
+ ],
+ operator: 'match_regex'
+ ]
+ ],
+ on_match: ['block']
+ ]
+ ]
+ ]
+
+ when:
+ initialRuleAddWithMap(rulesConfig)
+ wafModule.applyConfig(reconf)
+ def bundle = MapDataBundle.of(KnownAddresses.HEADERS_NO_COOKIES,
+ new CaseInsensitiveMap>(['user-agent': 'BlockTest']))
+ def flow = new ChangeableFlow()
+ dataListener.onDataAvailable(flow, ctx, bundle, gwCtx)
+ ctx.closeWafContext()
+
+ then:
+ 1 * ctx.getOrCreateWafContext(_, true, false)
+ 2 * ctx.getWafMetrics() >> metrics
+ 1 * ctx.isWafContextClosed() >> false
+ 1 * ctx.closeWafContext()
+ 1 * ctx.reportEvents(_)
+ 1 * ctx.setWafBlocked()
+ 1 * ctx.isThrottled(null)
+ 1 * ctx.setManuallyKept(true)
+ 0 * ctx._(*_)
+ flow.blocking
+ flow.action instanceof Flow.Action.RequestBlockingAction
+ with(flow.action as Flow.Action.RequestBlockingAction) {
+ assert it.statusCode == 403
+ assert it.blockingContentType == BlockingContentType.JSON
+ // securityResponseId should be extracted from libddwaf (or null if not present)
+ // With libddwaf v18.0.0, security_response_id is automatically generated
+ // We just verify the field is accessible
+ def securityResponseId = it.securityResponseId
+ assert securityResponseId == null || securityResponseId.matches('[0-9a-f-]{36}')
+ }
+ }
+
+ void 'security_response_id is unique across multiple blocking requests'() {
+ setup:
+ def rulesConfig = [
+ version: '2.1',
+ actions: [
+ [
+ id: 'block',
+ type: 'block_request',
+ parameters: [
+ status_code: 403,
+ type: 'auto'
+ ]
+ ]
+ ],
+ rules: [
+ [
+ id: 'test-block-unique',
+ name: 'Test unique security_response_id',
+ tags: [
+ type: 'test',
+ category: 'test'
+ ],
+ conditions: [
+ [
+ parameters: [
+ inputs: [
+ [
+ address: 'server.request.headers.no_cookies',
+ key_path: ['x-test-header']
+ ]
+ ],
+ regex: '^BlockUnique'
+ ],
+ operator: 'match_regex'
+ ]
+ ],
+ on_match: ['block']
+ ]
+ ]
+ ]
+
+ when: 'first blocking request'
+ initialRuleAddWithMap(rulesConfig)
+ wafModule.applyConfig(reconf)
+ def bundle1 = MapDataBundle.of(KnownAddresses.HEADERS_NO_COOKIES,
+ new CaseInsensitiveMap>(['x-test-header': 'BlockUnique1']))
+ def flow1 = new ChangeableFlow()
+ dataListener.onDataAvailable(flow1, ctx, bundle1, gwCtx)
+ ctx.closeWafContext()
+
+ and: 'second blocking request with fresh context'
+ def ctx2 = Spy(AppSecRequestContext)
+ def flow2 = new ChangeableFlow()
+ def bundle2 = MapDataBundle.of(KnownAddresses.HEADERS_NO_COOKIES,
+ new CaseInsensitiveMap>(['x-test-header': 'BlockUnique2']))
+ dataListener.onDataAvailable(flow2, ctx2, bundle2, gwCtx)
+ ctx2.closeWafContext()
+
+ then: 'both requests are blocked'
+ flow1.blocking
+ flow2.blocking
+
+ and: 'both have RequestBlockingAction with accessible securityResponseId'
+ flow1.action instanceof Flow.Action.RequestBlockingAction
+ flow2.action instanceof Flow.Action.RequestBlockingAction
+
+ and: 'if both securityResponseIds are present, they should be different'
+ def securityResponseId1 = (flow1.action as Flow.Action.RequestBlockingAction).securityResponseId
+ def securityResponseId2 = (flow2.action as Flow.Action.RequestBlockingAction).securityResponseId
+ // If libddwaf generates securityResponseIds, they should be unique
+ if (securityResponseId1 != null && securityResponseId2 != null) {
+ assert securityResponseId1 != securityResponseId2
+ assert securityResponseId1.matches('[0-9a-f-]{36}')
+ assert securityResponseId2.matches('[0-9a-f-]{36}')
+ }
+ }
+
+ void 'RequestBlockingAction handles null security_response_id gracefully'() {
+ setup:
+ def rulesConfig = [
+ version: '2.1',
+ actions: [
+ [
+ id: 'block_no_id',
+ type: 'block_request',
+ parameters: [
+ status_code: 418,
+ type: 'html'
+ ]
+ ]
+ ],
+ rules: [
+ [
+ id: 'test-null-securityResponseId',
+ name: 'Test null security_response_id handling',
+ tags: [
+ type: 'test',
+ category: 'test'
+ ],
+ conditions: [
+ [
+ parameters: [
+ inputs: [
+ [
+ address: 'server.request.headers.no_cookies',
+ key_path: ['user-agent']
+ ]
+ ],
+ regex: '^NullSecurityResponseId'
+ ],
+ operator: 'match_regex'
+ ]
+ ],
+ on_match: ['block_no_id']
+ ]
+ ]
+ ]
+
+ when:
+ initialRuleAddWithMap(rulesConfig)
+ wafModule.applyConfig(reconf)
+ def bundle = MapDataBundle.of(KnownAddresses.HEADERS_NO_COOKIES,
+ new CaseInsensitiveMap>(['user-agent': 'NullSecurityResponseIdTest']))
+ def flow = new ChangeableFlow()
+ dataListener.onDataAvailable(flow, ctx, bundle, gwCtx)
+ ctx.closeWafContext()
+
+ then:
+ flow.blocking
+ flow.action instanceof Flow.Action.RequestBlockingAction
+ with(flow.action as Flow.Action.RequestBlockingAction) {
+ assert it.statusCode == 418
+ assert it.blockingContentType == BlockingContentType.HTML
+ // securityResponseId may be null or a valid UUID - both are acceptable
+ def securityResponseId = it.securityResponseId
+ assert securityResponseId == null || securityResponseId.matches('[0-9a-f-]{36}')
+ }
+ }
+
+ void 'security_response_id is present in redirect action with Location header'() {
+ setup:
+ def rulesConfig = [
+ version: '2.1',
+ actions: [
+ [
+ id: 'redirect_with_id',
+ type: 'redirect_request',
+ parameters: [
+ status_code: 302,
+ location: 'https://example.com/blocked'
+ ]
+ ]
+ ],
+ rules: [
+ [
+ id: 'test-redirect-blockid',
+ name: 'Test redirect with security_response_id',
+ tags: [
+ type: 'test',
+ category: 'test'
+ ],
+ conditions: [
+ [
+ parameters: [
+ inputs: [
+ [
+ address: 'server.request.headers.no_cookies',
+ key_path: ['user-agent']
+ ]
+ ],
+ regex: '^RedirectWithSecurityResponseId'
+ ],
+ operator: 'match_regex'
+ ]
+ ],
+ on_match: ['redirect_with_id']
+ ]
+ ]
+ ]
+
+ when:
+ initialRuleAddWithMap(rulesConfig)
+ wafModule.applyConfig(reconf)
+ def bundle = MapDataBundle.of(KnownAddresses.HEADERS_NO_COOKIES,
+ new CaseInsensitiveMap>(['user-agent': 'RedirectWithSecurityResponseId']))
+ def flow = new ChangeableFlow()
+ dataListener.onDataAvailable(flow, ctx, bundle, gwCtx)
+ ctx.closeWafContext()
+
+ then:
+ 1 * ctx.getOrCreateWafContext(_, true, false)
+ 2 * ctx.getWafMetrics() >> metrics
+ 1 * ctx.isWafContextClosed() >> false
+ 1 * ctx.closeWafContext()
+ 1 * ctx.reportEvents(_)
+ 1 * ctx.setWafBlocked()
+ 1 * ctx.isThrottled(null)
+ 1 * ctx.setManuallyKept(true)
+ 0 * ctx._(*_)
+ flow.blocking
+ flow.action instanceof Flow.Action.RequestBlockingAction
+
+ and: 'redirect has Location header and possibly security_response_id'
+ with(flow.action as Flow.Action.RequestBlockingAction) {
+ assert it.statusCode == 302
+ assert it.blockingContentType == BlockingContentType.NONE
+ assert it.extraHeaders.containsKey('Location')
+ def location = it.extraHeaders['Location']
+ assert location.startsWith('https://example.com/blocked')
+
+ // securityResponseId should be accessible (may be null or a valid UUID)
+ def securityResponseId = it.securityResponseId
+ assert securityResponseId == null || securityResponseId.matches('[0-9a-f-]{36}')
+ }
+ }
+
private static class BadConfig implements Map {
@Delegate
private Map delegate
diff --git a/dd-java-agent/instrumentation-testing/src/main/groovy/datadog/trace/agent/test/base/HttpServerTest.groovy b/dd-java-agent/instrumentation-testing/src/main/groovy/datadog/trace/agent/test/base/HttpServerTest.groovy
index 083a0a98d5b..2938dba392e 100644
--- a/dd-java-agent/instrumentation-testing/src/main/groovy/datadog/trace/agent/test/base/HttpServerTest.groovy
+++ b/dd-java-agent/instrumentation-testing/src/main/groovy/datadog/trace/agent/test/base/HttpServerTest.groovy
@@ -1991,7 +1991,7 @@ abstract class HttpServerTest extends WithHttpServer {
if (blockResponseFunction == null) {
throw new UnsupportedOperationException("Do not know how to commit blocking response for this server")
}
- blockResponseFunction.tryCommitBlockingResponse(reqCtx.traceSegment, statusCode, type, extraHeaders)
+ blockResponseFunction.tryCommitBlockingResponse(reqCtx.traceSegment, statusCode, type, extraHeaders, null)
}
}
Blocking.blockingService = bs
diff --git a/dd-java-agent/instrumentation/akka/akka-http/akka-http-10.0/src/main/java/datadog/trace/instrumentation/akkahttp/appsec/AkkaBlockResponseFunction.java b/dd-java-agent/instrumentation/akka/akka-http/akka-http-10.0/src/main/java/datadog/trace/instrumentation/akkahttp/appsec/AkkaBlockResponseFunction.java
index 7421a8f9e01..00f20e1639b 100644
--- a/dd-java-agent/instrumentation/akka/akka-http/akka-http-10.0/src/main/java/datadog/trace/instrumentation/akkahttp/appsec/AkkaBlockResponseFunction.java
+++ b/dd-java-agent/instrumentation/akka/akka-http/akka-http-10.0/src/main/java/datadog/trace/instrumentation/akkahttp/appsec/AkkaBlockResponseFunction.java
@@ -55,13 +55,16 @@ public boolean tryCommitBlockingResponse(
TraceSegment segment,
int statusCode,
BlockingContentType templateType,
- Map extraHeaders) {
+ Map extraHeaders,
+ String securityResponseId) {
AgentSpan agentSpan = AgentTracer.activeSpan();
if (agentSpan == null) {
return false;
}
if (rba == null) {
- rba = new Flow.Action.RequestBlockingAction(statusCode, templateType, extraHeaders);
+ rba =
+ new Flow.Action.RequestBlockingAction(
+ statusCode, templateType, extraHeaders, securityResponseId);
this.traceSegment = segment;
}
return true;
diff --git a/dd-java-agent/instrumentation/akka/akka-http/akka-http-10.0/src/main/java/datadog/trace/instrumentation/akkahttp/appsec/BlockingResponseHelper.java b/dd-java-agent/instrumentation/akka/akka-http/akka-http-10.0/src/main/java/datadog/trace/instrumentation/akkahttp/appsec/BlockingResponseHelper.java
index dd53aaa1557..68d6a9d84c0 100644
--- a/dd-java-agent/instrumentation/akka/akka-http/akka-http-10.0/src/main/java/datadog/trace/instrumentation/akkahttp/appsec/BlockingResponseHelper.java
+++ b/dd-java-agent/instrumentation/akka/akka-http/akka-http-10.0/src/main/java/datadog/trace/instrumentation/akkahttp/appsec/BlockingResponseHelper.java
@@ -70,7 +70,7 @@ public static HttpResponse maybeCreateBlockingResponse(
if (bct != BlockingContentType.NONE) {
BlockingActionHelper.TemplateType tt =
BlockingActionHelper.determineTemplateType(bct, accept.map(h -> h.value()).orElse(null));
- byte[] template = BlockingActionHelper.getTemplate(tt);
+ byte[] template = BlockingActionHelper.getTemplate(tt, rba.getSecurityResponseId());
if (tt == BlockingActionHelper.TemplateType.HTML) {
entity =
HttpEntity$.MODULE$.apply(
diff --git a/dd-java-agent/instrumentation/grizzly/grizzly-2.0/src/main/java/datadog/trace/instrumentation/grizzly/GrizzlyBlockingHelper.java b/dd-java-agent/instrumentation/grizzly/grizzly-2.0/src/main/java/datadog/trace/instrumentation/grizzly/GrizzlyBlockingHelper.java
index 076d3ab66ae..f2dc26c04d8 100644
--- a/dd-java-agent/instrumentation/grizzly/grizzly-2.0/src/main/java/datadog/trace/instrumentation/grizzly/GrizzlyBlockingHelper.java
+++ b/dd-java-agent/instrumentation/grizzly/grizzly-2.0/src/main/java/datadog/trace/instrumentation/grizzly/GrizzlyBlockingHelper.java
@@ -44,6 +44,7 @@ public static boolean block(
rba.getStatusCode(),
rba.getBlockingContentType(),
rba.getExtraHeaders(),
+ rba.getSecurityResponseId(),
context);
}
@@ -54,6 +55,17 @@ public static boolean block(
BlockingContentType bct,
Map extraHeaders,
Context context) {
+ return block(request, response, statusCode, bct, extraHeaders, null, context);
+ }
+
+ public static boolean block(
+ Request request,
+ Response response,
+ int statusCode,
+ BlockingContentType bct,
+ Map extraHeaders,
+ String securityResponseId,
+ Context context) {
if (GET_OUTPUT_STREAM == null) {
return false;
}
@@ -72,7 +84,7 @@ public static boolean block(
BlockingActionHelper.TemplateType type =
BlockingActionHelper.determineTemplateType(bct, acceptHeader);
response.setHeader("Content-type", BlockingActionHelper.getContentType(type));
- byte[] template = BlockingActionHelper.getTemplate(type);
+ byte[] template = BlockingActionHelper.getTemplate(type, securityResponseId);
response.setHeader("Content-length", Integer.toString(template.length));
os.write(template);
}
diff --git a/dd-java-agent/instrumentation/grizzly/grizzly-2.0/src/main/java/datadog/trace/instrumentation/grizzly/GrizzlyDecorator.java b/dd-java-agent/instrumentation/grizzly/grizzly-2.0/src/main/java/datadog/trace/instrumentation/grizzly/GrizzlyDecorator.java
index 3b3e5118565..5e74f3780a9 100644
--- a/dd-java-agent/instrumentation/grizzly/grizzly-2.0/src/main/java/datadog/trace/instrumentation/grizzly/GrizzlyDecorator.java
+++ b/dd-java-agent/instrumentation/grizzly/grizzly-2.0/src/main/java/datadog/trace/instrumentation/grizzly/GrizzlyDecorator.java
@@ -89,7 +89,8 @@ public boolean tryCommitBlockingResponse(
TraceSegment segment,
int statusCode,
BlockingContentType templateType,
- Map extraHeaders) {
+ Map extraHeaders,
+ String securityResponseId) {
AgentSpan agentSpan = AgentTracer.get().activeSpan();
if (agentSpan == null) {
log.warn("Can't block: no active span");
diff --git a/dd-java-agent/instrumentation/grizzly/grizzly-http-2.3.20/src/main/java/datadog/trace/instrumentation/grizzlyhttp232/GrizzlyDecorator.java b/dd-java-agent/instrumentation/grizzly/grizzly-http-2.3.20/src/main/java/datadog/trace/instrumentation/grizzlyhttp232/GrizzlyDecorator.java
index adf307e2cbf..9b917f65941 100644
--- a/dd-java-agent/instrumentation/grizzly/grizzly-http-2.3.20/src/main/java/datadog/trace/instrumentation/grizzlyhttp232/GrizzlyDecorator.java
+++ b/dd-java-agent/instrumentation/grizzly/grizzly-http-2.3.20/src/main/java/datadog/trace/instrumentation/grizzlyhttp232/GrizzlyDecorator.java
@@ -180,12 +180,13 @@ public boolean tryCommitBlockingResponse(
TraceSegment segment,
int statusCode,
BlockingContentType templateType,
- Map extraHeaders) {
+ Map extraHeaders,
+ String securityResponseId) {
if (ctx == null) {
return false;
}
return GrizzlyHttpBlockingHelper.block(
- ctx, acceptHeader, statusCode, templateType, extraHeaders, segment);
+ ctx, acceptHeader, statusCode, templateType, extraHeaders, segment, securityResponseId);
}
}
}
diff --git a/dd-java-agent/instrumentation/grizzly/grizzly-http-2.3.20/src/main/java/datadog/trace/instrumentation/grizzlyhttp232/GrizzlyHttpBlockingHelper.java b/dd-java-agent/instrumentation/grizzly/grizzly-http-2.3.20/src/main/java/datadog/trace/instrumentation/grizzlyhttp232/GrizzlyHttpBlockingHelper.java
index 3ac61b25ac7..700ad1a13a1 100644
--- a/dd-java-agent/instrumentation/grizzly/grizzly-http-2.3.20/src/main/java/datadog/trace/instrumentation/grizzlyhttp232/GrizzlyHttpBlockingHelper.java
+++ b/dd-java-agent/instrumentation/grizzly/grizzly-http-2.3.20/src/main/java/datadog/trace/instrumentation/grizzlyhttp232/GrizzlyHttpBlockingHelper.java
@@ -105,7 +105,7 @@ public static NextAction block(
BlockingActionHelper.determineTemplateType(rba.getBlockingContentType(), acceptHeader);
httpResponse.setHeader("Content-type", BlockingActionHelper.getContentType(type));
- byte[] template = BlockingActionHelper.getTemplate(type);
+ byte[] template = BlockingActionHelper.getTemplate(type, rba.getSecurityResponseId());
httpResponse.setContentLength(template.length);
httpContent =
HttpContent.builder(httpResponse).content(HeapBuffer.wrap(template)).last(true).build();
@@ -139,7 +139,8 @@ public static boolean block(
int statusCode,
BlockingContentType templateType,
Map extraHeaders,
- TraceSegment segment) {
+ TraceSegment segment,
+ String securityResponseId) {
if (ENCODE_HTTP_PACKET == null) {
return false;
}
@@ -166,7 +167,7 @@ public static boolean block(
BlockingActionHelper.determineTemplateType(templateType, acceptHeader);
httpResponse.setHeader("Content-type", BlockingActionHelper.getContentType(type));
- byte[] template = BlockingActionHelper.getTemplate(type);
+ byte[] template = BlockingActionHelper.getTemplate(type, securityResponseId);
httpResponse.setContentLength(template.length);
httpContent =
HttpContent.builder(httpResponse).content(HeapBuffer.wrap(template)).last(true).build();
diff --git a/dd-java-agent/instrumentation/jetty/jetty-common/src/main/java/datadog/trace/instrumentation/jetty/JettyBlockResponseFunction.java b/dd-java-agent/instrumentation/jetty/jetty-common/src/main/java/datadog/trace/instrumentation/jetty/JettyBlockResponseFunction.java
index 6ad591576a0..5775d5b687d 100644
--- a/dd-java-agent/instrumentation/jetty/jetty-common/src/main/java/datadog/trace/instrumentation/jetty/JettyBlockResponseFunction.java
+++ b/dd-java-agent/instrumentation/jetty/jetty-common/src/main/java/datadog/trace/instrumentation/jetty/JettyBlockResponseFunction.java
@@ -19,9 +19,10 @@ public boolean tryCommitBlockingResponse(
TraceSegment segment,
int statusCode,
BlockingContentType templateType,
- Map extraHeaders) {
+ Map extraHeaders,
+ String securityResponseId) {
Response response = request.getResponse();
return JettyBlockingHelper.block(
- segment, request, response, statusCode, templateType, extraHeaders);
+ segment, request, response, statusCode, templateType, extraHeaders, securityResponseId);
}
}
diff --git a/dd-java-agent/instrumentation/jetty/jetty-common/src/main/java/datadog/trace/instrumentation/jetty/JettyBlockingHelper.java b/dd-java-agent/instrumentation/jetty/jetty-common/src/main/java/datadog/trace/instrumentation/jetty/JettyBlockingHelper.java
index 57667466b7b..e9e4848244b 100644
--- a/dd-java-agent/instrumentation/jetty/jetty-common/src/main/java/datadog/trace/instrumentation/jetty/JettyBlockingHelper.java
+++ b/dd-java-agent/instrumentation/jetty/jetty-common/src/main/java/datadog/trace/instrumentation/jetty/JettyBlockingHelper.java
@@ -161,7 +161,8 @@ public static boolean block(
Response response,
int statusCode,
BlockingContentType bct,
- Map extraHeaders) {
+ Map extraHeaders,
+ String securityResponseId) {
if (!INITIALIZED) {
return false;
}
@@ -185,7 +186,7 @@ public static boolean block(
BlockingActionHelper.determineTemplateType(bct, acceptHeader);
response.setCharacterEncoding("utf-8");
response.setHeader("Content-type", BlockingActionHelper.getContentType(type));
- byte[] template = BlockingActionHelper.getTemplate(type);
+ byte[] template = BlockingActionHelper.getTemplate(type, securityResponseId);
if (!response.isWriting()) {
response.setHeader("Content-length", Integer.toString(template.length));
@@ -239,7 +240,8 @@ public static boolean block(Request request, Response response, Context context)
response,
rba.getStatusCode(),
rba.getBlockingContentType(),
- rba.getExtraHeaders());
+ rba.getExtraHeaders(),
+ rba.getSecurityResponseId());
}
public static boolean hasRequestBlockingAction(Context context) {
diff --git a/dd-java-agent/instrumentation/jetty/jetty-common/src/test/groovy/datadog/trace/instrumentation/jetty/JettyBlockingHelperSpecification.groovy b/dd-java-agent/instrumentation/jetty/jetty-common/src/test/groovy/datadog/trace/instrumentation/jetty/JettyBlockingHelperSpecification.groovy
index dcf9c7bed42..a9daf7f467f 100644
--- a/dd-java-agent/instrumentation/jetty/jetty-common/src/test/groovy/datadog/trace/instrumentation/jetty/JettyBlockingHelperSpecification.groovy
+++ b/dd-java-agent/instrumentation/jetty/jetty-common/src/test/groovy/datadog/trace/instrumentation/jetty/JettyBlockingHelperSpecification.groovy
@@ -20,7 +20,7 @@ class JettyBlockingHelperSpecification extends DDSpecification {
def rba = new Flow.Action.RequestBlockingAction(402, AUTO)
when:
- JettyBlockingHelper.block(seg, req, resp, rba.getStatusCode(), rba.getBlockingContentType(), rba.getExtraHeaders())
+ JettyBlockingHelper.block(seg, req, resp, rba.getStatusCode(), rba.getBlockingContentType(), rba.getExtraHeaders(), rba.getSecurityResponseId())
then:
1 * resp.isCommitted() >> false
diff --git a/dd-java-agent/instrumentation/jetty/jetty-server/jetty-server-10.0/src/main/java11/datadog/trace/instrumentation/jetty10/JettyOnCommitBlockingHelper.java b/dd-java-agent/instrumentation/jetty/jetty-server/jetty-server-10.0/src/main/java11/datadog/trace/instrumentation/jetty10/JettyOnCommitBlockingHelper.java
index f80642fe2b5..7b8ccc4fb6e 100644
--- a/dd-java-agent/instrumentation/jetty/jetty-server/jetty-server-10.0/src/main/java11/datadog/trace/instrumentation/jetty10/JettyOnCommitBlockingHelper.java
+++ b/dd-java-agent/instrumentation/jetty/jetty-server/jetty-server-10.0/src/main/java11/datadog/trace/instrumentation/jetty10/JettyOnCommitBlockingHelper.java
@@ -54,7 +54,7 @@ public static boolean block(
BlockingActionHelper.TemplateType type =
BlockingActionHelper.determineTemplateType(bct, acceptHeader);
putHeader(fields, "Content-type", BlockingActionHelper.getContentType(type));
- byte[] template = BlockingActionHelper.getTemplate(type);
+ byte[] template = BlockingActionHelper.getTemplate(type, rba.getSecurityResponseId());
putHeader(fields, "Content-length", Integer.toString(template.length));
info = new MetaData.Response(request.getHttpVersion(), statusCode, fields, template.length);
diff --git a/dd-java-agent/instrumentation/jetty/jetty-server/jetty-server-9.0.4/src/main/java/datadog/trace/instrumentation/jetty904/JettyOnCommitBlockingHelper.java b/dd-java-agent/instrumentation/jetty/jetty-server/jetty-server-9.0.4/src/main/java/datadog/trace/instrumentation/jetty904/JettyOnCommitBlockingHelper.java
index 59ee13dc229..1f2f770170a 100644
--- a/dd-java-agent/instrumentation/jetty/jetty-server/jetty-server-9.0.4/src/main/java/datadog/trace/instrumentation/jetty904/JettyOnCommitBlockingHelper.java
+++ b/dd-java-agent/instrumentation/jetty/jetty-server/jetty-server-9.0.4/src/main/java/datadog/trace/instrumentation/jetty904/JettyOnCommitBlockingHelper.java
@@ -56,7 +56,7 @@ public static boolean block(
BlockingActionHelper.TemplateType type =
BlockingActionHelper.determineTemplateType(bct, acceptHeader);
fields.put("Content-type", BlockingActionHelper.getContentType(type));
- byte[] template = BlockingActionHelper.getTemplate(type);
+ byte[] template = BlockingActionHelper.getTemplate(type, rba.getSecurityResponseId());
fields.put("Content-length", Integer.toString(template.length));
info =
diff --git a/dd-java-agent/instrumentation/jetty/jetty-server/jetty-server-9.3/src/main/java/datadog/trace/instrumentation/jetty93/JettyOnCommitBlockingHelper.java b/dd-java-agent/instrumentation/jetty/jetty-server/jetty-server-9.3/src/main/java/datadog/trace/instrumentation/jetty93/JettyOnCommitBlockingHelper.java
index 0120520da4a..c12168089f7 100644
--- a/dd-java-agent/instrumentation/jetty/jetty-server/jetty-server-9.3/src/main/java/datadog/trace/instrumentation/jetty93/JettyOnCommitBlockingHelper.java
+++ b/dd-java-agent/instrumentation/jetty/jetty-server/jetty-server-9.3/src/main/java/datadog/trace/instrumentation/jetty93/JettyOnCommitBlockingHelper.java
@@ -55,7 +55,7 @@ public static boolean block(
BlockingActionHelper.TemplateType type =
BlockingActionHelper.determineTemplateType(bct, acceptHeader);
fields.put("Content-type", BlockingActionHelper.getContentType(type));
- byte[] template = BlockingActionHelper.getTemplate(type);
+ byte[] template = BlockingActionHelper.getTemplate(type, rba.getSecurityResponseId());
fields.put("Content-length", Integer.toString(template.length));
info = new MetaData.Response(request.getHttpVersion(), statusCode, fields, template.length);
diff --git a/dd-java-agent/instrumentation/jetty/jetty-server/jetty-server-9.4.21/src/main/java/datadog/trace/instrumentation/jetty9421/JettyOnCommitBlockingHelper.java b/dd-java-agent/instrumentation/jetty/jetty-server/jetty-server-9.4.21/src/main/java/datadog/trace/instrumentation/jetty9421/JettyOnCommitBlockingHelper.java
index c406b765895..10282df2415 100644
--- a/dd-java-agent/instrumentation/jetty/jetty-server/jetty-server-9.4.21/src/main/java/datadog/trace/instrumentation/jetty9421/JettyOnCommitBlockingHelper.java
+++ b/dd-java-agent/instrumentation/jetty/jetty-server/jetty-server-9.4.21/src/main/java/datadog/trace/instrumentation/jetty9421/JettyOnCommitBlockingHelper.java
@@ -55,7 +55,7 @@ public static boolean block(
BlockingActionHelper.TemplateType type =
BlockingActionHelper.determineTemplateType(bct, acceptHeader);
fields.put("Content-type", BlockingActionHelper.getContentType(type));
- byte[] template = BlockingActionHelper.getTemplate(type);
+ byte[] template = BlockingActionHelper.getTemplate(type, rba.getSecurityResponseId());
fields.put("Content-length", Integer.toString(template.length));
info = new MetaData.Response(request.getHttpVersion(), statusCode, fields, template.length);
diff --git a/dd-java-agent/instrumentation/liberty/liberty-20.0/src/main/java/datadog/trace/instrumentation/liberty20/LibertyBlockingHelper.java b/dd-java-agent/instrumentation/liberty/liberty-20.0/src/main/java/datadog/trace/instrumentation/liberty20/LibertyBlockingHelper.java
index 8ebaf920b40..719ba39378b 100644
--- a/dd-java-agent/instrumentation/liberty/liberty-20.0/src/main/java/datadog/trace/instrumentation/liberty20/LibertyBlockingHelper.java
+++ b/dd-java-agent/instrumentation/liberty/liberty-20.0/src/main/java/datadog/trace/instrumentation/liberty20/LibertyBlockingHelper.java
@@ -90,7 +90,7 @@ public static BlockingException syncBufferEnter(
BlockingActionHelper.TemplateType type =
BlockingActionHelper.determineTemplateType(
bct, thiz.getRequest().getHeader("Accept").asString());
- byte[] template = BlockingActionHelper.getTemplate(type);
+ byte[] template = BlockingActionHelper.getTemplate(type, rba.getSecurityResponseId());
response.setHeader("Content-length", Integer.toString(template.length));
response.setHeader("Content-type", BlockingActionHelper.getContentType(type));
WsByteBufferImpl buffer = new WsByteBufferImpl(ByteBuffer.wrap(template));
diff --git a/dd-java-agent/instrumentation/liberty/liberty-20.0/src/main/java/datadog/trace/instrumentation/liberty20/LibertyDecorator.java b/dd-java-agent/instrumentation/liberty/liberty-20.0/src/main/java/datadog/trace/instrumentation/liberty20/LibertyDecorator.java
index 45fdb6adab1..e3b34ef74c4 100644
--- a/dd-java-agent/instrumentation/liberty/liberty-20.0/src/main/java/datadog/trace/instrumentation/liberty20/LibertyDecorator.java
+++ b/dd-java-agent/instrumentation/liberty/liberty-20.0/src/main/java/datadog/trace/instrumentation/liberty20/LibertyDecorator.java
@@ -181,7 +181,8 @@ public boolean tryCommitBlockingResponse(
TraceSegment segment,
int statusCode,
BlockingContentType bct,
- Map extraHeaders) {
+ Map extraHeaders,
+ String securityResponseId) {
if (!(request instanceof SRTServletRequest)) {
log.warn("Can't block; request not of type SRTServletRequest");
return false;
@@ -192,7 +193,13 @@ public boolean tryCommitBlockingResponse(
return false;
}
ServletBlockingHelper.commitBlockingResponse(
- segment, request, (HttpServletResponse) response, statusCode, bct, extraHeaders);
+ segment,
+ request,
+ (HttpServletResponse) response,
+ statusCode,
+ bct,
+ extraHeaders,
+ securityResponseId);
return true;
}
diff --git a/dd-java-agent/instrumentation/liberty/liberty-23.0/src/main/java/datadog/trace/instrumentation/liberty23/LibertyBlockingHelper.java b/dd-java-agent/instrumentation/liberty/liberty-23.0/src/main/java/datadog/trace/instrumentation/liberty23/LibertyBlockingHelper.java
index 07e012e6a35..bc35ec1ef3c 100644
--- a/dd-java-agent/instrumentation/liberty/liberty-23.0/src/main/java/datadog/trace/instrumentation/liberty23/LibertyBlockingHelper.java
+++ b/dd-java-agent/instrumentation/liberty/liberty-23.0/src/main/java/datadog/trace/instrumentation/liberty23/LibertyBlockingHelper.java
@@ -90,7 +90,7 @@ public static BlockingException syncBufferEnter(
BlockingActionHelper.TemplateType type =
BlockingActionHelper.determineTemplateType(
bct, thiz.getRequest().getHeader("Accept").asString());
- byte[] template = BlockingActionHelper.getTemplate(type);
+ byte[] template = BlockingActionHelper.getTemplate(type, rba.getSecurityResponseId());
response.setHeader("Content-length", Integer.toString(template.length));
response.setHeader("Content-type", BlockingActionHelper.getContentType(type));
WsByteBufferImpl buffer = new WsByteBufferImpl(ByteBuffer.wrap(template));
diff --git a/dd-java-agent/instrumentation/liberty/liberty-23.0/src/main/java/datadog/trace/instrumentation/liberty23/LibertyDecorator.java b/dd-java-agent/instrumentation/liberty/liberty-23.0/src/main/java/datadog/trace/instrumentation/liberty23/LibertyDecorator.java
index 5a46a20028c..ae19d67a054 100644
--- a/dd-java-agent/instrumentation/liberty/liberty-23.0/src/main/java/datadog/trace/instrumentation/liberty23/LibertyDecorator.java
+++ b/dd-java-agent/instrumentation/liberty/liberty-23.0/src/main/java/datadog/trace/instrumentation/liberty23/LibertyDecorator.java
@@ -182,7 +182,8 @@ public boolean tryCommitBlockingResponse(
TraceSegment segment,
int statusCode,
BlockingContentType bct,
- Map extraHeaders) {
+ Map extraHeaders,
+ String securityResponseId) {
if (!(request instanceof SRTServletRequest)) {
log.warn("Can't block; request not of type SRTServletRequest");
return false;
@@ -193,7 +194,13 @@ public boolean tryCommitBlockingResponse(
return false;
}
JakartaServletBlockingHelper.commitBlockingResponse(
- segment, request, (HttpServletResponse) response, statusCode, bct, extraHeaders);
+ segment,
+ request,
+ (HttpServletResponse) response,
+ statusCode,
+ bct,
+ extraHeaders,
+ securityResponseId);
return true;
}
diff --git a/dd-java-agent/instrumentation/netty/netty-3.8/src/main/java/datadog/trace/instrumentation/netty38/server/BlockingResponseHandler.java b/dd-java-agent/instrumentation/netty/netty-3.8/src/main/java/datadog/trace/instrumentation/netty38/server/BlockingResponseHandler.java
index 7cc148e3117..3a8e75e2777 100644
--- a/dd-java-agent/instrumentation/netty/netty-3.8/src/main/java/datadog/trace/instrumentation/netty38/server/BlockingResponseHandler.java
+++ b/dd-java-agent/instrumentation/netty/netty-3.8/src/main/java/datadog/trace/instrumentation/netty38/server/BlockingResponseHandler.java
@@ -27,6 +27,7 @@ public class BlockingResponseHandler extends SimpleChannelUpstreamHandler {
private final int statusCode;
private final BlockingContentType bct;
private final Map extraHeaders;
+ private final String securityResponseId;
private static final Logger log = LoggerFactory.getLogger(BlockingResponseHandler.class);
private static volatile boolean HAS_WARNED;
@@ -37,15 +38,22 @@ public BlockingResponseHandler(
TraceSegment segment,
int statusCode,
BlockingContentType bct,
- Map extraHeaders) {
+ Map extraHeaders,
+ String securityResponseId) {
this.segment = segment;
this.statusCode = statusCode;
this.bct = bct;
this.extraHeaders = extraHeaders;
+ this.securityResponseId = securityResponseId;
}
public BlockingResponseHandler(TraceSegment segment, Flow.Action.RequestBlockingAction rba) {
- this(segment, rba.getStatusCode(), rba.getBlockingContentType(), rba.getExtraHeaders());
+ this(
+ segment,
+ rba.getStatusCode(),
+ rba.getBlockingContentType(),
+ rba.getExtraHeaders(),
+ rba.getSecurityResponseId());
}
@Override
@@ -117,7 +125,7 @@ public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Ex
BlockingActionHelper.TemplateType type =
BlockingActionHelper.determineTemplateType(bct, acceptHeader);
headers.set("Content-type", BlockingActionHelper.getContentType(type));
- byte[] template = BlockingActionHelper.getTemplate(type);
+ byte[] template = BlockingActionHelper.getTemplate(type, this.securityResponseId);
setContentLength(response, template.length);
ChannelBuffer buf = ChannelBuffers.wrappedBuffer(template);
response.setContent(buf);
diff --git a/dd-java-agent/instrumentation/netty/netty-3.8/src/main/java/datadog/trace/instrumentation/netty38/server/MaybeBlockResponseHandler.java b/dd-java-agent/instrumentation/netty/netty-3.8/src/main/java/datadog/trace/instrumentation/netty38/server/MaybeBlockResponseHandler.java
index 7511cff8c56..d7451780a5b 100644
--- a/dd-java-agent/instrumentation/netty/netty-3.8/src/main/java/datadog/trace/instrumentation/netty38/server/MaybeBlockResponseHandler.java
+++ b/dd-java-agent/instrumentation/netty/netty-3.8/src/main/java/datadog/trace/instrumentation/netty38/server/MaybeBlockResponseHandler.java
@@ -98,7 +98,7 @@ public void writeRequested(ChannelHandlerContext ctx, MessageEvent msg) throws E
BlockingActionHelper.TemplateType type =
BlockingActionHelper.determineTemplateType(bct, acceptHeader);
headers.set("Content-type", BlockingActionHelper.getContentType(type));
- byte[] template = BlockingActionHelper.getTemplate(type);
+ byte[] template = BlockingActionHelper.getTemplate(type, rba.getSecurityResponseId());
setContentLength(response, template.length);
ChannelBuffer buf = ChannelBuffers.wrappedBuffer(template);
response.setContent(buf);
diff --git a/dd-java-agent/instrumentation/netty/netty-3.8/src/main/java/datadog/trace/instrumentation/netty38/server/NettyHttpServerDecorator.java b/dd-java-agent/instrumentation/netty/netty-3.8/src/main/java/datadog/trace/instrumentation/netty38/server/NettyHttpServerDecorator.java
index 51f876cffb5..ddda952fd1b 100644
--- a/dd-java-agent/instrumentation/netty/netty-3.8/src/main/java/datadog/trace/instrumentation/netty38/server/NettyHttpServerDecorator.java
+++ b/dd-java-agent/instrumentation/netty/netty-3.8/src/main/java/datadog/trace/instrumentation/netty38/server/NettyHttpServerDecorator.java
@@ -133,7 +133,8 @@ public boolean tryCommitBlockingResponse(
TraceSegment segment,
int statusCode,
BlockingContentType templateType,
- Map extraHeaders) {
+ Map extraHeaders,
+ String securityResponseId) {
ChannelHandler handlerBefore = pipeline.get(HttpServerTracingHandler.class);
if (handlerBefore == null) {
handlerBefore = pipeline.get(HttpServerRequestTracingHandler.class);
@@ -148,7 +149,8 @@ public boolean tryCommitBlockingResponse(
pipeline.addAfter(
handlerBefore.getClass().getName(),
"blocking_handler",
- new BlockingResponseHandler(segment, statusCode, templateType, extraHeaders));
+ new BlockingResponseHandler(
+ segment, statusCode, templateType, extraHeaders, securityResponseId));
pipeline.addBefore(
"blocking_handler", "before_blocking_handler", new SimpleChannelUpstreamHandler());
} catch (RuntimeException rte) {
diff --git a/dd-java-agent/instrumentation/netty/netty-4.0/src/main/java/datadog/trace/instrumentation/netty40/server/BlockingResponseHandler.java b/dd-java-agent/instrumentation/netty/netty-4.0/src/main/java/datadog/trace/instrumentation/netty40/server/BlockingResponseHandler.java
index 32042ff464a..b31435dd801 100644
--- a/dd-java-agent/instrumentation/netty/netty-4.0/src/main/java/datadog/trace/instrumentation/netty40/server/BlockingResponseHandler.java
+++ b/dd-java-agent/instrumentation/netty/netty-4.0/src/main/java/datadog/trace/instrumentation/netty40/server/BlockingResponseHandler.java
@@ -29,6 +29,7 @@ public class BlockingResponseHandler extends ChannelInboundHandlerAdapter {
private final BlockingContentType bct;
private final Map extraHeaders;
private final TraceSegment segment;
+ private final String securityResponseId;
private boolean hasBlockedAlready;
@@ -36,15 +37,22 @@ public BlockingResponseHandler(
TraceSegment segment,
int statusCode,
BlockingContentType bct,
- Map extraHeaders) {
+ Map extraHeaders,
+ String securityResponseId) {
this.segment = segment;
this.statusCode = statusCode;
this.bct = bct;
this.extraHeaders = extraHeaders;
+ this.securityResponseId = securityResponseId;
}
public BlockingResponseHandler(TraceSegment segment, Flow.Action.RequestBlockingAction rba) {
- this(segment, rba.getStatusCode(), rba.getBlockingContentType(), rba.getExtraHeaders());
+ this(
+ segment,
+ rba.getStatusCode(),
+ rba.getBlockingContentType(),
+ rba.getExtraHeaders(),
+ rba.getSecurityResponseId());
}
@Override
@@ -98,7 +106,7 @@ public void channelRead(final ChannelHandlerContext ctx, final Object msg) {
BlockingActionHelper.determineTemplateType(bct, acceptHeader);
headers.set("Content-type", BlockingActionHelper.getContentType(type));
- byte[] template = BlockingActionHelper.getTemplate(type);
+ byte[] template = BlockingActionHelper.getTemplate(type, this.securityResponseId);
setContentLength(response, template.length);
response.content().writeBytes(template);
}
diff --git a/dd-java-agent/instrumentation/netty/netty-4.0/src/main/java/datadog/trace/instrumentation/netty40/server/MaybeBlockResponseHandler.java b/dd-java-agent/instrumentation/netty/netty-4.0/src/main/java/datadog/trace/instrumentation/netty40/server/MaybeBlockResponseHandler.java
index c5abbe0c807..8ccc6af32e1 100644
--- a/dd-java-agent/instrumentation/netty/netty-4.0/src/main/java/datadog/trace/instrumentation/netty40/server/MaybeBlockResponseHandler.java
+++ b/dd-java-agent/instrumentation/netty/netty-4.0/src/main/java/datadog/trace/instrumentation/netty40/server/MaybeBlockResponseHandler.java
@@ -121,7 +121,7 @@ public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise prm) thr
BlockingActionHelper.TemplateType type =
BlockingActionHelper.determineTemplateType(bct, acceptHeader);
headers.set("Content-type", BlockingActionHelper.getContentType(type));
- byte[] template = BlockingActionHelper.getTemplate(type);
+ byte[] template = BlockingActionHelper.getTemplate(type, rba.getSecurityResponseId());
setContentLength(response, template.length);
response.content().writeBytes(template);
}
diff --git a/dd-java-agent/instrumentation/netty/netty-4.0/src/main/java/datadog/trace/instrumentation/netty40/server/NettyHttpServerDecorator.java b/dd-java-agent/instrumentation/netty/netty-4.0/src/main/java/datadog/trace/instrumentation/netty40/server/NettyHttpServerDecorator.java
index 0fce7fe28b9..f0844e00184 100644
--- a/dd-java-agent/instrumentation/netty/netty-4.0/src/main/java/datadog/trace/instrumentation/netty40/server/NettyHttpServerDecorator.java
+++ b/dd-java-agent/instrumentation/netty/netty-4.0/src/main/java/datadog/trace/instrumentation/netty40/server/NettyHttpServerDecorator.java
@@ -129,7 +129,8 @@ public boolean tryCommitBlockingResponse(
TraceSegment segment,
int statusCode,
BlockingContentType templateType,
- Map extraHeaders) {
+ Map extraHeaders,
+ String securityResponseId) {
ChannelHandler handlerBefore = pipeline.get(HttpServerTracingHandler.class);
if (handlerBefore == null) {
handlerBefore = pipeline.get(HttpServerRequestTracingHandler.class);
@@ -145,7 +146,8 @@ public boolean tryCommitBlockingResponse(
.addAfter(
handlerBefore.getClass().getName(),
"blocking_handler",
- new BlockingResponseHandler(segment, statusCode, templateType, extraHeaders))
+ new BlockingResponseHandler(
+ segment, statusCode, templateType, extraHeaders, securityResponseId))
.addBefore(
"blocking_handler", "before_blocking_handler", new ChannelInboundHandlerAdapter());
} catch (RuntimeException rte) {
diff --git a/dd-java-agent/instrumentation/netty/netty-4.1/src/main/java/datadog/trace/instrumentation/netty41/server/BlockingResponseHandler.java b/dd-java-agent/instrumentation/netty/netty-4.1/src/main/java/datadog/trace/instrumentation/netty41/server/BlockingResponseHandler.java
index bb05ac8573c..1c49fceae2f 100644
--- a/dd-java-agent/instrumentation/netty/netty-4.1/src/main/java/datadog/trace/instrumentation/netty41/server/BlockingResponseHandler.java
+++ b/dd-java-agent/instrumentation/netty/netty-4.1/src/main/java/datadog/trace/instrumentation/netty41/server/BlockingResponseHandler.java
@@ -28,6 +28,7 @@ public class BlockingResponseHandler extends ChannelInboundHandlerAdapter {
private final int statusCode;
private final BlockingContentType bct;
private final Map extraHeaders;
+ private final String securityResponseId;
private boolean hasBlockedAlready;
@@ -35,15 +36,22 @@ public BlockingResponseHandler(
TraceSegment segment,
int statusCode,
BlockingContentType bct,
- Map extraHeaders) {
+ Map extraHeaders,
+ String securityResponseId) {
this.segment = segment;
this.statusCode = statusCode;
this.bct = bct;
this.extraHeaders = extraHeaders;
+ this.securityResponseId = securityResponseId;
}
public BlockingResponseHandler(TraceSegment segment, Flow.Action.RequestBlockingAction rba) {
- this(segment, rba.getStatusCode(), rba.getBlockingContentType(), rba.getExtraHeaders());
+ this(
+ segment,
+ rba.getStatusCode(),
+ rba.getBlockingContentType(),
+ rba.getExtraHeaders(),
+ rba.getSecurityResponseId());
}
@Override
@@ -97,7 +105,7 @@ public void channelRead(final ChannelHandlerContext ctx, final Object msg) {
BlockingActionHelper.determineTemplateType(bct, acceptHeader);
headers.set("Content-type", BlockingActionHelper.getContentType(type));
- byte[] template = BlockingActionHelper.getTemplate(type);
+ byte[] template = BlockingActionHelper.getTemplate(type, this.securityResponseId);
HttpUtil.setContentLength(response, template.length);
response.content().writeBytes(template);
}
diff --git a/dd-java-agent/instrumentation/netty/netty-4.1/src/main/java/datadog/trace/instrumentation/netty41/server/MaybeBlockResponseHandler.java b/dd-java-agent/instrumentation/netty/netty-4.1/src/main/java/datadog/trace/instrumentation/netty41/server/MaybeBlockResponseHandler.java
index 7503e871d65..99da41b19d6 100644
--- a/dd-java-agent/instrumentation/netty/netty-4.1/src/main/java/datadog/trace/instrumentation/netty41/server/MaybeBlockResponseHandler.java
+++ b/dd-java-agent/instrumentation/netty/netty-4.1/src/main/java/datadog/trace/instrumentation/netty41/server/MaybeBlockResponseHandler.java
@@ -118,7 +118,7 @@ public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise prm) thr
BlockingActionHelper.TemplateType type =
BlockingActionHelper.determineTemplateType(bct, acceptHeader);
headers.set("Content-type", BlockingActionHelper.getContentType(type));
- byte[] template = BlockingActionHelper.getTemplate(type);
+ byte[] template = BlockingActionHelper.getTemplate(type, rba.getSecurityResponseId());
setContentLength(response, template.length);
response.content().writeBytes(template);
}
diff --git a/dd-java-agent/instrumentation/netty/netty-4.1/src/main/java/datadog/trace/instrumentation/netty41/server/NettyHttpServerDecorator.java b/dd-java-agent/instrumentation/netty/netty-4.1/src/main/java/datadog/trace/instrumentation/netty41/server/NettyHttpServerDecorator.java
index 362e792256a..101b35bc4ac 100644
--- a/dd-java-agent/instrumentation/netty/netty-4.1/src/main/java/datadog/trace/instrumentation/netty41/server/NettyHttpServerDecorator.java
+++ b/dd-java-agent/instrumentation/netty/netty-4.1/src/main/java/datadog/trace/instrumentation/netty41/server/NettyHttpServerDecorator.java
@@ -127,7 +127,8 @@ public boolean tryCommitBlockingResponse(
TraceSegment segment,
int statusCode,
BlockingContentType templateType,
- Map extraHeaders) {
+ Map extraHeaders,
+ String securityResponseId) {
ChannelHandler handlerBefore = pipeline.get(HttpServerTracingHandler.class);
if (handlerBefore == null) {
handlerBefore = pipeline.get(HttpServerRequestTracingHandler.class);
@@ -143,7 +144,8 @@ public boolean tryCommitBlockingResponse(
.addAfter(
pipeline.context(handlerBefore).name(),
"blocking_handler",
- new BlockingResponseHandler(segment, statusCode, templateType, extraHeaders))
+ new BlockingResponseHandler(
+ segment, statusCode, templateType, extraHeaders, securityResponseId))
.addBefore(
"blocking_handler", "before_blocking_handler", new ChannelInboundHandlerAdapter());
} catch (RuntimeException rte) {
diff --git a/dd-java-agent/instrumentation/servlet/jakarta-servlet-5.0/src/main/java/datadog/trace/instrumentation/servlet5/JakartaServletBlockingHelper.java b/dd-java-agent/instrumentation/servlet/jakarta-servlet-5.0/src/main/java/datadog/trace/instrumentation/servlet5/JakartaServletBlockingHelper.java
index ee46c9efa42..0b3f5d649d4 100644
--- a/dd-java-agent/instrumentation/servlet/jakarta-servlet-5.0/src/main/java/datadog/trace/instrumentation/servlet5/JakartaServletBlockingHelper.java
+++ b/dd-java-agent/instrumentation/servlet/jakarta-servlet-5.0/src/main/java/datadog/trace/instrumentation/servlet5/JakartaServletBlockingHelper.java
@@ -22,7 +22,8 @@ public static void commitBlockingResponse(
HttpServletResponse resp,
int statusCode_,
BlockingContentType bct,
- Map extraHeaders) {
+ Map extraHeaders,
+ String securityResponseId) {
int statusCode = BlockingActionHelper.getHttpCode(statusCode_);
if (!start(resp, statusCode)) {
return;
@@ -37,7 +38,7 @@ public static void commitBlockingResponse(
String acceptHeader = httpServletRequest.getHeader("Accept");
BlockingActionHelper.TemplateType type =
BlockingActionHelper.determineTemplateType(bct, acceptHeader);
- template = BlockingActionHelper.getTemplate(type);
+ template = BlockingActionHelper.getTemplate(type, securityResponseId);
String contentType = BlockingActionHelper.getContentType(type);
resp.setHeader("Content-length", Integer.toString(template.length));
@@ -68,7 +69,8 @@ public static void commitBlockingResponse(
resp,
rba.getStatusCode(),
rba.getBlockingContentType(),
- rba.getExtraHeaders());
+ rba.getExtraHeaders(),
+ rba.getSecurityResponseId());
}
private static boolean start(HttpServletResponse resp, int statusCode) {
diff --git a/dd-java-agent/instrumentation/servlet/javax-servlet/javax-servlet-iast/src/main/java/datadog/trace/instrumentation/servlet/ServletBlockingHelper.java b/dd-java-agent/instrumentation/servlet/javax-servlet/javax-servlet-iast/src/main/java/datadog/trace/instrumentation/servlet/ServletBlockingHelper.java
index 48e51382c31..41e5bc73916 100644
--- a/dd-java-agent/instrumentation/servlet/javax-servlet/javax-servlet-iast/src/main/java/datadog/trace/instrumentation/servlet/ServletBlockingHelper.java
+++ b/dd-java-agent/instrumentation/servlet/javax-servlet/javax-servlet-iast/src/main/java/datadog/trace/instrumentation/servlet/ServletBlockingHelper.java
@@ -22,7 +22,8 @@ public static void commitBlockingResponse(
HttpServletResponse resp,
int statusCode_,
BlockingContentType bct,
- Map extraHeaders) {
+ Map extraHeaders,
+ String securityResponseId) {
int statusCode = BlockingActionHelper.getHttpCode(statusCode_);
if (!start(resp, statusCode)) {
return;
@@ -37,7 +38,7 @@ public static void commitBlockingResponse(
String acceptHeader = httpServletRequest.getHeader("Accept");
BlockingActionHelper.TemplateType type =
BlockingActionHelper.determineTemplateType(bct, acceptHeader);
- template = BlockingActionHelper.getTemplate(type);
+ template = BlockingActionHelper.getTemplate(type, securityResponseId);
String contentType = BlockingActionHelper.getContentType(type);
resp.setHeader("Content-length", Integer.toString(template.length));
@@ -69,7 +70,8 @@ public static void commitBlockingResponse(
resp,
rba.getStatusCode(),
rba.getBlockingContentType(),
- rba.getExtraHeaders());
+ rba.getExtraHeaders(),
+ rba.getSecurityResponseId());
}
private static boolean start(HttpServletResponse resp, int statusCode) {
diff --git a/dd-java-agent/instrumentation/spring/spring-webmvc/spring-webmvc-3.1/src/latestDepTest/groovy/test/SetupSpecHelper.groovy b/dd-java-agent/instrumentation/spring/spring-webmvc/spring-webmvc-3.1/src/latestDepTest/groovy/test/SetupSpecHelper.groovy
index b4fb296da8f..04912808d9b 100644
--- a/dd-java-agent/instrumentation/spring/spring-webmvc/spring-webmvc-3.1/src/latestDepTest/groovy/test/SetupSpecHelper.groovy
+++ b/dd-java-agent/instrumentation/spring/spring-webmvc/spring-webmvc-3.1/src/latestDepTest/groovy/test/SetupSpecHelper.groovy
@@ -41,11 +41,11 @@ class SetupSpecHelper {
INSTANCE
@Override
- boolean tryCommitBlockingResponse(TraceSegment segment, int statusCode, BlockingContentType templateType, Map extraHeaders) {
+ boolean tryCommitBlockingResponse(TraceSegment segment, int statusCode, BlockingContentType templateType, Map extraHeaders, String securityResponseId) {
ServletRequestAttributes attributes = RequestContextHolder.requestAttributes
if (attributes) {
ServletBlockingHelper
- .commitBlockingResponse(segment, attributes.request, attributes.response, statusCode, templateType, extraHeaders)
+ .commitBlockingResponse(segment, attributes.request, attributes.response, statusCode, templateType, extraHeaders, securityResponseId)
}
true
}
diff --git a/dd-java-agent/instrumentation/spring/spring-webmvc/spring-webmvc-3.1/src/test/groovy/test/SetupSpecHelper.groovy b/dd-java-agent/instrumentation/spring/spring-webmvc/spring-webmvc-3.1/src/test/groovy/test/SetupSpecHelper.groovy
index b4fb296da8f..04912808d9b 100644
--- a/dd-java-agent/instrumentation/spring/spring-webmvc/spring-webmvc-3.1/src/test/groovy/test/SetupSpecHelper.groovy
+++ b/dd-java-agent/instrumentation/spring/spring-webmvc/spring-webmvc-3.1/src/test/groovy/test/SetupSpecHelper.groovy
@@ -41,11 +41,11 @@ class SetupSpecHelper {
INSTANCE
@Override
- boolean tryCommitBlockingResponse(TraceSegment segment, int statusCode, BlockingContentType templateType, Map extraHeaders) {
+ boolean tryCommitBlockingResponse(TraceSegment segment, int statusCode, BlockingContentType templateType, Map extraHeaders, String securityResponseId) {
ServletRequestAttributes attributes = RequestContextHolder.requestAttributes
if (attributes) {
ServletBlockingHelper
- .commitBlockingResponse(segment, attributes.request, attributes.response, statusCode, templateType, extraHeaders)
+ .commitBlockingResponse(segment, attributes.request, attributes.response, statusCode, templateType, extraHeaders, securityResponseId)
}
true
}
diff --git a/dd-java-agent/instrumentation/spring/spring-webmvc/spring-webmvc-6.0/src/test/groovy/datadog/trace/instrumentation/springweb6/SetupSpecHelper.groovy b/dd-java-agent/instrumentation/spring/spring-webmvc/spring-webmvc-6.0/src/test/groovy/datadog/trace/instrumentation/springweb6/SetupSpecHelper.groovy
index fb13c29c96a..e409483dc6b 100644
--- a/dd-java-agent/instrumentation/spring/spring-webmvc/spring-webmvc-6.0/src/test/groovy/datadog/trace/instrumentation/springweb6/SetupSpecHelper.groovy
+++ b/dd-java-agent/instrumentation/spring/spring-webmvc/spring-webmvc-6.0/src/test/groovy/datadog/trace/instrumentation/springweb6/SetupSpecHelper.groovy
@@ -41,11 +41,11 @@ class SetupSpecHelper {
INSTANCE
@Override
- boolean tryCommitBlockingResponse(TraceSegment segment, int statusCode, BlockingContentType templateType, Map extraHeaders) {
+ boolean tryCommitBlockingResponse(TraceSegment segment, int statusCode, BlockingContentType templateType, Map extraHeaders, String securityResponseId) {
ServletRequestAttributes attributes = RequestContextHolder.requestAttributes
if (attributes) {
JakartaServletBlockingHelper
- .commitBlockingResponse(segment, attributes.request, attributes.response, statusCode, templateType, extraHeaders)
+ .commitBlockingResponse(segment, attributes.request, attributes.response, statusCode, templateType, extraHeaders, securityResponseId)
}
true
}
diff --git a/dd-java-agent/instrumentation/tomcat/tomcat-appsec/tomcat-appsec-7.0/src/main/java/datadog/trace/instrumentation/tomcat7/ErrorReportValueAdvice.java b/dd-java-agent/instrumentation/tomcat/tomcat-appsec/tomcat-appsec-7.0/src/main/java/datadog/trace/instrumentation/tomcat7/ErrorReportValueAdvice.java
index c92c217c02f..32ca712623b 100644
--- a/dd-java-agent/instrumentation/tomcat/tomcat-appsec/tomcat-appsec-7.0/src/main/java/datadog/trace/instrumentation/tomcat7/ErrorReportValueAdvice.java
+++ b/dd-java-agent/instrumentation/tomcat/tomcat-appsec/tomcat-appsec-7.0/src/main/java/datadog/trace/instrumentation/tomcat7/ErrorReportValueAdvice.java
@@ -48,7 +48,7 @@ public static void onEnter(
return;
}
- byte[] template = BlockingActionHelper.getTemplate(HTML);
+ byte[] template = BlockingActionHelper.getTemplate(HTML, null);
if (template == null) {
return;
}
diff --git a/dd-java-agent/instrumentation/tomcat/tomcat-common/src/main/java/datadog/trace/instrumentation/tomcat/TomcatBlockingHelper.java b/dd-java-agent/instrumentation/tomcat/tomcat-common/src/main/java/datadog/trace/instrumentation/tomcat/TomcatBlockingHelper.java
index 676c069883c..aab5ea6f0b0 100644
--- a/dd-java-agent/instrumentation/tomcat/tomcat-common/src/main/java/datadog/trace/instrumentation/tomcat/TomcatBlockingHelper.java
+++ b/dd-java-agent/instrumentation/tomcat/tomcat-common/src/main/java/datadog/trace/instrumentation/tomcat/TomcatBlockingHelper.java
@@ -42,7 +42,8 @@ public static void commitBlockingResponse(
resp,
rba.getStatusCode(),
rba.getBlockingContentType(),
- rba.getExtraHeaders());
+ rba.getExtraHeaders(),
+ rba.getSecurityResponseId());
}
public static boolean commitBlockingResponse(
@@ -51,7 +52,8 @@ public static boolean commitBlockingResponse(
Response resp,
int statusCode,
BlockingContentType templateType,
- Map extraHeaders) {
+ Map extraHeaders,
+ String securityResponseId) {
if (GET_OUTPUT_STREAM == null) {
return false;
}
@@ -70,9 +72,9 @@ public static boolean commitBlockingResponse(
try {
try {
- tryWriteWithOutputStream(request, resp, templateType);
+ tryWriteWithOutputStream(request, resp, templateType, securityResponseId);
} catch (IllegalStateException ise) {
- tryWriteWithWriter(request, resp, templateType);
+ tryWriteWithWriter(request, resp, templateType, securityResponseId);
}
segment.effectivelyBlocked();
} catch (Throwable e) {
@@ -82,12 +84,13 @@ public static boolean commitBlockingResponse(
}
private static void tryWriteWithOutputStream(
- Request request, Response resp, BlockingContentType templateType) throws Throwable {
+ Request request, Response resp, BlockingContentType templateType, String securityResponseId)
+ throws Throwable {
OutputStream os = (OutputStream) GET_OUTPUT_STREAM.invoke(resp);
if (templateType != BlockingContentType.NONE) {
TemplateType type =
BlockingActionHelper.determineTemplateType(templateType, request.getHeader("Accept"));
- byte[] template = BlockingActionHelper.getTemplate(type);
+ byte[] template = BlockingActionHelper.getTemplate(type, securityResponseId);
resp.setHeader("Content-length", Integer.toString(template.length));
resp.setHeader("Content-type", BlockingActionHelper.getContentType(type));
@@ -97,12 +100,13 @@ private static void tryWriteWithOutputStream(
}
private static void tryWriteWithWriter(
- Request request, Response resp, BlockingContentType templateType) throws IOException {
+ Request request, Response resp, BlockingContentType templateType, String securityResponseId)
+ throws IOException {
PrintWriter writer = resp.getWriter();
if (templateType != BlockingContentType.NONE) {
TemplateType type =
BlockingActionHelper.determineTemplateType(templateType, request.getHeader("Accept"));
- byte[] template = BlockingActionHelper.getTemplate(type);
+ byte[] template = BlockingActionHelper.getTemplate(type, securityResponseId);
String templateStr = new String(template, StandardCharsets.UTF_8);
resp.setHeader("Content-length", Integer.toString(template.length));
diff --git a/dd-java-agent/instrumentation/tomcat/tomcat-common/src/main/java/datadog/trace/instrumentation/tomcat/TomcatDecorator.java b/dd-java-agent/instrumentation/tomcat/tomcat-common/src/main/java/datadog/trace/instrumentation/tomcat/TomcatDecorator.java
index 8beb6991b45..7d20ed65e15 100644
--- a/dd-java-agent/instrumentation/tomcat/tomcat-common/src/main/java/datadog/trace/instrumentation/tomcat/TomcatDecorator.java
+++ b/dd-java-agent/instrumentation/tomcat/tomcat-common/src/main/java/datadog/trace/instrumentation/tomcat/TomcatDecorator.java
@@ -155,9 +155,16 @@ public boolean tryCommitBlockingResponse(
TraceSegment segment,
int statusCode,
BlockingContentType bct,
- Map extraHeaders) {
+ Map extraHeaders,
+ String securityResponseId) {
return TomcatBlockingHelper.commitBlockingResponse(
- segment, request, request.getResponse(), statusCode, bct, extraHeaders);
+ segment,
+ request,
+ request.getResponse(),
+ statusCode,
+ bct,
+ extraHeaders,
+ securityResponseId);
}
}
}
diff --git a/dd-java-agent/instrumentation/undertow/src/main/java/datadog/trace/instrumentation/undertow/UndertowBlockResponseFunction.java b/dd-java-agent/instrumentation/undertow/src/main/java/datadog/trace/instrumentation/undertow/UndertowBlockResponseFunction.java
index 20440c188d4..1e74d63bc93 100644
--- a/dd-java-agent/instrumentation/undertow/src/main/java/datadog/trace/instrumentation/undertow/UndertowBlockResponseFunction.java
+++ b/dd-java-agent/instrumentation/undertow/src/main/java/datadog/trace/instrumentation/undertow/UndertowBlockResponseFunction.java
@@ -19,9 +19,11 @@ public boolean tryCommitBlockingResponse(
TraceSegment segment,
int statusCode,
BlockingContentType templateType,
- Map extraHeaders) {
+ Map extraHeaders,
+ String securityResponseId) {
Flow.Action.RequestBlockingAction rab =
- new Flow.Action.RequestBlockingAction(statusCode, templateType, extraHeaders);
+ new Flow.Action.RequestBlockingAction(
+ statusCode, templateType, extraHeaders, securityResponseId);
exchange.putAttachment(UndertowBlockingHandler.TRACE_SEGMENT, segment);
exchange.putAttachment(UndertowBlockingHandler.REQUEST_BLOCKING_DATA, rab);
if (exchange.isInIoThread()) {
diff --git a/dd-java-agent/instrumentation/undertow/src/main/java/datadog/trace/instrumentation/undertow/UndertowBlockingHandler.java b/dd-java-agent/instrumentation/undertow/src/main/java/datadog/trace/instrumentation/undertow/UndertowBlockingHandler.java
index 9435d3df277..d8be722a514 100644
--- a/dd-java-agent/instrumentation/undertow/src/main/java/datadog/trace/instrumentation/undertow/UndertowBlockingHandler.java
+++ b/dd-java-agent/instrumentation/undertow/src/main/java/datadog/trace/instrumentation/undertow/UndertowBlockingHandler.java
@@ -65,7 +65,7 @@ private static void commitBlockingResponse(
String acceptHeader = acceptHeaderValues != null ? acceptHeaderValues.peekLast() : null;
BlockingActionHelper.TemplateType type =
BlockingActionHelper.determineTemplateType(rba.getBlockingContentType(), acceptHeader);
- byte[] template = BlockingActionHelper.getTemplate(type);
+ byte[] template = BlockingActionHelper.getTemplate(type, rba.getSecurityResponseId());
headers.add(Headers.CONTENT_LENGTH, Integer.toString(template.length));
headers.add(Headers.CONTENT_TYPE, BlockingActionHelper.getContentType(type));
diff --git a/dd-smoke-tests/appsec/springboot/src/test/groovy/datadog/smoketest/appsec/SecurityResponseIdSmokeTest.groovy b/dd-smoke-tests/appsec/springboot/src/test/groovy/datadog/smoketest/appsec/SecurityResponseIdSmokeTest.groovy
new file mode 100644
index 00000000000..3f3e46eb6c6
--- /dev/null
+++ b/dd-smoke-tests/appsec/springboot/src/test/groovy/datadog/smoketest/appsec/SecurityResponseIdSmokeTest.groovy
@@ -0,0 +1,327 @@
+package datadog.smoketest.appsec
+
+import datadog.trace.agent.test.utils.OkHttpUtils
+import okhttp3.Request
+import spock.lang.Shared
+
+import java.util.regex.Pattern
+
+class SecurityResponseIdSmokeTest extends AbstractAppSecServerSmokeTest {
+
+ @Shared
+ String buildDir = new File(System.getProperty("datadog.smoketest.builddir")).absolutePath
+ @Shared
+ String customRulesPath = "${buildDir}/appsec_blockid_rules.json"
+
+ // UUID v4 pattern: 8-4-4-4-12 hexadecimal characters
+ private static final Pattern UUID_PATTERN = Pattern.compile(
+ '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}'
+ )
+
+ def prepareCustomConfiguration() {
+ // Create custom rules with custom actions to test security_response_id
+ def customRules = [
+ [
+ id: '__test_security_response_id_trigger',
+ name: 'Security Response ID Test Rule',
+ tags: [
+ type: 'block_test',
+ category: 'attack_attempt'
+ ],
+ conditions: [
+ [
+ parameters: [
+ inputs: [[address: 'server.request.headers.no_cookies']],
+ key_path: ['user-agent'],
+ regex: 'SecurityResponseIdTestAgent.*'
+ ],
+ operator: 'match_regex'
+ ]
+ ],
+ transformers: ['lowercase'],
+ on_match: ['block_action']
+ ],
+ [
+ id: '__test_security_response_id_redirect_no_placeholder',
+ name: 'Security Response ID Redirect Test Rule Without Placeholder',
+ tags: [
+ type: 'redirect_test_no_placeholder',
+ category: 'attack_attempt'
+ ],
+ conditions: [
+ [
+ parameters: [
+ inputs: [[address: 'server.request.headers.no_cookies']],
+ key_path: ['user-agent'],
+ regex: 'RedirectTestAgent.*'
+ ],
+ operator: 'match_regex'
+ ]
+ ],
+ transformers: ['lowercase'],
+ on_match: ['redirect_action_no_placeholder']
+ ]
+ ]
+
+ def customActions = [
+ [
+ id: 'block_action',
+ type: 'block_request',
+ parameters: [
+ status_code: 403,
+ type: 'auto'
+ ]
+ ],
+ [
+ id: 'redirect_action_no_placeholder',
+ type: 'redirect_request',
+ parameters: [
+ status_code: 303,
+ location: 'https://custom.example.com/redirect'
+ ]
+ ]
+ ]
+
+ // Write the custom configuration using mergeRules
+ mergeRules(customRulesPath, customRules, customActions)
+ }
+
+ @Override
+ ProcessBuilder createProcessBuilder() {
+ // Prepare custom configuration before starting the process
+ prepareCustomConfiguration()
+
+ String springBootShadowJar = System.getProperty("datadog.smoketest.appsec.springboot.shadowJar.path")
+
+ List command = new ArrayList<>()
+ command.add(javaPath())
+ command.addAll(defaultJavaProperties)
+ command.addAll(defaultAppSecProperties)
+ command.addAll((String[]) ["-jar", springBootShadowJar, "--server.port=${httpPort}"])
+
+ ProcessBuilder processBuilder = new ProcessBuilder(command)
+ processBuilder.directory(new File(buildDirectory))
+ }
+
+ void 'test security_response_id is present in JSON blocking response'() {
+ setup:
+ // Clear previous traces/spans from other tests
+ rootSpans.clear()
+
+ and: 'a request that triggers blocking'
+ def url = "http://localhost:${httpPort}/greeting"
+ def client = OkHttpUtils.clientBuilder().build()
+ def request = new Request.Builder()
+ .url(url)
+ .header('User-Agent', 'SecurityResponseIdTestAgent/1.0')
+ .header('Accept', 'application/json')
+ .get()
+ .build()
+
+ when: 'the request is sent'
+ def response = client.newCall(request).execute()
+
+ then: 'the request is blocked with 403'
+ response.code() == 403
+
+ and: 'the response is JSON'
+ response.header('Content-Type').contains('application/json')
+
+ and: 'the response body contains security_response_id with valid UUID format'
+ def body = response.body().string()
+ body.contains('"security_response_id"')
+ def matcher = UUID_PATTERN.matcher(body)
+ assert matcher.find(), "security_response_id with valid UUID format not found in response: ${body}"
+ def securityResponseIdFromResponse = matcher.group()
+
+ // Verify it's in the expected JSON structure
+ body.contains('"errors"')
+ body.contains('"You\'ve been blocked"')
+
+ and: 'the trace contains the same security_response_id in _dd.appsec.json triggers'
+ waitForTraceCount(1) == 1
+ rootSpans.size() == 1
+ def rootSpan = rootSpans.first()
+ assert rootSpan != null, "Root span not found in trace"
+
+ def appsecJson = rootSpan.meta?.'_dd.appsec.json'
+ assert appsecJson != null, "_dd.appsec.json not found in trace"
+
+ // Parse the appsec JSON to verify security_response_id is in the trigger
+ def appsecData = new groovy.json.JsonSlurper().parseText(appsecJson)
+ assert appsecData.triggers != null && !appsecData.triggers.isEmpty(), "No triggers found in _dd.appsec.json: ${appsecJson}"
+ def trigger = appsecData.triggers[0]
+ assert trigger.security_response_id != null, "security_response_id not found in trigger: ${appsecJson}"
+ assert trigger.security_response_id == securityResponseIdFromResponse, "security_response_id in trace (${trigger.security_response_id}) does not match response (${securityResponseIdFromResponse})"
+ assert UUID_PATTERN.matcher(trigger.security_response_id).matches(), "security_response_id in trace is not a valid UUID: ${trigger.security_response_id}"
+ }
+
+ void 'test security_response_id is present in HTML blocking response'() {
+ setup:
+ // Clear previous traces/spans from other tests
+ rootSpans.clear()
+
+ and: 'a request that triggers blocking'
+ def url = "http://localhost:${httpPort}/greeting"
+ def client = OkHttpUtils.clientBuilder().build()
+ def request = new Request.Builder()
+ .url(url)
+ .header('User-Agent', 'SecurityResponseIdTestAgent/1.0')
+ .header('Accept', 'text/html')
+ .get()
+ .build()
+
+ when: 'the request is sent'
+ def response = client.newCall(request).execute()
+
+ then: 'the request is blocked with 403'
+ response.code() == 403
+
+ and: 'the response is HTML'
+ response.header('Content-Type').contains('text/html')
+
+ and: 'the response body contains security_response_id with valid UUID format'
+ def body = response.body().string()
+ body.contains('Security Response ID:')
+ def matcher = UUID_PATTERN.matcher(body)
+ assert matcher.find(), "security_response_id with valid UUID format not found in response: ${body}"
+ def securityResponseIdFromResponse = matcher.group()
+
+ // Verify the placeholder [security_response_id] was replaced (should not be present)
+ assert !body.contains('[security_response_id]'), "Placeholder [security_response_id] was not replaced in HTML response"
+
+ // Verify it's in the expected HTML structure
+ body.contains('You\'ve been blocked')
+ body.contains(' extraHeaders);
+ Map extraHeaders,
+ String securityResponseId);
/**
* Commits blocking response using a RequestBlockingAction.
@@ -30,12 +31,17 @@ boolean tryCommitBlockingResponse(
* finished.
*
* @param segment the trace segment
- * @param action the blocking action containing status code, content type, and headers
+ * @param action the blocking action containing status code, content type, headers, and security
+ * response ID
* @return true unless blocking could not be attempted
*/
default boolean tryCommitBlockingResponse(
TraceSegment segment, Flow.Action.RequestBlockingAction action) {
return tryCommitBlockingResponse(
- segment, action.getStatusCode(), action.getBlockingContentType(), action.getExtraHeaders());
+ segment,
+ action.getStatusCode(),
+ action.getBlockingContentType(),
+ action.getExtraHeaders(),
+ action.getSecurityResponseId());
}
}
diff --git a/internal-api/src/main/java/datadog/trace/api/gateway/Flow.java b/internal-api/src/main/java/datadog/trace/api/gateway/Flow.java
index 2ee300568f0..06a14359400 100644
--- a/internal-api/src/main/java/datadog/trace/api/gateway/Flow.java
+++ b/internal-api/src/main/java/datadog/trace/api/gateway/Flow.java
@@ -32,23 +32,36 @@ class RequestBlockingAction implements Action {
private final int statusCode;
private final BlockingContentType blockingContentType;
private final Map extraHeaders;
+ private final String securityResponseId;
public RequestBlockingAction(
int statusCode,
BlockingContentType blockingContentType,
Map extraHeaders) {
+ this(statusCode, blockingContentType, extraHeaders, null);
+ }
+
+ public RequestBlockingAction(
+ int statusCode,
+ BlockingContentType blockingContentType,
+ Map extraHeaders,
+ String securityResponseId) {
this.statusCode = statusCode;
this.blockingContentType = blockingContentType;
this.extraHeaders = extraHeaders;
+ this.securityResponseId = securityResponseId;
}
public RequestBlockingAction(int statusCode, BlockingContentType blockingContentType) {
- this(statusCode, blockingContentType, Collections.emptyMap());
+ this(statusCode, blockingContentType, Collections.emptyMap(), null);
}
public static RequestBlockingAction forRedirect(int statusCode, String location) {
return new RequestBlockingAction(
- statusCode, BlockingContentType.NONE, Collections.singletonMap("Location", location));
+ statusCode,
+ BlockingContentType.NONE,
+ Collections.singletonMap("Location", location),
+ null);
}
@Override
@@ -67,6 +80,10 @@ public BlockingContentType getBlockingContentType() {
public Map getExtraHeaders() {
return extraHeaders;
}
+
+ public String getSecurityResponseId() {
+ return securityResponseId;
+ }
}
}