Use RFC2045 Encoding for SAML 2.0 Logout

Closes gh-10923
This commit is contained in:
Josh Cummings 2022-03-01 14:48:24 -07:00
parent 68e2586f06
commit 0b59e7797d
5 changed files with 62 additions and 4 deletions

View File

@ -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) {

View File

@ -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) {

View File

@ -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));

View File

@ -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));

View File

@ -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());