[java-identity-provider] branch main updated: IDP-2076 - Implement new SAML profile settings
Scott Cantor
cantor.2 at osu.edu
Thu Feb 23 14:24:10 UTC 2023
This is an automated email from the git hooks/post-receive script.
scantor pushed a commit to branch main
in repository java-identity-provider.
View the commit online:
http://git.shibboleth.net/view/?p=java-identity-provider.git;a=commit;h=34c6649b13bc93a7ae3ebc4048e5b11bc050968b
The following commit(s) were added to refs/heads/main by this push:
new 34c6649b1 IDP-2076 - Implement new SAML profile settings
34c6649b1 is described below
commit 34c6649b13bc93a7ae3ebc4048e5b11bc050968b
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Thu Feb 23 09:24:03 2023 -0500
IDP-2076 - Implement new SAML profile settings
https://shibboleth.atlassian.net/browse/IDP-2076
Add SPNameQualifier, ACS Index, and RequestedAttrbutes support.
---
.../saml/saml2/profile/impl/AddAuthnRequest.java | 63 +++++++++++++++-
.../saml2/profile/impl/AddAuthnRequestTest.java | 85 +++++++++++++++++++---
2 files changed, 135 insertions(+), 13 deletions(-)
diff --git a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/saml2/profile/impl/AddAuthnRequest.java b/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/saml2/profile/impl/AddAuthnRequest.java
index 5da1dbf48..ebbab37f5 100644
--- a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/saml2/profile/impl/AddAuthnRequest.java
+++ b/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/saml2/profile/impl/AddAuthnRequest.java
@@ -19,6 +19,7 @@ package net.shibboleth.idp.saml.saml2.profile.impl;
import java.security.Principal;
import java.time.Instant;
+import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.function.Function;
@@ -42,6 +43,9 @@ import net.shibboleth.shared.security.IdentifierGenerationStrategy;
import org.opensaml.core.xml.XMLObjectBuilderFactory;
import org.opensaml.core.xml.config.XMLObjectProviderRegistrySupport;
+import org.opensaml.core.xml.io.MarshallingException;
+import org.opensaml.core.xml.io.UnmarshallingException;
+import org.opensaml.core.xml.util.XMLObjectSupport;
import org.opensaml.messaging.context.MessageContext;
import org.opensaml.messaging.context.navigate.ChildContextLookup;
import org.opensaml.messaging.context.navigate.ParentContextLookup;
@@ -53,8 +57,10 @@ import org.opensaml.profile.context.ProxiedRequesterContext;
import org.opensaml.profile.context.navigate.InboundMessageContextLookup;
import org.opensaml.saml.common.SAMLObjectBuilder;
import org.opensaml.saml.common.SAMLVersion;
+import org.opensaml.saml.ext.reqattr.RequestedAttributes;
import org.opensaml.saml.saml2.core.AuthnContextComparisonTypeEnumeration;
import org.opensaml.saml.saml2.core.AuthnRequest;
+import org.opensaml.saml.saml2.core.Extensions;
import org.opensaml.saml.saml2.core.IDPEntry;
import org.opensaml.saml.saml2.core.IDPList;
import org.opensaml.saml.saml2.core.Issuer;
@@ -62,6 +68,7 @@ import org.opensaml.saml.saml2.core.NameIDPolicy;
import org.opensaml.saml.saml2.core.RequestedAuthnContext;
import org.opensaml.saml.saml2.core.RequesterID;
import org.opensaml.saml.saml2.core.Scoping;
+import org.opensaml.saml.saml2.metadata.RequestedAttribute;
import org.slf4j.Logger;
import net.shibboleth.shared.primitive.LoggerFactory;
@@ -259,6 +266,13 @@ public class AddAuthnRequest extends AbstractAuthenticationAction {
object.setID(idGenerator.generateIdentifier());
object.setIssueInstant(Instant.now());
object.setVersion(SAMLVersion.VERSION_20);
+
+ final Integer index = profileConfiguration.getAttributeIndex(profileRequestContext);
+ if (index != null) {
+ log.debug("{} Setting AttributeConsumingServiceIndex to '{}' for SAML AuthnRequest", getLogPrefix(),
+ index);
+ object.setAttributeConsumingServiceIndex(index);
+ }
if (issuerId != null) {
log.debug("{} Setting Issuer to {}", getLogPrefix(), issuerId);
@@ -286,6 +300,12 @@ public class AddAuthnRequest extends AbstractAuthenticationAction {
final NameIDPolicy nip = nipBuilder.buildObject();
nip.setAllowCreate(true);
+ final String qualifier = profileConfiguration.getSPNameQualifier(profileRequestContext);
+ if (qualifier != null) {
+ log.debug("{} Setting NameIDPolicy SPNameQualifier to '{}' for SAML AuthnRequest", getLogPrefix(),
+ qualifier);
+ nip.setSPNameQualifier(qualifier);
+ }
// TODO: use metadata for NameID Formats too?
final List<String> formats = profileConfiguration.getNameIDFormatPrecedence(profileRequestContext);
@@ -293,7 +313,7 @@ public class AddAuthnRequest extends AbstractAuthenticationAction {
log.debug("{} Setting NameIDPolicy Format to '{}' for SAML AuthnRequest", getLogPrefix(), formats.get(0));
nip.setFormat(formats.get(0));
}
-
+
object.setNameIDPolicy(nip);
final RequestedAuthnContext rac = getRequestedAuthnContext(profileRequestContext);
@@ -309,6 +329,8 @@ public class AddAuthnRequest extends AbstractAuthenticationAction {
object.setScoping(buildScoping(profileRequestContext, authenticationContext.getProxyCount(),
authenticationContext.getProxiableAuthorities()));
+
+ object.setExtensions(buildExtensions(profileRequestContext));
profileRequestContext.getOutboundMessageContext().setMessage(object);
}
@@ -393,7 +415,7 @@ public class AddAuthnRequest extends AbstractAuthenticationAction {
*
* @return populated {@link Scoping}
*/
- @Nullable public Scoping buildScoping(@Nonnull final ProfileRequestContext profileRequestContext,
+ @Nullable private Scoping buildScoping(@Nonnull final ProfileRequestContext profileRequestContext,
@Nullable final Integer count, @Nonnull @NonnullElements final Set<String> idplist) {
boolean include = false;
@@ -454,5 +476,40 @@ public class AddAuthnRequest extends AbstractAuthenticationAction {
return include ? scoping : null;
}
+
+ /**
+ * Build {@link RequestedAttributes} extension if required.
+ *
+ * @param profileRequestContext current profile request context
+ *
+ * @return extension or null
+ */
+ @Nullable private Extensions buildExtensions(
+ @Nonnull final ProfileRequestContext profileRequestContext) {
+
+ final Collection<RequestedAttribute> attrs = profileConfiguration.getRequestedAttributes(profileRequestContext);
+ if (!attrs.isEmpty()) {
+ final XMLObjectBuilderFactory bf = XMLObjectProviderRegistrySupport.getBuilderFactory();
+ final SAMLObjectBuilder<Extensions> extBuilder =
+ (SAMLObjectBuilder<Extensions>) bf.<Extensions>getBuilderOrThrow(
+ Extensions.DEFAULT_ELEMENT_NAME);
+ final SAMLObjectBuilder<RequestedAttributes> reqExtBuilder =
+ (SAMLObjectBuilder<RequestedAttributes>) bf.<RequestedAttributes>getBuilderOrThrow(
+ RequestedAttributes.DEFAULT_ELEMENT_NAME);
+ final RequestedAttributes reqExt = reqExtBuilder.buildObject();
+ attrs.forEach(attr -> {
+ try {
+ reqExt.getRequestedAttributes().add(XMLObjectSupport.cloneXMLObject(attr));
+ } catch (final MarshallingException|UnmarshallingException e) {
+ log.error("{} Error cloning RequestedAttribute from profile configuration", getLogPrefix(), e);
+ }
+ });
+ final Extensions ext = extBuilder.buildObject();
+ ext.getUnknownXMLObjects().add(reqExt);
+ return ext;
+ }
+
+ return null;
+ }
-}
+}
\ No newline at end of file
diff --git a/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/saml2/profile/impl/AddAuthnRequestTest.java b/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/saml2/profile/impl/AddAuthnRequestTest.java
index 88e997b64..25ea792a4 100644
--- a/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/saml2/profile/impl/AddAuthnRequestTest.java
+++ b/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/saml2/profile/impl/AddAuthnRequestTest.java
@@ -39,13 +39,19 @@ import net.shibboleth.idp.saml.authn.principal.AuthenticationMethodPrincipal;
import net.shibboleth.idp.saml.authn.principal.AuthnContextClassRefPrincipal;
import net.shibboleth.idp.saml.saml2.profile.config.impl.BrowserSSOProfileConfiguration;
import net.shibboleth.profile.context.RelyingPartyContext;
+import net.shibboleth.shared.collection.CollectionSupport;
import net.shibboleth.shared.component.ComponentInitializationException;
import org.opensaml.core.testing.OpenSAMLInitBaseTestCase;
+import org.opensaml.core.xml.XMLObjectBuilderFactory;
+import org.opensaml.core.xml.config.XMLObjectProviderRegistrySupport;
import org.opensaml.messaging.context.MessageContext;
import org.opensaml.messaging.context.navigate.ChildContextLookup;
import org.opensaml.messaging.context.navigate.ParentContextLookup;
+import org.opensaml.saml.common.SAMLObjectBuilder;
+import org.opensaml.saml.ext.reqattr.RequestedAttributes;
import org.opensaml.saml.saml1.core.AuthenticationStatement;
+import org.opensaml.saml.saml2.core.Attribute;
import org.opensaml.saml.saml2.core.AuthnContext;
import org.opensaml.saml.saml2.core.AuthnContextComparisonTypeEnumeration;
import org.opensaml.saml.saml2.core.AuthnRequest;
@@ -54,6 +60,7 @@ import org.opensaml.saml.saml2.core.NameIDPolicy;
import org.opensaml.saml.saml2.core.NameIDType;
import org.opensaml.saml.saml2.core.RequestedAuthnContext;
import org.opensaml.saml.saml2.core.Scoping;
+import org.opensaml.saml.saml2.metadata.RequestedAttribute;
import org.opensaml.xmlsec.config.BasicXMLSecurityConfiguration;
import org.springframework.webflow.execution.Event;
import org.springframework.webflow.execution.RequestContext;
@@ -138,10 +145,13 @@ public class AddAuthnRequestTest extends OpenSAMLInitBaseTestCase {
assertEquals(request.getIssuer().getValue(), ActionTestingSupport.OUTBOUND_MSG_ISSUER);
assertFalse(request.isForceAuthn());
assertFalse(request.isPassive());
+ assertNull(request.getAttributeConsumingServiceIndex());
+ assertNull(request.getExtensions());
final NameIDPolicy nid = request.getNameIDPolicy();
assertNotNull(nid);
assertNull(nid.getFormat());
+ assertNull(nid.getSPNameQualifier());
assertTrue(nid.getAllowCreate());
assertNull(request.getRequestedAuthnContext());
@@ -177,9 +187,9 @@ public class AddAuthnRequestTest extends OpenSAMLInitBaseTestCase {
/** Test that the action works with a NameID format set. */
@Test public void testNameIDFormat() {
((BrowserSSOProfileConfiguration) rpc.getProfileConfig()).setNameIDFormatPrecedence(
- Arrays.asList(NameIDType.EMAIL, NameIDType.KERBEROS));
+ CollectionSupport.listOf(NameIDType.EMAIL, NameIDType.KERBEROS));
- Event event = action.execute(rc);
+ final Event event = action.execute(rc);
ActionTestingSupport.assertProceedEvent(event);
assertNotNull(prc2.getOutboundMessageContext().getMessage());
@@ -192,12 +202,71 @@ public class AddAuthnRequestTest extends OpenSAMLInitBaseTestCase {
assertTrue(nid.getAllowCreate());
}
+ /** Test that the action works with SPNameQualifier set. */
+ @Test public void testSPNameQualifier() {
+ ((BrowserSSOProfileConfiguration) rpc.getProfileConfig()).setSPNameQualifier(ActionTestingSupport.INBOUND_MSG_ISSUER);
+
+ final Event event = action.execute(rc);
+ ActionTestingSupport.assertProceedEvent(event);
+
+ assertNotNull(prc2.getOutboundMessageContext().getMessage());
+ assertTrue(prc2.getOutboundMessageContext().getMessage() instanceof AuthnRequest);
+
+ final AuthnRequest request = (AuthnRequest) prc2.getOutboundMessageContext().getMessage();
+ final NameIDPolicy nid = request.getNameIDPolicy();
+ assertNotNull(nid);
+ assertEquals(nid.getSPNameQualifier(), ActionTestingSupport.INBOUND_MSG_ISSUER);
+ }
+
+ /** Test that the action works with AttributeConsumingrServiceIndex set. */
+ @Test public void testAttributeIndex() {
+ ((BrowserSSOProfileConfiguration) rpc.getProfileConfig()).setAttributeIndex(42);
+
+ final Event event = action.execute(rc);
+ ActionTestingSupport.assertProceedEvent(event);
+
+ assertNotNull(prc2.getOutboundMessageContext().getMessage());
+ assertTrue(prc2.getOutboundMessageContext().getMessage() instanceof AuthnRequest);
+
+ final AuthnRequest request = (AuthnRequest) prc2.getOutboundMessageContext().getMessage();
+ assertEquals(request.getAttributeConsumingServiceIndex(), 42);
+ }
+
+ /** Test that the action works with RequestedAttributes set. */
+ @Test public void testRequestedAttributes() {
+ final XMLObjectBuilderFactory bf = XMLObjectProviderRegistrySupport.getBuilderFactory();
+ final SAMLObjectBuilder<RequestedAttribute> reqAttrBuilder =
+ (SAMLObjectBuilder<RequestedAttribute>) bf.<RequestedAttribute>getBuilderOrThrow(
+ RequestedAttribute.DEFAULT_ELEMENT_NAME);
+ final RequestedAttribute attr1 = reqAttrBuilder.buildObject();
+ attr1.setNameFormat(Attribute.URI_REFERENCE);
+ attr1.setName("https://attr1.example.org");
+ final RequestedAttribute attr2 = reqAttrBuilder.buildObject();
+ attr2.setNameFormat(Attribute.URI_REFERENCE);
+ attr2.setName("https://attr2.example.org");
+
+ ((BrowserSSOProfileConfiguration) rpc.getProfileConfig()).setRequestedAttributes(CollectionSupport.listOf(attr1, attr2));
+
+ final Event event = action.execute(rc);
+ ActionTestingSupport.assertProceedEvent(event);
+
+ assertNotNull(prc2.getOutboundMessageContext().getMessage());
+ assertTrue(prc2.getOutboundMessageContext().getMessage() instanceof AuthnRequest);
+
+ final AuthnRequest request = (AuthnRequest) prc2.getOutboundMessageContext().getMessage();
+ assertNotNull(request.getExtensions());
+ assertEquals(request.getExtensions().getUnknownXMLObjects(RequestedAttributes.DEFAULT_ELEMENT_NAME).size(), 1);
+ final RequestedAttributes extension =
+ (RequestedAttributes) request.getExtensions().getUnknownXMLObjects(RequestedAttributes.DEFAULT_ELEMENT_NAME).get(0);
+ assertEquals(extension.getRequestedAttributes().size(), 2);
+ }
+
/** Test with Scoping element but no count. */
@Test public void testScopingNoCount() {
ac.getProxiableAuthorities().add("foo");
ac.getProxiableAuthorities().add("bar");
- Event event = action.execute(rc);
+ final Event event = action.execute(rc);
ActionTestingSupport.assertProceedEvent(event);
assertNotNull(prc2.getOutboundMessageContext().getMessage());
@@ -221,10 +290,9 @@ public class AddAuthnRequestTest extends OpenSAMLInitBaseTestCase {
/** Test with Scoping element and count of 1. */
@Test public void testScopingCount1() {
-
ac.setProxyCount(1);
- Event event = action.execute(rc);
+ final Event event = action.execute(rc);
ActionTestingSupport.assertProceedEvent(event);
assertNotNull(prc2.getOutboundMessageContext().getMessage());
@@ -240,10 +308,9 @@ public class AddAuthnRequestTest extends OpenSAMLInitBaseTestCase {
/** Test with Scoping element and count of 5. */
@Test public void testScopingCount5() {
-
ac.setProxyCount(5);
- Event event = action.execute(rc);
+ final Event event = action.execute(rc);
ActionTestingSupport.assertProceedEvent(event);
assertNotNull(prc2.getOutboundMessageContext().getMessage());
@@ -259,10 +326,9 @@ public class AddAuthnRequestTest extends OpenSAMLInitBaseTestCase {
/** Test with Scoping element and count of 0 (this shouldn't really happen). */
@Test public void testScopingCount0() {
-
ac.setProxyCount(0);
- Event event = action.execute(rc);
+ final Event event = action.execute(rc);
ActionTestingSupport.assertProceedEvent(event);
assertNotNull(prc2.getOutboundMessageContext().getMessage());
@@ -278,7 +344,6 @@ public class AddAuthnRequestTest extends OpenSAMLInitBaseTestCase {
/** Test that the action works for RequestedAuthnContext. */
@Test public void testAuthnContext() {
-
final RequestedPrincipalContext reqctx = ac.getSubcontext(RequestedPrincipalContext.class, true);
reqctx.setOperator("exact");
reqctx.setRequestedPrincipals(
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list