[java-plugin-shibd-oidc] branch main updated: Improve authentication request lookup strategies

Phil Smart philip.smart at jisc.ac.uk
Fri Oct 3 12:54:18 UTC 2025


This is an automated email from the git hooks/post-receive script.

philsmart pushed a commit to branch main
in repository java-plugin-shibd-oidc.

View the commit online:
http://git.shibboleth.net/view/?p=java-plugin-shibd-oidc.git;a=commit;h=eeb6bef1a058b1a25aa4872b2c7588785bb22575

The following commit(s) were added to refs/heads/main by this push:
     new eeb6bef  Improve authentication request lookup strategies
eeb6bef is described below

commit eeb6bef1a058b1a25aa4872b2c7588785bb22575
Author: Phil Smart <philip.smart at jisc.ac.uk>
AuthorDate: Fri Oct 3 13:54:15 2025 +0100

    Improve authentication request lookup strategies
    
     - Add disallowed feature support
     - Add fallback to profile config (for those driven by the DDF)
     - Improve tests
---
 pom.xml                                            |   2 +-
 .../idp/flows/sp/initiator/oidc/oidc-beans.xml     |  13 +-
 .../sp/oidc/flows/OIDCAuthenticationFlowTest.java  | 105 ++++++++------
 .../idp/module/conf/sp/oidc-test.properties        |   2 +-
 ...tAgentAndRelyingPartyContextLookupFunction.java |  24 +++-
 ...uthenticationContextClassRefLookupStrategy.java |  32 +++--
 .../impl/DefaultRedirectUriCreationFunction.java   | 151 ---------------------
 .../impl/DisplayParameterLookupStrategy.java       |  18 ++-
 .../impl/ForceAuthnParameterLookupStrategy.java    |  51 ++++---
 .../oidc/profile/impl/LoginHintLookupStrategy.java |  37 ++++-
 .../sp/oidc/profile/impl/MaxAgeLookupStrategy.java |  18 ++-
 .../profile/impl/ResponseModeLookupStrategy.java   |   5 +-
 .../profile/impl/ResponseTypeLookupStrategy.java   |   8 +-
 .../impl/SetAuthenticationRequestTimeHandler.java  |   3 +-
 .../AbstractAuthenticationLookupStrategyTest.java  |  84 ++++++++++++
 .../impl/DisplayParameterLookupStrategyTest.java   |  84 ++++++++++++
 .../ForceAuthnParameterLookupStrategyTest.java     | 106 +++++++++++++++
 17 files changed, 479 insertions(+), 264 deletions(-)

diff --git a/pom.xml b/pom.xml
index d81cbb3..f44c83f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -30,7 +30,7 @@ copyright/license information. -->
         <shib-profile.groupId>net.shibboleth</shib-profile.groupId>
         <shib-profile.version>5.2.0-SNAPSHOT</shib-profile.version>
         <oidc-common.groupId>net.shibboleth.oidc</oidc-common.groupId>
-        <oidc-common.version>3.3.0</oidc-common.version>
+        <oidc-common.version>3.3.1-SNAPSHOT</oidc-common.version>
         <oidc-config.groupId>net.shibboleth.idp.plugin.config.oidc</oidc-config.groupId>
         <oidc-config.version>3.0.0</oidc-config.version>
         <idp.groupId>net.shibboleth.idp</idp.groupId>
diff --git a/sp-oidc-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/initiator/oidc/oidc-beans.xml b/sp-oidc-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/initiator/oidc/oidc-beans.xml
index e1d1855..4646a30 100644
--- a/sp-oidc-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/initiator/oidc/oidc-beans.xml
+++ b/sp-oidc-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/initiator/oidc/oidc-beans.xml
@@ -182,17 +182,10 @@
         <property name="errorEvent">
             <util:constant static-field="org.opensaml.profile.action.EventIds.INVALID_MESSAGE" />
         </property>
-    </bean>
-    
-    <!--  TODO, this needs to come from the agent config? -->
-    <bean id="DefaultRedirectUriCreationStrategy" scope="prototype"
-        p:callbackServletPath="sp/callback"
-        p:allowedOrigins="%{sp.oidc.redirecturl.allowedOrigins:}"
-        class="net.shibboleth.sp.oidc.profile.impl.DefaultRedirectUriCreationFunction" />
+    </bean>    
         
     <bean id="RequestObjectRequiredAndSupportedPredicate" scope="prototype"
-        class="net.shibboleth.sp.oidc.config.logic.RequestObjectRequiredAndSupported" />
-    
+        class="net.shibboleth.sp.oidc.config.logic.RequestObjectRequiredAndSupported" />    
     
     <bean id="PopulateRequestObjectSignatureSigningParameters" scope="prototype"
         class="net.shibboleth.oidc.profile.impl.PopulateJWTSignatureSigningParameters"
@@ -321,7 +314,7 @@
                     </property>
                 </bean>
                  <bean id="SetAuthenticationRequestTime"
-                    class="net.shibboleth.sp.oidc.profile.impl.SetAuthenticationRequestTimeHandler" scope="prototype"/>
+                    class="net.shibboleth.sp.oidc.profile.request.impl.SetAuthenticationRequestTimeHandler" scope="prototype"/>
             </list>
         </property>
     </bean>
diff --git a/sp-oidc-conf-impl/src/test/java/net/shibboleth/sp/oidc/flows/OIDCAuthenticationFlowTest.java b/sp-oidc-conf-impl/src/test/java/net/shibboleth/sp/oidc/flows/OIDCAuthenticationFlowTest.java
index 59bdc14..a4b2d97 100644
--- a/sp-oidc-conf-impl/src/test/java/net/shibboleth/sp/oidc/flows/OIDCAuthenticationFlowTest.java
+++ b/sp-oidc-conf-impl/src/test/java/net/shibboleth/sp/oidc/flows/OIDCAuthenticationFlowTest.java
@@ -27,11 +27,14 @@ import org.opensaml.profile.context.ProfileRequestContext;
 import org.opensaml.saml.common.binding.SAMLBindingSupport;
 import org.springframework.test.context.ContextConfiguration;
 import org.springframework.test.context.web.WebAppConfiguration;
+import org.springframework.util.ObjectUtils;
 import org.springframework.webflow.executor.FlowExecutionResult;
 import org.testng.Assert;
 import org.testng.annotations.Test;
 
-import com.nimbusds.oauth2.sdk.AuthorizationRequest;
+import com.nimbusds.jwt.JWTClaimsSet;
+import com.nimbusds.jwt.PlainJWT;
+import com.nimbusds.jwt.SignedJWT;
 import com.nimbusds.oauth2.sdk.ParseException;
 import com.nimbusds.openid.connect.sdk.AuthenticationRequest;
 
@@ -46,7 +49,7 @@ import net.shibboleth.sp.profile.SPConstants;
 import net.shibboleth.sp.profile.impl.IssueCorrelationCookie;
 
 /**
- *
+ * TODO these tests work using a signed request object atm, but the asserts need to work on url params as well
  */
 @ContextConfiguration(
         locations = {
@@ -74,7 +77,7 @@ public class OIDCAuthenticationFlowTest extends AbstractSPFlowTest {
     }
     
     /**
-     * Basic flow test, mainly for TDD.
+     * Basic flow test.
      * 
      * @throws IOException on error
      * @throws MessageDecodingException 
@@ -93,17 +96,16 @@ public class OIDCAuthenticationFlowTest extends AbstractSPFlowTest {
         assertFlowExecutionResult(result, FLOW_ID);
         assertFlowExecutionOutcome(result.getOutcome());
         
-        final AuthorizationRequest req = validateOutputMessage(result);
+        validateOutputMessage(result);
     }
     
     /**
      * Basic flow test with forceAuthn.
      * 
-     * @throws IOException on error
-     * @throws MessageDecodingException 
+     * @throws Exception on error
      */
     @Test
-    public void testForceAuthnFromAgent() throws IOException, MessageDecodingException {
+    public void testForceAuthnFromAgent() throws Exception {
         setDefaultAuth();
         
         final DDF input = new DDF(null).structure();
@@ -117,17 +119,18 @@ public class OIDCAuthenticationFlowTest extends AbstractSPFlowTest {
         assertFlowExecutionResult(result, FLOW_ID);
         assertFlowExecutionOutcome(result.getOutcome());
         
-        final AuthorizationRequest req = validateOutputMessage(result);
+        final AuthenticationRequest req = validateOutputMessage(result);
+        assertValueForParameter(req, "max_age", 0l);
+        assertValueForParameter(req, "prompt", "login");
     }
     
     /**
      * Basic flow test with max_age.
      * 
-     * @throws IOException on error
-     * @throws MessageDecodingException 
+     * @throws Exception on error
      */
     @Test
-    public void testMaxAgeFromAgent() throws IOException, MessageDecodingException {
+    public void testMaxAgeFromAgent() throws Exception {
         setDefaultAuth();
         
         final DDF input = new DDF(null).structure();
@@ -141,17 +144,17 @@ public class OIDCAuthenticationFlowTest extends AbstractSPFlowTest {
         assertFlowExecutionResult(result, FLOW_ID);
         assertFlowExecutionOutcome(result.getOutcome());
         
-        final AuthorizationRequest req = validateOutputMessage(result);
+        final AuthenticationRequest req = validateOutputMessage(result);
+        assertValueForParameter(req, "max_age", 60l);
     }
     
     /**
      * Basic flow test with prompt=none.
      * 
-     * @throws IOException on error
-     * @throws MessageDecodingException 
+     * @throws Exception on error 
      */
     @Test
-    public void testPromptFromAgent() throws IOException, MessageDecodingException {
+    public void testPromptFromAgent() throws Exception {
         setDefaultAuth();
         
         final DDF input = new DDF(null).structure();
@@ -165,17 +168,17 @@ public class OIDCAuthenticationFlowTest extends AbstractSPFlowTest {
         assertFlowExecutionResult(result, FLOW_ID);
         assertFlowExecutionOutcome(result.getOutcome());
         
-        final AuthorizationRequest req = validateOutputMessage(result);
+        final AuthenticationRequest req = validateOutputMessage(result);
+        assertValueForParameter(req, "prompt", "none");
     }
     
     /**
-     * Basic flow test with prompt=none.
+     * Basic flow test with two ACRs.
      * 
-     * @throws IOException on error
-     * @throws MessageDecodingException 
+     * @throws Exception on error
      */
     @Test
-    public void testACRFromAgent() throws IOException, MessageDecodingException {
+    public void testACRFromAgent() throws Exception {
         setDefaultAuth();
         
         final DDF input = new DDF(null).structure();
@@ -192,17 +195,17 @@ public class OIDCAuthenticationFlowTest extends AbstractSPFlowTest {
         assertFlowExecutionResult(result, FLOW_ID);
         assertFlowExecutionOutcome(result.getOutcome());
         
-        final AuthorizationRequest req = validateOutputMessage(result);
+        final AuthenticationRequest req = validateOutputMessage(result);
+        assertValueForParameter(req, "acr_values", "loa1 loa2");
     }
     
     /**
      * Basic flow test with scope=email profile.
      * 
-     * @throws IOException on error
-     * @throws MessageDecodingException 
+     * @throws Exception on error
      */
     @Test
-    public void testScopeFromAgent() throws IOException, MessageDecodingException {
+    public void testScopeFromAgent() throws Exception {
         setDefaultAuth();
         
         final DDF input = new DDF(null).structure();
@@ -215,19 +218,19 @@ public class OIDCAuthenticationFlowTest extends AbstractSPFlowTest {
         final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
         assertFlowExecutionResult(result, FLOW_ID);
         assertFlowExecutionOutcome(result.getOutcome());
-        //TODO TEST THE SCOPES
-        final AuthorizationRequest req = validateOutputMessage(result);
+        
+        final AuthenticationRequest req = validateOutputMessage(result);
+        assertValueForParameter(req, "scope", "openid email profile");
     }
     
     
     /**
      * Basic flow test with display.
      * 
-     * @throws IOException on error
-     * @throws MessageDecodingException 
+     * @throws Exception on error
      */
     @Test
-    public void testDisplayFromAgent() throws IOException, MessageDecodingException {
+    public void testDisplayFromAgent() throws Exception {
         setDefaultAuth();
         
         final DDF input = new DDF(null).structure();
@@ -240,8 +243,9 @@ public class OIDCAuthenticationFlowTest extends AbstractSPFlowTest {
         final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
         assertFlowExecutionResult(result, FLOW_ID);
         assertFlowExecutionOutcome(result.getOutcome());
-        
-        final AuthorizationRequest req = validateOutputMessage(result);
+
+        final AuthenticationRequest req = validateOutputMessage(result);
+        assertValueForParameter(req, "display", "page");
     }
     
     /**
@@ -253,7 +257,7 @@ public class OIDCAuthenticationFlowTest extends AbstractSPFlowTest {
      * 
      * @throws MessageDecodingException
      */
-    @Nonnull private AuthorizationRequest validateOutputMessage(@Nonnull final FlowExecutionResult result)
+    @Nonnull private AuthenticationRequest validateOutputMessage(@Nonnull final FlowExecutionResult result)
             throws MessageDecodingException {
         final ProfileRequestContext prc = retrieveProfileRequestContext(result);
         assert prc != null;
@@ -266,7 +270,7 @@ public class OIDCAuthenticationFlowTest extends AbstractSPFlowTest {
         final DDF http = output.getmember(RemotedHttpServletResponse.STRUCTURE_NAME);
         Assert.assertTrue(http.isstruct());
         
-        final AuthorizationRequest authnRequest;
+        final AuthenticationRequest authnRequest;
         final byte[] redirect = http.getmember(RemotedHttpServletResponse.REDIRECT).unsafe_string();
         if (redirect != null) {
             final String redirectURL = new String(redirect, StandardCharsets.UTF_8);
@@ -310,14 +314,37 @@ public class OIDCAuthenticationFlowTest extends AbstractSPFlowTest {
            //TODO Not Set yet:  Assert.assertTrue(foundCorrelationCookie);
         }
         
-//        final NameIDPolicy pol = authnRequest.getNameIDPolicy();
-//        assert pol != null;
-//        assertTrue(pol.getAllowCreate());
-//        Assert.assertEquals(pol.getFormat(), format);
         
         return authnRequest;
     }
     
+    /**
+     * Find the String value for the parameter from the {@link AuthenticationRequest}, either in the params or inside
+     * a claim in the Request Object.
+     * 
+     * @param request the request to locate the parameter from
+     * @param claim the claim to find
+     * 
+     * @return the value if found.
+     * @throws java.text.ParseException 
+     */
+    private void assertValueForParameter(final AuthenticationRequest request, @Nonnull final String claim,
+            final Object expectedClaimValue) 
+                throws java.text.ParseException {
+        JWTClaimsSet requestObjectClaims = null;
+        if (request.getRequestObject() instanceof final SignedJWT signed) {
+            requestObjectClaims = signed.getJWTClaimsSet();
+        } else if (request.getRequestObject() instanceof final PlainJWT jwt){
+            requestObjectClaims = jwt.getJWTClaimsSet();
+        }
+        
+        Object claimValue = null;
+        if (requestObjectClaims != null) {
+            claimValue = requestObjectClaims.getClaim(claim);
+        }
+        assertTrue(ObjectUtils.nullSafeEquals(claimValue, expectedClaimValue));
+    }
+    
     /**
      * Decodes an OAuth authorization message encoded via HTTP-Redirect binding.
      * 
@@ -327,13 +354,13 @@ public class OIDCAuthenticationFlowTest extends AbstractSPFlowTest {
      * @return decoded message
      * @throws MessageDecodingException 
      */
-    @Nonnull protected AuthorizationRequest decodeRedirect(@Nullable final String url, @Nullable final String relayState)
+    @Nonnull protected AuthenticationRequest decodeRedirect(@Nullable final String url, @Nullable final String relayState)
             throws MessageDecodingException {
         if (url == null) {
             throw new MessageDecodingException("URl is null");
         }
         try {
-            return AuthorizationRequest.parse(new URI(url));
+            return AuthenticationRequest.parse(new URI(url));
         } catch (final ParseException | URISyntaxException e) {
             throw new MessageDecodingException("No message, or incorrect type.", e);
         }
diff --git a/sp-oidc-conf-impl/src/test/resources/net/shibboleth/idp/module/conf/sp/oidc-test.properties b/sp-oidc-conf-impl/src/test/resources/net/shibboleth/idp/module/conf/sp/oidc-test.properties
index bff09e5..f374c9b 100644
--- a/sp-oidc-conf-impl/src/test/resources/net/shibboleth/idp/module/conf/sp/oidc-test.properties
+++ b/sp-oidc-conf-impl/src/test/resources/net/shibboleth/idp/module/conf/sp/oidc-test.properties
@@ -20,7 +20,7 @@ sp.oidc.signing.rsa.enc.key = %{idp.home}/credentials/sp/sp-encryption-rsa.jwk
 sp.oidc.redirecturl.allowedOrigins = http://localhost
 
 ## TEST ENC FOR NOW from profile config
-idp.oidc.requestobject.encrypted = true
+idp.oidc.requestobject.encrypted = false
 
 #idp.oidc.encryption.config = dummy.oidc.EncryptionConfiguration
 
diff --git a/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/AbstractAgentAndRelyingPartyContextLookupFunction.java b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/AbstractAgentAndRelyingPartyContextLookupFunction.java
index 69d1f4d..48177ab 100644
--- a/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/AbstractAgentAndRelyingPartyContextLookupFunction.java
+++ b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/AbstractAgentAndRelyingPartyContextLookupFunction.java
@@ -96,7 +96,7 @@ public abstract class AbstractAgentAndRelyingPartyContextLookupFunction<ResultTy
      * 
      * @return the agent
      */
-    @Nullable public Agent getAgent(@Nullable final MessageContext input) {
+    @Nullable protected Agent getAgent(@Nullable final MessageContext input) {
         final AgentRequestContext arc = agentRequestContextLookupStrategy.apply(input);
         if (arc == null) {
             return null;
@@ -109,7 +109,7 @@ public abstract class AbstractAgentAndRelyingPartyContextLookupFunction<ResultTy
      * 
      * @return the agent
      */
-    @Nullable public Application getApplication(@Nullable final MessageContext input) {
+    @Nullable protected Application getApplication(@Nullable final MessageContext input) {
         final AgentRequestContext arc = agentRequestContextLookupStrategy.apply(input);
         if (arc == null) {
             return null;
@@ -122,7 +122,7 @@ public abstract class AbstractAgentAndRelyingPartyContextLookupFunction<ResultTy
      * 
      * @return the input or output DDF
      */
-    @Nullable public DDF getDDF(@Nullable final MessageContext input, @Nonnull final DDFDirection direction) {
+    @Nullable protected DDF getDDF(@Nullable final MessageContext input, @Nonnull final DDFDirection direction) {
         final AgentRequestContext arc = agentRequestContextLookupStrategy.apply(input);
         if (arc == null) {
             return null;
@@ -136,6 +136,24 @@ public abstract class AbstractAgentAndRelyingPartyContextLookupFunction<ResultTy
                 return null; 
         }
     }
+    /**
+     * Determine if the feature is disallowed for the current relying party configuration.
+     * 
+     * @param feature the feature to check
+     * @param messageCtx the message context to extract the profile configuration from
+     * 
+     * @return true iff the feature is disallowed, false otherwise
+     */
+    protected boolean isFeatureDisallowed(final int feature, @Nullable final MessageContext messageCtx) {
+        
+        final OIDCAuthenticationRelyingPartyProfileConfiguration config = 
+                getOIDCRelyingPartyProfileConfiguration(messageCtx);
+        
+        if (config != null) {
+            return config.isFeatureDisallowed(PRC_LOOKUP.apply(messageCtx), feature);
+        }
+        return false;
+    }
     
 
     /**
diff --git a/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/AuthenticationContextClassRefLookupStrategy.java b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/AuthenticationContextClassRefLookupStrategy.java
index 935b2e7..e569b4e 100644
--- a/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/AuthenticationContextClassRefLookupStrategy.java
+++ b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/AuthenticationContextClassRefLookupStrategy.java
@@ -25,6 +25,8 @@ import org.slf4j.Logger;
 
 import com.nimbusds.openid.connect.sdk.claims.ACR;
 
+import net.shibboleth.oidc.profile.config.OIDCAuthenticationRelyingPartyProfileConfiguration;
+import net.shibboleth.oidc.profile.config.OIDCAuthorizationConfiguration;
 import net.shibboleth.shared.collection.CollectionSupport;
 import net.shibboleth.shared.primitive.LoggerFactory;
 import net.shibboleth.sp.ddf.DDF;
@@ -32,12 +34,10 @@ import net.shibboleth.sp.oidc.profile.OIDCInitiatorConstants;
 
 
 /**
- * A lookup strategy that extracts a list of {@link ACR} (Authentication Context Class References)
- * from the input {@link DDF} message within the current {@link MessageContext}.
- * <p>
- * The extracted strings are converted into {@link ACR} objects and returned as an immutable list.
- * If no input is available or the context is missing, the strategy returns {@code null}.
- * </p>
+ * A strategy function that extracts requested Authentication Context Class References (ACRs)
+ * from the inbound {@link MessageContext} and returns them as a list of {@link ACR} objects. Takes them from
+ * the inbound {@link DDF} object if they exist, if they do not exist or they were disallowed by the Hub configuration
+ * they are taken from the relying party configuration.
  */
 public class AuthenticationContextClassRefLookupStrategy 
         extends AbstractAgentAndRelyingPartyContextLookupFunction<List<ACR>> {
@@ -50,18 +50,24 @@ public class AuthenticationContextClassRefLookupStrategy
         final DDF input = getDDF(messageCtx, DDFDirection.INPUT);
         if (input == null) {
             return null;
-        }
-        final List<String> classrefs = input.getmember(OIDCInitiatorConstants.AUTHN_CONTEXT_CLASS_REF).asList()
+        }        
+        final OIDCAuthenticationRelyingPartyProfileConfiguration rpConfig = 
+                getOIDCRelyingPartyProfileConfiguration(messageCtx);
+        
+        List<String> classrefs = input.getmember(OIDCInitiatorConstants.AUTHN_CONTEXT_CLASS_REF).asList()
                 .stream()
                 .map(DDF::string)
                 .collect(CollectionSupport.nonnullCollector(Collectors.toUnmodifiableList())).get();
         
+        if (!classrefs.isEmpty() && isFeatureDisallowed(OIDCAuthorizationConfiguration.FEATURE_ESSENTIAL_ACR_REQUEST, 
+                messageCtx)) {
+            log.warn("Agent disallowed from overriding ACR request");
+            classrefs = CollectionSupport.emptyList();
+        }
         
-//        if (!classrefs.isEmpty() && profileConfiguration.isFeatureDisallowed(profileRequestContext,
-//                BrowserSSOProfileConfiguration.FEATURE_AUTHNCONTEXT)) {
-//            log.warn("{} Agent disallowed from overriding RequestedAuthnContext", getLogPrefix());
-//            classrefs = CollectionSupport.emptyList();
-//        }
+        if (rpConfig != null && classrefs.isEmpty()) {
+            rpConfig.getAuthnContextClassRefs(PRC_LOOKUP.apply(messageCtx));
+        }
         
         return classrefs.stream().map(ACR::new).toList();
 
diff --git a/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/DefaultRedirectUriCreationFunction.java b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/DefaultRedirectUriCreationFunction.java
deleted file mode 100644
index d3c85ed..0000000
--- a/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/DefaultRedirectUriCreationFunction.java
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package net.shibboleth.sp.oidc.profile.impl;
-
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.util.Collections;
-import java.util.Set;
-import java.util.function.BiFunction;
-import java.util.function.Function;
-
-import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
-
-import org.opensaml.messaging.context.navigate.ChildContextLookup;
-import org.opensaml.profile.context.ProfileRequestContext;
-import org.opensaml.profile.context.navigate.OutboundMessageContextLookup;
-import org.slf4j.Logger;
-
-import jakarta.servlet.http.HttpServletRequest;
-import net.shibboleth.oidc.profile.messaging.context.OIDCPeerEntityContext;
-import net.shibboleth.shared.annotation.constraint.NonnullAfterInit;
-import net.shibboleth.shared.annotation.constraint.NotEmpty;
-import net.shibboleth.shared.annotation.constraint.ThreadSafeAfterInit;
-import net.shibboleth.shared.component.AbstractIdentifiableInitializableComponent;
-import net.shibboleth.shared.component.ComponentInitializationException;
-import net.shibboleth.shared.logic.Constraint;
-import net.shibboleth.shared.primitive.LoggerFactory;
-import net.shibboleth.shared.primitive.StringSupport;
-import net.shibboleth.sp.oidc.context.OAuth2ClientContext;
-
-/**
- *  Constructive, pure, function that returns a redirect_uri from one of (ordered):
- *  <ol>
- *      <li>A pre-registered redirect_uri on the {@link OAuth2ClientContext#getRedirectUriOverride()}. 
- *      Or, if none are pre-registered;
- *      <li>Derived from the HTTP Servlet request server parameters, checking the origin
- *          against an allowed set of origins - to prevent Host header injection.
- *   </ol>
- *  
- *  <p>Returns null if one can not be constructed.</p>
- *  
- *  <p>Is thread-safe and immutable</p> 
- */
- at ThreadSafeAfterInit
-public class DefaultRedirectUriCreationFunction extends AbstractIdentifiableInitializableComponent
-                        implements BiFunction<HttpServletRequest, ProfileRequestContext, URI> {
-    
-    /** Class logger. */
-    @Nonnull private final Logger log = LoggerFactory.getLogger(DefaultRedirectUriCreationFunction.class);
-    
-    /** The strategy used to lookup or create the {@link OAuth2ClientContext} for storing the client_id.*/
-    @Nonnull private Function<ProfileRequestContext, OAuth2ClientContext> oauth2ClientContextLookupStrategy;
-    
-    /** The path, excluding the context and servlet paths, to the RP callback handler.*/
-    @NonnullAfterInit @NotEmpty private String callbackServletPath;
-    
-    /** 
-     * A set of 'allowed' origins that can be used as the scheme, host, and port portion of the redirectURI.
-     * Can be null, if so a redirect_uri must be specified in the context tree.
-     */
-    @NonnullAfterInit private Set<String> allowedOrigins;
-    
-    /**
-     * Constructor.
-     */
-    public DefaultRedirectUriCreationFunction() {          
-        // Default under OIDCPeerEntityContext in the outbound context (create true) under the nested PRC.
-        oauth2ClientContextLookupStrategy = new ChildContextLookup<>(OAuth2ClientContext.class).compose(
-                new ChildContextLookup<>(OIDCPeerEntityContext.class).compose(
-                        new OutboundMessageContextLookup()));        
-    }
-    
-    @Override
-    protected void doInitialize() throws ComponentInitializationException {
-        super.doInitialize();
-        
-        if (StringSupport.trimOrNull(callbackServletPath) == null) {
-            throw new ComponentInitializationException("Callback servlet path can not be null");
-        }
-        if (allowedOrigins == null) {
-            allowedOrigins = Collections.emptySet();
-        }
-    }
-    
-    /**
-     * Set the path segment relative to the servlet path of the callback endpoint.
-     * 
-     * @param path the callback servlet path
-     */
-    public void setCallbackServletPath(@Nonnull @NotEmpty final String path) {
-    	checkSetterPreconditions();
-
-        callbackServletPath = Constraint.isNotEmpty(path, "callbackServletPath can not be null");
-    }
-    
-    /**
-     * Set the allowed origins to use if a redirect_uri is computed.
-     * 
-     * @param origins the origins
-     */
-    public void setAllowedOrigins(@Nullable final Set<String> origins) {
-    	checkSetterPreconditions();
-        
-        if (origins == null) {
-            allowedOrigins = Collections.emptySet();
-        }
-        allowedOrigins = Collections.unmodifiableSet(origins);
-    }
-
-    
-    /**
-     * Set the strategy to lookup the {@link OAuth2ClientContext} 
-     * from the {@link ProfileRequestContext}.
-     * 
-     * @param strgy the strategy.
-     */
-    public void setOAuth2ClientContextLookupStrategy(
-            @Nonnull final Function<ProfileRequestContext, OAuth2ClientContext> strgy) {        
-    	checkSetterPreconditions();
-
-        oauth2ClientContextLookupStrategy = Constraint.isNotNull(strgy, 
-                "OAuth2 client context lookup strategy cannot be null");
-    }
-
-    @Override
-    @Nullable public URI apply(@Nullable final HttpServletRequest request, @Nullable final ProfileRequestContext prc) {
-        
-        //TODO from the agent context, but maybe still use allowedOrigins concept? not sure relevant if not comming from
-        //user input, depends where the Agent gets it from.
-        try {
-            return new URI(String.format("%s://%s/%s", "http","localhost","callback"));
-        } catch (final URISyntaxException e) {
-            return null;
-        }
-    }
-    
-    
-}
diff --git a/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/DisplayParameterLookupStrategy.java b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/DisplayParameterLookupStrategy.java
index 55c0e0d..dd54868 100644
--- a/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/DisplayParameterLookupStrategy.java
+++ b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/DisplayParameterLookupStrategy.java
@@ -18,21 +18,29 @@ import javax.annotation.Nullable;
 
 import org.opensaml.messaging.context.MessageContext;
 
+import net.shibboleth.oidc.profile.config.OIDCAuthenticationRelyingPartyProfileConfiguration;
 import net.shibboleth.sp.ddf.DDF;
 import net.shibboleth.sp.oidc.profile.OIDCInitiatorConstants;
 
 /**
- * Retrieve the 'display' parameter from the {@link DDF}.
+ * Retrieve the 'display' parameter from either the {@link DDF} if present, or the profile configuration.
  */
 public class DisplayParameterLookupStrategy extends AbstractAgentAndRelyingPartyContextLookupFunction<String> {
 
     /** {@inheritDoc} */
     @Nullable public String apply(final MessageContext messageCtx) {
+
         final DDF input = getDDF(messageCtx, DDFDirection.INPUT);
-        if (input == null) {
-            return null;
+        if (input != null) {
+            final String display = input.getmember(OIDCInitiatorConstants.DISPLAY).string();
+            if (display != null) {
+                return display;
+            }
         }
-        return input.getmember(OIDCInitiatorConstants.DISPLAY).string();
+    
+        final OIDCAuthenticationRelyingPartyProfileConfiguration rpConfig =
+                getOIDCRelyingPartyProfileConfiguration(messageCtx);
+    
+        return rpConfig != null ? rpConfig.getDisplay(PRC_LOOKUP.apply(messageCtx)) :  null;    
     }
-
 }
diff --git a/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/ForceAuthnParameterLookupStrategy.java b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/ForceAuthnParameterLookupStrategy.java
index 0f93fb7..1ec550c 100644
--- a/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/ForceAuthnParameterLookupStrategy.java
+++ b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/ForceAuthnParameterLookupStrategy.java
@@ -14,17 +14,33 @@
 
 package net.shibboleth.sp.oidc.profile.impl;
 
+import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 
 import org.opensaml.messaging.context.MessageContext;
+import org.slf4j.Logger;
 
+import net.shibboleth.oidc.profile.config.OIDCAuthenticationRelyingPartyProfileConfiguration;
+import net.shibboleth.oidc.profile.config.OIDCAuthorizationConfiguration;
+import net.shibboleth.shared.primitive.LoggerFactory;
 import net.shibboleth.sp.ddf.DDF;
 import net.shibboleth.sp.oidc.profile.OIDCInitiatorConstants;
 
 /**
- * Retrieve the ForceAuthn parameter from the {@link DDF}.
+ * Retrieve the ForceAuthn parameter. 
+ * 
+ * <p>This method first checks the inbound {@link DDF} input for the {@code FORCE_AUTHN} parameter.
+ * If present, set to {@code 1}, and the Hub has not disallowed it, it returns {@code true}. If the feature is 
+ * disallowed, it returns {@code false}.</p>
+ *
+ * <p>If the parameter is not present in the {@link DDF}, the method falls back to using the the relying party profile
+ * configuration.</p>
+
  */
 public class ForceAuthnParameterLookupStrategy extends AbstractAgentAndRelyingPartyContextLookupFunction<Boolean> {
+    
+    /** Logger. */
+    @Nonnull private final Logger log = LoggerFactory.getLogger(ForceAuthnParameterLookupStrategy.class);
 
     /** {@inheritDoc} */
     @Nullable public Boolean apply(final MessageContext messageCtx) {
@@ -35,31 +51,22 @@ public class ForceAuthnParameterLookupStrategy extends AbstractAgentAndRelyingPa
         final Integer forceAuthn = input.getmember(OIDCInitiatorConstants.FORCE_AUTHN).integer();
         
         if (forceAuthn != null) {
-            // TODO disallow feature if set but not allowed
-//            if (profileConfiguration.isFeatureDisallowed(profileRequestContext,
-//                    BrowserSSOProfileConfiguration.FEATURE_FORCEAUTHN)) {
-//                log.warn("{} Agent disallowed from overriding ForceAuthn", getLogPrefix());
-//            } 
-            if (forceAuthn == 1) {
+            if (isFeatureDisallowed(OIDCAuthorizationConfiguration.FEATURE_FORCEAUTHN, messageCtx)) {
+                log.warn("Agent disallowed from overriding ForceAuthn");
+                return false;
+            }
+            else if (forceAuthn == 1) {
                 return true;
             }
-            return false;
+        }
+        
+        final OIDCAuthenticationRelyingPartyProfileConfiguration rpConfig = 
+                getOIDCRelyingPartyProfileConfiguration(messageCtx);
+        
+        if (rpConfig != null) {
+            return rpConfig.isForceAuthn(PRC_LOOKUP.apply(messageCtx));
         }
         return false;
-        // Else try from Profile config
-//        if (getProfileConfiguration().isForceAuthn(lookupProfileRequestContext(messageContext))) {
-//            log.trace("{} Setting prompt=login and max_age=0 (ForceAuthn) for OIDC AuthnRequest", getLogPrefix());
-//            try {
-//                getAuthenticationRequest().setPrompt(Prompt.parse(Prompt.Type.LOGIN.toString()));
-//                getAuthenticationRequest().setMaxAge(Duration.ofSeconds(0));
-//            } catch (final ParseException e) {
-//                // This should never happen
-//                throw new MessageHandlerException("Unable to honour force-authn, "
-//                        + "setting prompt to force-login as failed", e);
-//            }
-//        } else {
-//            log.trace("{} No ForceAuthn requirement, so no prompt or max_age set", getLogPrefix());
-//        }
     }
 
 }
diff --git a/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/LoginHintLookupStrategy.java b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/LoginHintLookupStrategy.java
index 8f45297..3d23a25 100644
--- a/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/LoginHintLookupStrategy.java
+++ b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/LoginHintLookupStrategy.java
@@ -14,25 +14,56 @@
 
 package net.shibboleth.sp.oidc.profile.impl;
 
+import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 
 import org.opensaml.messaging.context.MessageContext;
+import org.slf4j.Logger;
 
+import net.shibboleth.oidc.profile.config.OIDCAuthenticationRelyingPartyProfileConfiguration;
+import net.shibboleth.oidc.profile.config.OIDCAuthorizationConfiguration;
+import net.shibboleth.shared.primitive.LoggerFactory;
 import net.shibboleth.sp.ddf.DDF;
 import net.shibboleth.sp.oidc.profile.OIDCInitiatorConstants;
 
 /**
- * Retrieve the 'login_hint' parameter from the {@link DDF}.
+ * Retrieve the 'login_hint' parameter from the {@link DDF} if it is present and
+ * the Hub configuration has not disallowed the Agent from setting it.
+ *
+ * <p>
+ * If the parameter is not present in the {@link DDF}, the method falls back to
+ * using the the relying party profile configuration.
+ * </p>
  */
 public class LoginHintLookupStrategy extends AbstractAgentAndRelyingPartyContextLookupFunction<String> {
 
+    /** Logger. */
+    @Nonnull
+    private final Logger log = LoggerFactory.getLogger(LoginHintLookupStrategy.class);
+
     /** {@inheritDoc} */
-    @Nullable public String apply(final MessageContext messageCtx) {
+    @Nullable
+    public String apply(final MessageContext messageCtx) {
         final DDF input = getDDF(messageCtx, DDFDirection.INPUT);
         if (input == null) {
             return null;
         }
-        return input.getmember(OIDCInitiatorConstants.LOGIN_HINT).string();
+        
+        final String loginHint = input.getmember(OIDCInitiatorConstants.LOGIN_HINT).string();    
+
+        if (loginHint != null) {
+            if (isFeatureDisallowed(OIDCAuthorizationConfiguration.FEATURE_LOGIN_HINT, messageCtx)) {
+                log.warn("Agent disallowed from setting the login_hint");
+                return null;
+            }
+            return loginHint;
+        }
+
+        final OIDCAuthenticationRelyingPartyProfileConfiguration rpConfig = getOIDCRelyingPartyProfileConfiguration(
+                messageCtx);
+
+        return rpConfig != null ? rpConfig.getLoginHint(PRC_LOOKUP.apply(messageCtx)) : null;
+
     }
 
 }
diff --git a/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/MaxAgeLookupStrategy.java b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/MaxAgeLookupStrategy.java
index 0f00321..3f9b409 100644
--- a/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/MaxAgeLookupStrategy.java
+++ b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/MaxAgeLookupStrategy.java
@@ -20,11 +20,17 @@ import javax.annotation.Nullable;
 
 import org.opensaml.messaging.context.MessageContext;
 
+import net.shibboleth.oidc.profile.config.OIDCAuthenticationRelyingPartyProfileConfiguration;
 import net.shibboleth.sp.ddf.DDF;
 import net.shibboleth.sp.oidc.profile.OIDCInitiatorConstants;
 
 /**
- * Retrieve the max_age parameter from the {@link DDF}.
+ * Retrieve the max_age parameter from the {@link DDF} if present.
+ *
+ * <p>
+ * If the parameter is not present in the {@link DDF}, the method falls back to
+ * using the the relying party profile configuration.
+ * </p>
  */
 public class MaxAgeLookupStrategy extends AbstractAgentAndRelyingPartyContextLookupFunction<Duration> {
 
@@ -35,10 +41,14 @@ public class MaxAgeLookupStrategy extends AbstractAgentAndRelyingPartyContextLoo
             return null;
         }
         final Long maxAge = input.getmember(OIDCInitiatorConstants.MAX_AGE).longinteger();
-        if (maxAge == null) {
-            return null;
+        if (maxAge != null) {
+            return Duration.ofSeconds(maxAge);
         }
-        return Duration.ofSeconds(maxAge);
+        final OIDCAuthenticationRelyingPartyProfileConfiguration rpConfig = getOIDCRelyingPartyProfileConfiguration(
+                messageCtx);
+
+        return rpConfig != null ? rpConfig.getMaxAuthenticationAge(PRC_LOOKUP.apply(messageCtx)) : null;       
+        
     }
 
 }
diff --git a/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/ResponseModeLookupStrategy.java b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/ResponseModeLookupStrategy.java
index d9e8f1b..44e67e4 100644
--- a/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/ResponseModeLookupStrategy.java
+++ b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/ResponseModeLookupStrategy.java
@@ -21,12 +21,9 @@ import org.opensaml.messaging.context.MessageContext;
 import com.nimbusds.oauth2.sdk.ResponseMode;
 
 import net.shibboleth.oidc.profile.config.OIDCAuthenticationRelyingPartyProfileConfiguration;
-import net.shibboleth.profile.context.RelyingPartyContext;
 
 /**
- * A lookup strategy that resolves an OpenID Connect {@link ResponseMode} from the current {@link MessageContext}.
- * <p>
- * This strategy inspects the active {@link RelyingPartyContext} and its associated
+ * A lookup strategy that resolves an OpenID Connect {@link ResponseMode} from the
  * {@link OIDCAuthenticationRelyingPartyProfileConfiguration}. If a response mode
  * is configured in the relying party profile, it is parsed into a known
  * {@link ResponseMode} value. If no configuration is available or the configured
diff --git a/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/ResponseTypeLookupStrategy.java b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/ResponseTypeLookupStrategy.java
index 1d3a910..553a071 100644
--- a/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/ResponseTypeLookupStrategy.java
+++ b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/ResponseTypeLookupStrategy.java
@@ -24,15 +24,9 @@ import org.opensaml.profile.context.navigate.ParentProfileRequestContextLookup;
 import com.nimbusds.oauth2.sdk.ResponseType;
 
 import net.shibboleth.oidc.profile.config.OIDCAuthenticationRelyingPartyProfileConfiguration;
-import net.shibboleth.profile.context.RelyingPartyContext;
 
 /**
- * A lookup strategy that resolves the {@link ResponseType} to use
- * for a relying party, based the {@link OIDCAuthenticationRelyingPartyProfileConfiguration}.
- * 
- *  A lookup strategy that resolves an OpenID Connect {@link ResponseType} from the current {@link MessageContext}.
- * <p>
- * This strategy inspects the active {@link RelyingPartyContext} and its associated
+ *  A lookup strategy that resolves an OpenID Connect {@link ResponseType} from the 
  * {@link OIDCAuthenticationRelyingPartyProfileConfiguration}. If a response type
  * is configured in the relying party profile, it is parsed into a known
  * {@link ResponseType} value. If no configuration is available or the configured
diff --git a/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/SetAuthenticationRequestTimeHandler.java b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/request/impl/SetAuthenticationRequestTimeHandler.java
similarity index 90%
rename from sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/SetAuthenticationRequestTimeHandler.java
rename to sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/request/impl/SetAuthenticationRequestTimeHandler.java
index 51bdeba..7d92943 100644
--- a/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/SetAuthenticationRequestTimeHandler.java
+++ b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/request/impl/SetAuthenticationRequestTimeHandler.java
@@ -12,7 +12,7 @@
  * limitations under the License.
  */
 
-package net.shibboleth.sp.oidc.profile.impl;
+package net.shibboleth.sp.oidc.profile.request.impl;
 
 import java.time.Instant;
 
@@ -23,6 +23,7 @@ import org.opensaml.messaging.handler.MessageHandlerException;
 import org.slf4j.Logger;
 
 import net.shibboleth.shared.primitive.LoggerFactory;
+import net.shibboleth.sp.oidc.profile.impl.AbstractAuthenticationRequestParameterValueMessageHandler;
 
 
 /** Handler that adds the authentication request time to the authentication request.*/
diff --git a/sp-oidc-impl/src/test/java/net/shibboleth/sp/oidc/profile/impl/AbstractAuthenticationLookupStrategyTest.java b/sp-oidc-impl/src/test/java/net/shibboleth/sp/oidc/profile/impl/AbstractAuthenticationLookupStrategyTest.java
new file mode 100644
index 0000000..8f10c41
--- /dev/null
+++ b/sp-oidc-impl/src/test/java/net/shibboleth/sp/oidc/profile/impl/AbstractAuthenticationLookupStrategyTest.java
@@ -0,0 +1,84 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.shibboleth.sp.oidc.profile.impl;
+
+import java.nio.charset.StandardCharsets;
+
+import javax.annotation.Nonnull;
+
+import org.opensaml.messaging.context.MessageContext;
+import org.opensaml.profile.context.ProfileRequestContext;
+import org.springframework.webflow.execution.RequestContext;
+import org.testng.annotations.BeforeMethod;
+
+import net.shibboleth.idp.authn.context.AuthenticationContext;
+import net.shibboleth.idp.profile.context.navigate.WebflowRequestContextProfileRequestContextLookup;
+import net.shibboleth.idp.profile.testing.RequestContextBuilder;
+import net.shibboleth.oidc.profile.config.impl.DefaultOIDCAuthorizationConfiguration;
+import net.shibboleth.profile.context.RelyingPartyContext;
+import net.shibboleth.shared.component.ComponentInitializationException;
+import net.shibboleth.sp.context.AgentRequestContext;
+import net.shibboleth.sp.ddf.DDF;
+
+/**
+ * An abstract test class for lookup functions that work to build authentication requests.
+ */
+public abstract class AbstractAuthenticationLookupStrategyTest {    
+
+    /** Resource URL. */
+    @Nonnull
+    public static final byte[] RESOURCE_URL = "https://sp.example.org/secure".getBytes(StandardCharsets.UTF_8);
+
+    /** REDIRECT URI. */
+    @Nonnull
+    public static final String RESPONSE_URL = "https://sp.example.org/Shibboleth.sso/callback";
+    
+    protected RequestContext rc;
+    protected MessageContext mc;
+    protected AuthenticationContext ac;
+    protected ProfileRequestContext prc;
+    protected RelyingPartyContext rpc;
+    protected AgentRequestContext arc;
+    protected RelyingPartyContext partyContext;
+    
+    /** The RP config.*/
+    protected DefaultOIDCAuthorizationConfiguration rpConfig;
+    
+    @BeforeMethod
+    public void setUp() throws ComponentInitializationException {
+        rc = new RequestContextBuilder().buildRequestContext();
+        prc = new WebflowRequestContextProfileRequestContextLookup().apply(rc);
+        ac = prc.ensureSubcontext(AuthenticationContext.class);
+        mc = new MessageContext();
+        prc.setOutboundMessageContext(mc);
+        arc = new AgentRequestContext();
+        prc.addSubcontext(arc);
+        
+        partyContext = prc.ensureSubcontext(RelyingPartyContext.class);
+        rpConfig = new DefaultOIDCAuthorizationConfiguration();
+        partyContext.setProfileConfig(rpConfig);
+        prc.addSubcontext(partyContext);
+    }
+    
+    /**
+     * Add the {@link DDF} to the agent request context.
+     * 
+     * @param input the {@link DDF} to add.
+     */
+    protected void addDDFToAgentRequestContext(final DDF input) {
+        arc.setInput(input);
+    }
+
+}
diff --git a/sp-oidc-impl/src/test/java/net/shibboleth/sp/oidc/profile/impl/DisplayParameterLookupStrategyTest.java b/sp-oidc-impl/src/test/java/net/shibboleth/sp/oidc/profile/impl/DisplayParameterLookupStrategyTest.java
new file mode 100644
index 0000000..49dcf72
--- /dev/null
+++ b/sp-oidc-impl/src/test/java/net/shibboleth/sp/oidc/profile/impl/DisplayParameterLookupStrategyTest.java
@@ -0,0 +1,84 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.shibboleth.sp.oidc.profile.impl;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertNull;
+
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import net.shibboleth.shared.component.ComponentInitializationException;
+import net.shibboleth.sp.ddf.DDF;
+import net.shibboleth.sp.messaging.RemotedHttpServletRequest;
+import net.shibboleth.sp.oidc.profile.OIDCInitiatorConstants;
+import net.shibboleth.sp.profile.InitiatorConstants;
+import net.shibboleth.sp.profile.SPConstants;
+
+/**
+ * Tests for {@link DisplayParameterLookupStrategy}.
+ */
+public class DisplayParameterLookupStrategyTest extends AbstractAuthenticationLookupStrategyTest {
+    
+    /** The strategy to test.*/
+    private DisplayParameterLookupStrategy strategy;
+
+    /** The DDF to store input parameters.*/
+    private DDF ddf;
+
+    @Override
+    @BeforeMethod
+    public void setUp() throws ComponentInitializationException {
+        super.setUp();
+        strategy = new DisplayParameterLookupStrategy();
+
+        ddf = new DDF(null).structure();
+        ddf.addmember(RemotedHttpServletRequest.STRUCTURE_NAME).structure();
+        ddf.addmember(InitiatorConstants.RESPONSE_URL).string(RESPONSE_URL);
+        ddf.addmember(SPConstants.TARGET).unsafe_string(RESOURCE_URL);
+        addDDFToAgentRequestContext(ddf);
+    }
+    
+
+    @Test
+    public void testDisplayParameterPresent() {
+        ddf.addmember(OIDCInitiatorConstants.DISPLAY).string("page");
+        final String result = strategy.apply(mc);
+        assertNotNull(result);
+        assert result != null;
+        assertEquals(result, "page");
+    }
+
+
+    @Test
+    public void testDisplayParameterMissingUsesRpConfig() {
+        rpConfig.setDisplay("popup");
+        final String result = strategy.apply(mc);
+        assertNotNull(result);
+        assert result != null;
+        assertEquals(result, "popup");
+    }
+
+    @Test
+    public void testDisplayParameterMissingNoRpConfig() {
+        prc.removeSubcontext(partyContext);
+        final String result = strategy.apply(mc);
+        assertNull(result);
+    }
+
+
+
+}
diff --git a/sp-oidc-impl/src/test/java/net/shibboleth/sp/oidc/profile/impl/ForceAuthnParameterLookupStrategyTest.java b/sp-oidc-impl/src/test/java/net/shibboleth/sp/oidc/profile/impl/ForceAuthnParameterLookupStrategyTest.java
new file mode 100644
index 0000000..ee437b0
--- /dev/null
+++ b/sp-oidc-impl/src/test/java/net/shibboleth/sp/oidc/profile/impl/ForceAuthnParameterLookupStrategyTest.java
@@ -0,0 +1,106 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.shibboleth.sp.oidc.profile.impl;
+
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import net.shibboleth.oidc.profile.config.OIDCAuthorizationConfiguration;
+import net.shibboleth.shared.component.ComponentInitializationException;
+import net.shibboleth.sp.ddf.DDF;
+import net.shibboleth.sp.messaging.RemotedHttpServletRequest;
+import net.shibboleth.sp.oidc.profile.OIDCInitiatorConstants;
+import net.shibboleth.sp.profile.InitiatorConstants;
+import net.shibboleth.sp.profile.SPConstants;
+
+/**
+ * Tests for {@link ForceAuthnParameterLookupStrategy}.
+ */
+public class ForceAuthnParameterLookupStrategyTest extends AbstractAuthenticationLookupStrategyTest {
+    
+    /** The strategy to test.*/
+    private ForceAuthnParameterLookupStrategy strategy;
+
+    /** The DDF to store input parameters.*/
+    private DDF ddf;
+
+    @Override
+    @BeforeMethod
+    public void setUp() throws ComponentInitializationException {
+        super.setUp();
+        strategy = new ForceAuthnParameterLookupStrategy();
+
+        ddf = new DDF(null).structure();
+        ddf.addmember(RemotedHttpServletRequest.STRUCTURE_NAME).structure();
+        ddf.addmember(InitiatorConstants.RESPONSE_URL).string(RESPONSE_URL);
+        ddf.addmember(SPConstants.TARGET).unsafe_string(RESOURCE_URL);
+        addDDFToAgentRequestContext(ddf);
+    }
+
+    @Test
+    public void testForceAuthnSetToOne() {
+        ddf.addmember(OIDCInitiatorConstants.FORCE_AUTHN).integer(1);
+        final Boolean result = strategy.apply(mc);
+        assertNotNull(result);
+        assert result != null;
+        assertTrue(result);
+    }
+
+    @Test
+    public void testForceAuthnSetToZero() {
+        ddf.addmember(OIDCInitiatorConstants.FORCE_AUTHN).integer(0);
+        final Boolean result = strategy.apply(mc);
+        assertNotNull(result);
+        assert result != null;
+        assertFalse(result);
+    }
+
+    @Test
+    public void testForceAuthnDisallowed() {
+        ddf.addmember(OIDCInitiatorConstants.FORCE_AUTHN).integer(1);
+        rpConfig.setDisallowedFeatures(OIDCAuthorizationConfiguration.FEATURE_FORCEAUTHN);
+        final Boolean result = strategy.apply(mc);
+        assertNotNull(result);
+        assert result != null;
+        assertFalse(result);
+    }
+    
+
+    @Test
+    public void testForceAuthnNotPresentUsesRpConfig() {
+        rpConfig.setForceAuthn(true);
+        final Boolean result = strategy.apply(mc);
+        assertNotNull(result);
+        assert result != null;
+        assertTrue(result);
+    }
+    
+
+    @Test
+    public void testForceAuthnNotPresentNoRpConfig() {
+        prc.removeSubcontext(partyContext);
+        final Boolean result = strategy.apply(mc);
+        assertNotNull(result);
+        assert result != null;
+        assertFalse(result);
+    }
+
+
+
+}

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


More information about the commits mailing list