浏览代码

Add Response Status Check

Closes gh-9718
Josh Cummings 4 年之前
父节点
当前提交
457c2a2d06

+ 1 - 1
saml2/saml2-service-provider/opensaml3/src/test/java/org/springframework/security/saml2/provider/service/authentication/OpenSamlAuthenticationProviderTests.java

@@ -573,7 +573,7 @@ public class OpenSamlAuthenticationProviderTests {
 		Saml2AuthenticationToken token = token(response, verifying(registration()));
 		assertThatExceptionOfType(Saml2AuthenticationException.class)
 				.isThrownBy(() -> this.provider.authenticate(token))
-				.satisfies(errorOf(Saml2ErrorCodes.INVALID_RESPONSE));
+				.satisfies(errorOf(Saml2ErrorCodes.INVALID_RESPONSE, "Invalid status"));
 	}
 
 	@Test

+ 17 - 0
saml2/saml2-service-provider/opensaml4/src/main/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml4AuthenticationProvider.java

@@ -61,6 +61,7 @@ import org.opensaml.saml.saml2.core.Condition;
 import org.opensaml.saml.saml2.core.EncryptedAssertion;
 import org.opensaml.saml.saml2.core.OneTimeUse;
 import org.opensaml.saml.saml2.core.Response;
+import org.opensaml.saml.saml2.core.StatusCode;
 import org.opensaml.saml.saml2.core.SubjectConfirmation;
 import org.opensaml.saml.saml2.core.impl.ResponseUnmarshaller;
 import org.opensaml.saml.saml2.encryption.Decrypter;
@@ -491,6 +492,12 @@ public final class OpenSaml4AuthenticationProvider implements AuthenticationProv
 			Response response = responseToken.getResponse();
 			Saml2AuthenticationToken token = responseToken.getToken();
 			Saml2ResponseValidatorResult result = Saml2ResponseValidatorResult.success();
+			String statusCode = getStatusCode(response);
+			if (!StatusCode.SUCCESS.equals(statusCode)) {
+				String message = String.format("Invalid status [%s] for SAML response [%s]", statusCode,
+						response.getID());
+				result = result.concat(new Saml2Error(Saml2ErrorCodes.INVALID_RESPONSE, message));
+			}
 			String issuer = response.getIssuer().getValue();
 			String destination = response.getDestination();
 			String location = token.getRelyingPartyRegistration().getAssertionConsumerServiceLocation();
@@ -513,6 +520,16 @@ public final class OpenSaml4AuthenticationProvider implements AuthenticationProv
 		};
 	}
 
+	private String getStatusCode(Response response) {
+		if (response.getStatus() == null) {
+			return StatusCode.SUCCESS;
+		}
+		if (response.getStatus().getStatusCode() == null) {
+			return StatusCode.SUCCESS;
+		}
+		return response.getStatus().getStatusCode().getValue();
+	}
+
 	private Converter<AssertionToken, Saml2ResponseValidatorResult> createDefaultAssertionSignatureValidator() {
 		return createAssertionValidator(Saml2ErrorCodes.INVALID_SIGNATURE, (assertionToken) -> {
 			RelyingPartyRegistration registration = assertionToken.getToken().getRelyingPartyRegistration();

+ 20 - 0
saml2/saml2-service-provider/opensaml4/src/test/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml4AuthenticationProviderTests.java

@@ -52,6 +52,7 @@ import org.opensaml.saml.saml2.core.EncryptedID;
 import org.opensaml.saml.saml2.core.NameID;
 import org.opensaml.saml.saml2.core.OneTimeUse;
 import org.opensaml.saml.saml2.core.Response;
+import org.opensaml.saml.saml2.core.StatusCode;
 import org.opensaml.saml.saml2.core.SubjectConfirmation;
 import org.opensaml.saml.saml2.core.SubjectConfirmationData;
 import org.opensaml.saml.saml2.core.impl.AttributeBuilder;
@@ -565,6 +566,25 @@ public class OpenSaml4AuthenticationProviderTests {
 		assertThat(authentication.getName()).isEqualTo("decrypted name");
 	}
 
+	@Test
+	public void authenticateWhenResponseStatusIsNotSuccessThenFails() {
+		Response response = TestOpenSamlObjects.signedResponseWithOneAssertion(
+				(r) -> r.setStatus(TestOpenSamlObjects.status(StatusCode.AUTHN_FAILED)));
+		Saml2AuthenticationToken token = token(response, verifying(registration()));
+		assertThatExceptionOfType(Saml2AuthenticationException.class)
+				.isThrownBy(() -> this.provider.authenticate(token))
+				.satisfies(errorOf(Saml2ErrorCodes.INVALID_RESPONSE, "Invalid status"));
+	}
+
+	@Test
+	public void authenticateWhenResponseStatusIsSuccessThenSucceeds() {
+		Response response = TestOpenSamlObjects
+				.signedResponseWithOneAssertion((r) -> r.setStatus(TestOpenSamlObjects.successStatus()));
+		Saml2AuthenticationToken token = token(response, verifying(registration()));
+		Authentication authentication = this.provider.authenticate(token);
+		assertThat(authentication.getName()).isEqualTo("test@saml.user");
+	}
+
 	private <T extends XMLObject> T build(QName qName) {
 		return (T) XMLObjectProviderRegistrySupport.getBuilderFactory().getBuilder(qName).buildObject(qName);
 	}