Polish LogoutRequest#EncryptedID Support

Issue gh-10663
This commit is contained in:
Josh Cummings 2022-01-13 16:22:26 -07:00
parent 700cae8d3b
commit 3c45d46bd7
4 changed files with 39 additions and 29 deletions

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2021 the original author or authors. * Copyright 2002-2022 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -46,16 +46,16 @@ import org.springframework.security.saml2.provider.service.registration.RelyingP
* *
* @author Robert Stoiber * @author Robert Stoiber
*/ */
final class LogoutRequestEncryptedIDUtils { final class LogoutRequestEncryptedIdUtils {
private static final EncryptedKeyResolver encryptedKeyResolver = new ChainingEncryptedKeyResolver( private static final EncryptedKeyResolver encryptedKeyResolver = new ChainingEncryptedKeyResolver(
Arrays.asList(new InlineEncryptedKeyResolver(), new EncryptedElementTypeEncryptedKeyResolver(), Arrays.asList(new InlineEncryptedKeyResolver(), new EncryptedElementTypeEncryptedKeyResolver(),
new SimpleRetrievalMethodEncryptedKeyResolver())); new SimpleRetrievalMethodEncryptedKeyResolver()));
static SAMLObject decryptEncryptedID(EncryptedID encryptedID, RelyingPartyRegistration registration) { static SAMLObject decryptEncryptedId(EncryptedID encryptedId, RelyingPartyRegistration registration) {
Decrypter decrypter = decrypter(registration); Decrypter decrypter = decrypter(registration);
try { try {
return decrypter.decrypt(encryptedID); return decrypter.decrypt(encryptedId);
} }
catch (Exception ex) { catch (Exception ex) {
@ -75,7 +75,7 @@ final class LogoutRequestEncryptedIDUtils {
return decrypter; return decrypter;
} }
private LogoutRequestEncryptedIDUtils() { private LogoutRequestEncryptedIdUtils() {
} }
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2021 the original author or authors. * Copyright 2002-2022 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -161,25 +161,30 @@ public final class OpenSamlLogoutRequestValidator implements Saml2LogoutRequestV
if (authentication == null) { if (authentication == null) {
return; return;
} }
NameID nameId = request.getNameID(); NameID nameId = getNameId(request, registration);
EncryptedID encryptedID = request.getEncryptedID(); if (nameId == null) {
if (nameId == null && encryptedID == null) {
errors.add( errors.add(
new Saml2Error(Saml2ErrorCodes.SUBJECT_NOT_FOUND, "Failed to find subject in LogoutRequest")); new Saml2Error(Saml2ErrorCodes.SUBJECT_NOT_FOUND, "Failed to find subject in LogoutRequest"));
return; return;
} }
if (nameId != null) { validateNameId(nameId, authentication, errors);
validateNameID(nameId, authentication, errors);
}
else {
final NameID nameIDFromEncryptedID = decryptNameID(encryptedID, registration);
validateNameID(nameIDFromEncryptedID, authentication, errors);
}
}; };
} }
private void validateNameID(NameID nameId, Authentication authentication, Collection<Saml2Error> errors) { private NameID getNameId(LogoutRequest request, RelyingPartyRegistration registration) {
NameID nameId = request.getNameID();
if (nameId != null) {
return nameId;
}
EncryptedID encryptedId = request.getEncryptedID();
if (encryptedId == null) {
return null;
}
return decryptNameId(encryptedId, registration);
}
private void validateNameId(NameID nameId, Authentication authentication, Collection<Saml2Error> errors) {
String name = nameId.getValue(); String name = nameId.getValue();
if (!name.equals(authentication.getName())) { if (!name.equals(authentication.getName())) {
errors.add(new Saml2Error(Saml2ErrorCodes.INVALID_REQUEST, errors.add(new Saml2Error(Saml2ErrorCodes.INVALID_REQUEST,
@ -187,8 +192,8 @@ public final class OpenSamlLogoutRequestValidator implements Saml2LogoutRequestV
} }
} }
private NameID decryptNameID(EncryptedID encryptedID, RelyingPartyRegistration registration) { private NameID decryptNameId(EncryptedID encryptedId, RelyingPartyRegistration registration) {
final SAMLObject decryptedId = LogoutRequestEncryptedIDUtils.decryptEncryptedID(encryptedID, registration); final SAMLObject decryptedId = LogoutRequestEncryptedIdUtils.decryptEncryptedId(encryptedId, registration);
if (decryptedId instanceof NameID) { if (decryptedId instanceof NameID) {
return ((NameID) decryptedId); return ((NameID) decryptedId);
} }

View File

@ -373,8 +373,10 @@ public final class TestOpenSamlObjects {
NameID nameId = nameIdBuilder.buildObject(); NameID nameId = nameIdBuilder.buildObject();
nameId.setValue("user"); nameId.setValue("user");
logoutRequest.setNameID(null); logoutRequest.setNameID(null);
logoutRequest.setEncryptedID(encrypted(nameId, Saml2X509Credential credential = registration.getAssertingPartyDetails().getEncryptionX509Credentials()
registration.getAssertingPartyDetails().getEncryptionX509Credentials().stream().findFirst().get())); .iterator().next();
EncryptedID encrypted = encrypted(nameId, credential);
logoutRequest.setEncryptedID(encrypted);
IssuerBuilder issuerBuilder = new IssuerBuilder(); IssuerBuilder issuerBuilder = new IssuerBuilder();
Issuer issuer = issuerBuilder.buildObject(); Issuer issuer = issuerBuilder.buildObject();
issuer.setValue(registration.getAssertingPartyDetails().getEntityId()); issuer.setValue(registration.getAssertingPartyDetails().getEntityId());

View File

@ -61,17 +61,16 @@ public class OpenSamlLogoutRequestValidatorTests {
} }
@Test @Test
public void handleWhenNameIdInEncryptedIdPostThenValidates() { public void handleWhenNameIdIsEncryptedIdPostThenValidates() {
RelyingPartyRegistration registration = registrationWithEncryption() RelyingPartyRegistration registration = decrypting(encrypting(registration())).build();
.assertingPartyDetails((party) -> party.singleLogoutServiceBinding(Saml2MessageBinding.POST)).build();
LogoutRequest logoutRequest = TestOpenSamlObjects.assertingPartyLogoutRequestNameIdInEncryptedId(registration); LogoutRequest logoutRequest = TestOpenSamlObjects.assertingPartyLogoutRequestNameIdInEncryptedId(registration);
sign(logoutRequest, registration); sign(logoutRequest, registration);
Saml2LogoutRequest request = post(logoutRequest, registration); Saml2LogoutRequest request = post(logoutRequest, registration);
Saml2LogoutRequestValidatorParameters parameters = new Saml2LogoutRequestValidatorParameters(request, Saml2LogoutRequestValidatorParameters parameters = new Saml2LogoutRequestValidatorParameters(request,
registration, authentication(registration)); registration, authentication(registration));
Saml2LogoutValidatorResult result = this.manager.validate(parameters); Saml2LogoutValidatorResult result = this.manager.validate(parameters);
assertThat(result.hasErrors()).withFailMessage(() -> result.getErrors().toString()).isFalse().isFalse(); assertThat(result.hasErrors()).withFailMessage(() -> result.getErrors().toString()).isFalse();
} }
@ -149,10 +148,14 @@ public class OpenSamlLogoutRequestValidatorTests {
.assertingPartyDetails((party) -> party.singleLogoutServiceBinding(Saml2MessageBinding.POST)); .assertingPartyDetails((party) -> party.singleLogoutServiceBinding(Saml2MessageBinding.POST));
} }
private RelyingPartyRegistration.Builder registrationWithEncryption() { private RelyingPartyRegistration.Builder decrypting(RelyingPartyRegistration.Builder builder) {
return signing(verifying(TestRelyingPartyRegistrations.full())) return builder
.assertingPartyDetails((party) -> party.encryptionX509Credentials( .decryptionX509Credentials((c) -> c.add(TestSaml2X509Credentials.relyingPartyDecryptingCredential()));
(c) -> c.add(TestSaml2X509Credentials.assertingPartyEncryptingCredential()))); }
private RelyingPartyRegistration.Builder encrypting(RelyingPartyRegistration.Builder builder) {
return builder.assertingPartyDetails((party) -> party.encryptionX509Credentials(
(c) -> c.add(TestSaml2X509Credentials.assertingPartyEncryptingCredential())));
} }
private RelyingPartyRegistration.Builder verifying(RelyingPartyRegistration.Builder builder) { private RelyingPartyRegistration.Builder verifying(RelyingPartyRegistration.Builder builder) {