Skip to content

Commit 4b319d7

Browse files
authored
SAML: Process only signed data (#30420)
As conformance to best practices, this changes ensures that if a SAML Response is signed, we verify the signature before processing it any further. We were only checking the InResponseTo and Destination attributes before potential signature validation but there was no reason to do that up front either.
1 parent bf2365d commit 4b319d7

File tree

1 file changed

+12
-14
lines changed

1 file changed

+12
-14
lines changed

x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/saml/SamlAuthenticator.java

+12-14
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,14 @@ private SamlAttributes authenticateResponse(Element element, Collection<String>
8787
if (logger.isTraceEnabled()) {
8888
logger.trace(SamlUtils.describeSamlObject(response));
8989
}
90+
final boolean requireSignedAssertions;
91+
if (response.isSigned()) {
92+
validateSignature(response.getSignature());
93+
requireSignedAssertions = false;
94+
} else {
95+
requireSignedAssertions = true;
96+
}
97+
9098
if (Strings.hasText(response.getInResponseTo()) && allowedSamlRequestIds.contains(response.getInResponseTo()) == false) {
9199
logger.debug("The SAML Response with ID {} is unsolicited. A user might have used a stale URL or the Identity Provider " +
92100
"incorrectly populates the InResponseTo attribute", response.getID());
@@ -102,10 +110,10 @@ private SamlAttributes authenticateResponse(Element element, Collection<String>
102110
throw samlException("SAML Response is not a 'success' response: Code={} Message={} Detail={}",
103111
status.getStatusCode().getValue(), getMessage(status), getDetail(status));
104112
}
105-
113+
checkIssuer(response.getIssuer(), response);
106114
checkResponseDestination(response);
107115

108-
Tuple<Assertion, List<Attribute>> details = extractDetails(response, allowedSamlRequestIds);
116+
Tuple<Assertion, List<Attribute>> details = extractDetails(response, allowedSamlRequestIds, requireSignedAssertions);
109117
final Assertion assertion = details.v1();
110118
final SamlNameId nameId = SamlNameId.forSubject(assertion.getSubject());
111119
final String session = getSessionIndex(assertion);
@@ -156,17 +164,8 @@ private void checkResponseDestination(Response response) {
156164
}
157165
}
158166

159-
private Tuple<Assertion, List<Attribute>> extractDetails(Response response, Collection<String> allowedSamlRequestIds) {
160-
final boolean requireSignedAssertions;
161-
if (response.isSigned()) {
162-
validateSignature(response.getSignature());
163-
requireSignedAssertions = false;
164-
} else {
165-
requireSignedAssertions = true;
166-
}
167-
168-
checkIssuer(response.getIssuer(), response);
169-
167+
private Tuple<Assertion, List<Attribute>> extractDetails(Response response, Collection<String> allowedSamlRequestIds,
168+
boolean requireSignedAssertions) {
170169
final int assertionCount = response.getAssertions().size() + response.getEncryptedAssertions().size();
171170
if (assertionCount > 1) {
172171
throw samlException("Expecting only 1 assertion, but response contains multiple (" + assertionCount + ")");
@@ -328,5 +327,4 @@ private void checkLifetimeRestrictions(Conditions conditions) {
328327
private void checkLifetimeRestrictions(SubjectConfirmationData subjectConfirmationData) {
329328
validateNotOnOrAfter(subjectConfirmationData.getNotOnOrAfter());
330329
}
331-
332330
}

0 commit comments

Comments
 (0)