2
0
Эх сурвалжийг харах

Use RFC2045 Encoding for SAML 2.0 Logout

Closes gh-10923
Josh Cummings 3 жил өмнө
parent
commit
238616da80

+ 2 - 2
saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/authentication/logout/Saml2Utils.java

@@ -40,11 +40,11 @@ final class Saml2Utils {
 	}
 
 	static String samlEncode(byte[] b) {
-		return Base64.getEncoder().encodeToString(b);
+		return Base64.getMimeEncoder().encodeToString(b);
 	}
 
 	static byte[] samlDecode(String s) {
-		return Base64.getDecoder().decode(s);
+		return Base64.getMimeDecoder().decode(s);
 	}
 
 	static byte[] samlDeflate(String s) {

+ 2 - 2
saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/Saml2Utils.java

@@ -40,11 +40,11 @@ final class Saml2Utils {
 	}
 
 	static String samlEncode(byte[] b) {
-		return Base64.getEncoder().encodeToString(b);
+		return Base64.getMimeEncoder().encodeToString(b);
 	}
 
 	static byte[] samlDecode(String s) {
-		return Base64.getDecoder().decode(s);
+		return Base64.getMimeDecoder().decode(s);
 	}
 
 	static byte[] samlDeflate(String s) {

+ 17 - 0
saml2/saml2-service-provider/src/test/java/org/springframework/security/saml2/provider/service/authentication/logout/OpenSamlLogoutRequestValidatorTests.java

@@ -143,6 +143,23 @@ public class OpenSamlLogoutRequestValidatorTests {
 		assertThat(result.getErrors().iterator().next().getErrorCode()).isEqualTo(Saml2ErrorCodes.INVALID_DESTINATION);
 	}
 
+	// gh-10923
+	@Test
+	public void handleWhenLogoutResponseHasLineBreaksThenHandles() {
+		RelyingPartyRegistration registration = registration().build();
+		LogoutRequest logoutRequest = TestOpenSamlObjects.assertingPartyLogoutRequest(registration);
+		sign(logoutRequest, registration);
+		String encoded = new StringBuffer(
+				Saml2Utils.samlEncode(serialize(logoutRequest).getBytes(StandardCharsets.UTF_8))).insert(10, "\r\n")
+						.toString();
+		Saml2LogoutRequest request = Saml2LogoutRequest.withRelyingPartyRegistration(registration).samlRequest(encoded)
+				.build();
+		Saml2LogoutRequestValidatorParameters parameters = new Saml2LogoutRequestValidatorParameters(request,
+				registration, authentication(registration));
+		Saml2LogoutValidatorResult result = this.manager.validate(parameters);
+		assertThat(result.hasErrors()).isFalse();
+	}
+
 	private RelyingPartyRegistration.Builder registration() {
 		return signing(verifying(TestRelyingPartyRegistrations.noCredentials()))
 				.assertingPartyDetails((party) -> party.singleLogoutServiceBinding(Saml2MessageBinding.POST));

+ 18 - 0
saml2/saml2-service-provider/src/test/java/org/springframework/security/saml2/provider/service/authentication/logout/OpenSamlLogoutResponseValidatorTests.java

@@ -119,6 +119,24 @@ public class OpenSamlLogoutResponseValidatorTests {
 		assertThat(result.getErrors().iterator().next().getErrorCode()).isEqualTo(Saml2ErrorCodes.INVALID_RESPONSE);
 	}
 
+	// gh-10923
+	@Test
+	public void handleWhenLogoutResponseHasLineBreaksThenHandles() {
+		RelyingPartyRegistration registration = signing(verifying(registration())).build();
+		Saml2LogoutRequest logoutRequest = Saml2LogoutRequest.withRelyingPartyRegistration(registration).id("id")
+				.build();
+		LogoutResponse logoutResponse = TestOpenSamlObjects.assertingPartyLogoutResponse(registration);
+		sign(logoutResponse, registration);
+		String encoded = new StringBuilder(
+				Saml2Utils.samlEncode(serialize(logoutResponse).getBytes(StandardCharsets.UTF_8))).insert(10, "\r\n")
+						.toString();
+		Saml2LogoutResponse response = Saml2LogoutResponse.withRelyingPartyRegistration(registration)
+				.samlResponse(encoded).build();
+		Saml2LogoutResponseValidatorParameters parameters = new Saml2LogoutResponseValidatorParameters(response,
+				logoutRequest, registration);
+		this.manager.validate(parameters);
+	}
+
 	private RelyingPartyRegistration.Builder registration() {
 		return signing(verifying(TestRelyingPartyRegistrations.noCredentials()))
 				.assertingPartyDetails((party) -> party.singleLogoutServiceBinding(Saml2MessageBinding.POST));

+ 23 - 0
saml2/saml2-service-provider/src/test/java/org/springframework/security/saml2/provider/service/web/authentication/logout/OpenSamlLogoutResponseResolverTests.java

@@ -98,6 +98,29 @@ public class OpenSamlLogoutResponseResolverTests {
 		assertThat(logoutResponse.getStatus().getStatusCode().getValue()).isEqualTo(StatusCode.SUCCESS);
 	}
 
+	// gh-10923
+	@Test
+	public void resolvePostWithLineBreaksWhenAuthenticatedThenSuccess() {
+		RelyingPartyRegistration registration = TestRelyingPartyRegistrations.full()
+				.assertingPartyDetails((party) -> party.singleLogoutServiceBinding(Saml2MessageBinding.POST)).build();
+		MockHttpServletRequest request = new MockHttpServletRequest();
+		LogoutRequest logoutRequest = TestOpenSamlObjects.assertingPartyLogoutRequest(registration);
+		String encoded = new StringBuffer(
+				Saml2Utils.samlEncode(OpenSamlSigningUtils.serialize(logoutRequest).getBytes())).insert(10, "\r\n")
+						.toString();
+		request.setParameter(Saml2ParameterNames.SAML_REQUEST, encoded);
+		request.setParameter(Saml2ParameterNames.RELAY_STATE, "abcd");
+		Authentication authentication = authentication(registration);
+		given(this.relyingPartyRegistrationResolver.resolve(any(), any())).willReturn(registration);
+		Saml2LogoutResponse saml2LogoutResponse = this.logoutResponseResolver.resolve(request, authentication);
+		assertThat(saml2LogoutResponse.getParameter(Saml2ParameterNames.SIG_ALG)).isNull();
+		assertThat(saml2LogoutResponse.getParameter(Saml2ParameterNames.SIGNATURE)).isNull();
+		assertThat(saml2LogoutResponse.getParameter(Saml2ParameterNames.RELAY_STATE)).isSameAs("abcd");
+		Saml2MessageBinding binding = registration.getAssertingPartyDetails().getSingleLogoutServiceBinding();
+		LogoutResponse logoutResponse = getLogoutResponse(saml2LogoutResponse.getSamlResponse(), binding);
+		assertThat(logoutResponse.getStatus().getStatusCode().getValue()).isEqualTo(StatusCode.SUCCESS);
+	}
+
 	private Saml2Authentication authentication(RelyingPartyRegistration registration) {
 		DefaultSaml2AuthenticatedPrincipal principal = new DefaultSaml2AuthenticatedPrincipal("user", new HashMap<>());
 		principal.setRelyingPartyRegistrationId(registration.getRegistrationId());