From d0f762f9a4051d6c65c4ab661690f57d5da77db0 Mon Sep 17 00:00:00 2001 From: YoungKi Hong Date: Wed, 13 Mar 2024 23:50:59 +0900 Subject: [PATCH 1/5] [ISSUE-11725] Add secondary statusCode messages on error --- .../OpenSaml4AuthenticationProvider.java | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml4AuthenticationProvider.java b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml4AuthenticationProvider.java index 83ad3cace45..91c0ef43b06 100644 --- a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml4AuthenticationProvider.java +++ b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml4AuthenticationProvider.java @@ -26,6 +26,9 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.Set; +import java.util.HashSet; +import java.util.Arrays; import java.util.function.Consumer; import javax.annotation.Nonnull; @@ -94,6 +97,8 @@ import org.springframework.util.MultiValueMap; import org.springframework.util.StringUtils; +import static org.opensaml.saml.saml2.core.StatusCode.*; + /** * Implementation of {@link AuthenticationProvider} for SAML authentications when * receiving a {@code Response} object containing an {@code Assertion}. This @@ -621,7 +626,17 @@ private static String getStatusCode(Response response) { if (response.getStatus().getStatusCode() == null) { return StatusCode.SUCCESS; } - return response.getStatus().getStatusCode().getValue(); + + Set statusCodes = new HashSet<>(Arrays.asList(REQUESTER, RESPONDER, VERSION_MISMATCH)); + StatusCode parentStatusCode = response.getStatus().getStatusCode(); + String parentStatusCodeValue = parentStatusCode.getValue(); + if (statusCodes.contains(parentStatusCodeValue)) { + StatusCode childStatusCode = parentStatusCode.getStatusCode(); + String childStatusCodeValue = childStatusCode.getValue(); + return parentStatusCodeValue + childStatusCodeValue; + } + + return parentStatusCodeValue; } private Converter createDefaultAssertionSignatureValidator() { From 75b669b109d4dd15fe65cfab5e698e88c4518a3b Mon Sep 17 00:00:00 2001 From: youngkih Date: Sat, 16 Mar 2024 21:58:26 +0900 Subject: [PATCH 2/5] Use Optional in case child status code is null --- .../OpenSaml4AuthenticationProvider.java | 43 ++++++++++--------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml4AuthenticationProvider.java b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml4AuthenticationProvider.java index 91c0ef43b06..5ca2bbcc5c2 100644 --- a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml4AuthenticationProvider.java +++ b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml4AuthenticationProvider.java @@ -29,6 +29,7 @@ import java.util.Set; import java.util.HashSet; import java.util.Arrays; +import java.util.Optional; import java.util.function.Consumer; import javax.annotation.Nonnull; @@ -173,6 +174,8 @@ public final class OpenSaml4AuthenticationProvider implements AuthenticationProv private Converter responseAuthenticationConverter = createDefaultResponseAuthenticationConverter(); + private static final Set includeChildStatusCodes = new HashSet<>(Arrays.asList(REQUESTER, RESPONDER, VERSION_MISMATCH)); + /** * Creates an {@link OpenSaml4AuthenticationProvider} */ @@ -409,6 +412,26 @@ public static Converter createDefau }; } + private static String getStatusCode(Response response) { + if (response.getStatus() == null) { + return StatusCode.SUCCESS; + } + if (response.getStatus().getStatusCode() == null) { + return StatusCode.SUCCESS; + } + + StatusCode parentStatusCode = response.getStatus().getStatusCode(); + String parentStatusCodeValue = parentStatusCode.getValue(); + if (includeChildStatusCodes.contains(parentStatusCodeValue)) { + return Optional.ofNullable(parentStatusCode.getStatusCode()) + .map(StatusCode::getValue) + .map(childStatusCodeValue -> parentStatusCodeValue + childStatusCodeValue) + .orElse(parentStatusCodeValue); + } + + return parentStatusCodeValue; + } + private static Saml2ResponseValidatorResult validateInResponseTo(AbstractSaml2AuthenticationRequest storedRequest, String inResponseTo) { if (!StringUtils.hasText(inResponseTo)) { @@ -619,26 +642,6 @@ private Consumer createDefaultResponseElementsDecrypter() { }; } - private static String getStatusCode(Response response) { - if (response.getStatus() == null) { - return StatusCode.SUCCESS; - } - if (response.getStatus().getStatusCode() == null) { - return StatusCode.SUCCESS; - } - - Set statusCodes = new HashSet<>(Arrays.asList(REQUESTER, RESPONDER, VERSION_MISMATCH)); - StatusCode parentStatusCode = response.getStatus().getStatusCode(); - String parentStatusCodeValue = parentStatusCode.getValue(); - if (statusCodes.contains(parentStatusCodeValue)) { - StatusCode childStatusCode = parentStatusCode.getStatusCode(); - String childStatusCodeValue = childStatusCode.getValue(); - return parentStatusCodeValue + childStatusCodeValue; - } - - return parentStatusCodeValue; - } - private Converter createDefaultAssertionSignatureValidator() { return createAssertionValidator(Saml2ErrorCodes.INVALID_SIGNATURE, (assertionToken) -> { RelyingPartyRegistration registration = assertionToken.getToken().getRelyingPartyRegistration(); From eedb3770f7003aca970b18d9bc8bb77f273073fb Mon Sep 17 00:00:00 2001 From: youngkih Date: Sat, 16 Mar 2024 22:01:58 +0900 Subject: [PATCH 3/5] Update copywrite to 2024 --- .../service/authentication/OpenSaml4AuthenticationProvider.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml4AuthenticationProvider.java b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml4AuthenticationProvider.java index 5ca2bbcc5c2..af362b2d56e 100644 --- a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml4AuthenticationProvider.java +++ b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml4AuthenticationProvider.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2023 the original author or authors. + * Copyright 2002-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. From 42e1843e78e7d26c21230c365010560c0a48a150 Mon Sep 17 00:00:00 2001 From: youngkih Date: Sat, 16 Mar 2024 23:49:57 +0900 Subject: [PATCH 4/5] Add test for status code returning parent and child status code --- .../OpenSaml4AuthenticationProviderTests.java | 77 +++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/saml2/saml2-service-provider/src/test/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml4AuthenticationProviderTests.java b/saml2/saml2-service-provider/src/test/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml4AuthenticationProviderTests.java index eccc42693f8..53aeaba17f7 100644 --- a/saml2/saml2-service-provider/src/test/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml4AuthenticationProviderTests.java +++ b/saml2/saml2-service-provider/src/test/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml4AuthenticationProviderTests.java @@ -51,9 +51,11 @@ import org.opensaml.saml.saml2.core.EncryptedAssertion; import org.opensaml.saml.saml2.core.EncryptedAttribute; import org.opensaml.saml.saml2.core.EncryptedID; +import org.opensaml.saml.saml2.core.Issuer; 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.Status; import org.opensaml.saml.saml2.core.StatusCode; import org.opensaml.saml.saml2.core.SubjectConfirmation; import org.opensaml.saml.saml2.core.SubjectConfirmationData; @@ -61,6 +63,8 @@ import org.opensaml.saml.saml2.core.impl.EncryptedAssertionBuilder; import org.opensaml.saml.saml2.core.impl.EncryptedIDBuilder; import org.opensaml.saml.saml2.core.impl.NameIDBuilder; +import org.opensaml.saml.saml2.core.impl.StatusBuilder; +import org.opensaml.saml.saml2.core.impl.StatusCodeBuilder; import org.opensaml.xmlsec.encryption.impl.EncryptedDataBuilder; import org.opensaml.xmlsec.signature.support.SignatureConstants; import org.w3c.dom.Element; @@ -82,6 +86,8 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.atLeastOnce; @@ -729,6 +735,77 @@ public void authenticateWhenCustomResponseValidatorThenUses() { verify(validator).convert(any(OpenSaml4AuthenticationProvider.ResponseToken.class)); } + @Test + public void setsOnlyParentStatusCodeOnResultDescription() { + ResponseToken mockResponseToken = mock(ResponseToken.class); + Saml2AuthenticationToken mockSamlToken = mock(Saml2AuthenticationToken.class); + given(mockResponseToken.getToken()).willReturn(mockSamlToken); + + RelyingPartyRegistration mockRelyingPartyRegistration = mock(RelyingPartyRegistration.class); + given(mockSamlToken.getRelyingPartyRegistration()).willReturn(mockRelyingPartyRegistration); + + RelyingPartyRegistration.AssertingPartyDetails mockAssertingPartyDetails = mock(RelyingPartyRegistration.AssertingPartyDetails.class); + given(mockRelyingPartyRegistration.getAssertingPartyDetails()).willReturn(mockAssertingPartyDetails); + + Status parentStatus = new StatusBuilder().buildObject(); + StatusCode parentStatusCode = new StatusCodeBuilder().buildObject(); + parentStatusCode.setValue(StatusCode.AUTHN_FAILED); + StatusCode childStatusCode = new StatusCodeBuilder().buildObject(); + childStatusCode.setValue(StatusCode.NO_PASSIVE); + parentStatusCode.setStatusCode(childStatusCode); + parentStatus.setStatusCode(parentStatusCode); + + Response mockResponse = mock(Response.class); + given(mockResponse.getStatus()).willReturn(parentStatus); + Issuer mockIssuer = mock(Issuer.class); + given(mockIssuer.getValue()).willReturn("mockedIssuer"); + given(mockResponse.getIssuer()).willReturn(mockIssuer); + + given(mockResponseToken.getResponse()).willReturn(mockResponse); + + Converter validator = OpenSaml4AuthenticationProvider.createDefaultResponseValidator(); + Saml2ResponseValidatorResult result = validator.convert(mockResponseToken); + + String expectedErrorMessage = String.format("Invalid status [%s] for SAML response", parentStatusCode.getValue()); + assertTrue(result.getErrors().stream().anyMatch(error -> error.getDescription().contains(expectedErrorMessage))); + assertFalse(result.getErrors().stream().anyMatch(error -> error.getDescription().contains(childStatusCode.getValue()))); + } + + @Test + public void setsParentAndChildStatusCodeOnResultDescription() { + ResponseToken mockResponseToken = mock(ResponseToken.class); + Saml2AuthenticationToken mockSamlToken = mock(Saml2AuthenticationToken.class); + given(mockResponseToken.getToken()).willReturn(mockSamlToken); + + RelyingPartyRegistration mockRelyingPartyRegistration = mock(RelyingPartyRegistration.class); + given(mockSamlToken.getRelyingPartyRegistration()).willReturn(mockRelyingPartyRegistration); + + RelyingPartyRegistration.AssertingPartyDetails mockAssertingPartyDetails = mock(RelyingPartyRegistration.AssertingPartyDetails.class); + given(mockRelyingPartyRegistration.getAssertingPartyDetails()).willReturn(mockAssertingPartyDetails); + + Status parentStatus = new StatusBuilder().buildObject(); + StatusCode parentStatusCode = new StatusCodeBuilder().buildObject(); + parentStatusCode.setValue(StatusCode.REQUESTER); + StatusCode childStatusCode = new StatusCodeBuilder().buildObject(); + childStatusCode.setValue(StatusCode.NO_PASSIVE); + parentStatusCode.setStatusCode(childStatusCode); + parentStatus.setStatusCode(parentStatusCode); + + Response mockResponse = mock(Response.class); + given(mockResponse.getStatus()).willReturn(parentStatus); + Issuer mockIssuer = mock(Issuer.class); + given(mockIssuer.getValue()).willReturn("mockedIssuer"); + given(mockResponse.getIssuer()).willReturn(mockIssuer); + + given(mockResponseToken.getResponse()).willReturn(mockResponse); + + Converter validator = OpenSaml4AuthenticationProvider.createDefaultResponseValidator(); + Saml2ResponseValidatorResult result = validator.convert(mockResponseToken); + + String expectedErrorMessage = String.format("Invalid status [%s] for SAML response", parentStatusCode.getValue() + childStatusCode.getValue()); + assertTrue(result.getErrors().stream().anyMatch(error -> error.getDescription().contains(expectedErrorMessage))); + } + @Test public void authenticateWhenAssertionIssuerNotValidThenFailsWithInvalidIssuer() { OpenSaml4AuthenticationProvider provider = new OpenSaml4AuthenticationProvider(); From 7877b3874aec2ea5acbd20e59f04a97e641b0107 Mon Sep 17 00:00:00 2001 From: YoungKi Hong Date: Thu, 21 Mar 2024 23:56:03 +0900 Subject: [PATCH 5/5] Update to return List of StatusCodes and add Saml2Error to result object and other formatting --- .../OpenSaml4AuthenticationProvider.java | 51 ++++++++++++------- .../OpenSaml4AuthenticationProviderTests.java | 42 ++++++++++----- 2 files changed, 60 insertions(+), 33 deletions(-) diff --git a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml4AuthenticationProvider.java b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml4AuthenticationProvider.java index af362b2d56e..a1318a7eb9b 100644 --- a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml4AuthenticationProvider.java +++ b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml4AuthenticationProvider.java @@ -20,16 +20,15 @@ import java.nio.charset.StandardCharsets; import java.time.Duration; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Set; -import java.util.HashSet; -import java.util.Arrays; -import java.util.Optional; import java.util.function.Consumer; import javax.annotation.Nonnull; @@ -98,8 +97,6 @@ import org.springframework.util.MultiValueMap; import org.springframework.util.StringUtils; -import static org.opensaml.saml.saml2.core.StatusCode.*; - /** * Implementation of {@link AuthenticationProvider} for SAML authentications when * receiving a {@code Response} object containing an {@code Assertion}. This @@ -174,7 +171,8 @@ public final class OpenSaml4AuthenticationProvider implements AuthenticationProv private Converter responseAuthenticationConverter = createDefaultResponseAuthenticationConverter(); - private static final Set includeChildStatusCodes = new HashSet<>(Arrays.asList(REQUESTER, RESPONDER, VERSION_MISMATCH)); + private static final Set includeChildStatusCodes = new HashSet<>( + Arrays.asList(StatusCode.REQUESTER, StatusCode.RESPONDER, StatusCode.VERSION_MISMATCH)); /** * Creates an {@link OpenSaml4AuthenticationProvider} @@ -379,11 +377,13 @@ public static Converter createDefau 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)); + List statusCodes = getStatusCodes(response); + if (!isSuccess(statusCodes)) { + for (String statusCode : statusCodes) { + String message = String.format("Invalid status [%s] for SAML response [%s]", statusCode, + response.getID()); + result = result.concat(new Saml2Error(Saml2ErrorCodes.INVALID_RESPONSE, message)); + } } String inResponseTo = response.getInResponseTo(); @@ -412,24 +412,37 @@ public static Converter createDefau }; } - private static String getStatusCode(Response response) { + private static List getStatusCodes(Response response) { if (response.getStatus() == null) { - return StatusCode.SUCCESS; + return Arrays.asList(StatusCode.SUCCESS); } if (response.getStatus().getStatusCode() == null) { - return StatusCode.SUCCESS; + return Arrays.asList(StatusCode.SUCCESS); } StatusCode parentStatusCode = response.getStatus().getStatusCode(); String parentStatusCodeValue = parentStatusCode.getValue(); if (includeChildStatusCodes.contains(parentStatusCodeValue)) { - return Optional.ofNullable(parentStatusCode.getStatusCode()) - .map(StatusCode::getValue) - .map(childStatusCodeValue -> parentStatusCodeValue + childStatusCodeValue) - .orElse(parentStatusCodeValue); + StatusCode statusCode = parentStatusCode.getStatusCode(); + if (statusCode != null) { + String childStatusCodeValue = statusCode.getValue(); + if (childStatusCodeValue != null) { + return Arrays.asList(parentStatusCodeValue, childStatusCodeValue); + } + } + return Arrays.asList(parentStatusCodeValue); + } + + return Arrays.asList(parentStatusCodeValue); + } + + private static boolean isSuccess(List statusCodes) { + if (statusCodes.size() != 1) { + return false; } - return parentStatusCodeValue; + String statusCode = statusCodes.get(0); + return StatusCode.SUCCESS.equals(statusCode); } private static Saml2ResponseValidatorResult validateInResponseTo(AbstractSaml2AuthenticationRequest storedRequest, diff --git a/saml2/saml2-service-provider/src/test/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml4AuthenticationProviderTests.java b/saml2/saml2-service-provider/src/test/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml4AuthenticationProviderTests.java index 53aeaba17f7..8432b5760a2 100644 --- a/saml2/saml2-service-provider/src/test/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml4AuthenticationProviderTests.java +++ b/saml2/saml2-service-provider/src/test/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml4AuthenticationProviderTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2023 the original author or authors. + * Copyright 2002-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -86,8 +86,6 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.atLeastOnce; @@ -736,7 +734,7 @@ public void authenticateWhenCustomResponseValidatorThenUses() { } @Test - public void setsOnlyParentStatusCodeOnResultDescription() { + public void authenticateWhenResponseStatusIsNotSuccessThenOnlyReturnParentStatusCodes() { ResponseToken mockResponseToken = mock(ResponseToken.class); Saml2AuthenticationToken mockSamlToken = mock(Saml2AuthenticationToken.class); given(mockResponseToken.getToken()).willReturn(mockSamlToken); @@ -744,7 +742,8 @@ public void setsOnlyParentStatusCodeOnResultDescription() { RelyingPartyRegistration mockRelyingPartyRegistration = mock(RelyingPartyRegistration.class); given(mockSamlToken.getRelyingPartyRegistration()).willReturn(mockRelyingPartyRegistration); - RelyingPartyRegistration.AssertingPartyDetails mockAssertingPartyDetails = mock(RelyingPartyRegistration.AssertingPartyDetails.class); + RelyingPartyRegistration.AssertingPartyDetails mockAssertingPartyDetails = mock( + RelyingPartyRegistration.AssertingPartyDetails.class); given(mockRelyingPartyRegistration.getAssertingPartyDetails()).willReturn(mockAssertingPartyDetails); Status parentStatus = new StatusBuilder().buildObject(); @@ -763,16 +762,21 @@ public void setsOnlyParentStatusCodeOnResultDescription() { given(mockResponseToken.getResponse()).willReturn(mockResponse); - Converter validator = OpenSaml4AuthenticationProvider.createDefaultResponseValidator(); + Converter validator = OpenSaml4AuthenticationProvider + .createDefaultResponseValidator(); Saml2ResponseValidatorResult result = validator.convert(mockResponseToken); - String expectedErrorMessage = String.format("Invalid status [%s] for SAML response", parentStatusCode.getValue()); - assertTrue(result.getErrors().stream().anyMatch(error -> error.getDescription().contains(expectedErrorMessage))); - assertFalse(result.getErrors().stream().anyMatch(error -> error.getDescription().contains(childStatusCode.getValue()))); + String expectedErrorMessage = String.format("Invalid status [%s] for SAML response", + parentStatusCode.getValue()); + assertThat( + result.getErrors().stream().anyMatch((error) -> error.getDescription().contains(expectedErrorMessage))); + assertThat(result.getErrors() + .stream() + .noneMatch((error) -> error.getDescription().contains(childStatusCode.getValue()))); } @Test - public void setsParentAndChildStatusCodeOnResultDescription() { + public void authenticateWhenResponseStatusIsNotSuccessThenReturnParentAndChildStatusCode() { ResponseToken mockResponseToken = mock(ResponseToken.class); Saml2AuthenticationToken mockSamlToken = mock(Saml2AuthenticationToken.class); given(mockResponseToken.getToken()).willReturn(mockSamlToken); @@ -780,7 +784,8 @@ public void setsParentAndChildStatusCodeOnResultDescription() { RelyingPartyRegistration mockRelyingPartyRegistration = mock(RelyingPartyRegistration.class); given(mockSamlToken.getRelyingPartyRegistration()).willReturn(mockRelyingPartyRegistration); - RelyingPartyRegistration.AssertingPartyDetails mockAssertingPartyDetails = mock(RelyingPartyRegistration.AssertingPartyDetails.class); + RelyingPartyRegistration.AssertingPartyDetails mockAssertingPartyDetails = mock( + RelyingPartyRegistration.AssertingPartyDetails.class); given(mockRelyingPartyRegistration.getAssertingPartyDetails()).willReturn(mockAssertingPartyDetails); Status parentStatus = new StatusBuilder().buildObject(); @@ -799,11 +804,20 @@ public void setsParentAndChildStatusCodeOnResultDescription() { given(mockResponseToken.getResponse()).willReturn(mockResponse); - Converter validator = OpenSaml4AuthenticationProvider.createDefaultResponseValidator(); + Converter validator = OpenSaml4AuthenticationProvider + .createDefaultResponseValidator(); Saml2ResponseValidatorResult result = validator.convert(mockResponseToken); - String expectedErrorMessage = String.format("Invalid status [%s] for SAML response", parentStatusCode.getValue() + childStatusCode.getValue()); - assertTrue(result.getErrors().stream().anyMatch(error -> error.getDescription().contains(expectedErrorMessage))); + String expectedParentErrorMessage = String.format("Invalid status [%s] for SAML response", + parentStatusCode.getValue()); + String expectedChildErrorMessage = String.format("Invalid status [%s] for SAML response", + childStatusCode.getValue()); + assertThat(result.getErrors() + .stream() + .anyMatch((error) -> error.getDescription().contains(expectedParentErrorMessage))); + assertThat(result.getErrors() + .stream() + .anyMatch((error) -> error.getDescription().contains(expectedChildErrorMessage))); } @Test