[java-identity-provider] branch main updated: IDP-2003 - Allow for NameID within AuthnRequests while proxying

Scott Cantor cantor.2 at osu.edu
Tue Apr 25 19:51:47 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=9c6f619ed19ac36582c8c190b9eb24ccb9bc46b6

The following commit(s) were added to refs/heads/main by this push:
     new 9c6f619ed IDP-2003 - Allow for NameID within AuthnRequests while proxying
9c6f619ed is described below

commit 9c6f619ed19ac36582c8c190b9eb24ccb9bc46b6
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Tue Apr 25 15:51:44 2023 -0400

    IDP-2003 - Allow for NameID within AuthnRequests while proxying
    
    https://shibboleth.atlassian.net/browse/IDP-2003
    
    Added a brute force function hook to produce the NameID to use.
---
 .../idp/flows/authn/saml-authn-beans.xml           |  3 +-
 .../saml/saml2/profile/impl/AddAuthnRequest.java   | 59 ++++++++++++++++++++--
 .../saml2/profile/impl/AddAuthnRequestTest.java    | 45 ++++++++++++++---
 3 files changed, 95 insertions(+), 12 deletions(-)

diff --git a/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/authn/saml-authn-beans.xml b/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/authn/saml-authn-beans.xml
index 9535adfd3..021de88a2 100644
--- a/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/authn/saml-authn-beans.xml
+++ b/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/authn/saml-authn-beans.xml
@@ -154,7 +154,8 @@
             class="net.shibboleth.idp.saml.saml2.profile.impl.AddAuthnRequest" scope="prototype"
             p:profileContextLookupStrategy-ref="shibboleth.ChildLookup.ProxyProfileRequestContext"
             p:overwriteExisting="true"
-            p:issuerLookupStrategy-ref="shibboleth.IssuerLookup.Simple">
+            p:issuerLookupStrategy-ref="shibboleth.IssuerLookup.Simple"
+            p:nameIDLookupStrategy="#{getObject('%{idp.authn.SAML.NameIDLookupStrategy:}'.trim())}">
         <property name="identifierGeneratorLookupStrategy">
             <bean class="net.shibboleth.profile.config.navigate.IdentifierGenerationStrategyLookupFunction"
                 p:defaultIdentifierGenerationStrategy-ref="shibboleth.DefaultIdentifierGenerationStrategy" />
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 ed710014e..37b3a4e02 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
@@ -65,10 +65,12 @@ 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;
+import org.opensaml.saml.saml2.core.NameID;
 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.core.Subject;
 import org.opensaml.saml.saml2.metadata.RequestedAttribute;
 import org.slf4j.Logger;
 import net.shibboleth.shared.primitive.LoggerFactory;
@@ -109,6 +111,9 @@ public class AddAuthnRequest extends AbstractAuthenticationAction {
     /** Strategy used to obtain the proxied requester context. */
     @Nonnull private Function<ProfileRequestContext,ProxiedRequesterContext> proxiedRequesterContextLookupStrategy;
     
+    /** Optional strategy to populate request with a {@link NameID}. */
+    @Nullable private Function<ProfileRequestContext,NameID> nameIDLookupStrategy;
+    
     /** The generator to use. */
     @NonnullBeforeExec private IdentifierGenerationStrategy idGenerator;
     
@@ -199,6 +204,19 @@ public class AddAuthnRequest extends AbstractAuthenticationAction {
         proxiedRequesterContextLookupStrategy =
                 Constraint.isNotNull(strategy, "ProxiedRequesterContext lookup strategy cannot be null");
     }
+    
+    /**
+     * Set optional strategy to derive a {@link NameID} to populate into the {@link AuthnRequest}'s
+     * {@link Subject} element.
+     * 
+     * @param strategy lookup strategy
+     * 
+     * @since 5.0.0
+     */
+    public void setNameIDLookupStrategy(@Nullable final Function<ProfileRequestContext,NameID> strategy) {
+        checkSetterPreconditions();
+        nameIDLookupStrategy = strategy;
+    }
 
 // Checkstyle: CyclomaticComplexity OFF
     /** {@inheritDoc} */
@@ -319,7 +337,7 @@ public class AddAuthnRequest extends AbstractAuthenticationAction {
 
         object.setNameIDPolicy(nip);
 
-        final RequestedAuthnContext rac = getRequestedAuthnContext(profileRequestContext);
+        final RequestedAuthnContext rac = buildRequestedAuthnContext(profileRequestContext);
         if (rac != null) {
             final AuthnContextComparisonTypeEnumeration operator =
                     profileConfiguration.getAuthnContextComparison(profileRequestContext);
@@ -329,11 +347,12 @@ public class AddAuthnRequest extends AbstractAuthenticationAction {
             }
             object.setRequestedAuthnContext(rac);
         }
-        
+
+        object.setSubject(buildSubject(profileRequestContext));
         object.setScoping(buildScoping(profileRequestContext, authenticationContext.getProxyCount(),
                 authenticationContext.getProxiableAuthorities()));
-
         object.setExtensions(buildExtensions(profileRequestContext));
+        
         final MessageContext omc = profileRequestContext.getOutboundMessageContext();
         assert omc != null;
         omc.setMessage(object);
@@ -347,7 +366,7 @@ public class AddAuthnRequest extends AbstractAuthenticationAction {
      * 
      * @return the object to include in the request, or null
      */
-    @Nullable private RequestedAuthnContext getRequestedAuthnContext(
+    @Nullable private RequestedAuthnContext buildRequestedAuthnContext(
             @Nullable final ProfileRequestContext profileRequestContext) {
         
         // RequestedAuthnContext also based on profile configuration.
@@ -411,6 +430,36 @@ public class AddAuthnRequest extends AbstractAuthenticationAction {
         return null;
     }
     
+    /**
+     * Build a {@link Subject} element if necessary.
+     * 
+     * @param profileRequestContext profile request context
+     * 
+     * @return the {@link Subject} element to include
+     * 
+     * @since 5.0.0
+     */
+    @Nullable private Subject buildSubject(@Nonnull final ProfileRequestContext profileRequestContext) {
+
+        final NameID nameID = nameIDLookupStrategy != null
+                ? nameIDLookupStrategy.apply(profileRequestContext) : null;
+        if (nameID == null) {
+            return null;
+        }
+        
+        final XMLObjectBuilderFactory bf = XMLObjectProviderRegistrySupport.getBuilderFactory();
+        final SAMLObjectBuilder<Subject> subjectBuilder =
+                (SAMLObjectBuilder<Subject>) bf.<Subject>ensureBuilder(Subject.DEFAULT_ELEMENT_NAME);
+        
+        final Subject subject = subjectBuilder.buildObject();
+        subject.setNameID(nameID);
+        
+        log.debug("{} Populating request with NameID '{}' and Format '{}'", getLogPrefix(),
+                nameID.getValue(), nameID.getFormat());
+        
+        return subject;
+    }
+    
     /**
      * Build a {@link Scoping} element, decrementing the proxy count if set.
      * 
@@ -425,7 +474,7 @@ public class AddAuthnRequest extends AbstractAuthenticationAction {
 
         boolean include = false;
         
-        assert profileConfiguration!=null;
+        assert profileConfiguration != null;
         if (profileConfiguration.isIgnoreScoping(profileRequestContext)) {
             log.warn("{} Skipping generation of Scoping element in violation of standard", getLogPrefix());
             return null;
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 62689dc8d..1c508664f 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
@@ -46,10 +46,12 @@ 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;
+import org.opensaml.saml.saml2.core.NameID;
 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.core.Subject;
 import org.opensaml.saml.saml2.metadata.RequestedAttribute;
 import org.opensaml.xmlsec.config.BasicXMLSecurityConfiguration;
 import org.springframework.webflow.execution.Event;
@@ -80,6 +82,7 @@ public class AddAuthnRequestTest extends OpenSAMLInitBaseTestCase {
     private ProfileRequestContext prc1,prc2;
     private RelyingPartyContext rpc;
     private AddAuthnRequest action;
+    private NameID nameID;
     
     /**
      * Set up test state.
@@ -103,10 +106,12 @@ public class AddAuthnRequestTest extends OpenSAMLInitBaseTestCase {
         rp.initialize();
         rpc.setConfiguration(rp);
         rpc.setProfileConfig(new BrowserSSOProfileConfiguration());
-        BrowserSSOProfileConfiguration bspc = (BrowserSSOProfileConfiguration) rpc.getProfileConfig();
+        final BrowserSSOProfileConfiguration bspc = (BrowserSSOProfileConfiguration) rpc.getProfileConfig();
         assert bspc!=null;
         bspc.setSecurityConfiguration(new BasicXMLSecurityConfiguration());
         
+        nameID = null;
+        
         action = new AddAuthnRequest();
         action.setProfileContextLookupStrategy(
                 new ChildContextLookup<>(ProfileRequestContext.class).compose(
@@ -114,6 +119,7 @@ public class AddAuthnRequestTest extends OpenSAMLInitBaseTestCase {
                                 new WebflowRequestContextProfileRequestContextLookup())));
         action.setAuthenticationContextLookupStrategy(new ParentContextLookup<>(AuthenticationContext.class));
         action.setIssuerLookupStrategy(new IssuerLookupFunction());
+        action.setNameIDLookupStrategy(prc -> nameID);
         action.initialize();
     }
     
@@ -173,6 +179,7 @@ public class AddAuthnRequestTest extends OpenSAMLInitBaseTestCase {
         assertTrue(allowCreate != null && allowCreate);
         
         assertNull(request.getRequestedAuthnContext());
+        assertNull(request.getSubject());
         
         final Scoping scoping = request.getScoping();
         assert scoping != null;
@@ -204,7 +211,7 @@ public class AddAuthnRequestTest extends OpenSAMLInitBaseTestCase {
         assertTrue(passive != null && passive);
         
         omc.setMessage(null);
-        BrowserSSOProfileConfiguration bspc = (BrowserSSOProfileConfiguration) rpc.getProfileConfig();
+        final BrowserSSOProfileConfiguration bspc = (BrowserSSOProfileConfiguration) rpc.getProfileConfig();
         assert bspc!=null;
         bspc.setForceAuthn(false);
 
@@ -218,7 +225,7 @@ public class AddAuthnRequestTest extends OpenSAMLInitBaseTestCase {
 
     /** Test that the action works with a NameID format set. */
     @Test public void testNameIDFormat() {
-        BrowserSSOProfileConfiguration bspc = (BrowserSSOProfileConfiguration) rpc.getProfileConfig();
+        final BrowserSSOProfileConfiguration bspc = (BrowserSSOProfileConfiguration) rpc.getProfileConfig();
         assert bspc!=null;
         bspc.setNameIDFormatPrecedence(
                 CollectionSupport.listOf(NameIDType.EMAIL, NameIDType.KERBEROS));
@@ -242,7 +249,7 @@ public class AddAuthnRequestTest extends OpenSAMLInitBaseTestCase {
 
     /** Test that the action works with SPNameQualifier set. */
     @Test public void testSPNameQualifier() {
-        BrowserSSOProfileConfiguration bspc = (BrowserSSOProfileConfiguration) rpc.getProfileConfig();
+        final BrowserSSOProfileConfiguration bspc = (BrowserSSOProfileConfiguration) rpc.getProfileConfig();
         assert bspc!=null;
         bspc.setSPNameQualifier(ActionTestingSupport.INBOUND_MSG_ISSUER);
         
@@ -264,7 +271,7 @@ public class AddAuthnRequestTest extends OpenSAMLInitBaseTestCase {
     /** Test that the action works with AttributeConsumingrServiceIndex set. */
     @Test public void testAttributeIndex() {
         
-        BrowserSSOProfileConfiguration bspc = (BrowserSSOProfileConfiguration) rpc.getProfileConfig();
+        final BrowserSSOProfileConfiguration bspc = (BrowserSSOProfileConfiguration) rpc.getProfileConfig();
         assert bspc!=null;
         bspc.setAttributeIndex(42);
         
@@ -294,7 +301,7 @@ public class AddAuthnRequestTest extends OpenSAMLInitBaseTestCase {
         attr2.setNameFormat(Attribute.URI_REFERENCE);
         attr2.setName("https://attr2.example.org");
 
-        BrowserSSOProfileConfiguration bspc = (BrowserSSOProfileConfiguration) rpc.getProfileConfig();
+        final BrowserSSOProfileConfiguration bspc = (BrowserSSOProfileConfiguration) rpc.getProfileConfig();
         assert bspc!=null;
         bspc.setRequestedAttributes(CollectionSupport.listOf(attr1, attr2));
         
@@ -316,6 +323,32 @@ public class AddAuthnRequestTest extends OpenSAMLInitBaseTestCase {
         assertEquals(extension.getRequestedAttributes().size(), 2);
     }
 
+    /** Test that the action works with a NameID set. */
+    @Test public void testNameIDForSubject() {
+        final XMLObjectBuilderFactory bf = XMLObjectProviderRegistrySupport.getBuilderFactory();
+        final SAMLObjectBuilder<NameID> nameIDBuilder =
+                (SAMLObjectBuilder<NameID>) bf.<NameID>ensureBuilder(
+                        NameID.DEFAULT_ELEMENT_NAME);
+        nameID = nameIDBuilder.buildObject();
+        nameID.setValue("foo");
+        
+        final Event event = action.execute(rc);
+        ActionTestingSupport.assertProceedEvent(event);
+        final MessageContext omc = prc2.getOutboundMessageContext();
+        assert omc!=null;
+
+        assertNotNull(omc.getMessage());
+        assertTrue(omc.getMessage() instanceof AuthnRequest);
+
+        final AuthnRequest request = (AuthnRequest) omc.getMessage();
+        assert request!=null;
+        final Subject subject = request.getSubject();
+        assert subject != null;
+        final NameID n = subject.getNameID();
+        assert n != null;
+        assertEquals(n.getValue(), "foo");
+    }
+    
     /** Test with Scoping element but no count. */
     @Test public void testScopingNoCount() {
         ac.getProxiableAuthorities().add("foo");

-- 
To stop receiving notification emails like this one, please contact
the administrator of this repository.


More information about the commits mailing list