[java-identity-provider] branch main updated: IDP-2155 - Discovery request builder should be overrideable

Scott Cantor cantor.2 at osu.edu
Wed Aug 16 19:56:25 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=9ed74add9f77e8fab9950c8e946717f807487ea1

The following commit(s) were added to refs/heads/main by this push:
     new 9ed74add9 IDP-2155 - Discovery request builder should be overrideable
9ed74add9 is described below

commit 9ed74add9f77e8fab9950c8e946717f807487ea1
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Wed Aug 16 15:56:05 2023 -0400

    IDP-2155 - Discovery request builder should be overrideable
    
    https://shibboleth.atlassian.net/browse/IDP-2155
---
 .../impl/DiscoveryProfileRequestFunction.java      | 52 +++++++++++++++-------
 .../impl/DiscoveryProfileRequestFunctionTest.java  |  2 +-
 .../shibboleth/idp/flows/authn/discovery-beans.xml |  3 +-
 .../shibboleth/idp/flows/authn/discovery-flow.xml  |  4 +-
 4 files changed, 41 insertions(+), 20 deletions(-)

diff --git a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/proxy/impl/DiscoveryProfileRequestFunction.java b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/proxy/impl/DiscoveryProfileRequestFunction.java
index 1ad8f773e..7c9fc37d2 100644
--- a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/proxy/impl/DiscoveryProfileRequestFunction.java
+++ b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/proxy/impl/DiscoveryProfileRequestFunction.java
@@ -14,6 +14,7 @@
 
 package net.shibboleth.idp.authn.proxy.impl;
 
+import java.util.function.BiFunction;
 import java.util.function.Function;
 
 import javax.annotation.Nonnull;
@@ -32,7 +33,6 @@ import net.shibboleth.idp.authn.context.AuthenticationContext;
 import net.shibboleth.profile.context.RelyingPartyContext;
 import net.shibboleth.profile.relyingparty.RelyingPartyConfiguration;
 import net.shibboleth.shared.annotation.constraint.NonnullAfterInit;
-import net.shibboleth.shared.collection.Pair;
 import net.shibboleth.shared.component.AbstractInitializableComponent;
 import net.shibboleth.shared.component.ComponentInitializationException;
 import net.shibboleth.shared.logic.Constraint;
@@ -47,7 +47,7 @@ import net.shibboleth.shared.logic.Constraint;
  */
 @ThreadSafe
 public class DiscoveryProfileRequestFunction extends AbstractInitializableComponent
-        implements Function<Pair<RequestContext,ProfileRequestContext>,String> {
+        implements BiFunction<RequestContext,ProfileRequestContext,String> {
 
     /** URL query parameter escaper. */
     @Nonnull private Escaper escaper;
@@ -58,6 +58,9 @@ public class DiscoveryProfileRequestFunction extends AbstractInitializableCompon
     /** Lookup strategy for determining the "base" discovery URL. */
     @NonnullAfterInit private Function<ProfileRequestContext,String> discoveryURLLookupStrategy;
     
+    /** Overrides this function via an injected bean. */
+    @Nullable private BiFunction<RequestContext,ProfileRequestContext,String> delegatedRequestFunction;
+    
     /** Constructor. */
     public DiscoveryProfileRequestFunction() {
         final Escaper esc = UrlEscapers.urlFormParameterEscaper();
@@ -88,6 +91,21 @@ public class DiscoveryProfileRequestFunction extends AbstractInitializableCompon
         discoveryURLLookupStrategy = Constraint.isNotNull(strategy, "Discovery URL lookup strategy cannot be null");
     }
     
+    /**
+     * Set a function to call in place of this built-in class to generate the request.
+     * 
+     * <p>This is a mechanism to account for how this function gets used in the discovery flow.</p>
+     * 
+     * @param delegate the function to delegate to
+     * 
+     * @since 5.0.0
+     */
+    public void setDelegatedRequestFunction(
+            @Nullable final BiFunction<RequestContext,ProfileRequestContext,String> delegate) {
+        checkSetterPreconditions();
+        delegatedRequestFunction = delegate;
+    }
+    
     /** {@inheritDoc} */
     @Override protected void doInitialize() throws ComponentInitializationException {
         super.doInitialize();
@@ -98,38 +116,40 @@ public class DiscoveryProfileRequestFunction extends AbstractInitializableCompon
     }
     
     /** {@inheritDoc} */
-    @Nullable public String apply(@Nullable final Pair<RequestContext,ProfileRequestContext> input) {
+    @Nullable public String apply(@Nullable final RequestContext springRequestContext,
+            @Nullable final ProfileRequestContext profileRequestContext) {
+        
+        if (delegatedRequestFunction != null) {
+            return delegatedRequestFunction.apply(springRequestContext, profileRequestContext);
+        }
+        
+        if (springRequestContext == null) {
+            throw new IllegalArgumentException("Spring RequestContext cannot be null");
+        }
         
-        assert input != null;
-        final RelyingPartyContext rpCtx = relyingPartyContextLookupStrategy.apply(input.getSecond());
+        final RelyingPartyContext rpCtx = relyingPartyContextLookupStrategy.apply(profileRequestContext);
         Constraint.isNotNull(rpCtx, "RelyingPartyContext cannot be null");
         Constraint.isNotNull(rpCtx.getConfiguration(), "RelyingPartyConfiguration cannot be null");
         
-        final String baseURL = discoveryURLLookupStrategy.apply(input.getSecond());
+        final String baseURL = discoveryURLLookupStrategy.apply(profileRequestContext);
         Constraint.isNotEmpty(baseURL, "Discovery URL cannot be null or empty");
 
         final RelyingPartyConfiguration rpConfig = rpCtx.getConfiguration();
         assert rpConfig!=null;
-        Constraint.isTrue(rpConfig instanceof net.shibboleth.profile.relyingparty.RelyingPartyConfiguration,
-                "RelyingPartyConfiguration was not of expected subclass");
-        final String entityID = ((net.shibboleth.profile.relyingparty.RelyingPartyConfiguration) rpConfig).getIssuer(
-                input.getSecond());
+        final String entityID =rpConfig.getIssuer(profileRequestContext);
 
         final StringBuilder builder = new StringBuilder(baseURL);
         
         builder.append(baseURL.contains("?") ? '&' : '?').append("entityID=").append(escaper.escape(entityID));
         
-        final RequestContext requestCtx = input.getFirst();
-        final ProfileRequestContext prc = input.getSecond();
-        assert requestCtx != null && prc != null;
         final AuthenticationContext authenticationContext =
-                prc.getSubcontext(AuthenticationContext.class);
+                profileRequestContext != null ? profileRequestContext.getSubcontext(AuthenticationContext.class) : null;
         if (authenticationContext != null && authenticationContext.isPassive()) {
             builder.append("&isPassive=true");
         }
         
         final HttpServletRequest httpServletRequest =
-                (HttpServletRequest) requestCtx.getExternalContext().getNativeRequest();
+                (HttpServletRequest) springRequestContext.getExternalContext().getNativeRequest();
         
         final StringBuilder selfBuilder = new StringBuilder(httpServletRequest.getScheme());
         selfBuilder.append("://").append(httpServletRequest.getServerName());
@@ -139,7 +159,7 @@ public class DiscoveryProfileRequestFunction extends AbstractInitializableCompon
             selfBuilder.append(':').append(port);
         }
         
-        selfBuilder.append(requestCtx.getFlowExecutionUrl()).append("&_eventId_proceed=1");
+        selfBuilder.append(springRequestContext.getFlowExecutionUrl()).append("&_eventId_proceed=1");
         
         builder.append("&return=").append(escaper.escape(selfBuilder.toString()));
         
diff --git a/idp-authn-impl/src/test/java/net/shibboleth/idp/authn/proxy/impl/DiscoveryProfileRequestFunctionTest.java b/idp-authn-impl/src/test/java/net/shibboleth/idp/authn/proxy/impl/DiscoveryProfileRequestFunctionTest.java
index 4677800f2..008a79d33 100644
--- a/idp-authn-impl/src/test/java/net/shibboleth/idp/authn/proxy/impl/DiscoveryProfileRequestFunctionTest.java
+++ b/idp-authn-impl/src/test/java/net/shibboleth/idp/authn/proxy/impl/DiscoveryProfileRequestFunctionTest.java
@@ -51,7 +51,7 @@ public class DiscoveryProfileRequestFunctionTest extends BaseAuthenticationConte
     }
     
     @Test public void test() throws MalformedURLException {
-        final URL url = new URL(function.apply(new Pair<>(src, prc)));
+        final URL url = new URL(function.apply(src, prc));
         
         Assert.assertEquals(url.getProtocol(), "https");
         Assert.assertEquals(url.getHost(), "ds.example.org");
diff --git a/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/authn/discovery-beans.xml b/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/authn/discovery-beans.xml
index 4d62045bb..d8d3a0e19 100644
--- a/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/authn/discovery-beans.xml
+++ b/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/authn/discovery-beans.xml
@@ -21,7 +21,8 @@
 
     <bean id="DiscoveryProfileRequestFunction" lazy-init="true"
         class="net.shibboleth.idp.authn.proxy.impl.DiscoveryProfileRequestFunction"
-        p:discoveryURLLookupStrategy="#{getObject('shibboleth.authn.discoveryURLStrategy') ?: getObject('DefaultDiscoveryURLStrategy')}" />
+        p:discoveryURLLookupStrategy="#{getObject('shibboleth.authn.discoveryURLStrategy') ?: getObject('DefaultDiscoveryURLStrategy')}"
+        p:delegatedRequestFunction="#{getObject('shibboleth.authn.discoveryRequestFunction')}" />
 
     <!-- Action beans. -->
 
diff --git a/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/authn/discovery-flow.xml b/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/authn/discovery-flow.xml
index 64b3df1a0..facff0dcc 100644
--- a/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/authn/discovery-flow.xml
+++ b/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/authn/discovery-flow.xml
@@ -6,10 +6,10 @@
     <!-- This is a one-off flow for performing IdP Discovery using a standard SAML discovery service. -->
 
     <on-start>
-        <evaluate expression="opensamlProfileRequestContext.getSubcontext(T(net.shibboleth.idp.authn.context.AuthenticationContext)).setAuthenticatingAuthority(null)" />
+        <evaluate expression="opensamlProfileRequestContext.ensureSubcontext(T(net.shibboleth.idp.authn.context.AuthenticationContext)).setAuthenticatingAuthority(null)" />
     </on-start>
 
-    <view-state id="IssueDiscoveryRequest" view="externalRedirect:#{DiscoveryProfileRequestFunction.apply(new net.shibboleth.shared.collection.Pair(flowRequestContext, opensamlProfileRequestContext))}">
+    <view-state id="IssueDiscoveryRequest" view="externalRedirect:#{DiscoveryProfileRequestFunction.apply(flowRequestContext, opensamlProfileRequestContext)}">
         <attribute name="csrf_excluded" value="true" type="boolean"/>
         <transition on="proceed" to="ExtractDiscoveryResponse" />
     </view-state>

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


More information about the commits mailing list