diff --git a/documentation/docs/release-notes.md b/documentation/docs/release-notes.md index f8a6d0fdcc..e82025912a 100644 --- a/documentation/docs/release-notes.md +++ b/documentation/docs/release-notes.md @@ -16,6 +16,7 @@ title: Release notes: - Renamed the `SAMLMessageStorage*` classes as `SAMLMessageStore*` (based on `Store`) **v3.6.0**: +- Multiple authn context class refs can be set in the SAML protocol support **v3.5.0**: diff --git a/pac4j-saml/src/main/java/org/pac4j/saml/config/SAML2Configuration.java b/pac4j-saml/src/main/java/org/pac4j/saml/config/SAML2Configuration.java index 2bc2d60e47..06c4201f7f 100644 --- a/pac4j-saml/src/main/java/org/pac4j/saml/config/SAML2Configuration.java +++ b/pac4j-saml/src/main/java/org/pac4j/saml/config/SAML2Configuration.java @@ -105,7 +105,7 @@ public class SAML2Configuration extends InitializableObject { private String spLogoutResponseBindingType = SAMLConstants.SAML2_POST_BINDING_URI; - private String authnContextClassRef = null; + private List authnContextClassRefs = null; private String nameIdPolicyFormat = null; @@ -439,12 +439,12 @@ public void setSpLogoutResponseBindingType(final String spLogoutResponseBindingT this.spLogoutResponseBindingType = spLogoutResponseBindingType; } - public String getAuthnContextClassRef() { - return authnContextClassRef; + public List getAuthnContextClassRefs() { + return authnContextClassRefs; } - public void setAuthnContextClassRef(final String authnContextClassRef) { - this.authnContextClassRef = authnContextClassRef; + public void setAuthnContextClassRefs(final List authnContextClassRefs) { + this.authnContextClassRefs = authnContextClassRefs; } public String getNameIdPolicyFormat() { diff --git a/pac4j-saml/src/main/java/org/pac4j/saml/sso/impl/SAML2AuthnRequestBuilder.java b/pac4j-saml/src/main/java/org/pac4j/saml/sso/impl/SAML2AuthnRequestBuilder.java index 3da91c43f0..535047171f 100644 --- a/pac4j-saml/src/main/java/org/pac4j/saml/sso/impl/SAML2AuthnRequestBuilder.java +++ b/pac4j-saml/src/main/java/org/pac4j/saml/sso/impl/SAML2AuthnRequestBuilder.java @@ -44,7 +44,7 @@ public class SAML2AuthnRequestBuilder implements SAML2ObjectBuilder authnContextClassRefs; private String nameIdPolicyFormat; @@ -71,7 +71,7 @@ public SAML2AuthnRequestBuilder(final SAML2Configuration cfg) { this.forceAuth = cfg.isForceAuth(); this.comparisonType = getComparisonTypeEnumFromString(cfg.getComparisonType()); this.bindingType = cfg.getAuthnRequestBindingType(); - this.authnContextClassRef = cfg.getAuthnContextClassRef(); + this.authnContextClassRefs = cfg.getAuthnContextClassRefs(); this.nameIdPolicyFormat = cfg.getNameIdPolicyFormat(); this.passive = cfg.isPassive(); this.attributeConsumingServiceIndex = cfg.getAttributeConsumingServiceIndex(); @@ -101,10 +101,9 @@ protected final AuthnRequest buildAuthnRequest(final SAML2MessageContext context final RequestedAuthnContext authnContext = new RequestedAuthnContextBuilder().buildObject(); authnContext.setComparison(comparisonType); - if (authnContextClassRef != null) { - final AuthnContextClassRef classRef = new AuthnContextClassRefBuilder().buildObject(); - classRef.setAuthnContextClassRef(authnContextClassRef); - authnContext.getAuthnContextClassRefs().add(classRef); + if (authnContextClassRefs != null && !authnContextClassRefs.isEmpty()) { + final List refs = authnContext.getAuthnContextClassRefs(); + authnContextClassRefs.forEach(r -> refs.add(buildAuthnContextClassRef(r))); } request.setRequestedAuthnContext(authnContext); } @@ -149,6 +148,12 @@ protected final AuthnRequest buildAuthnRequest(final SAML2MessageContext context return request; } + protected AuthnContextClassRef buildAuthnContextClassRef(final String authnContextClassRef) { + final AuthnContextClassRef classRef = new AuthnContextClassRefBuilder().buildObject(); + classRef.setAuthnContextClassRef(authnContextClassRef); + return classRef; + } + @SuppressWarnings("unchecked") protected final Issuer getIssuer(final String spEntityId) { final SAMLObjectBuilder issuerBuilder = (SAMLObjectBuilder) this.builderFactory diff --git a/pac4j-saml/src/test/java/org/pac4j/saml/client/RedirectSAML2ClientTests.java b/pac4j-saml/src/test/java/org/pac4j/saml/client/RedirectSAML2ClientTests.java index f9130c51d6..4b707bcff2 100644 --- a/pac4j-saml/src/test/java/org/pac4j/saml/client/RedirectSAML2ClientTests.java +++ b/pac4j-saml/src/test/java/org/pac4j/saml/client/RedirectSAML2ClientTests.java @@ -17,6 +17,7 @@ import java.io.IOException; import java.io.InputStreamReader; import java.nio.charset.StandardCharsets; +import java.util.Arrays; import java.util.Base64; import java.util.List; import java.util.zip.Inflater; @@ -82,7 +83,8 @@ public void testNameIdPolicyFormat() { public void testAuthnContextClassRef() { final SAML2Client client = getClient(); client.getConfiguration().setComparisonType(AuthnContextComparisonTypeEnumeration.EXACT.toString()); - client.getConfiguration().setAuthnContextClassRef("urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport"); + client.getConfiguration() + .setAuthnContextClassRefs(Arrays.asList("urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport")); final WebContext context = new JEEContext(new MockHttpServletRequest(), new MockHttpServletResponse()); final FoundAction action = (FoundAction) client.redirect(context);