[java-identity-provider] branch master updated: IDP-1430 - Review and cleanup of ProfileConfig classes

Scott Cantor cantor.2 at osu.edu
Wed Mar 27 09:39:38 EDT 2019


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

scantor pushed a commit to branch master
in repository java-identity-provider.

View the commit online:
http://git.shibboleth.net/view/?p=java-identity-provider.git;a=commit;h=102dcf34443e1139cde5c10164c22909f92f8e5d

The following commit(s) were added to refs/heads/master by this push:
       new  102dcf3   IDP-1430 - Review and cleanup of ProfileConfig classes
102dcf3 is described below

commit 102dcf34443e1139cde5c10164c22909f92f8e5d
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Wed Mar 27 09:39:34 2019 -0400

    IDP-1430 - Review and cleanup of ProfileConfig classes
    
    https://issues.shibboleth.net/jira/browse/IDP-1430
    
    First set of changes, base classes, CAS configs,
    authentication configs.
---
 .../idp/admin/AdministrativeFlowDescriptor.java    |  17 +-
 .../admin/BasicAdministrativeFlowDescriptor.java   | 166 +++++++-----
 ...InitializeAdministrativeProfileContextTree.java |   2 +-
 .../config/AuthenticationProfileConfiguration.java |  34 ++-
 .../AuthenticationFlowsLookupFunction.java         |   2 +-
 .../ForceAuthnProfileConfigPredicate.java          |  15 +-
 .../PostAuthenticationFlowsLookupFunction.java     |   2 +-
 .../MockAuthenticationProfileConfiguration.java    |  29 +-
 .../impl/InitializeRequestedPrincipalContext.java  |   5 +-
 .../config/impl/AbstractProtocolConfiguration.java |  67 ++---
 .../idp/cas/config/impl/LoginConfiguration.java    | 151 +++++------
 .../idp/cas/config/impl/ValidateConfiguration.java | 110 ++++----
 .../impl/BuildAuthenticationContextAction.java     |   2 +-
 .../idp/cas/flow/impl/GrantProxyTicketAction.java  |  28 +-
 .../cas/flow/impl/GrantServiceTicketAction.java    |  34 +--
 .../PrepareTicketValidationResponseAction.java     |   9 +-
 .../cas/flow/impl/ValidateProxyCallbackAction.java |  31 ++-
 .../idp/cas/flow/impl/ValidateTicketAction.java    |   3 +-
 .../system/conf/relying-party-mddriven.xml         |  27 +-
 .../resources/system/conf/relying-party-system.xml |   1 -
 .../system/flows/admin/admin-abstract-beans.xml    |   2 +-
 .../system/flows/admin/admin-abstract-flow.xml     |   4 +-
 .../system/flows/cas/login/login-flow.xml          |   2 +-
 .../flows/cas/samlValidate/samlValidate-flow.xml   |   2 +-
 .../system/flows/cas/validate-abstract-flow.xml    |   2 +-
 .../test/flows/c14n/actions/SetupForSAML1C14N.java |   2 +-
 .../test/flows/c14n/actions/SetupForSAML2C14N.java |   2 +-
 .../test/flows/cas/LoginFlowInitialAuthnTest.java  |  97 -------
 .../idp/test/flows/cas/LoginFlowTest.java          |   2 +-
 .../src/test/resources/test/test-cas-beans.xml     |   1 +
 .../test/resources/test/test-relying-party-cas.xml |  24 +-
 .../config/AbstractProfileConfiguration.java       |  98 +++----
 .../idp/profile/config/ProfileConfiguration.java   |  17 +-
 .../config/logic/DetailedErrorsPredicate.java      |   2 +-
 ...ntTLSValidationConfigurationLookupFunction.java |   7 +-
 .../DecryptionConfigurationLookupFunction.java     |   7 +-
 .../EncryptionConfigurationLookupFunction.java     |   7 +-
 ...IdentifierGenerationStrategyLookupFunction.java |   8 +-
 .../navigate/InboundFlowsLookupFunction.java       |   4 +-
 .../navigate/OutboundFlowsLookupFunction.java      |   4 +-
 ...ignatureSigningConfigurationLookupFunction.java |   7 +-
 ...atureValidationConfigurationLookupFunction.java |   7 +-
 ...pClientSecurityConfigurationLookupFunction.java |   8 +-
 ...ignatureSigningConfigurationLookupFunction.java |   8 +-
 ...atureValidationConfigurationLookupFunction.java |   8 +-
 .../navigate/ResponderIdLookupFunction.java        |   2 +-
 .../AbstractRelyingPartyLookupFunction.java        |  43 ++-
 .../relyingparty/RelyingPartyConfiguration.java    | 171 ++++--------
 .../idp/profile/RequestContextBuilder.java         |   2 +-
 .../config/AbstractProfileConfigurationTest.java   |  40 ++-
 .../RelyingPartyConfigurationTest.java             |  51 ++--
 .../profile/impl/SelectProfileConfiguration.java   |   3 +-
 .../messaging/impl/SelectProfileConfiguration.java |  35 ++-
 .../impl/CriteriaSelfEntityIDResolver.java         | 133 +++++++++-
 ...gCriteriaRelyingPartyConfigurationResolver.java |   8 +-
 .../impl/SelectRelyingPartyConfigurationTest.java  |   4 +-
 ...tMetadataDrivenConfigurationLookupStrategy.java |  26 +-
 .../config/AbstractSAMLProfileConfiguration.java   |   5 +-
 .../DetailedErrorsProfileConfigPredicate.java      |   2 +-
 .../logic/IncludeAttributeStatementPredicate.java  |   4 +-
 .../ResolveAttributesProfileConfigPredicate.java   |   4 +-
 .../navigate/SessionLifetimeLookupFunction.java    |   2 +-
 .../logic/DefaultNameIdentifierFormatStrategy.java |   5 +-
 .../config/BrowserSSOProfileConfiguration.java     | 190 +++++---------
 .../config/BrowserSSOProfileConfiguration.java     | 291 ++++++++++-----------
 .../saml/saml1/profile/SAML1ActionSupportTest.java |   8 +-
 .../saml1/profile/SAML1ActionTestingSupport.java   |   2 +-
 .../config/BrowserSSOProfileConfigurationTest.java |  56 ++--
 .../saml/saml2/profile/SAML2ActionSupportTest.java |   8 +-
 .../saml2/profile/SAML2ActionTestingSupport.java   |   2 +-
 .../config/BrowserSSOProfileConfigurationTest.java |  84 +++---
 .../impl/InitializeAuthenticationContext.java      |   2 +-
 .../impl/PopulateBindingAndEndpointContexts.java   |   4 +-
 .../impl/AddDelegationPolicyToAssertion.java       |   2 +-
 .../impl/DecorateDelegatedAssertion.java           |   2 +-
 .../delegation/impl/PopulateDelegationContext.java |   4 +-
 .../profile/impl/ProcessRequestedAuthnContext.java |   2 +-
 ...uteSourcedSAML1NameIdentifierGeneratorTest.java |   4 +-
 .../AttributeSourcedSAML2NameIDGeneratorTest.java  |   4 +-
 ...oTransientSAML1NameIdentifierGeneratorTest.java |   2 +-
 .../CryptoTransientSAML2NameIDGeneratorTest.java   |   2 +-
 ...dTransientSAML1NameIdentifierGeneratorTest.java |   2 +-
 .../StoredTransientSAML2NameIDGeneratorTest.java   |   2 +-
 .../impl/PopulateDelegationContextTest.java        |  12 +-
 84 files changed, 1172 insertions(+), 1120 deletions(-)

diff --git a/idp-admin-api/src/main/java/net/shibboleth/idp/admin/AdministrativeFlowDescriptor.java b/idp-admin-api/src/main/java/net/shibboleth/idp/admin/AdministrativeFlowDescriptor.java
index a490e9c..b07d759 100644
--- a/idp-admin-api/src/main/java/net/shibboleth/idp/admin/AdministrativeFlowDescriptor.java
+++ b/idp-admin-api/src/main/java/net/shibboleth/idp/admin/AdministrativeFlowDescriptor.java
@@ -19,6 +19,7 @@ package net.shibboleth.idp.admin;
 
 import javax.annotation.Nullable;
 
+import org.opensaml.profile.context.ProfileRequestContext;
 import org.opensaml.saml.ext.saml2mdui.UIInfo;
 
 import net.shibboleth.idp.authn.config.AuthenticationProfileConfiguration;
@@ -47,16 +48,20 @@ public interface AdministrativeFlowDescriptor extends FlowDescriptor, Authentica
     /**
      * Get whether this flow supports non-browser clients (default is true).
      * 
+     * @param profileRequestContext current profile request context
+     * 
      * @return whether this flow supports non-browser clients
      */
-    boolean isNonBrowserSupported();
+    boolean isNonBrowserSupported(@Nullable final ProfileRequestContext profileRequestContext);
     
     /**
      * Get whether user authentication is required (default is false).
      * 
+     * @param profileRequestContext current profile request context
+     * 
      * @return whether user authentication is required
      */
-    boolean isAuthenticated();
+    boolean isAuthenticated(@Nullable final ProfileRequestContext profileRequestContext);
     
     /**
      * Get the user interface details for this profile.
@@ -68,15 +73,19 @@ public interface AdministrativeFlowDescriptor extends FlowDescriptor, Authentica
     /**
      * Get the access control policy for this flow.
      * 
+     * @param profileRequestContext current profile request context
+     * 
      * @return name of access control policy
      */
-    @Nullable String getPolicyName();
+    @Nullable String getPolicyName(@Nullable final ProfileRequestContext profileRequestContext);
 
     /**
      * Get whether to resolve attributes during the profile (default is false).
      * 
+     * @param profileRequestContext current profile request context
+     * 
      * @return whether to resolve attributes during the profile
      */
-    boolean resolveAttributes();
+    boolean isResolveAttributes(@Nullable final ProfileRequestContext profileRequestContext);
 
 }
\ No newline at end of file
diff --git a/idp-admin-api/src/main/java/net/shibboleth/idp/admin/BasicAdministrativeFlowDescriptor.java b/idp-admin-api/src/main/java/net/shibboleth/idp/admin/BasicAdministrativeFlowDescriptor.java
index 7f60eca..1bbc0e5 100644
--- a/idp-admin-api/src/main/java/net/shibboleth/idp/admin/BasicAdministrativeFlowDescriptor.java
+++ b/idp-admin-api/src/main/java/net/shibboleth/idp/admin/BasicAdministrativeFlowDescriptor.java
@@ -38,6 +38,7 @@ import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
 import net.shibboleth.utilities.java.support.annotation.constraint.NotLive;
 import net.shibboleth.utilities.java.support.annotation.constraint.Positive;
 import net.shibboleth.utilities.java.support.annotation.constraint.Unmodifiable;
+import net.shibboleth.utilities.java.support.collection.CollectionSupport;
 import net.shibboleth.utilities.java.support.logic.Constraint;
 import net.shibboleth.utilities.java.support.logic.FunctionSupport;
 import net.shibboleth.utilities.java.support.primitive.LangBearingString;
@@ -56,8 +57,6 @@ import org.opensaml.saml.ext.saml2mdui.UIInfo;
 import com.google.common.base.MoreObjects;
 import com.google.common.base.Predicates;
 import com.google.common.collect.Collections2;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
 
 /**
  * A descriptor for an administrative flow.
@@ -92,15 +91,18 @@ public class BasicAdministrativeFlowDescriptor extends AbstractProfileConfigurat
     @Nonnull private Predicate<ProfileRequestContext> resolveAttributesPredicate;
     
     /** Selects, and limits, the authentication flows to use for requests by supported principals. */
-    @Nullable private Function<ProfileRequestContext,Collection<Principal>>
+    @Nonnull private Function<ProfileRequestContext,Collection<Principal>>
             defaultAuthenticationMethodsLookupStrategy;
 
     /** Filters the usable authentication flows. */
-    @Nullable private Function<ProfileRequestContext,Set<String>> authenticationFlowsLookupStrategy;
+    @Nonnull private Function<ProfileRequestContext,Set<String>> authenticationFlowsLookupStrategy;
 
     /** Enables post-authentication interceptor flows. */
-    @Nullable private Function<ProfileRequestContext,Collection<String>> postAuthenticationFlowsLookupStrategy;
+    @Nonnull private Function<ProfileRequestContext,Collection<String>> postAuthenticationFlowsLookupStrategy;
     
+    /** Whether to mandate forced authentication for the request. */
+    @Nonnull private Predicate<ProfileRequestContext> forceAuthnPredicate;
+
     /** Builder factory for XMLObjects needed in UIInfo emulation. */
     @Nonnull private final XMLObjectBuilderFactory builderFactory;
     
@@ -116,10 +118,15 @@ public class BasicAdministrativeFlowDescriptor extends AbstractProfileConfigurat
         authenticatedPredicate = Predicates.alwaysFalse();
         policyNameLookupStrategy = FunctionSupport.constant(null);
         resolveAttributesPredicate = Predicates.alwaysFalse();
+        forceAuthnPredicate = Predicates.alwaysFalse();
         
         builderFactory = XMLObjectProviderRegistrySupport.getBuilderFactory();
         uiInfo = ((SAMLObjectBuilder<UIInfo>) builderFactory.<UIInfo>getBuilderOrThrow(
                 UIInfo.DEFAULT_ELEMENT_NAME)).buildObject();
+        
+        defaultAuthenticationMethodsLookupStrategy = FunctionSupport.constant(null);
+        authenticationFlowsLookupStrategy = FunctionSupport.constant(null);
+        postAuthenticationFlowsLookupStrategy = FunctionSupport.constant(null);
     }
     
     /** {@inheritDoc} */
@@ -137,20 +144,19 @@ public class BasicAdministrativeFlowDescriptor extends AbstractProfileConfigurat
     }
     
     /** {@inheritDoc} */
-    public boolean isNonBrowserSupported() {
-        return supportsNonBrowserPredicate.test(getProfileRequestContext());
+    public boolean isNonBrowserSupported(@Nullable final ProfileRequestContext profileRequestContext) {
+        return supportsNonBrowserPredicate.test(profileRequestContext);
     }
 
     /**
-     * Set whether this flow supports non-browser clients (default is true).
+     * Set whether this flow supports non-browser clients.
      * 
-     * @param isSupported whether this flow supports non-browser clients
+     * @param flag flag to set
      */
-    public void setNonBrowserSupported(final boolean isSupported) {
-        supportsNonBrowserPredicate = isSupported ? Predicates.<ProfileRequestContext>alwaysTrue()
-                : Predicates.<ProfileRequestContext>alwaysFalse();
+    public void setNonBrowserSupported(final boolean flag) {
+        supportsNonBrowserPredicate = flag ? Predicates.alwaysTrue() : Predicates.alwaysFalse();
     }
-
+    
     /**
      * Set condition to determine whether this flow supports non-browser clients.
      * 
@@ -161,18 +167,17 @@ public class BasicAdministrativeFlowDescriptor extends AbstractProfileConfigurat
     }
     
     /** {@inheritDoc} */
-    public boolean isAuthenticated() {
-        return authenticatedPredicate.test(getProfileRequestContext());
+    public boolean isAuthenticated(@Nullable final ProfileRequestContext profileRequestContext) {
+        return authenticatedPredicate.test(profileRequestContext);
     }
-    
+
     /**
      * Set whether user authentication is required (default is false).
      * 
      * @param flag flag to set
      */
     public void setAuthenticated(final boolean flag) {
-        authenticatedPredicate = flag ? Predicates.<ProfileRequestContext>alwaysTrue()
-                : Predicates.<ProfileRequestContext>alwaysFalse();
+        authenticatedPredicate = flag ? Predicates.alwaysTrue() : Predicates.alwaysFalse();
     }
     
     /**
@@ -279,44 +284,42 @@ public class BasicAdministrativeFlowDescriptor extends AbstractProfileConfigurat
     }
 
     /** {@inheritDoc} */
-    @Nullable public String getPolicyName() {
-        return getIndirectProperty(policyNameLookupStrategy, null);
+    @Nullable public String getPolicyName(@Nullable final ProfileRequestContext profileRequestContext) {
+        return policyNameLookupStrategy.apply(profileRequestContext);
     }  
     
     /**
-     * Set a lookup strategy to use to obtain the access control policy for this flow.
+     * Set an explicit access control policy name to apply.
      * 
-     * @param strategy  lookup strategy
+     * @param name  policy name
      */
-    public void setPolicyNameLookupStrategy(@Nonnull final Function<ProfileRequestContext,String> strategy) {
-        policyNameLookupStrategy = Constraint.isNotNull(strategy, "Policy lookup strategy cannot be null");
+    public void setPolicyName(@Nullable final String name) {
+        policyNameLookupStrategy = FunctionSupport.constant(StringSupport.trimOrNull(name));
     }
 
     /**
-     * Set an explicit access control policy name to apply.
+     * Set a lookup strategy to use to obtain the access control policy for this flow.
      * 
-     * @param name  policy name
+     * @param strategy  lookup strategy
      */
-    public void setPolicyName(@Nonnull @NotEmpty final String name) {
-        policyNameLookupStrategy = FunctionSupport.constant(
-                Constraint.isNotNull(StringSupport.trimOrNull(name), "Policy name cannot be null or empty"));
+    public void setPolicyNameLookupStrategy(@Nonnull final Function<ProfileRequestContext,String> strategy) {
+        policyNameLookupStrategy = Constraint.isNotNull(strategy, "Policy lookup strategy cannot be null");
     }
-
+    
     /** {@inheritDoc} */
-    public boolean resolveAttributes() {
-        return resolveAttributesPredicate.test(getProfileRequestContext());
+    public boolean isResolveAttributes(@Nullable final ProfileRequestContext profileRequestContext) {
+        return resolveAttributesPredicate.test(profileRequestContext);
     }
 
     /**
      * Set whether attributes should be resolved during the profile.
      *
-     * @param flag  flag to set
+     * @param flag flag to set
      */
     public void setResolveAttributes(final boolean flag) {
-        resolveAttributesPredicate = flag ? Predicates.<ProfileRequestContext>alwaysTrue()
-                : Predicates.<ProfileRequestContext>alwaysFalse();
+        resolveAttributesPredicate = flag ? Predicates.alwaysTrue() : Predicates.alwaysFalse();
     }
-
+    
     /**
      * Set a condition to determine whether attributes should be resolved during the profile.
      *
@@ -327,24 +330,28 @@ public class BasicAdministrativeFlowDescriptor extends AbstractProfileConfigurat
     }
     
     /** {@inheritDoc} */
-    @Nonnull @NonnullElements @NotLive @Unmodifiable public List<String> getInboundInterceptorFlows() {
+    @Nonnull @NonnullElements @NotLive @Unmodifiable public List<String> getInboundInterceptorFlows(
+            @Nullable final ProfileRequestContext profileRequestContext) {
         return Collections.emptyList();
     }
 
     /** {@inheritDoc} */
-    @Nonnull @NonnullElements @NotLive @Unmodifiable public List<String> getOutboundInterceptorFlows() {
+    @Nonnull @NonnullElements @NotLive @Unmodifiable public List<String> getOutboundInterceptorFlows(
+            @Nullable final ProfileRequestContext profileRequestContext) {
         return Collections.emptyList();
     }
 
     /** {@inheritDoc} */
-    @Nullable public SecurityConfiguration getSecurityConfiguration() {
+    @Nullable public SecurityConfiguration getSecurityConfiguration(
+            @Nullable final ProfileRequestContext profileRequestContext) {
         return null;
     }
 
     /** {@inheritDoc} */
-    @Nonnull @NonnullElements @NotLive @Unmodifiable public List<Principal> getDefaultAuthenticationMethods() {
-        return ImmutableList.<Principal>copyOf(getIndirectProperty(defaultAuthenticationMethodsLookupStrategy,
-                Collections.<Principal>emptyList()));
+    @Nonnull @NonnullElements @NotLive @Unmodifiable public List<Principal> getDefaultAuthenticationMethods(
+            @Nullable final ProfileRequestContext profileRequestContext) {
+        return CollectionSupport.buildImmutableList(
+                defaultAuthenticationMethodsLookupStrategy.apply(profileRequestContext));
     }
     
     /**
@@ -352,14 +359,13 @@ public class BasicAdministrativeFlowDescriptor extends AbstractProfileConfigurat
      * 
      * @param methods   default authentication methods to use
      */
-    public void setDefaultAuthenticationMethods(
-            @Nullable @NonnullElements final Collection<Principal> methods) {
+    public void setDefaultAuthenticationMethods(@Nullable @NonnullElements final Collection<Principal> methods) {
 
         if (methods != null) {
-            defaultAuthenticationMethodsLookupStrategy = FunctionSupport.constant(
-                    (Collection<Principal>) new ArrayList<>(Collections2.filter(methods, Predicates.notNull())));
+            defaultAuthenticationMethodsLookupStrategy =
+                    FunctionSupport.constant(new ArrayList<>(Collections2.filter(methods, Predicates.notNull())));
         } else {
-            defaultAuthenticationMethodsLookupStrategy = null;
+            defaultAuthenticationMethodsLookupStrategy = FunctionSupport.constant(null);
         }
     }
 
@@ -369,14 +375,14 @@ public class BasicAdministrativeFlowDescriptor extends AbstractProfileConfigurat
      * @param strategy  lookup strategy
      */
     public void setDefaultAuthenticationMethodsLookupStrategy(
-            @Nullable final Function<ProfileRequestContext,Collection<Principal>> strategy) {
-        defaultAuthenticationMethodsLookupStrategy = strategy;
+            @Nonnull final Function<ProfileRequestContext,Collection<Principal>> strategy) {
+        defaultAuthenticationMethodsLookupStrategy = Constraint.isNotNull(strategy, "Lookup strategy cannot be null");
     }
-    
+
     /** {@inheritDoc} */
-    @Nonnull @NonnullElements @NotLive @Unmodifiable public Set<String> getAuthenticationFlows() {
-        return ImmutableSet.<String>copyOf(getIndirectProperty(authenticationFlowsLookupStrategy,
-                Collections.<String>emptySet()));
+    @Nonnull @NonnullElements @NotLive @Unmodifiable public Set<String> getAuthenticationFlows(
+            @Nullable final ProfileRequestContext profileRequestContext) {
+        return CollectionSupport.buildImmutableSet(authenticationFlowsLookupStrategy.apply(profileRequestContext));
     }
 
     /**
@@ -387,10 +393,10 @@ public class BasicAdministrativeFlowDescriptor extends AbstractProfileConfigurat
     public void setAuthenticationFlows(@Nullable @NonnullElements final Collection<String> flows) {
 
         if (flows != null) {
-            authenticationFlowsLookupStrategy = FunctionSupport.<ProfileRequestContext,Set<String>>constant(
-                    new HashSet<>(StringSupport.normalizeStringCollection(flows)));
+            authenticationFlowsLookupStrategy =
+                    FunctionSupport.constant(new HashSet<>(StringSupport.normalizeStringCollection(flows)));
         } else {
-            authenticationFlowsLookupStrategy = null;
+            authenticationFlowsLookupStrategy = FunctionSupport.constant(null);
         }
     }
 
@@ -400,14 +406,14 @@ public class BasicAdministrativeFlowDescriptor extends AbstractProfileConfigurat
      * @param strategy  lookup strategy
      */
     public void setAuthenticationFlowsLookupStrategy(
-            @Nullable final Function<ProfileRequestContext,Set<String>> strategy) {
-        authenticationFlowsLookupStrategy = strategy;
+            @Nonnull final Function<ProfileRequestContext,Set<String>> strategy) {
+        authenticationFlowsLookupStrategy = Constraint.isNotNull(strategy, "Lookup strategy cannot be null");
     }
-    
+
     /** {@inheritDoc} */
-    @Nonnull @NonnullElements @NotLive @Unmodifiable public List<String> getPostAuthenticationFlows() {
-        return ImmutableList.<String>copyOf(getIndirectProperty(postAuthenticationFlowsLookupStrategy,
-                Collections.<String>emptyList()));
+    @Nonnull @NonnullElements @NotLive @Unmodifiable public List<String> getPostAuthenticationFlows(
+            @Nullable final ProfileRequestContext profileRequestContext) {
+        return CollectionSupport.buildImmutableList(postAuthenticationFlowsLookupStrategy.apply(profileRequestContext));
     }
     
     /**
@@ -418,10 +424,10 @@ public class BasicAdministrativeFlowDescriptor extends AbstractProfileConfigurat
     public void setPostAuthenticationFlows(@Nullable @NonnullElements final Collection<String> flows) {
 
         if (flows != null) {
-            postAuthenticationFlowsLookupStrategy = FunctionSupport.<ProfileRequestContext,Collection<String>>constant(
-                    new ArrayList<>(StringSupport.normalizeStringCollection(flows)));
+            postAuthenticationFlowsLookupStrategy =
+                    FunctionSupport.constant(new ArrayList<>(StringSupport.normalizeStringCollection(flows)));
         } else {
-            postAuthenticationFlowsLookupStrategy = null;
+            postAuthenticationFlowsLookupStrategy = FunctionSupport.constant(null);
         }
     }
 
@@ -431,16 +437,40 @@ public class BasicAdministrativeFlowDescriptor extends AbstractProfileConfigurat
      * @param strategy  lookup strategy
      */
     public void setPostAuthenticationFlowsLookupStrategy(
-            @Nullable final Function<ProfileRequestContext,Collection<String>> strategy) {
-        postAuthenticationFlowsLookupStrategy = strategy;
+            @Nonnull final Function<ProfileRequestContext,Collection<String>> strategy) {
+        postAuthenticationFlowsLookupStrategy = Constraint.isNotNull(strategy, "Lookup strategy cannot be null");
     }
 
     /** {@inheritDoc} */
-    @Nonnull @NonnullElements @NotLive @Unmodifiable public List<String> getNameIDFormatPrecedence() {
+    @Nonnull @NonnullElements @NotLive @Unmodifiable public List<String> getNameIDFormatPrecedence(
+            @Nullable final ProfileRequestContext profileRequestContext) {
         return Collections.emptyList();
     }
 
     /** {@inheritDoc} */
+    public boolean isForceAuthn(@Nullable final ProfileRequestContext profileRequestContext) {
+        return forceAuthnPredicate.test(profileRequestContext);
+    }
+    
+    /**
+     * Set whether a fresh user presence proof should be required for this request.
+     *
+     * @param flag flag to set
+     */
+    public void setForceAuthn(final boolean flag) {
+        forceAuthnPredicate = flag ? Predicates.alwaysTrue() : Predicates.alwaysFalse();
+    }
+    
+    /**
+     * Set a condition to determine whether a fresh user presence proof should be required for this request.
+     * 
+     * @param condition condition to set
+     */
+    public void setForceAuthnPredicate(@Nonnull final Predicate<ProfileRequestContext> condition) {
+        forceAuthnPredicate = Constraint.isNotNull(condition, "Forced authentication predicate cannot be null");
+    }
+
+    /** {@inheritDoc} */
     @Override public int hashCode() {
         return getId().hashCode();
     }
diff --git a/idp-admin-impl/src/main/java/net/shibboleth/idp/admin/impl/InitializeAdministrativeProfileContextTree.java b/idp-admin-impl/src/main/java/net/shibboleth/idp/admin/impl/InitializeAdministrativeProfileContextTree.java
index 4a0b51b..48db62c 100644
--- a/idp-admin-impl/src/main/java/net/shibboleth/idp/admin/impl/InitializeAdministrativeProfileContextTree.java
+++ b/idp-admin-impl/src/main/java/net/shibboleth/idp/admin/impl/InitializeAdministrativeProfileContextTree.java
@@ -118,7 +118,7 @@ public class InitializeAdministrativeProfileContextTree extends AbstractProfileA
     protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
         
         profileRequestContext.setLoggingId(flowDescriptor.getLoggingId());
-        profileRequestContext.setBrowserProfile(!flowDescriptor.isNonBrowserSupported());
+        profileRequestContext.setBrowserProfile(!flowDescriptor.isNonBrowserSupported(profileRequestContext));
         
         final RelyingPartyContext rpCtx = new RelyingPartyContext();
         profileRequestContext.addSubcontext(rpCtx, true);
diff --git a/idp-authn-api/src/main/java/net/shibboleth/idp/authn/config/AuthenticationProfileConfiguration.java b/idp-authn-api/src/main/java/net/shibboleth/idp/authn/config/AuthenticationProfileConfiguration.java
index a782792..afa06d9 100644
--- a/idp-authn-api/src/main/java/net/shibboleth/idp/authn/config/AuthenticationProfileConfiguration.java
+++ b/idp-authn-api/src/main/java/net/shibboleth/idp/authn/config/AuthenticationProfileConfiguration.java
@@ -22,6 +22,9 @@ import java.util.List;
 import java.util.Set;
 
 import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.opensaml.profile.context.ProfileRequestContext;
 
 import net.shibboleth.idp.profile.config.ProfileConfiguration;
 import net.shibboleth.utilities.java.support.annotation.constraint.NonnullElements;
@@ -34,9 +37,12 @@ public interface AuthenticationProfileConfiguration extends ProfileConfiguration
     /**
      * Get the default authentication methods to use, expressed as custom principals.
      * 
+     * @param profileRequestContext current profile request context
+     * 
      * @return  default authentication methods to use
      */
-    @Nonnull @NonnullElements @NotLive @Unmodifiable List<Principal> getDefaultAuthenticationMethods();
+    @Nonnull @NonnullElements @NotLive @Unmodifiable List<Principal> getDefaultAuthenticationMethods(
+            @Nullable final ProfileRequestContext profileRequestContext);
     
     /**
      * Get the allowable authentication flows for this profile.
@@ -45,9 +51,12 @@ public interface AuthenticationProfileConfiguration extends ProfileConfiguration
      * {@link net.shibboleth.idp.authn.AuthenticationFlowDescriptor#FLOW_ID_PREFIX}
      * prefix common to all interceptor flows.</p>
      * 
+     * @param profileRequestContext current profile request context
+     * 
      * @return  a set of authentication flow IDs to allow 
      */
-    @Nonnull @NonnullElements @NotLive @Unmodifiable Set<String> getAuthenticationFlows();
+    @Nonnull @NonnullElements @NotLive @Unmodifiable Set<String> getAuthenticationFlows(
+            @Nullable final ProfileRequestContext profileRequestContext);
 
     /**
      * Get an ordered list of post-authentication interceptor flows to run for this profile.
@@ -56,15 +65,32 @@ public interface AuthenticationProfileConfiguration extends ProfileConfiguration
      * {@link net.shibboleth.idp.profile.interceptor.ProfileInterceptorFlowDescriptor#FLOW_ID_PREFIX}
      * prefix common to all interceptor flows.</p>
      * 
+     * @param profileRequestContext current profile request context
+     * 
      * @return  a set of interceptor flow IDs to enable
      */
-    @Nonnull @NonnullElements @NotLive @Unmodifiable List<String> getPostAuthenticationFlows();
+    @Nonnull @NonnullElements @NotLive @Unmodifiable List<String> getPostAuthenticationFlows(
+            @Nullable final ProfileRequestContext profileRequestContext);
 
     /**
      * Get the name identifier formats to use with this relying party, in order of preference.
      * 
+     * @param profileRequestContext current profile request context
+     * 
      * @return  name identifier formats to use
      */
-    @Nonnull @NonnullElements @NotLive @Unmodifiable List<String> getNameIDFormatPrecedence();
+    @Nonnull @NonnullElements @NotLive @Unmodifiable List<String> getNameIDFormatPrecedence(
+            @Nullable final ProfileRequestContext profileRequestContext);
 
+    /**
+     * Get whether the authentication process should include a proof of user presence.
+     * 
+     * @param profileRequestContext current profile request context
+     * 
+     * @return true iff authentication should require user presence
+     * 
+     * @since 4.0.0
+     */
+    boolean isForceAuthn(@Nullable final ProfileRequestContext profileRequestContext);
+    
 }
\ No newline at end of file
diff --git a/idp-authn-api/src/main/java/net/shibboleth/idp/authn/config/navigate/AuthenticationFlowsLookupFunction.java b/idp-authn-api/src/main/java/net/shibboleth/idp/authn/config/navigate/AuthenticationFlowsLookupFunction.java
index ae093a6..3fa1603 100644
--- a/idp-authn-api/src/main/java/net/shibboleth/idp/authn/config/navigate/AuthenticationFlowsLookupFunction.java
+++ b/idp-authn-api/src/main/java/net/shibboleth/idp/authn/config/navigate/AuthenticationFlowsLookupFunction.java
@@ -52,7 +52,7 @@ public class AuthenticationFlowsLookupFunction extends AbstractRelyingPartyLooku
             final ProfileConfiguration pc = rpc.getProfileConfig();
             if (pc != null && pc instanceof AuthenticationProfileConfiguration) {
                 return ImmutableList.<String>copyOf(
-                        ((AuthenticationProfileConfiguration) pc).getAuthenticationFlows());
+                        ((AuthenticationProfileConfiguration) pc).getAuthenticationFlows(input));
             }
         }
         
diff --git a/idp-saml-api/src/main/java/net/shibboleth/idp/saml/profile/config/logic/ForceAuthnProfileConfigPredicate.java b/idp-authn-api/src/main/java/net/shibboleth/idp/authn/config/navigate/ForceAuthnProfileConfigPredicate.java
similarity index 68%
rename from idp-saml-api/src/main/java/net/shibboleth/idp/saml/profile/config/logic/ForceAuthnProfileConfigPredicate.java
rename to idp-authn-api/src/main/java/net/shibboleth/idp/authn/config/navigate/ForceAuthnProfileConfigPredicate.java
index ff97dce..bbdb224 100644
--- a/idp-saml-api/src/main/java/net/shibboleth/idp/saml/profile/config/logic/ForceAuthnProfileConfigPredicate.java
+++ b/idp-authn-api/src/main/java/net/shibboleth/idp/authn/config/navigate/ForceAuthnProfileConfigPredicate.java
@@ -15,10 +15,11 @@
  * limitations under the License.
  */
 
-package net.shibboleth.idp.saml.profile.config.logic;
+package net.shibboleth.idp.authn.config.navigate;
 
 import javax.annotation.Nullable;
 
+import net.shibboleth.idp.authn.config.AuthenticationProfileConfiguration;
 import net.shibboleth.idp.profile.context.RelyingPartyContext;
 import net.shibboleth.idp.profile.logic.AbstractRelyingPartyPredicate;
 
@@ -39,16 +40,8 @@ public class ForceAuthnProfileConfigPredicate extends AbstractRelyingPartyPredic
     public boolean test(@Nullable final ProfileRequestContext input) {
         
         final RelyingPartyContext rpc = getRelyingPartyContextLookupStrategy().apply(input);
-        if (rpc != null) {
-            if (rpc.getProfileConfig()
-                    instanceof net.shibboleth.idp.saml.saml1.profile.config.BrowserSSOProfileConfiguration) {
-                return ((net.shibboleth.idp.saml.saml1.profile.config.BrowserSSOProfileConfiguration)
-                        rpc.getProfileConfig()).getForceAuthnPredicate().test(input);
-            } else if (rpc.getProfileConfig()
-                    instanceof net.shibboleth.idp.saml.saml2.profile.config.BrowserSSOProfileConfiguration) {
-                return ((net.shibboleth.idp.saml.saml2.profile.config.BrowserSSOProfileConfiguration)
-                        rpc.getProfileConfig()).getForceAuthnPredicate().test(input);
-            }
+        if (rpc != null && rpc.getProfileConfig() instanceof AuthenticationProfileConfiguration) {
+            return ((AuthenticationProfileConfiguration) rpc.getProfileConfig()).isForceAuthn(input);
         }
         
         return false;
diff --git a/idp-authn-api/src/main/java/net/shibboleth/idp/authn/config/navigate/PostAuthenticationFlowsLookupFunction.java b/idp-authn-api/src/main/java/net/shibboleth/idp/authn/config/navigate/PostAuthenticationFlowsLookupFunction.java
index e07fde4..86c75c2 100644
--- a/idp-authn-api/src/main/java/net/shibboleth/idp/authn/config/navigate/PostAuthenticationFlowsLookupFunction.java
+++ b/idp-authn-api/src/main/java/net/shibboleth/idp/authn/config/navigate/PostAuthenticationFlowsLookupFunction.java
@@ -52,7 +52,7 @@ public class PostAuthenticationFlowsLookupFunction extends AbstractRelyingPartyL
             final ProfileConfiguration pc = rpc.getProfileConfig();
             if (pc != null && pc instanceof AuthenticationProfileConfiguration) {
                 return ImmutableList.<String>copyOf(
-                        ((AuthenticationProfileConfiguration) pc).getPostAuthenticationFlows());
+                        ((AuthenticationProfileConfiguration) pc).getPostAuthenticationFlows(input));
             }
         }
         
diff --git a/idp-authn-api/src/test/java/net/shibboleth/idp/authn/config/MockAuthenticationProfileConfiguration.java b/idp-authn-api/src/test/java/net/shibboleth/idp/authn/config/MockAuthenticationProfileConfiguration.java
index 96843b5..d3109db 100644
--- a/idp-authn-api/src/test/java/net/shibboleth/idp/authn/config/MockAuthenticationProfileConfiguration.java
+++ b/idp-authn-api/src/test/java/net/shibboleth/idp/authn/config/MockAuthenticationProfileConfiguration.java
@@ -24,8 +24,12 @@ import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
+import java.util.function.Predicate;
 
 import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.opensaml.profile.context.ProfileRequestContext;
 
 import com.google.common.base.Predicates;
 import com.google.common.collect.Collections2;
@@ -57,6 +61,9 @@ public class MockAuthenticationProfileConfiguration extends AbstractProfileConfi
     /** Precedence of name identifier formats to use for requests. */
     @Nonnull @NonnullElements private List<String> nameIDFormatPrecedence;
     
+    /** ForceAuthn predicate. */
+    @Nonnull private Predicate<ProfileRequestContext> forceAuthnPredicate;
+    
     /**
      * Constructor.
      * 
@@ -84,11 +91,12 @@ public class MockAuthenticationProfileConfiguration extends AbstractProfileConfi
         setDefaultAuthenticationMethods(methods);
         setAuthenticationFlows(flows);
         setNameIDFormatPrecedence(formats);
+        forceAuthnPredicate = Predicates.alwaysFalse();
     }
     
     /** {@inheritDoc} */
-    @Override
-    @Nonnull @NonnullElements @NotLive @Unmodifiable public List<Principal> getDefaultAuthenticationMethods() {
+    @Nonnull @NonnullElements @NotLive @Unmodifiable public List<Principal> getDefaultAuthenticationMethods(
+            @Nullable final ProfileRequestContext profileRequestContext) {
         return ImmutableList.copyOf(defaultAuthenticationMethods);
     }
     
@@ -104,8 +112,8 @@ public class MockAuthenticationProfileConfiguration extends AbstractProfileConfi
     }
     
     /** {@inheritDoc} */
-    @Override
-    @Nonnull @NonnullElements @NotLive @Unmodifiable public List<String> getNameIDFormatPrecedence() {
+    @Nonnull @NonnullElements @NotLive @Unmodifiable public List<String> getNameIDFormatPrecedence(
+            @Nullable final ProfileRequestContext profileRequestContext) {
         return ImmutableList.copyOf(nameIDFormatPrecedence);
     }
 
@@ -121,8 +129,8 @@ public class MockAuthenticationProfileConfiguration extends AbstractProfileConfi
     }
 
     /** {@inheritDoc} */
-    @Override
-    @Nonnull @NonnullElements @NotLive @Unmodifiable public Set<String> getAuthenticationFlows() {
+    @Nonnull @NonnullElements @NotLive @Unmodifiable public Set<String> getAuthenticationFlows(
+            @Nullable final ProfileRequestContext profileRequestContext) {
         return authenticationFlows;
     }
 
@@ -138,8 +146,8 @@ public class MockAuthenticationProfileConfiguration extends AbstractProfileConfi
     }
 
     /** {@inheritDoc} */
-    @Override
-    @Nonnull @NonnullElements @NotLive @Unmodifiable public List<String> getPostAuthenticationFlows() {
+    @Nonnull @NonnullElements @NotLive @Unmodifiable public List<String> getPostAuthenticationFlows(
+            @Nullable final ProfileRequestContext profileRequestContext) {
         return postAuthenticationFlows;
     }
 
@@ -154,4 +162,9 @@ public class MockAuthenticationProfileConfiguration extends AbstractProfileConfi
         postAuthenticationFlows = new ArrayList<>(StringSupport.normalizeStringCollection(flows));
     }
 
+    /** {@inheritDoc} */
+    public boolean isForceAuthn(ProfileRequestContext profileRequestContext) {
+        return forceAuthnPredicate.test(profileRequestContext);
+    }
+
 }
\ No newline at end of file
diff --git a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/InitializeRequestedPrincipalContext.java b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/InitializeRequestedPrincipalContext.java
index bd14e72..9ddaedb 100644
--- a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/InitializeRequestedPrincipalContext.java
+++ b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/InitializeRequestedPrincipalContext.java
@@ -146,8 +146,9 @@ public class InitializeRequestedPrincipalContext extends AbstractAuthenticationA
     protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext,
             @Nonnull final AuthenticationContext authenticationContext) {
 
-        final List<Principal> principals = authenticationProfileConfig.getDefaultAuthenticationMethods();
-        if (authenticationProfileConfig.getDefaultAuthenticationMethods().isEmpty()) {
+        final List<Principal> principals =
+                authenticationProfileConfig.getDefaultAuthenticationMethods(profileRequestContext);
+        if (principals.isEmpty()) {
             log.debug("{} Profile configuration did not supply any default authentication methods", getLogPrefix());
             return;
         }
diff --git a/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/config/impl/AbstractProtocolConfiguration.java b/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/config/impl/AbstractProtocolConfiguration.java
index 57bb661..6117b56 100644
--- a/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/config/impl/AbstractProtocolConfiguration.java
+++ b/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/config/impl/AbstractProtocolConfiguration.java
@@ -28,9 +28,9 @@ import net.shibboleth.idp.cas.ticket.impl.TicketIdentifierGenerationStrategy;
 import net.shibboleth.idp.profile.config.AbstractConditionalProfileConfiguration;
 import net.shibboleth.idp.profile.config.SecurityConfiguration;
 import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
-import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
 import net.shibboleth.utilities.java.support.component.InitializableComponent;
 import net.shibboleth.utilities.java.support.logic.Constraint;
+import net.shibboleth.utilities.java.support.logic.FunctionSupport;
 
 import org.opensaml.profile.context.ProfileRequestContext;
 
@@ -48,13 +48,13 @@ public abstract class AbstractProtocolConfiguration extends AbstractConditionalP
     public static final String PROTOCOL_URI = "https://www.apereo.org/cas/protocol";
 
     /** Lookup function to supply {@link #ticketValidityPeriod} property. */
-    @Nullable private Function<ProfileRequestContext,Duration> ticketValidityPeriodLookupStrategy;
-
-    /** Validity time period of tickets. */
-    @Nonnull private Duration ticketValidityPeriod;
+    @Nonnull private Function<ProfileRequestContext,Duration> ticketValidityPeriodLookupStrategy;
 
     /** Whether attributes should be resolved in the course of the profile. */
     @Nonnull private Predicate<ProfileRequestContext> resolveAttributesPredicate;
+    
+    /** Holds default security config object to use. */
+    @Nonnull private final SecurityConfiguration defaultSecurityConfiguration;
 
     /**
      * Creates a new configuration instance.
@@ -65,26 +65,29 @@ public abstract class AbstractProtocolConfiguration extends AbstractConditionalP
         super(profileId);
         
         resolveAttributesPredicate = Predicates.alwaysTrue();
-        ticketValidityPeriod = Duration.ofSeconds(15);
+        ticketValidityPeriodLookupStrategy = FunctionSupport.constant(Duration.ofSeconds(15));
         
-        setSecurityConfiguration(new SecurityConfiguration(Duration.ofMinutes(5),
-                new TicketIdentifierGenerationStrategy(getDefaultTicketPrefix(), getDefaultTicketLength())));
+        defaultSecurityConfiguration = new SecurityConfiguration(Duration.ofMinutes(5),
+                new TicketIdentifierGenerationStrategy(getDefaultTicketPrefix(), getDefaultTicketLength()));
     }
 
     /** {@inheritDoc} */
-    @Override public void doInitialize() throws ComponentInitializationException {
-        Constraint.isNotNull(getSecurityConfiguration(), "Security configuration cannot be null.");
-        Constraint.isNotNull(getSecurityConfiguration().getIdGenerator(),
-                "Security configuration ID generator cannot be null.");
+    @Override
+    @Nullable public SecurityConfiguration getSecurityConfiguration(
+            @Nullable final ProfileRequestContext profileRequestContext) {
+        final SecurityConfiguration sc = super.getSecurityConfiguration(profileRequestContext);
+        return sc != null ? sc : defaultSecurityConfiguration;
     }
-
+    
     /**
      * Get ticket validity period.
      * 
+     * @param profileRequestContext current profile request context
+     * 
      * @return ticket validity period
      */
-    @Nonnull public Duration getTicketValidityPeriod() {
-        return getIndirectProperty(ticketValidityPeriodLookupStrategy, ticketValidityPeriod);
+    @Nonnull public Duration getTicketValidityPeriod(@Nullable final ProfileRequestContext profileRequestContext) {
+        return ticketValidityPeriodLookupStrategy.apply(profileRequestContext);
     }
 
     /**
@@ -96,7 +99,7 @@ public abstract class AbstractProtocolConfiguration extends AbstractConditionalP
         Constraint.isNotNull(ticketTTL, "Ticket lifetime cannot be null");
         Constraint.isFalse(ticketTTL.isNegative() || ticketTTL.isZero(), "Ticket lifetime must be greater than 0");
 
-        ticketValidityPeriod = ticketTTL;
+        ticketValidityPeriodLookupStrategy = FunctionSupport.constant(ticketTTL);
     }
 
     /**
@@ -107,24 +110,19 @@ public abstract class AbstractProtocolConfiguration extends AbstractConditionalP
      * @since 3.3.0
      */
     public void setTicketValidityPeriodLookupStrategy(
-            @Nullable final Function<ProfileRequestContext,Duration> strategy) {
-        ticketValidityPeriodLookupStrategy = strategy;
+            @Nonnull final Function<ProfileRequestContext,Duration> strategy) {
+        ticketValidityPeriodLookupStrategy = Constraint.isNotNull(strategy, "Lookup strategy cannot be null");
     }
 
     /**
-     * Get whether attributes should be resolved during the profile.
+     * Get whether attributes should be resolved during the profile (defaults to true).
      * 
-     * <p>
-     * Default is true
-     * </p>
+     * @param profileRequestContext current profile request context
      * 
      * @return true iff attributes should be resolved
-     * 
-     * @deprecated Use {@link #getResolveAttributesPredicate()} instead.
      */
-    @Deprecated
-    public boolean isResolveAttributes() {
-        return resolveAttributesPredicate.test(getProfileRequestContext());
+    public boolean isResolveAttributes(@Nullable final ProfileRequestContext profileRequestContext) {
+        return resolveAttributesPredicate.test(profileRequestContext);
     }
 
     /**
@@ -133,20 +131,7 @@ public abstract class AbstractProtocolConfiguration extends AbstractConditionalP
      * @param flag flag to set
      */
     public void setResolveAttributes(final boolean flag) {
-        resolveAttributesPredicate =
-                flag ? Predicates.<ProfileRequestContext> alwaysTrue() : Predicates
-                        .<ProfileRequestContext> alwaysFalse();
-    }
-
-    /**
-     * Get a condition to determine whether attributes should be resolved during the profile.
-     * 
-     * @return condition
-     * 
-     * @since 3.3.0
-     */
-    @Nonnull public Predicate<ProfileRequestContext> getResolveAttributesPredicate() {
-        return resolveAttributesPredicate;
+        resolveAttributesPredicate = flag ? Predicates.alwaysTrue() : Predicates.alwaysFalse();
     }
 
     /**
diff --git a/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/config/impl/LoginConfiguration.java b/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/config/impl/LoginConfiguration.java
index d766766..d5fbcf2 100644
--- a/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/config/impl/LoginConfiguration.java
+++ b/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/config/impl/LoginConfiguration.java
@@ -20,7 +20,6 @@ package net.shibboleth.idp.cas.config.impl;
 import java.security.Principal;
 import java.util.ArrayList;
 import java.util.Collection;
-import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
@@ -34,8 +33,6 @@ import org.opensaml.profile.context.ProfileRequestContext;
 
 import com.google.common.base.Predicates;
 import com.google.common.collect.Collections2;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
 
 import net.shibboleth.idp.authn.config.AuthenticationProfileConfiguration;
 import net.shibboleth.idp.saml.authn.principal.AuthnContextClassRefPrincipal;
@@ -43,9 +40,12 @@ import net.shibboleth.utilities.java.support.annotation.constraint.NonnullElemen
 import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
 import net.shibboleth.utilities.java.support.annotation.constraint.NotLive;
 import net.shibboleth.utilities.java.support.annotation.constraint.Unmodifiable;
+import net.shibboleth.utilities.java.support.collection.CollectionSupport;
 import net.shibboleth.utilities.java.support.logic.Constraint;
+import net.shibboleth.utilities.java.support.logic.FunctionSupport;
 import net.shibboleth.utilities.java.support.primitive.StringSupport;
 
+
 /**
  * CAS protocol configuration that applies to the <code>/login</code> URI.
  *
@@ -55,57 +55,46 @@ public class LoginConfiguration extends AbstractProtocolConfiguration
         implements AuthenticationProfileConfiguration {
 
     /** Proxy ticket profile URI. */
-    public static final String PROFILE_ID = PROTOCOL_URI + "/login";
+    @Nonnull @NotEmpty public static final String PROFILE_ID = PROTOCOL_URI + "/login";
 
     /** Default ticket prefix. */
-    public static final String DEFAULT_TICKET_PREFIX = "ST";
+    @Nonnull @NotEmpty public static final String DEFAULT_TICKET_PREFIX = "ST";
 
     /** Default ticket length (random part). */
     public static final int DEFAULT_TICKET_LENGTH = 25;
 
     /** Lookup function to supply {@link #authenticationFlows} property. */
-    @Nullable private Function<ProfileRequestContext,Set<String>> authenticationFlowsLookupStrategy;
-    
-    /** Filters the usable authentication flows. */
-    @Nonnull @NonnullElements private Set<String> authenticationFlows;
+    @Nonnull private Function<ProfileRequestContext,Set<String>> authenticationFlowsLookupStrategy;
 
     /** Lookup function to supply {@link #postAuthenticationFlows} property. */
-    @Nullable private Function<ProfileRequestContext,Collection<String>> postAuthenticationFlowsLookupStrategy;
-
-    /** Enables post-authentication interceptor flows. */
-    @Nonnull @NonnullElements private List<String> postAuthenticationFlows;
+    @Nonnull private Function<ProfileRequestContext,Collection<String>> postAuthenticationFlowsLookupStrategy;
 
     /** Lookup function to supply {@link #defaultAuthenticationContexts} property. */
-    @Nullable private Function<ProfileRequestContext,Collection<AuthnContextClassRefPrincipal>>
+    @Nonnull private Function<ProfileRequestContext,Collection<AuthnContextClassRefPrincipal>>
             defaultAuthenticationContextsLookupStrategy;
-    
-    /** Selects, and limits, the authentication contexts to use for requests. */
-    @Nonnull @NonnullElements private List<AuthnContextClassRefPrincipal> defaultAuthenticationContexts;
 
     /** Lookup function to supply {@link #nameIDFormatPrecedence} property. */
-    @Nullable private Function<ProfileRequestContext,Collection<String>> nameIDFormatPrecedenceLookupStrategy;
-
-    /** Precedence of name identifier formats to use for requests. */
-    @Nonnull @NonnullElements private List<String> nameIDFormatPrecedence;
+    @Nonnull private Function<ProfileRequestContext,Collection<String>> nameIDFormatPrecedenceLookupStrategy;
     
     /** Whether to mandate forced authentication for the request. */
     @Nonnull private Predicate<ProfileRequestContext> forceAuthnPredicate;
-    
+
     /** Creates a new instance. */
     public LoginConfiguration() {
         super(PROFILE_ID);
-        authenticationFlows = Collections.emptySet();
-        postAuthenticationFlows = Collections.emptyList();
-        defaultAuthenticationContexts = Collections.emptyList();
-        nameIDFormatPrecedence = Collections.emptyList();
+        
+        authenticationFlowsLookupStrategy = FunctionSupport.constant(null);
+        postAuthenticationFlowsLookupStrategy = FunctionSupport.constant(null);
+        defaultAuthenticationContextsLookupStrategy = FunctionSupport.constant(null);
+        nameIDFormatPrecedenceLookupStrategy = FunctionSupport.constant(null);
         forceAuthnPredicate = Predicates.alwaysFalse();
     }
 
     /** {@inheritDoc} */
-    @Override
-    @Nonnull @NonnullElements @NotLive @Unmodifiable public List<Principal> getDefaultAuthenticationMethods() {
-        return ImmutableList.<Principal>copyOf(getIndirectProperty(defaultAuthenticationContextsLookupStrategy,
-                defaultAuthenticationContexts));
+    @Nonnull @NonnullElements @NotLive @Unmodifiable public List<Principal> getDefaultAuthenticationMethods(
+            @Nullable final ProfileRequestContext profileRequestContext) {
+        return CollectionSupport.buildImmutableList(
+                defaultAuthenticationContextsLookupStrategy.apply(profileRequestContext));
     }
         
     /**
@@ -116,28 +105,27 @@ public class LoginConfiguration extends AbstractProtocolConfiguration
     public void setDefaultAuthenticationMethods(
             @Nullable @NonnullElements final Collection<AuthnContextClassRefPrincipal> contexts) {
         if (contexts != null) {
-            defaultAuthenticationContexts = new ArrayList<>(Collections2.filter(contexts, Predicates.notNull()));
+            defaultAuthenticationContextsLookupStrategy =
+                    FunctionSupport.constant(new ArrayList<>(Collections2.filter(contexts, Predicates.notNull())));
         } else {
-            defaultAuthenticationContexts = Collections.emptyList();
+            defaultAuthenticationContextsLookupStrategy = FunctionSupport.constant(null);
         }
     }
-    
+
     /**
      * Set a lookup strategy for the {@link #defaultAuthenticationContexts} property.
      *
      * @param strategy  lookup strategy
-     * 
-     * @since 3.3.0
      */
     public void setDefaultAuthenticationMethodsLookupStrategy(
-            @Nullable final Function<ProfileRequestContext,Collection<AuthnContextClassRefPrincipal>> strategy) {
-        defaultAuthenticationContextsLookupStrategy = strategy;
+            @Nonnull final Function<ProfileRequestContext,Collection<AuthnContextClassRefPrincipal>> strategy) {
+        defaultAuthenticationContextsLookupStrategy = Constraint.isNotNull(strategy, "Lookup strategy cannot be null");
     }
-
+    
     /** {@inheritDoc} */
-    @Override
-    @Nonnull @NonnullElements @NotLive @Unmodifiable public Set<String> getAuthenticationFlows() {
-        return ImmutableSet.copyOf(getIndirectProperty(authenticationFlowsLookupStrategy, authenticationFlows));
+    @Nonnull @NonnullElements @NotLive @Unmodifiable public Set<String> getAuthenticationFlows(
+            @Nullable final ProfileRequestContext profileRequestContext) {
+        return CollectionSupport.buildImmutableSet(authenticationFlowsLookupStrategy.apply(profileRequestContext));
     }
 
     /**
@@ -146,11 +134,11 @@ public class LoginConfiguration extends AbstractProtocolConfiguration
      * @param flows   flow identifiers to use
      */
     public void setAuthenticationFlows(@Nullable @NonnullElements final Collection<String> flows) {
-
         if (flows != null) {
-            authenticationFlows = new HashSet<>(StringSupport.normalizeStringCollection(flows));
+            authenticationFlowsLookupStrategy =
+                    FunctionSupport.constant(new HashSet<>(StringSupport.normalizeStringCollection(flows)));
         } else {
-            authenticationFlows = Collections.emptySet();
+            authenticationFlowsLookupStrategy = FunctionSupport.constant(null);
         }
     }
 
@@ -158,19 +146,16 @@ public class LoginConfiguration extends AbstractProtocolConfiguration
      * Set a lookup strategy for the {@link #authenticationFlows} property.
      *
      * @param strategy  lookup strategy
-     * 
-     * @since 3.3.0
      */
     public void setAuthenticationFlowsLookupStrategy(
-            @Nullable final Function<ProfileRequestContext,Set<String>> strategy) {
-        authenticationFlowsLookupStrategy = strategy;
+            @Nonnull final Function<ProfileRequestContext,Set<String>> strategy) {
+        authenticationFlowsLookupStrategy = Constraint.isNotNull(strategy, "Lookup strategy cannot be null");
     }
-
+    
     /** {@inheritDoc} */
-    @Override
-    @Nonnull @NonnullElements @NotLive @Unmodifiable public List<String> getPostAuthenticationFlows() {
-        return ImmutableList.copyOf(
-                getIndirectProperty(postAuthenticationFlowsLookupStrategy, postAuthenticationFlows));
+    @Nonnull @NonnullElements @NotLive @Unmodifiable public List<String> getPostAuthenticationFlows(
+            @Nullable final ProfileRequestContext profileRequestContext) {
+        return CollectionSupport.buildImmutableList(postAuthenticationFlowsLookupStrategy.apply(profileRequestContext));
     }
 
     /**
@@ -179,11 +164,11 @@ public class LoginConfiguration extends AbstractProtocolConfiguration
      * @param flows   flow identifiers to enable
      */
     public void setPostAuthenticationFlows(@Nullable @NonnullElements final Collection<String> flows) {
-
         if (flows != null) {
-            postAuthenticationFlows = new ArrayList<>(StringSupport.normalizeStringCollection(flows));
+            postAuthenticationFlowsLookupStrategy =
+                    FunctionSupport.constant(new ArrayList<>(StringSupport.normalizeStringCollection(flows)));
         } else {
-            postAuthenticationFlows = Collections.emptyList();
+            postAuthenticationFlowsLookupStrategy = FunctionSupport.constant(null);
         }
     }
 
@@ -191,18 +176,16 @@ public class LoginConfiguration extends AbstractProtocolConfiguration
      * Set a lookup strategy for the {@link #postAuthenticationFlows} property.
      *
      * @param strategy  lookup strategy
-     * 
-     * @since 3.3.0
      */
     public void setPostAuthenticationFlowsLookupStrategy(
-            @Nullable final Function<ProfileRequestContext,Collection<String>> strategy) {
-        postAuthenticationFlowsLookupStrategy = strategy;
+            @Nonnull final Function<ProfileRequestContext,Collection<String>> strategy) {
+        postAuthenticationFlowsLookupStrategy = Constraint.isNotNull(strategy, "Lookup strategy cannot be null");
     }
-
+    
     /** {@inheritDoc} */
-    @Override
-    @Nonnull @NonnullElements @NotLive @Unmodifiable public List<String> getNameIDFormatPrecedence() {
-        return ImmutableList.copyOf(getIndirectProperty(nameIDFormatPrecedenceLookupStrategy, nameIDFormatPrecedence));
+    @Nonnull @NonnullElements @NotLive @Unmodifiable public List<String> getNameIDFormatPrecedence(
+            @Nullable final ProfileRequestContext profileRequestContext) {
+        return CollectionSupport.buildImmutableList(nameIDFormatPrecedenceLookupStrategy.apply(profileRequestContext));
     }
 
     /**
@@ -213,55 +196,43 @@ public class LoginConfiguration extends AbstractProtocolConfiguration
     public void setNameIDFormatPrecedence(@Nonnull @NonnullElements final Collection<String> formats) {
         Constraint.isNotNull(formats, "List of formats cannot be null");
         
-        nameIDFormatPrecedence = new ArrayList<>(StringSupport.normalizeStringCollection(formats));
+        nameIDFormatPrecedenceLookupStrategy =
+                FunctionSupport.constant(new ArrayList<>(StringSupport.normalizeStringCollection(formats)));
     }
 
     /**
      * Set a lookup strategy for the {@link #nameIDFormatPrecedence} property.
      *
      * @param strategy  lookup strategy
-     * 
-     * @since 3.3.0
      */
     public void setNameIDFormatPrecedenceLookupStrategy(
-            @Nullable final Function<ProfileRequestContext,Collection<String>> strategy) {
-        nameIDFormatPrecedenceLookupStrategy = strategy;
+            @Nonnull final Function<ProfileRequestContext,Collection<String>> strategy) {
+        nameIDFormatPrecedenceLookupStrategy = Constraint.isNotNull(strategy, "Lookup strategy cannot be null");
+    }
+    
+    /** {@inheritDoc} */
+    public boolean isForceAuthn(@Nullable final ProfileRequestContext profileRequestContext) {
+        return forceAuthnPredicate.test(profileRequestContext);
     }
 
     /**
-     * Get a condition to determine whether a fresh user presence proof should be required for this request.
-     * 
-     * @return condition
+     * Set whether a fresh user presence proof should be required for this request.
      * 
-     * @since 3.4.0
+     * @param flag flag to set
      */
-    @Nonnull public Predicate<ProfileRequestContext> getForceAuthnPredicate() {
-        return forceAuthnPredicate;
+    public void setForceAuthn(final boolean flag) {
+        forceAuthnPredicate = flag ? Predicates.alwaysTrue() : Predicates.alwaysFalse();
     }
     
     /**
      * Set a condition to determine whether a fresh user presence proof should be required for this request.
      * 
      * @param condition condition to set
-     * 
-     * @since 3.4.0
      */
     public void setForceAuthnPredicate(@Nonnull final Predicate<ProfileRequestContext> condition) {
         forceAuthnPredicate = Constraint.isNotNull(condition, "Forced authentication predicate cannot be null");
     }
-    
-    /**
-     * Set whether a fresh user presence proof should be required for this request.
-     * 
-     * @param flag flag to set
-     * 
-     * @since 3.4.0
-     */
-    public void setForceAuthn(final boolean flag) {
-        forceAuthnPredicate = flag ? Predicates.<ProfileRequestContext>alwaysTrue()
-                : Predicates.<ProfileRequestContext>alwaysFalse();
-    }
-    
+            
     /** {@inheritDoc} */
     @Override
     @Nonnull @NotEmpty protected String getDefaultTicketPrefix() {
diff --git a/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/config/impl/ValidateConfiguration.java b/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/config/impl/ValidateConfiguration.java
index 73531d8..479b3f1 100644
--- a/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/config/impl/ValidateConfiguration.java
+++ b/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/config/impl/ValidateConfiguration.java
@@ -30,6 +30,7 @@ import net.shibboleth.idp.cas.service.impl.DefaultServiceComparator;
 import net.shibboleth.idp.cas.ticket.impl.TicketIdentifierGenerationStrategy;
 import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
 import net.shibboleth.utilities.java.support.logic.Constraint;
+import net.shibboleth.utilities.java.support.logic.FunctionSupport;
 import net.shibboleth.utilities.java.support.security.IdentifierGenerationStrategy;
 
 /**
@@ -45,31 +46,25 @@ import net.shibboleth.utilities.java.support.security.IdentifierGenerationStrate
 public class ValidateConfiguration extends AbstractProtocolConfiguration {
 
     /** Ticket validation profile ID. */
-    public static final String PROFILE_ID = PROTOCOL_URI + "/serviceValidate";
+    @Nonnull @NotEmpty public static final String PROFILE_ID = PROTOCOL_URI + "/serviceValidate";
 
     /** Default ticket prefix. */
-    public static final String DEFAULT_TICKET_PREFIX = "PGT";
+    @Nonnull @NotEmpty public static final String DEFAULT_TICKET_PREFIX = "PGT";
 
     /** Default ticket length (random part). */
     public static final int DEFAULT_TICKET_LENGTH = 50;
 
-    /** Lookup strategy for {@link #pgtIOUGenerator} property. */
-    @Nullable private Function<ProfileRequestContext,IdentifierGenerationStrategy> pgtIOUGeneratorLookupStrategy;
+    /** Lookup strategy for PGTIOU ticket ID generator. */
+    @Nonnull private Function<ProfileRequestContext,IdentifierGenerationStrategy> pgtIOUGeneratorLookupStrategy;
 
-    /** PGTIOU ticket ID generator. */
-    @Nullable private IdentifierGenerationStrategy pgtIOUGenerator;
+    /** Default PGTIOU ticket ID generator. */
+    @Nonnull private final IdentifierGenerationStrategy defaultPGTIOUGenerator;
 
-    /** Lookup strategy for {@link #serviceComparator} property. */
-    @Nullable private Function<ProfileRequestContext,Comparator<String>> serviceComparatorLookupStrategy;
+    /** Lookup strategy for enforcing ticket requester matches ticket validator. */
+    @Nonnull private Function<ProfileRequestContext,Comparator<String>> serviceComparatorLookupStrategy;
 
-    /** Component responsible for enforcing ticket requester matches ticket validator. */
-    @Nonnull private Comparator<String> serviceComparator;
-
-    /** Lookup strategy for {@link #userAttribute} property. */
-    @Nullable private Function<ProfileRequestContext,String> userAttributeLookupStrategy;
-    
-    /** Name of IdP attribute to use for user returned in CAS ticket validation response. */
-    @Nullable private String userAttribute;
+    /** Lookup strategy for Name of IdP attribute to use for user returned in CAS ticket validation response. */
+    @Nonnull private Function<ProfileRequestContext,String> userAttributeLookupStrategy;
 
     /** Creates a new instance. */
     public ValidateConfiguration() {
@@ -79,18 +74,25 @@ public class ValidateConfiguration extends AbstractProtocolConfiguration {
         // Default to 12H
         setTicketValidityPeriod(Duration.ofHours(12));
         
-        pgtIOUGenerator = new TicketIdentifierGenerationStrategy("PGTIOU", 50);
-        serviceComparator = new DefaultServiceComparator();
+        userAttributeLookupStrategy = FunctionSupport.constant(null);
+        serviceComparatorLookupStrategy = FunctionSupport.constant(new DefaultServiceComparator());
+        
+        defaultPGTIOUGenerator = new TicketIdentifierGenerationStrategy("PGTIOU", 50);
+        pgtIOUGeneratorLookupStrategy = FunctionSupport.constant(defaultPGTIOUGenerator);
     }
 
     /**
      * Get the PGTIOU ticket ID generator.
      * 
+     * @param profileRequestContext current profile request context
+     * 
      * @return PGTIOU ticket ID generator
      */
-    @Nonnull public IdentifierGenerationStrategy getPGTIOUGenerator() {
-        return Constraint.isNotNull(getIndirectProperty(pgtIOUGeneratorLookupStrategy, pgtIOUGenerator),
-                "PGTIOU generator cannot be null");
+    @Nonnull public IdentifierGenerationStrategy getPGTIOUGenerator(
+            @Nullable final ProfileRequestContext profileRequestContext) {
+        
+        final IdentifierGenerationStrategy strategy = pgtIOUGeneratorLookupStrategy.apply(profileRequestContext);
+        return strategy != null ? strategy : defaultPGTIOUGenerator;
     }
 
     /**
@@ -98,31 +100,34 @@ public class ValidateConfiguration extends AbstractProtocolConfiguration {
      *
      * @param generator ID generator
      */
-    public void setPGTIOUGenerator(@Nullable final IdentifierGenerationStrategy generator) {
-        pgtIOUGenerator = generator;
+    public void setPGTIOUGenerator(@Nonnull final IdentifierGenerationStrategy generator) {
+        pgtIOUGeneratorLookupStrategy = FunctionSupport.constant(
+                Constraint.isNotNull(generator, "Generator cannot be null"));
     }
     
     /**
-     * Set the lookup strategy to use for the name of the IdP attribute to use for username returned
-     * in CAS ticket validation response.
+     * Set the lookup strategy to use for the PGTIOU ticket ID generator.
      * 
      * @param strategy lookup strategy
      * 
      * @since 3.3.0
      */
     public void setPGTIOUGeneratorLookupStrategy(
-            @Nullable final Function<ProfileRequestContext,IdentifierGenerationStrategy> strategy) {
-        pgtIOUGeneratorLookupStrategy = strategy;
+            @Nonnull final Function<ProfileRequestContext,IdentifierGenerationStrategy> strategy) {
+        pgtIOUGeneratorLookupStrategy = Constraint.isNotNull(strategy, "Lookup strategy cannot be null");
     }
 
     /**
      * Get component responsible for enforcing ticket requester matches ticket validator.
      * 
+     * @param profileRequestContext current profile request context
+     * 
      * @return ticket requester/validator comparator
      */
-    @Nonnull public Comparator<String> getServiceComparator() {
-        return Constraint.isNotNull(getIndirectProperty(serviceComparatorLookupStrategy, serviceComparator),
-                "Service comparator cannot be null");
+    @Nonnull public Comparator<String> getServiceComparator(
+            @Nullable final ProfileRequestContext profileRequestContext) {
+        return Constraint.isNotNull(
+                serviceComparatorLookupStrategy.apply(profileRequestContext), "Service comparator cannot be null");
     }
 
     /**
@@ -130,8 +135,9 @@ public class ValidateConfiguration extends AbstractProtocolConfiguration {
      * 
      * @param comparator ticket requester/validator comparator
      */
-    public void setServiceComparator(@Nullable final Comparator<String> comparator) {
-        serviceComparator = comparator;
+    public void setServiceComparator(@Nonnull final Comparator<String> comparator) {
+        serviceComparatorLookupStrategy = FunctionSupport.constant(
+                Constraint.isNotNull(comparator, "ServiceComparator cannot be null"));
     }
 
     /**
@@ -143,29 +149,19 @@ public class ValidateConfiguration extends AbstractProtocolConfiguration {
      * @since 3.3.0
      */
     public void setServiceComparatorLookupStrategy(
-            @Nullable final Function<ProfileRequestContext,Comparator<String>> strategy) {
-        serviceComparatorLookupStrategy = strategy;
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    @Nonnull @NotEmpty protected String getDefaultTicketPrefix() {
-        return DEFAULT_TICKET_PREFIX;
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    protected int getDefaultTicketLength() {
-        return DEFAULT_TICKET_LENGTH;
+            @Nonnull final Function<ProfileRequestContext,Comparator<String>> strategy) {
+        serviceComparatorLookupStrategy = Constraint.isNotNull(strategy, "Lookup strategy cannot be null");
     }
 
     /**
      * Get name of IdP attribute to use for username returned in CAS ticket validation response.
      * 
+     * @param profileRequestContext current profile request context
+     * 
      * @return attribute name
      */
-    @Nullable public String getUserAttribute() {
-        return getIndirectProperty(userAttributeLookupStrategy, userAttribute);
+    @Nullable public String getUserAttribute(@Nullable final ProfileRequestContext profileRequestContext) {
+        return userAttributeLookupStrategy.apply(profileRequestContext);
     }
 
     /**
@@ -174,7 +170,7 @@ public class ValidateConfiguration extends AbstractProtocolConfiguration {
      * @param attribute attribute name to use
      */
     public void setUserAttribute(@Nullable final String attribute) {
-        userAttribute = attribute;
+        userAttributeLookupStrategy = FunctionSupport.constant(attribute);
     }
     
     /**
@@ -185,8 +181,20 @@ public class ValidateConfiguration extends AbstractProtocolConfiguration {
      * 
      * @since 3.3.0
      */
-    public void setUserAttributeLookupStrategy(@Nullable final Function<ProfileRequestContext,String> strategy) {
-        userAttributeLookupStrategy = strategy;
+    public void setUserAttributeLookupStrategy(@Nonnull final Function<ProfileRequestContext,String> strategy) {
+        userAttributeLookupStrategy = Constraint.isNotNull(strategy, "Lookup strategy cannot be null");
     }
     
+    /** {@inheritDoc} */
+    @Override
+    @Nonnull @NotEmpty protected String getDefaultTicketPrefix() {
+        return DEFAULT_TICKET_PREFIX;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected int getDefaultTicketLength() {
+        return DEFAULT_TICKET_LENGTH;
+    }
+
 }
\ No newline at end of file
diff --git a/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/BuildAuthenticationContextAction.java b/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/BuildAuthenticationContextAction.java
index 1ccccdf..9a85c64 100644
--- a/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/BuildAuthenticationContextAction.java
+++ b/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/BuildAuthenticationContextAction.java
@@ -53,7 +53,7 @@ public class BuildAuthenticationContextAction extends
         if (!ac.isForceAuthn()) {
             final LoginConfiguration config = configLookupFunction.apply(profileRequestContext);
             if (config != null) {
-                ac.setForceAuthn(config.getForceAuthnPredicate().test(profileRequestContext));
+                ac.setForceAuthn(config.isForceAuthn(profileRequestContext));
             }
         }
         
diff --git a/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/GrantProxyTicketAction.java b/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/GrantProxyTicketAction.java
index 30bd139..ff315f6 100644
--- a/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/GrantProxyTicketAction.java
+++ b/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/GrantProxyTicketAction.java
@@ -31,10 +31,12 @@ import net.shibboleth.idp.cas.protocol.ProxyTicketResponse;
 import net.shibboleth.idp.cas.ticket.ProxyGrantingTicket;
 import net.shibboleth.idp.cas.ticket.ProxyTicket;
 import net.shibboleth.idp.cas.ticket.TicketServiceEx;
+import net.shibboleth.idp.profile.config.SecurityConfiguration;
 import net.shibboleth.idp.session.IdPSession;
 import net.shibboleth.idp.session.SessionException;
 import net.shibboleth.idp.session.SessionResolver;
 import net.shibboleth.idp.session.criterion.SessionIdCriterion;
+import net.shibboleth.utilities.java.support.component.ComponentSupport;
 import net.shibboleth.utilities.java.support.logic.Constraint;
 import net.shibboleth.utilities.java.support.resolver.CriteriaSet;
 import net.shibboleth.utilities.java.support.resolver.ResolverException;
@@ -61,19 +63,16 @@ public class GrantProxyTicketAction extends AbstractCASProtocolAction<ProxyTicke
 
 
     /** Profile configuration lookup function. */
-    private final ConfigLookupFunction<ProxyConfiguration> configLookupFunction =
-            new ConfigLookupFunction<>(ProxyConfiguration.class);
+    @Nonnull private final ConfigLookupFunction<ProxyConfiguration> configLookupFunction;
 
     /** Manages CAS tickets. */
-    @Nonnull
-    private final TicketServiceEx casTicketService;
+    @Nonnull private final TicketServiceEx casTicketService;
 
     /** Looks up IdP sessions. */
-    @Nonnull
-    private final SessionResolver sessionResolver;
+    @Nonnull private final SessionResolver sessionResolver;
 
     /** Whether to resolve and validate IdP session as part of granting a proxy ticket. */
-    private Predicate<ProfileRequestContext> validateIdPSessionPredicate = Predicates.alwaysFalse();
+    @Nonnull private Predicate<ProfileRequestContext> validateIdPSessionPredicate;
 
 
     /**
@@ -86,6 +85,9 @@ public class GrantProxyTicketAction extends AbstractCASProtocolAction<ProxyTicke
             @Nonnull final TicketServiceEx ticketService, @Nonnull final SessionResolver resolver) {
         casTicketService = Constraint.isNotNull(ticketService, "TicketService cannot be null");
         sessionResolver = Constraint.isNotNull(resolver, "SessionResolver cannot be null");
+        
+        validateIdPSessionPredicate = Predicates.alwaysFalse();
+        configLookupFunction = new ConfigLookupFunction<>(ProxyConfiguration.class);
     }
 
     /**
@@ -99,7 +101,9 @@ public class GrantProxyTicketAction extends AbstractCASProtocolAction<ProxyTicke
      * @param predicate Session validation predicate. Default is <code>Predicates.alwaysFalse()</code>.
      */
     public void setValidateIdPSessionPredicate(@Nonnull final Predicate<ProfileRequestContext> predicate) {
-        validateIdPSessionPredicate = predicate;
+        ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+        
+        validateIdPSessionPredicate = Constraint.isNotNull(predicate, "Session validation condition cannot be null");
     }
 
     /** {@inheritDoc} */
@@ -118,7 +122,9 @@ public class GrantProxyTicketAction extends AbstractCASProtocolAction<ProxyTicke
             log.warn("Proxy ticket configuration undefined");
             return ProtocolError.IllegalState.event(this);
         }
-        if (config.getSecurityConfiguration() == null || config.getSecurityConfiguration().getIdGenerator() == null) {
+        
+        final SecurityConfiguration securityConfiguration = config.getSecurityConfiguration(profileRequestContext);
+        if (securityConfiguration == null || securityConfiguration.getIdGenerator() == null) {
             log.warn("Invalid proxy ticket configuration: SecurityConfiguration#idGenerator undefined");
             return ProtocolError.IllegalState.event(this);
         }
@@ -150,8 +156,8 @@ public class GrantProxyTicketAction extends AbstractCASProtocolAction<ProxyTicke
         try {
             log.debug("Granting proxy ticket for {}", request.getTargetService());
             pt = casTicketService.createProxyTicket(
-                    config.getSecurityConfiguration().getIdGenerator().generateIdentifier(),
-                    Instant.now().plus(config.getTicketValidityPeriod()),
+                    securityConfiguration.getIdGenerator().generateIdentifier(),
+                    Instant.now().plus(config.getTicketValidityPeriod(profileRequestContext)),
                     pgt,
                     request.getTargetService());
         } catch (final RuntimeException e) {
diff --git a/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/GrantServiceTicketAction.java b/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/GrantServiceTicketAction.java
index 901a30e..fa218e9 100644
--- a/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/GrantServiceTicketAction.java
+++ b/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/GrantServiceTicketAction.java
@@ -34,6 +34,7 @@ import net.shibboleth.idp.cas.protocol.ServiceTicketResponse;
 import net.shibboleth.idp.cas.ticket.ServiceTicket;
 import net.shibboleth.idp.cas.ticket.TicketServiceEx;
 import net.shibboleth.idp.cas.ticket.TicketState;
+import net.shibboleth.idp.profile.config.SecurityConfiguration;
 import net.shibboleth.idp.session.IdPSession;
 import net.shibboleth.idp.session.context.SessionContext;
 import net.shibboleth.utilities.java.support.logic.Constraint;
@@ -59,28 +60,19 @@ public class GrantServiceTicketAction extends AbstractCASProtocolAction<ServiceT
     @Nonnull private final Logger log = LoggerFactory.getLogger(GrantServiceTicketAction.class);
 
     /** Profile configuration lookup function. */
-    @Nonnull private final ConfigLookupFunction<LoginConfiguration> configLookupFunction =
-            new ConfigLookupFunction<>(LoginConfiguration.class);
+    @Nonnull private final ConfigLookupFunction<LoginConfiguration> configLookupFunction;
 
     /** Looks up an IdP session context from IdP profile request context. */
-    @Nonnull
-    private final Function<ProfileRequestContext, SessionContext> sessionContextFunction =
-            new ChildContextLookup<>(SessionContext.class);
+    @Nonnull private final Function<ProfileRequestContext, SessionContext> sessionContextFunction;
 
     /** AuthenticationContext lookup function. */
-    @Nonnull
-    private final Function<ProfileRequestContext, AuthenticationContext> authnCtxLookupFunction =
-            new ChildContextLookup<>(AuthenticationContext.class);
+    @Nonnull private final Function<ProfileRequestContext, AuthenticationContext> authnCtxLookupFunction;
 
     /** Function to retrieve subject principal name. */
-    @Nonnull
-    private final Function<ProfileRequestContext, String> principalLookupFunction =
-            new SubjectContextPrincipalLookupFunction().compose(
-                    new ChildContextLookup<>(SubjectContext.class));
+    @Nonnull private final Function<ProfileRequestContext, String> principalLookupFunction;
 
     /** Manages CAS tickets. */
-    @Nonnull
-    private final TicketServiceEx ticketServiceEx;
+    @Nonnull private final TicketServiceEx ticketServiceEx;
 
 
     /**
@@ -90,6 +82,12 @@ public class GrantServiceTicketAction extends AbstractCASProtocolAction<ServiceT
      */
     public GrantServiceTicketAction(@Nonnull final TicketServiceEx ticketService) {
         ticketServiceEx = Constraint.isNotNull(ticketService, "TicketService cannot be null");
+        
+        configLookupFunction = new ConfigLookupFunction<>(LoginConfiguration.class);
+        sessionContextFunction = new ChildContextLookup<>(SessionContext.class);
+        authnCtxLookupFunction = new ChildContextLookup<>(AuthenticationContext.class);
+        principalLookupFunction = new SubjectContextPrincipalLookupFunction().compose(
+                new ChildContextLookup<>(SubjectContext.class));
     }
 
     /** {@inheritDoc} */
@@ -105,7 +103,9 @@ public class GrantServiceTicketAction extends AbstractCASProtocolAction<ServiceT
         if (config == null) {
             throw new IllegalStateException("Service ticket configuration undefined");
         }
-        if (config.getSecurityConfiguration() == null || config.getSecurityConfiguration().getIdGenerator() == null) {
+        
+        final SecurityConfiguration securityConfiguration = config.getSecurityConfiguration(profileRequestContext);
+        if (securityConfiguration == null || securityConfiguration == null) {
             throw new IllegalStateException(
                     "Invalid service ticket configuration: SecurityConfiguration#idGenerator undefined");
         }
@@ -125,8 +125,8 @@ public class GrantServiceTicketAction extends AbstractCASProtocolAction<ServiceT
                     authnResult.getAuthenticationInstant(),
                     authnResult.getAuthenticationFlowId());
             ticket = ticketServiceEx.createServiceTicket(
-                    config.getSecurityConfiguration().getIdGenerator().generateIdentifier(),
-                    Instant.now().plus(config.getTicketValidityPeriod()),
+                    securityConfiguration.getIdGenerator().generateIdentifier(),
+                    Instant.now().plus(config.getTicketValidityPeriod(profileRequestContext)),
                     request.getService(),
                     state,
                     request.isRenew());
diff --git a/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/PrepareTicketValidationResponseAction.java b/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/PrepareTicketValidationResponseAction.java
index 208fbee..339cfd8 100644
--- a/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/PrepareTicketValidationResponseAction.java
+++ b/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/PrepareTicketValidationResponseAction.java
@@ -85,13 +85,14 @@ public class PrepareTicketValidationResponseAction extends
         }
 
         final String principal;
-        if (validateConfiguration.getUserAttribute() != null) {
-            log.debug("Using {} for CAS username", validateConfiguration.getUserAttribute());
-            final IdPAttribute attribute = ac.getIdPAttributes().get(validateConfiguration.getUserAttribute());
+        final String userAttributeName = validateConfiguration.getUserAttribute(profileRequestContext);
+        if (userAttributeName != null) {
+            log.debug("Using {} for CAS username", userAttributeName);
+            final IdPAttribute attribute = ac.getIdPAttributes().get(userAttributeName);
             if (attribute != null && !attribute.getValues().isEmpty()) {
                 principal = attribute.getValues().get(0).getValue().toString();
             } else {
-                log.debug("Filtered attribute {} has no value", validateConfiguration.getUserAttribute());
+                log.debug("Filtered attribute {} has no value", userAttributeName);
                 principal = null;
             }
         } else {
diff --git a/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/ValidateProxyCallbackAction.java b/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/ValidateProxyCallbackAction.java
index f45e5c0..66b2b03 100644
--- a/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/ValidateProxyCallbackAction.java
+++ b/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/ValidateProxyCallbackAction.java
@@ -42,7 +42,9 @@ import net.shibboleth.idp.cas.ticket.ProxyTicket;
 import net.shibboleth.idp.cas.ticket.ServiceTicket;
 import net.shibboleth.idp.cas.ticket.Ticket;
 import net.shibboleth.idp.cas.ticket.TicketServiceEx;
+import net.shibboleth.idp.profile.config.SecurityConfiguration;
 import net.shibboleth.utilities.java.support.logic.Constraint;
+import net.shibboleth.utilities.java.support.security.IdentifierGenerationStrategy;
 
 /**
  * Validates the proxy callback URL provided in the service ticket validation request and creates a PGT when
@@ -61,19 +63,16 @@ public class ValidateProxyCallbackAction
     extends AbstractCASProtocolAction<TicketValidationRequest, TicketValidationResponse> {
 
     /** Class logger. */
-    private final Logger log = LoggerFactory.getLogger(ValidateProxyCallbackAction.class);
+    @Nonnull private final Logger log = LoggerFactory.getLogger(ValidateProxyCallbackAction.class);
 
     /** Profile configuration lookup function. */
-    private final ConfigLookupFunction<ValidateConfiguration> configLookupFunction =
-            new ConfigLookupFunction<>(ValidateConfiguration.class);
+    @Nonnull private final ConfigLookupFunction<ValidateConfiguration> configLookupFunction;
 
     /** Validates the proxy callback endpoint. */
-    @Nonnull
-    private final ProxyValidator proxyValidator;
+    @Nonnull private final ProxyValidator proxyValidator;
 
     /** Manages CAS tickets. */
-    @Nonnull
-    private final TicketServiceEx ticketServiceEx;
+    @Nonnull private final TicketServiceEx ticketServiceEx;
 
 
     /**
@@ -87,10 +86,12 @@ public class ValidateProxyCallbackAction
             @Nonnull final TicketServiceEx ticketService) {
         proxyValidator = Constraint.isNotNull(validator, "ProxyValidator cannot be null");
         ticketServiceEx = Constraint.isNotNull(ticketService, "TicketService cannot be null");
+        
+        configLookupFunction = new ConfigLookupFunction<>(ValidateConfiguration.class);
     }
 
-    @Nonnull
     @Override
+    @Nonnull
     protected Event doExecute(
             final @Nonnull RequestContext springRequestContext,
             final @Nonnull ProfileRequestContext profileRequestContext) {
@@ -102,16 +103,20 @@ public class ValidateProxyCallbackAction
         if (config == null) {
             throw new IllegalStateException("Proxy-granting ticket configuration undefined");
         }
-        if (config.getSecurityConfiguration() == null || config.getSecurityConfiguration().getIdGenerator() == null) {
+        
+        final SecurityConfiguration securityConfiguration = config.getSecurityConfiguration(profileRequestContext);
+        if (securityConfiguration == null || securityConfiguration.getIdGenerator() == null) {
             throw new IllegalStateException(
                     "Invalid proxy-granting ticket configuration: SecurityConfiguration#idGenerator undefined");
         }
-        if (config.getPGTIOUGenerator() == null) {
+        
+        final IdentifierGenerationStrategy pgtGenerator = config.getPGTIOUGenerator(profileRequestContext);
+        if (pgtGenerator == null) {
             throw new IllegalStateException("Invalid proxy-granting ticket configuration: PGTIOUGenerator undefined");
         }
         final ProxyIdentifiers proxyIds = new ProxyIdentifiers(
-                config.getSecurityConfiguration().getIdGenerator().generateIdentifier(),
-                config.getPGTIOUGenerator().generateIdentifier());
+                securityConfiguration.getIdGenerator().generateIdentifier(),
+                pgtGenerator.generateIdentifier());
         final URI proxyCallbackUri;
         try {
             proxyCallbackUri = new URIBuilder(request.getPgtUrl())
@@ -124,7 +129,7 @@ public class ValidateProxyCallbackAction
         try {
             log.debug("Attempting proxy authentication to {}", proxyCallbackUri);
             proxyValidator.validate(profileRequestContext, proxyCallbackUri);
-            final Instant expiration = Instant.now().plus(config.getTicketValidityPeriod());
+            final Instant expiration = Instant.now().plus(config.getTicketValidityPeriod(profileRequestContext));
             if (ticket instanceof ServiceTicket) {
                 ticketServiceEx.createProxyGrantingTicket(proxyIds.getPgtId(), expiration, (ServiceTicket) ticket);
             } else {
diff --git a/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/ValidateTicketAction.java b/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/ValidateTicketAction.java
index 6b03b6e..74691c0 100644
--- a/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/ValidateTicketAction.java
+++ b/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/ValidateTicketAction.java
@@ -111,7 +111,8 @@ public class ValidateTicketAction extends AbstractCASProtocolAction<TicketValida
             return ProtocolError.TicketExpired.event(this);
         }
 
-        if (config.getServiceComparator().compare(ticket.getService(), request.getService()) != 0) {
+        if (config.getServiceComparator(profileRequestContext).compare(
+                ticket.getService(), request.getService()) != 0) {
             log.debug("Service issued for {} does not match {}", ticket.getService(), request.getService());
             return ProtocolError.ServiceMismatch.event(this);
         }
diff --git a/idp-conf/src/main/resources/system/conf/relying-party-mddriven.xml b/idp-conf/src/main/resources/system/conf/relying-party-mddriven.xml
index beacd93..3772af6 100644
--- a/idp-conf/src/main/resources/system/conf/relying-party-mddriven.xml
+++ b/idp-conf/src/main/resources/system/conf/relying-party-mddriven.xml
@@ -15,13 +15,17 @@
     <!--
     This is ALOT of wiring to pre-configure support for virtually system-wide support for deriving relying-party
     settings and profile settings through examination of metadata tags.
+    
+    Anywhere that the underlying non-metadata-driven beans contain default properties, there may need to be a
+    re-injection of the same defaults here because both constant and runtime-derived settings are actually handled
+    with strategy functions.
     -->
 
     <!-- Parent beans for defining metadata-driven config lookup strategies. -->
 
     <bean id="RelyingParty.MDDriven" abstract="true" parent="RelyingParty">
         <property name="responderIdLookupStrategy">
-            <bean parent="shibboleth.MDDrivenStringProperty" p:propertyName="responderId" />
+            <bean parent="shibboleth.MDDrivenStringProperty" p:propertyName="responderId" p:defaultValue="#{getObject('entityID')}" />
         </property>
         <property name="profileConfigurationsLookupStrategy">
             <bean parent="shibboleth.MDDrivenBeanProperty" p:propertyName="profileConfigurations"
@@ -91,7 +95,12 @@
                 p:propertyType="#{T(net.shibboleth.idp.profile.config.SecurityConfiguration)}" />
         </property>
         <property name="disallowedFeaturesLookupStrategy">
-            <bean parent="shibboleth.MDDrivenIntProperty" p:propertyName="disallowedFeatures" />
+            <bean parent="shibboleth.MDDrivenIntProperty" p:propertyName="disallowedFeatures">
+                <property name="defaultValue">
+                    <util:constant
+                        static-field="net.shibboleth.idp.profile.config.AbstractProfileConfiguration.DEFAULT_DISALLOWED_FEATURES" />
+                </property>
+            </bean>
         </property>
     </bean>
     
@@ -187,7 +196,7 @@
             </bean>
         </property>
         <property name="ticketValidityPeriodLookupStrategy">
-            <bean parent="shibboleth.MDDrivenDurationProperty" p:propertyName="ticketValidityPeriod" />
+            <bean parent="shibboleth.MDDrivenDurationProperty" p:propertyName="ticketValidityPeriod" p:defaultValue="PT15S" />
         </property>
     </bean>
 
@@ -368,7 +377,7 @@
         <property name="maximumSPSessionLifetimeLookupStrategy">
             <bean parent="shibboleth.MDDrivenDurationProperty" p:propertyName="maximumSPSessionLifetime" />
         </property>
-        <property name="allowDelegation">
+        <property name="allowDelegationPredicate">
             <bean class="net.shibboleth.utilities.java.support.logic.PredicateSupport" factory-method="fromFunction">
                 <constructor-arg>
                     <bean parent="shibboleth.MDDrivenBoolProperty" p:propertyName="allowDelegation" />
@@ -570,9 +579,17 @@
 
     <bean id="CAS.ValidateConfiguration.MDDriven" parent="AbstractMDDrivenCASProfile" lazy-init="true"
             class="net.shibboleth.idp.cas.config.impl.ValidateConfiguration">
+        <property name="ticketValidityPeriodLookupStrategy">
+            <bean parent="shibboleth.MDDrivenDurationProperty" p:propertyName="ticketValidityPeriod" p:defaultValue="PT12H" />
+        </property>
         <property name="serviceComparatorLookupStrategy">
             <bean parent="shibboleth.MDDrivenBeanProperty" p:propertyName="serviceComparator"
-                p:propertyType="#{T(java.util.Comparator)}" />
+                p:propertyType="#{T(java.util.Comparator)}"
+                p:defaultValue="#{getObject('shibboleth.CASServiceComparator') ?: getObject('shibboleth.DefaultCASServiceComparator')}" />
+        </property>
+        <property name="pGTIOUGeneratorLookupStrategy">
+            <bean parent="shibboleth.MDDrivenBeanProperty" p:propertyName="pGTIOUGenerator"
+                p:propertyType="#{T(net.shibboleth.utilities.java.support.security.IdentifierGenerationStrategy)}" />
         </property>
         <property name="userAttributeLookupStrategy">
             <bean parent="shibboleth.MDDrivenStringProperty" p:propertyName="userAttribute" />
diff --git a/idp-conf/src/main/resources/system/conf/relying-party-system.xml b/idp-conf/src/main/resources/system/conf/relying-party-system.xml
index b63eaf6..5c2e186 100644
--- a/idp-conf/src/main/resources/system/conf/relying-party-system.xml
+++ b/idp-conf/src/main/resources/system/conf/relying-party-system.xml
@@ -26,7 +26,6 @@
 
     <!-- Parent bean for generic RelyingParty overrides that establishes defaults. -->
     <bean id="RelyingParty" abstract="true" class="net.shibboleth.idp.relyingparty.RelyingPartyConfiguration"
-        p:servletRequest-ref="shibboleth.HttpServletRequest"
         p:responderId="#{getObject('entityID')}"
         p:detailedErrorsPredicate="%{idp.errors.detailed:false}" />
 
diff --git a/idp-conf/src/main/resources/system/flows/admin/admin-abstract-beans.xml b/idp-conf/src/main/resources/system/flows/admin/admin-abstract-beans.xml
index 215bfd9..6f2cd38 100644
--- a/idp-conf/src/main/resources/system/flows/admin/admin-abstract-beans.xml
+++ b/idp-conf/src/main/resources/system/flows/admin/admin-abstract-beans.xml
@@ -73,7 +73,7 @@
         class="net.shibboleth.idp.profile.context.navigate.SpringExpressionContextLookupFunction"
         c:inClass="#{T(org.opensaml.profile.context.ProfileRequestContext)}"
         c:outputType="#{T(java.lang.String)}"
-        c:expression="#input.getSubcontext(T(net.shibboleth.idp.profile.context.RelyingPartyContext)).getProfileConfig().getPolicyName()" />
+        c:expression="#input.getSubcontext(T(net.shibboleth.idp.profile.context.RelyingPartyContext)).getProfileConfig().getPolicyName(#input)" />
 
     <!-- Default operation/resource suppliers for access checks. -->
     <bean id="DefaultOperationLookupStrategy" parent="shibboleth.Functions.Constant">
diff --git a/idp-conf/src/main/resources/system/flows/admin/admin-abstract-flow.xml b/idp-conf/src/main/resources/system/flows/admin/admin-abstract-flow.xml
index 912a78f..d5bd24d 100644
--- a/idp-conf/src/main/resources/system/flows/admin/admin-abstract-flow.xml
+++ b/idp-conf/src/main/resources/system/flows/admin/admin-abstract-flow.xml
@@ -24,7 +24,7 @@
 
     <!-- Conditional check for user authentication. -->
     <decision-state id="CheckIfAuthenticationNeeded">
-        <if test="relyingPartyContext.getProfileConfig().isAuthenticated()"
+        <if test="relyingPartyContext.getProfileConfig().isAuthenticated(opensamlProfileRequestContext)"
             then="PopulateClientStorageLoadContext" else="DoProfileWork" />
     </decision-state>
 
@@ -58,7 +58,7 @@
     </subflow-state>
     
     <decision-state id="ResolveAttributes">
-        <if test="relyingPartyContext.getProfileConfig().resolveAttributes()"
+        <if test="relyingPartyContext.getProfileConfig().isResolveAttributes(opensamlProfileRequestContext)"
             then="AttributeResolution"
             else="PopulateClientStorageSaveContext" />
     </decision-state>
diff --git a/idp-conf/src/main/resources/system/flows/cas/login/login-flow.xml b/idp-conf/src/main/resources/system/flows/cas/login/login-flow.xml
index f19a142..d613646 100644
--- a/idp-conf/src/main/resources/system/flows/cas/login/login-flow.xml
+++ b/idp-conf/src/main/resources/system/flows/cas/login/login-flow.xml
@@ -83,7 +83,7 @@
     </subflow-state>
 
     <decision-state id="CheckResolveAttributes">
-        <if test="LoginConfigLookup.apply(opensamlProfileRequestContext).isResolveAttributes()"
+        <if test="LoginConfigLookup.apply(opensamlProfileRequestContext).isResolveAttributes(opensamlProfileRequestContext)"
             then="CheckForSubjectContext"
             else="GrantServiceTicket" />
     </decision-state>
diff --git a/idp-conf/src/main/resources/system/flows/cas/samlValidate/samlValidate-flow.xml b/idp-conf/src/main/resources/system/flows/cas/samlValidate/samlValidate-flow.xml
index 791cfb3..bbbd76e 100644
--- a/idp-conf/src/main/resources/system/flows/cas/samlValidate/samlValidate-flow.xml
+++ b/idp-conf/src/main/resources/system/flows/cas/samlValidate/samlValidate-flow.xml
@@ -20,7 +20,7 @@
        | Always resolve attributes for /samlValidate protocol endpoint.
        -->
     <decision-state id="CheckResolveAttributes">
-        <if test="ValidateConfigLookup.apply(opensamlProfileRequestContext).isResolveAttributes()"
+        <if test="ValidateConfigLookup.apply(opensamlProfileRequestContext).isResolveAttributes(opensamlProfileRequestContext)"
             then="ResolveAttributes"
             else="ResolveAttributes" />
     </decision-state>
diff --git a/idp-conf/src/main/resources/system/flows/cas/validate-abstract-flow.xml b/idp-conf/src/main/resources/system/flows/cas/validate-abstract-flow.xml
index 9ced6fc..56eb792 100644
--- a/idp-conf/src/main/resources/system/flows/cas/validate-abstract-flow.xml
+++ b/idp-conf/src/main/resources/system/flows/cas/validate-abstract-flow.xml
@@ -64,7 +64,7 @@
     </action-state>
 
     <decision-state id="CheckResolveAttributes">
-        <if test="ValidateConfigLookup.apply(opensamlProfileRequestContext).isResolveAttributes()"
+        <if test="ValidateConfigLookup.apply(opensamlProfileRequestContext).isResolveAttributes(opensamlProfileRequestContext)"
             then="ResolveAttributes"
             else="UpdateIdPSessionWithSPSession" />
     </decision-state>
diff --git a/idp-conf/src/test/java/net/shibboleth/idp/test/flows/c14n/actions/SetupForSAML1C14N.java b/idp-conf/src/test/java/net/shibboleth/idp/test/flows/c14n/actions/SetupForSAML1C14N.java
index 00c2587..5b5cba4 100644
--- a/idp-conf/src/test/java/net/shibboleth/idp/test/flows/c14n/actions/SetupForSAML1C14N.java
+++ b/idp-conf/src/test/java/net/shibboleth/idp/test/flows/c14n/actions/SetupForSAML1C14N.java
@@ -119,7 +119,7 @@ public class SetupForSAML1C14N extends AbstractProfileAction {
                 profileRequestContext.getSubcontext(SubjectCanonicalizationContext.class, true);
         scc.setSubject(sub);
         scc.setRequesterId(rpc.getRelyingPartyId());
-        scc.setResponderId(rpc.getConfiguration().getResponderId());
+        scc.setResponderId(rpc.getConfiguration().getResponderId(profileRequestContext));
     }
     
 }
\ No newline at end of file
diff --git a/idp-conf/src/test/java/net/shibboleth/idp/test/flows/c14n/actions/SetupForSAML2C14N.java b/idp-conf/src/test/java/net/shibboleth/idp/test/flows/c14n/actions/SetupForSAML2C14N.java
index c8136c4..6a2b0d8 100644
--- a/idp-conf/src/test/java/net/shibboleth/idp/test/flows/c14n/actions/SetupForSAML2C14N.java
+++ b/idp-conf/src/test/java/net/shibboleth/idp/test/flows/c14n/actions/SetupForSAML2C14N.java
@@ -119,7 +119,7 @@ public class SetupForSAML2C14N extends AbstractProfileAction {
                 profileRequestContext.getSubcontext(SubjectCanonicalizationContext.class, true);
         scc.setSubject(sub);
         scc.setRequesterId(rpc.getRelyingPartyId());
-        scc.setResponderId(rpc.getConfiguration().getResponderId());
+        scc.setResponderId(rpc.getConfiguration().getResponderId(profileRequestContext));
     }
     
 }
\ No newline at end of file
diff --git a/idp-conf/src/test/java/net/shibboleth/idp/test/flows/cas/LoginFlowInitialAuthnTest.java b/idp-conf/src/test/java/net/shibboleth/idp/test/flows/cas/LoginFlowInitialAuthnTest.java
deleted file mode 100644
index 83f97b6..0000000
--- a/idp-conf/src/test/java/net/shibboleth/idp/test/flows/cas/LoginFlowInitialAuthnTest.java
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Licensed to the University Corporation for Advanced Internet Development,
- * Inc. (UCAID) under one or more contributor license agreements.  See the
- * NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The UCAID licenses this file to You 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.idp.test.flows.cas;
-
-import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertNotNull;
-import static org.testng.Assert.assertTrue;
-
-import javax.annotation.Nonnull;
-
-import net.shibboleth.idp.authn.context.SubjectContext;
-import net.shibboleth.idp.cas.ticket.Ticket;
-import net.shibboleth.idp.cas.ticket.TicketService;
-import net.shibboleth.idp.session.IdPSession;
-import net.shibboleth.idp.session.criterion.SessionIdCriterion;
-import net.shibboleth.idp.session.impl.StorageBackedSessionManager;
-import net.shibboleth.idp.test.flows.AbstractFlowTest;
-import net.shibboleth.utilities.java.support.net.URISupport;
-import net.shibboleth.utilities.java.support.resolver.CriteriaSet;
-
-import org.opensaml.profile.context.ProfileRequestContext;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Qualifier;
-import org.springframework.test.context.ContextConfiguration;
-import org.springframework.webflow.execution.FlowExecutionOutcome;
-import org.springframework.webflow.executor.FlowExecutionResult;
-import org.testng.annotations.AfterClass;
-import org.testng.annotations.BeforeClass;
-import org.testng.annotations.Test;
-
-/**
- * Tests login flow with initial-authn enabled.
- *
- * @author Marvin S. Addison
- */
- at ContextConfiguration(locations = {
-        "/test/test-cas-beans.xml"
-})
-public class LoginFlowInitialAuthnTest extends AbstractFlowTest {
-    /** Flow id. */
-    @Nonnull
-    private static String FLOW_ID = "cas/login";
-
-    @Autowired
-    private StorageBackedSessionManager sessionManager;
-
-    @Autowired
-    @Qualifier("shibboleth.CASTicketService")
-    private TicketService ticketService;
-
-    @BeforeClass
-    public void enableInitialAuthn() {
-        System.setProperty("idp.authn.flows.initial", "Password");
-    }
-
-    @AfterClass
-    public void disableInitialAuthn() {
-        System.setProperty("idp.authn.flows.initial", "");
-    }
-
-    @Test
-    public void testLoginStartSession() throws Exception {
-        final String service = "https://start.example.org/";
-        externalContext.getMockRequestParameterMap().put("service", service);
-        overrideEndStateOutput(FLOW_ID, "RedirectToService");
-
-        final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
-        final FlowExecutionOutcome outcome = result.getOutcome();
-        assertEquals(outcome.getId(), "RedirectToService");
-        final String url = externalContext.getExternalRedirectUrl();
-        assertTrue(url.contains("ticket=ST-"));
-        final String ticketId = URISupport.doURLDecode(url.substring(url.indexOf("ticket=") + 7));
-        final Ticket st = ticketService.removeServiceTicket(ticketId);
-        assertNotNull(st);
-        final IdPSession session = sessionManager.resolveSingle(
-                new CriteriaSet(new SessionIdCriterion(st.getSessionId())));
-        assertNotNull(session);
-
-        final ProfileRequestContext prc = (ProfileRequestContext) outcome.getOutput().get(END_STATE_OUTPUT_ATTR_NAME);
-        assertNotNull(prc.getSubcontext(SubjectContext.class));
-    }
-}
diff --git a/idp-conf/src/test/java/net/shibboleth/idp/test/flows/cas/LoginFlowTest.java b/idp-conf/src/test/java/net/shibboleth/idp/test/flows/cas/LoginFlowTest.java
index e6d0971..866d7ce 100644
--- a/idp-conf/src/test/java/net/shibboleth/idp/test/flows/cas/LoginFlowTest.java
+++ b/idp-conf/src/test/java/net/shibboleth/idp/test/flows/cas/LoginFlowTest.java
@@ -260,7 +260,7 @@ public class LoginFlowTest extends AbstractFlowTest {
             throw new IllegalStateException("Relying party configuration not found");
         }
         final LoginConfiguration loginConfiguration =
-                (LoginConfiguration) rpConfig.getProfileConfiguration(LoginConfiguration.PROFILE_ID);
+                (LoginConfiguration) rpConfig.getProfileConfiguration(prc, LoginConfiguration.PROFILE_ID);
         if (loginConfiguration == null) {
             throw new IllegalStateException("CAS login profile configuration not found");
         }
diff --git a/idp-conf/src/test/resources/test/test-cas-beans.xml b/idp-conf/src/test/resources/test/test-cas-beans.xml
index 5f0e401..bcc1c08 100644
--- a/idp-conf/src/test/resources/test/test-cas-beans.xml
+++ b/idp-conf/src/test/resources/test/test-cas-beans.xml
@@ -28,6 +28,7 @@
     <util:list id="shibboleth.RelyingPartyResolverResources">
         <value>classpath:/test/test-relying-party-cas.xml</value>
         <value>classpath:/system/conf/relying-party-system.xml</value>
+        <value>classpath:/system/conf/relying-party-mddriven.xml</value>
         <value>classpath:/conf/credentials.xml</value>
     </util:list>
 
diff --git a/idp-conf/src/test/resources/test/test-relying-party-cas.xml b/idp-conf/src/test/resources/test/test-relying-party-cas.xml
index 512a2dc..a0dcfc4 100644
--- a/idp-conf/src/test/resources/test/test-relying-party-cas.xml
+++ b/idp-conf/src/test/resources/test/test-relying-party-cas.xml
@@ -15,32 +15,32 @@
         </property>
     </bean>
 
-    <bean id="shibboleth.DefaultRelyingParty" parent="RelyingParty">
+    <bean id="shibboleth.DefaultRelyingParty" parent="RelyingParty.MDDriven">
         <property name="profileConfigurations">
             <list>
-                <ref bean="CAS.LoginConfiguration" />
-                <ref bean="CAS.ProxyConfiguration" />
-                <ref bean="CAS.ValidateConfiguration" />
+                <ref bean="CAS.LoginConfiguration.MDDriven" />
+                <ref bean="CAS.ProxyConfiguration.MDDriven" />
+                <ref bean="CAS.ValidateConfiguration.MDDriven" />
             </list>
         </property>
     </bean>
 
     <util:list id="shibboleth.RelyingPartyOverrides">
-        <bean parent="RelyingPartyByName" c:relyingPartyIds="https://alt-username.example.org/">
+        <bean parent="RelyingPartyByName.MDDriven" c:relyingPartyIds="https://alt-username.example.org/">
             <property name="profileConfigurations">
                 <list>
-                    <ref bean="CAS.LoginConfiguration" />
-                    <ref bean="CAS.ProxyConfiguration" />
-                    <bean parent="CAS.ValidateConfiguration" p:userAttribute="mail" />
+                    <ref bean="CAS.LoginConfiguration.MDDriven" />
+                    <ref bean="CAS.ProxyConfiguration.MDDriven" />
+                    <bean parent="CAS.ValidateConfiguration.MDDriven" p:userAttribute="mail" />
                 </list>
             </property>
         </bean>
-        <bean parent="RelyingPartyByName" c:relyingPartyIds="https://no-attrs.example.org/">
+        <bean parent="RelyingPartyByName.MDDriven" c:relyingPartyIds="https://no-attrs.example.org/">
             <property name="profileConfigurations">
                 <list>
-                    <ref bean="CAS.LoginConfiguration" />
-                    <ref bean="CAS.ProxyConfiguration" />
-                    <bean parent="CAS.ValidateConfiguration" p:resolveAttributes="false" />
+                    <ref bean="CAS.LoginConfiguration.MDDriven" />
+                    <ref bean="CAS.ProxyConfiguration.MDDriven" />
+                    <bean parent="CAS.ValidateConfiguration.MDDriven" p:resolveAttributes="false" />
                 </list>
             </property>
         </bean>
diff --git a/idp-profile-api/src/main/java/net/shibboleth/idp/profile/config/AbstractProfileConfiguration.java b/idp-profile-api/src/main/java/net/shibboleth/idp/profile/config/AbstractProfileConfiguration.java
index fb8cff2..910e583 100644
--- a/idp-profile-api/src/main/java/net/shibboleth/idp/profile/config/AbstractProfileConfiguration.java
+++ b/idp-profile-api/src/main/java/net/shibboleth/idp/profile/config/AbstractProfileConfiguration.java
@@ -19,7 +19,6 @@ package net.shibboleth.idp.profile.config;
 
 import java.util.ArrayList;
 import java.util.Collection;
-import java.util.Collections;
 import java.util.List;
 import java.util.Objects;
 import java.util.function.Function;
@@ -28,14 +27,15 @@ import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 import javax.servlet.ServletRequest;
 
-import com.google.common.collect.ImmutableList;
-
 import net.shibboleth.utilities.java.support.annotation.ParameterName;
 import net.shibboleth.utilities.java.support.annotation.constraint.NonnullElements;
 import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
 import net.shibboleth.utilities.java.support.annotation.constraint.NotLive;
 import net.shibboleth.utilities.java.support.annotation.constraint.Unmodifiable;
+import net.shibboleth.utilities.java.support.collection.CollectionSupport;
 import net.shibboleth.utilities.java.support.component.AbstractIdentifiableInitializableComponent;
+import net.shibboleth.utilities.java.support.logic.Constraint;
+import net.shibboleth.utilities.java.support.logic.FunctionSupport;
 import net.shibboleth.utilities.java.support.primitive.StringSupport;
 import org.opensaml.profile.context.ProfileRequestContext;
 import org.slf4j.Logger;
@@ -44,6 +44,9 @@ import org.slf4j.LoggerFactory;
 /** Base class for {@link ProfileConfiguration} implementations. */
 public abstract class AbstractProfileConfiguration extends AbstractIdentifiableInitializableComponent
         implements ProfileConfiguration {
+    
+    /** Default value for disallowedFeatures property. */
+    @Nonnull public static final Integer DEFAULT_DISALLOWED_FEATURES = 0; 
 
     /** Class logger. */
     @Nonnull private final Logger log = LoggerFactory.getLogger(AbstractProfileConfiguration.class);
@@ -52,28 +55,16 @@ public abstract class AbstractProfileConfiguration extends AbstractIdentifiableI
     @Nullable private ServletRequest servletRequest;
 
     /** Lookup function to supply {@link #inboundFlows} property. */
-    @Nullable private Function<ProfileRequestContext,List<String>> inboundFlowsLookupStrategy;
-
-    /** Enables inbound interceptor flows. */
-    @Nonnull @NonnullElements private List<String> inboundFlows;
+    @Nonnull private Function<ProfileRequestContext,List<String>> inboundFlowsLookupStrategy;
 
     /** Lookup function to supply {@link #outboundFlows} property. */
-    @Nullable private Function<ProfileRequestContext,List<String>> outboundFlowsLookupStrategy;
-
-    /** Enables outbound interceptor flows. */
-    @Nonnull @NonnullElements private List<String> outboundFlows;
+    @Nonnull private Function<ProfileRequestContext,List<String>> outboundFlowsLookupStrategy;
 
     /** Lookup function to supply {@link #securityConfiguration} property. */
-    @Nullable private Function<ProfileRequestContext,SecurityConfiguration> securityConfigurationLookupStrategy;
+    @Nonnull private Function<ProfileRequestContext,SecurityConfiguration> securityConfigurationLookupStrategy;
 
-    /** The security configuration for this profile. */
-    @Nullable private SecurityConfiguration securityConfiguration;
-    
     /** Lookup function to return a bitmask of request features to disallow. */
-    @Nullable private Function<ProfileRequestContext,Integer> disallowedFeaturesLookupStrategy;
-    
-    /** Bitmask of request features to disallow. */
-    private int disallowedFeatures;
+    @Nonnull private Function<ProfileRequestContext,Integer> disallowedFeaturesLookupStrategy;
 
     /**
      * Constructor.
@@ -82,8 +73,10 @@ public abstract class AbstractProfileConfiguration extends AbstractIdentifiableI
      */
     public AbstractProfileConfiguration(@Nonnull @NotEmpty @ParameterName(name="id") final String id) {
         setId(id);
-        inboundFlows = Collections.emptyList();
-        outboundFlows = Collections.emptyList();
+        securityConfigurationLookupStrategy = FunctionSupport.constant(null);
+        inboundFlowsLookupStrategy = FunctionSupport.constant(null);
+        outboundFlowsLookupStrategy = FunctionSupport.constant(null);
+        disallowedFeaturesLookupStrategy = FunctionSupport.constant(DEFAULT_DISALLOWED_FEATURES);
     }
 
     /**
@@ -100,9 +93,9 @@ public abstract class AbstractProfileConfiguration extends AbstractIdentifiableI
     }
 
     /** {@inheritDoc} */
-    @Override
-    @Nullable public SecurityConfiguration getSecurityConfiguration() {
-        return getIndirectProperty(securityConfigurationLookupStrategy, securityConfiguration);
+    @Nullable public SecurityConfiguration getSecurityConfiguration(
+            @Nullable final ProfileRequestContext profileRequestContext) {
+        return securityConfigurationLookupStrategy.apply(profileRequestContext);
     }
 
     /**
@@ -111,7 +104,7 @@ public abstract class AbstractProfileConfiguration extends AbstractIdentifiableI
      * @param configuration security configuration for this profile
      */
     public void setSecurityConfiguration(@Nullable final SecurityConfiguration configuration) {
-        securityConfiguration = configuration;
+        securityConfigurationLookupStrategy = FunctionSupport.constant(configuration);
     }
 
     /**
@@ -122,14 +115,14 @@ public abstract class AbstractProfileConfiguration extends AbstractIdentifiableI
      * @since 3.3.0
      */
     public void setSecurityConfigurationLookupStrategy(
-            @Nullable final Function<ProfileRequestContext,SecurityConfiguration> strategy) {
-        securityConfigurationLookupStrategy = strategy;
+            @Nonnull final Function<ProfileRequestContext,SecurityConfiguration> strategy) {
+        securityConfigurationLookupStrategy = Constraint.isNotNull(strategy, "Lookup strategy cannot be null");
     }
 
     /** {@inheritDoc} */
-    @Override
-    @Nonnull @NonnullElements @NotLive @Unmodifiable public List<String> getInboundInterceptorFlows() {
-        return ImmutableList.copyOf(getIndirectProperty(inboundFlowsLookupStrategy, inboundFlows));
+    @Nonnull @NonnullElements @NotLive @Unmodifiable public List<String> getInboundInterceptorFlows(
+        @Nullable final ProfileRequestContext profileRequestContext) {
+        return CollectionSupport.buildImmutableList(inboundFlowsLookupStrategy.apply(profileRequestContext));
     }
 
     /**
@@ -139,9 +132,10 @@ public abstract class AbstractProfileConfiguration extends AbstractIdentifiableI
      */
     public void setInboundInterceptorFlows(@Nullable @NonnullElements final Collection<String> flows) {
         if (flows != null) {
-            inboundFlows = new ArrayList<>(StringSupport.normalizeStringCollection(flows));
+            inboundFlowsLookupStrategy =
+                    FunctionSupport.constant(new ArrayList<>(StringSupport.normalizeStringCollection(flows)));
         } else {
-            inboundFlows = Collections.emptyList();
+            inboundFlowsLookupStrategy = FunctionSupport.constant(null);
         }
     }
 
@@ -152,14 +146,15 @@ public abstract class AbstractProfileConfiguration extends AbstractIdentifiableI
      * 
      * @since 3.3.0
      */
-    public void setInboundFlowsLookupStrategy(@Nullable final Function<ProfileRequestContext,List<String>> strategy) {
-        inboundFlowsLookupStrategy = strategy;
+    public void setInboundFlowsLookupStrategy(@Nonnull final Function<ProfileRequestContext,List<String>> strategy) {
+        inboundFlowsLookupStrategy = Constraint.isNotNull(strategy, "Lookup strategy cannot be null");
     }
 
+
     /** {@inheritDoc} */
-    @Override
-    @Nonnull @NonnullElements @NotLive @Unmodifiable public List<String> getOutboundInterceptorFlows() {
-        return ImmutableList.copyOf(getIndirectProperty(outboundFlowsLookupStrategy, outboundFlows));
+    @Nonnull @NonnullElements @NotLive @Unmodifiable public List<String> getOutboundInterceptorFlows(
+            @Nullable final ProfileRequestContext profileRequestContext) {
+        return CollectionSupport.buildImmutableList(outboundFlowsLookupStrategy.apply(profileRequestContext));
     }
 
     /**
@@ -169,9 +164,10 @@ public abstract class AbstractProfileConfiguration extends AbstractIdentifiableI
      */
     public void setOutboundInterceptorFlows(@Nullable @NonnullElements final Collection<String> flows) {
         if (flows != null) {
-            outboundFlows = new ArrayList<>(StringSupport.normalizeStringCollection(flows));
+            outboundFlowsLookupStrategy =
+                    FunctionSupport.constant(new ArrayList<>(StringSupport.normalizeStringCollection(flows)));
         } else {
-            outboundFlows = Collections.emptyList();
+            outboundFlowsLookupStrategy = FunctionSupport.constant(null);
         }
     }
 
@@ -182,21 +178,22 @@ public abstract class AbstractProfileConfiguration extends AbstractIdentifiableI
      * 
      * @since 3.3.0
      */
-    public void setOutboundFlowsLookupStrategy(@Nullable final Function<ProfileRequestContext,List<String>> strategy) {
-        outboundFlowsLookupStrategy = strategy;
+    public void setOutboundFlowsLookupStrategy(@Nonnull final Function<ProfileRequestContext,List<String>> strategy) {
+        outboundFlowsLookupStrategy = Constraint.isNotNull(strategy, "Lookup strategy cannot be null");
     }
 
     /**
      * Return true iff the input feature constant is disallowed.
      * 
+     * @param profileRequestContext current profile request context
      * @param feature a bit constant
      * 
      * @return true iff the input feature constant is disallowed
      * 
      * @since 3.3.0
      */
-    public boolean isFeatureDisallowed(final int feature) {
-        return (getDisallowedFeatures() & feature) == feature;
+    public boolean isFeatureDisallowed(@Nullable final ProfileRequestContext profileRequestContext, final int feature) {
+        return (getDisallowedFeatures(profileRequestContext) & feature) == feature;
     }
     
     /**
@@ -204,12 +201,15 @@ public abstract class AbstractProfileConfiguration extends AbstractIdentifiableI
      * 
      * <p>Individual profiles define their own feature constants.</p>
      * 
+     * @param profileRequestContext current profile request context
+     * 
      * @return bitmask of features to block
      * 
      * @since 3.3.0
      */
-    public int getDisallowedFeatures() {
-        return getIndirectProperty(disallowedFeaturesLookupStrategy, disallowedFeatures);
+    public int getDisallowedFeatures(@Nullable final ProfileRequestContext profileRequestContext) {
+        final Integer mask = disallowedFeaturesLookupStrategy.apply(profileRequestContext); 
+        return mask != null ? mask : DEFAULT_DISALLOWED_FEATURES;
     }
     
     /**
@@ -220,7 +220,7 @@ public abstract class AbstractProfileConfiguration extends AbstractIdentifiableI
      * @since 3.3.0
      */
     public void setDisallowedFeatures(final int mask) {
-        disallowedFeatures = mask;
+        disallowedFeaturesLookupStrategy = FunctionSupport.constant(mask);
     }
     
     /**
@@ -230,8 +230,8 @@ public abstract class AbstractProfileConfiguration extends AbstractIdentifiableI
      * 
      * @since 3.3.0
      */
-    public void setDisallowedFeaturesLookupStrategy(@Nullable final Function<ProfileRequestContext,Integer> strategy) {
-        disallowedFeaturesLookupStrategy = strategy;
+    public void setDisallowedFeaturesLookupStrategy(@Nonnull final Function<ProfileRequestContext,Integer> strategy) {
+        disallowedFeaturesLookupStrategy = Constraint.isNotNull(strategy, "Lookup strategy cannot be null");
     }
     
     /** {@inheritDoc} */
@@ -266,6 +266,7 @@ public abstract class AbstractProfileConfiguration extends AbstractIdentifiableI
      * 
      * @since 3.3.0
      */
+    @Deprecated
     @Nullable protected ProfileRequestContext getProfileRequestContext() {
         if (servletRequest != null) {
             final Object object = servletRequest.getAttribute(ProfileRequestContext.BINDING_KEY);
@@ -291,6 +292,7 @@ public abstract class AbstractProfileConfiguration extends AbstractIdentifiableI
      * 
      * @since 3.3.0
      */
+    @Deprecated
     @Nullable protected <T> T getIndirectProperty(@Nullable final Function<ProfileRequestContext,T> lookupStrategy,
             @Nullable final T staticValue) {
 
diff --git a/idp-profile-api/src/main/java/net/shibboleth/idp/profile/config/ProfileConfiguration.java b/idp-profile-api/src/main/java/net/shibboleth/idp/profile/config/ProfileConfiguration.java
index 3ac6daa..77288c0 100644
--- a/idp-profile-api/src/main/java/net/shibboleth/idp/profile/config/ProfileConfiguration.java
+++ b/idp-profile-api/src/main/java/net/shibboleth/idp/profile/config/ProfileConfiguration.java
@@ -22,6 +22,8 @@ import java.util.List;
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 
+import org.opensaml.profile.context.ProfileRequestContext;
+
 import net.shibboleth.utilities.java.support.annotation.constraint.NonnullElements;
 import net.shibboleth.utilities.java.support.annotation.constraint.NotLive;
 import net.shibboleth.utilities.java.support.annotation.constraint.Unmodifiable;
@@ -38,9 +40,12 @@ public interface ProfileConfiguration extends IdentifiedComponent {
      * {@link net.shibboleth.idp.profile.interceptor.ProfileInterceptorFlowDescriptor#FLOW_ID_PREFIX}
      * prefix common to all interceptor flows.</p>
      * 
+     * @param profileRequestContext current profile request context
+     * 
      * @return  a set of interceptor flow IDs to enable
      */
-    @Nonnull @NonnullElements @NotLive @Unmodifiable List<String> getInboundInterceptorFlows();
+    @Nonnull @NonnullElements @NotLive @Unmodifiable List<String> getInboundInterceptorFlows(
+            @Nullable final ProfileRequestContext profileRequestContext);
 
     /**
      * Get an ordered list of interceptor flows to run for this profile before a final outbound
@@ -50,15 +55,21 @@ public interface ProfileConfiguration extends IdentifiedComponent {
      * {@link net.shibboleth.idp.profile.interceptor.ProfileInterceptorFlowDescriptor#FLOW_ID_PREFIX}
      * prefix common to all interceptor flows.</p>
      * 
+     * @param profileRequestContext current profile request context
+     * 
      * @return  a set of interceptor flow IDs to enable
      */
-    @Nonnull @NonnullElements @NotLive @Unmodifiable List<String> getOutboundInterceptorFlows();
+    @Nonnull @NonnullElements @NotLive @Unmodifiable List<String> getOutboundInterceptorFlows(
+            @Nullable final ProfileRequestContext profileRequestContext);
     
     /**
      * Get the {@link SecurityConfiguration} to use with this profile.
      * 
+     * @param profileRequestContext current profile request context
+     * 
      * @return security configuration to use with this profile
      */
-    @Nullable SecurityConfiguration getSecurityConfiguration();
+    @Nullable SecurityConfiguration getSecurityConfiguration(
+            @Nullable final ProfileRequestContext profileRequestContext);
     
 }
\ No newline at end of file
diff --git a/idp-profile-api/src/main/java/net/shibboleth/idp/profile/config/logic/DetailedErrorsPredicate.java b/idp-profile-api/src/main/java/net/shibboleth/idp/profile/config/logic/DetailedErrorsPredicate.java
index 80d5924..ba32600 100644
--- a/idp-profile-api/src/main/java/net/shibboleth/idp/profile/config/logic/DetailedErrorsPredicate.java
+++ b/idp-profile-api/src/main/java/net/shibboleth/idp/profile/config/logic/DetailedErrorsPredicate.java
@@ -34,7 +34,7 @@ public class DetailedErrorsPredicate extends AbstractRelyingPartyPredicate {
         if (input != null) {
             final RelyingPartyContext rpc = getRelyingPartyContextLookupStrategy().apply(input);
             if (rpc != null && rpc.getConfiguration() != null) {
-                return rpc.getConfiguration().getDetailedErrorsPredicate().test(input);
+                return rpc.getConfiguration().isDetailedErrors(input);
             }
         }
         
diff --git a/idp-profile-api/src/main/java/net/shibboleth/idp/profile/config/navigate/ClientTLSValidationConfigurationLookupFunction.java b/idp-profile-api/src/main/java/net/shibboleth/idp/profile/config/navigate/ClientTLSValidationConfigurationLookupFunction.java
index 86fa28a..d8a2988 100644
--- a/idp-profile-api/src/main/java/net/shibboleth/idp/profile/config/navigate/ClientTLSValidationConfigurationLookupFunction.java
+++ b/idp-profile-api/src/main/java/net/shibboleth/idp/profile/config/navigate/ClientTLSValidationConfigurationLookupFunction.java
@@ -61,8 +61,11 @@ public class ClientTLSValidationConfigurationLookupFunction
         final RelyingPartyContext rpc = getRelyingPartyContextLookupStrategy().apply(input);
         if (rpc != null) {
             final ProfileConfiguration pc = rpc.getProfileConfig();
-            if (pc != null && pc.getSecurityConfiguration() != null) {
-                configs.add(pc.getSecurityConfiguration().getClientTLSValidationConfiguration());
+            if (pc != null) {
+                final SecurityConfiguration sc = pc.getSecurityConfiguration(input);
+                if (sc != null) {
+                    configs.add(sc.getClientTLSValidationConfiguration());
+                }
             }
         }
         
diff --git a/idp-profile-api/src/main/java/net/shibboleth/idp/profile/config/navigate/DecryptionConfigurationLookupFunction.java b/idp-profile-api/src/main/java/net/shibboleth/idp/profile/config/navigate/DecryptionConfigurationLookupFunction.java
index 26af082..bd11bc1 100644
--- a/idp-profile-api/src/main/java/net/shibboleth/idp/profile/config/navigate/DecryptionConfigurationLookupFunction.java
+++ b/idp-profile-api/src/main/java/net/shibboleth/idp/profile/config/navigate/DecryptionConfigurationLookupFunction.java
@@ -61,8 +61,11 @@ public class DecryptionConfigurationLookupFunction
         final RelyingPartyContext rpc = getRelyingPartyContextLookupStrategy().apply(input);
         if (rpc != null) {
             final ProfileConfiguration pc = rpc.getProfileConfig();
-            if (pc != null && pc.getSecurityConfiguration() != null) {
-                configs.add(pc.getSecurityConfiguration().getDecryptionConfiguration());
+            if (pc != null) {
+                final SecurityConfiguration sc = pc.getSecurityConfiguration(input);
+                if (sc != null) {
+                    configs.add(sc.getDecryptionConfiguration());
+                }
             }
         }
         
diff --git a/idp-profile-api/src/main/java/net/shibboleth/idp/profile/config/navigate/EncryptionConfigurationLookupFunction.java b/idp-profile-api/src/main/java/net/shibboleth/idp/profile/config/navigate/EncryptionConfigurationLookupFunction.java
index d72a2b2..ca6af0f 100644
--- a/idp-profile-api/src/main/java/net/shibboleth/idp/profile/config/navigate/EncryptionConfigurationLookupFunction.java
+++ b/idp-profile-api/src/main/java/net/shibboleth/idp/profile/config/navigate/EncryptionConfigurationLookupFunction.java
@@ -61,8 +61,11 @@ public class EncryptionConfigurationLookupFunction
         final RelyingPartyContext rpc = getRelyingPartyContextLookupStrategy().apply(input);
         if (rpc != null) {
             final ProfileConfiguration pc = rpc.getProfileConfig();
-            if (pc != null && pc.getSecurityConfiguration() != null) {
-                configs.add(pc.getSecurityConfiguration().getEncryptionConfiguration());
+            if (pc != null) {
+                final SecurityConfiguration sc = pc.getSecurityConfiguration(input);
+                if (sc != null) {
+                    configs.add(sc.getEncryptionConfiguration());
+                }
             }
         }
         
diff --git a/idp-profile-api/src/main/java/net/shibboleth/idp/profile/config/navigate/IdentifierGenerationStrategyLookupFunction.java b/idp-profile-api/src/main/java/net/shibboleth/idp/profile/config/navigate/IdentifierGenerationStrategyLookupFunction.java
index 8f78432..d40248a 100644
--- a/idp-profile-api/src/main/java/net/shibboleth/idp/profile/config/navigate/IdentifierGenerationStrategyLookupFunction.java
+++ b/idp-profile-api/src/main/java/net/shibboleth/idp/profile/config/navigate/IdentifierGenerationStrategyLookupFunction.java
@@ -20,6 +20,7 @@ package net.shibboleth.idp.profile.config.navigate;
 import javax.annotation.Nullable;
 
 import net.shibboleth.idp.profile.config.ProfileConfiguration;
+import net.shibboleth.idp.profile.config.SecurityConfiguration;
 import net.shibboleth.idp.profile.context.RelyingPartyContext;
 import net.shibboleth.idp.profile.context.navigate.AbstractRelyingPartyLookupFunction;
 import net.shibboleth.utilities.java.support.security.IdentifierGenerationStrategy;
@@ -54,8 +55,11 @@ public class IdentifierGenerationStrategyLookupFunction
             final RelyingPartyContext rpc = getRelyingPartyContextLookupStrategy().apply(input);
             if (rpc != null) {
                 final ProfileConfiguration pc = rpc.getProfileConfig();
-                if (pc != null && pc.getSecurityConfiguration() != null) {
-                    return pc.getSecurityConfiguration().getIdGenerator();
+                if (pc != null) {
+                    final SecurityConfiguration sc = pc.getSecurityConfiguration(input);
+                    if (sc != null) {
+                        return sc.getIdGenerator();
+                    }
                 }
             }
         }
diff --git a/idp-profile-api/src/main/java/net/shibboleth/idp/profile/config/navigate/InboundFlowsLookupFunction.java b/idp-profile-api/src/main/java/net/shibboleth/idp/profile/config/navigate/InboundFlowsLookupFunction.java
index d761afe..b3e49d5 100644
--- a/idp-profile-api/src/main/java/net/shibboleth/idp/profile/config/navigate/InboundFlowsLookupFunction.java
+++ b/idp-profile-api/src/main/java/net/shibboleth/idp/profile/config/navigate/InboundFlowsLookupFunction.java
@@ -31,8 +31,6 @@ import net.shibboleth.utilities.java.support.annotation.constraint.Unmodifiable;
 
 import org.opensaml.profile.context.ProfileRequestContext;
 
-import com.google.common.collect.ImmutableList;
-
 /**
  * A function that returns {@link ProfileConfiguration#getInboundInterceptorFlows()} if such a profile is
  * available from a {@link RelyingPartyContext} obtained via a lookup function, by default a child of the
@@ -50,7 +48,7 @@ public class InboundFlowsLookupFunction extends AbstractRelyingPartyLookupFuncti
         if (rpc != null) {
             final ProfileConfiguration pc = rpc.getProfileConfig();
             if (pc != null) {
-                return ImmutableList.<String>copyOf(pc.getInboundInterceptorFlows());
+                return pc.getInboundInterceptorFlows(input);
             }
         }
         
diff --git a/idp-profile-api/src/main/java/net/shibboleth/idp/profile/config/navigate/OutboundFlowsLookupFunction.java b/idp-profile-api/src/main/java/net/shibboleth/idp/profile/config/navigate/OutboundFlowsLookupFunction.java
index f60642e..0cb4e2d 100644
--- a/idp-profile-api/src/main/java/net/shibboleth/idp/profile/config/navigate/OutboundFlowsLookupFunction.java
+++ b/idp-profile-api/src/main/java/net/shibboleth/idp/profile/config/navigate/OutboundFlowsLookupFunction.java
@@ -31,8 +31,6 @@ import net.shibboleth.utilities.java.support.annotation.constraint.Unmodifiable;
 
 import org.opensaml.profile.context.ProfileRequestContext;
 
-import com.google.common.collect.ImmutableList;
-
 /**
  * A function that returns {@link ProfileConfiguration#getOutboundInterceptorFlows()} if such a profile is
  * available from a {@link RelyingPartyContext} obtained via a lookup function, by default a child of the
@@ -50,7 +48,7 @@ public class OutboundFlowsLookupFunction extends AbstractRelyingPartyLookupFunct
         if (rpc != null) {
             final ProfileConfiguration pc = rpc.getProfileConfig();
             if (pc != null) {
-                return ImmutableList.<String>copyOf(pc.getOutboundInterceptorFlows());
+                return pc.getOutboundInterceptorFlows(input);
             }
         }
         
diff --git a/idp-profile-api/src/main/java/net/shibboleth/idp/profile/config/navigate/SignatureSigningConfigurationLookupFunction.java b/idp-profile-api/src/main/java/net/shibboleth/idp/profile/config/navigate/SignatureSigningConfigurationLookupFunction.java
index 037aeed..78dce19 100644
--- a/idp-profile-api/src/main/java/net/shibboleth/idp/profile/config/navigate/SignatureSigningConfigurationLookupFunction.java
+++ b/idp-profile-api/src/main/java/net/shibboleth/idp/profile/config/navigate/SignatureSigningConfigurationLookupFunction.java
@@ -61,8 +61,11 @@ public class SignatureSigningConfigurationLookupFunction
         final RelyingPartyContext rpc = getRelyingPartyContextLookupStrategy().apply(input);
         if (rpc != null) {
             final ProfileConfiguration pc = rpc.getProfileConfig();
-            if (pc != null && pc.getSecurityConfiguration() != null) {
-                configs.add(pc.getSecurityConfiguration().getSignatureSigningConfiguration());
+            if (pc != null) {
+                final SecurityConfiguration sc = pc.getSecurityConfiguration(input);
+                if (sc != null) {
+                    configs.add(sc.getSignatureSigningConfiguration());
+                }
             }
         }
         
diff --git a/idp-profile-api/src/main/java/net/shibboleth/idp/profile/config/navigate/SignatureValidationConfigurationLookupFunction.java b/idp-profile-api/src/main/java/net/shibboleth/idp/profile/config/navigate/SignatureValidationConfigurationLookupFunction.java
index c0d46e3..a54bb19 100644
--- a/idp-profile-api/src/main/java/net/shibboleth/idp/profile/config/navigate/SignatureValidationConfigurationLookupFunction.java
+++ b/idp-profile-api/src/main/java/net/shibboleth/idp/profile/config/navigate/SignatureValidationConfigurationLookupFunction.java
@@ -61,8 +61,11 @@ public class SignatureValidationConfigurationLookupFunction
         final RelyingPartyContext rpc = getRelyingPartyContextLookupStrategy().apply(input);
         if (rpc != null) {
             final ProfileConfiguration pc = rpc.getProfileConfig();
-            if (pc != null && pc.getSecurityConfiguration() != null) {
-                configs.add(pc.getSecurityConfiguration().getSignatureValidationConfiguration());
+            if (pc != null) {
+                final SecurityConfiguration sc = pc.getSecurityConfiguration(input);
+                if (sc != null) {
+                    configs.add(sc.getSignatureValidationConfiguration());
+                }
             }
         }
         
diff --git a/idp-profile-api/src/main/java/net/shibboleth/idp/profile/config/navigate/messaging/HttpClientSecurityConfigurationLookupFunction.java b/idp-profile-api/src/main/java/net/shibboleth/idp/profile/config/navigate/messaging/HttpClientSecurityConfigurationLookupFunction.java
index 62e3904..10ed156 100644
--- a/idp-profile-api/src/main/java/net/shibboleth/idp/profile/config/navigate/messaging/HttpClientSecurityConfigurationLookupFunction.java
+++ b/idp-profile-api/src/main/java/net/shibboleth/idp/profile/config/navigate/messaging/HttpClientSecurityConfigurationLookupFunction.java
@@ -62,8 +62,12 @@ public class HttpClientSecurityConfigurationLookupFunction
         final RelyingPartyContext rpc = getRelyingPartyContextLookupStrategy().apply(input);
         if (rpc != null) {
             final ProfileConfiguration pc = rpc.getProfileConfig();
-            if (pc != null && pc.getSecurityConfiguration() != null) {
-                configs.add(pc.getSecurityConfiguration().getHttpClientSecurityConfiguration());
+            if (pc != null) {
+                final SecurityConfiguration sc =
+                        pc.getSecurityConfiguration(this.getProfileRequestContextLookupStrategy().apply(input));
+                if (sc != null) {
+                    configs.add(sc.getHttpClientSecurityConfiguration());
+                }
             }
             
             // Check for a per-profile default (relying party independent) config.
diff --git a/idp-profile-api/src/main/java/net/shibboleth/idp/profile/config/navigate/messaging/SignatureSigningConfigurationLookupFunction.java b/idp-profile-api/src/main/java/net/shibboleth/idp/profile/config/navigate/messaging/SignatureSigningConfigurationLookupFunction.java
index ac90740..4472744 100644
--- a/idp-profile-api/src/main/java/net/shibboleth/idp/profile/config/navigate/messaging/SignatureSigningConfigurationLookupFunction.java
+++ b/idp-profile-api/src/main/java/net/shibboleth/idp/profile/config/navigate/messaging/SignatureSigningConfigurationLookupFunction.java
@@ -62,8 +62,12 @@ public class SignatureSigningConfigurationLookupFunction
         final RelyingPartyContext rpc = getRelyingPartyContextLookupStrategy().apply(input);
         if (rpc != null) {
             final ProfileConfiguration pc = rpc.getProfileConfig();
-            if (pc != null && pc.getSecurityConfiguration() != null) {
-                configs.add(pc.getSecurityConfiguration().getSignatureSigningConfiguration());
+            if (pc != null) {
+                final SecurityConfiguration sc =
+                        pc.getSecurityConfiguration(this.getProfileRequestContextLookupStrategy().apply(input));
+                if (sc != null) {
+                    configs.add(sc.getSignatureSigningConfiguration());
+                }
             }
             
             // Check for a per-profile default (relying party independent) config.
diff --git a/idp-profile-api/src/main/java/net/shibboleth/idp/profile/config/navigate/messaging/SignatureValidationConfigurationLookupFunction.java b/idp-profile-api/src/main/java/net/shibboleth/idp/profile/config/navigate/messaging/SignatureValidationConfigurationLookupFunction.java
index cda6e99..c5c1fa8 100644
--- a/idp-profile-api/src/main/java/net/shibboleth/idp/profile/config/navigate/messaging/SignatureValidationConfigurationLookupFunction.java
+++ b/idp-profile-api/src/main/java/net/shibboleth/idp/profile/config/navigate/messaging/SignatureValidationConfigurationLookupFunction.java
@@ -62,8 +62,12 @@ public class SignatureValidationConfigurationLookupFunction
         final RelyingPartyContext rpc = getRelyingPartyContextLookupStrategy().apply(input);
         if (rpc != null) {
             final ProfileConfiguration pc = rpc.getProfileConfig();
-            if (pc != null && pc.getSecurityConfiguration() != null) {
-                configs.add(pc.getSecurityConfiguration().getSignatureValidationConfiguration());
+            if (pc != null) {
+                final SecurityConfiguration sc =
+                        pc.getSecurityConfiguration(this.getProfileRequestContextLookupStrategy().apply(input));
+                if (sc != null) {
+                    configs.add(sc.getSignatureValidationConfiguration());
+                }
             }
             
             // Check for a per-profile default (relying party independent) config.
diff --git a/idp-profile-api/src/main/java/net/shibboleth/idp/profile/context/navigate/ResponderIdLookupFunction.java b/idp-profile-api/src/main/java/net/shibboleth/idp/profile/context/navigate/ResponderIdLookupFunction.java
index 592fa0b..cece4d2 100644
--- a/idp-profile-api/src/main/java/net/shibboleth/idp/profile/context/navigate/ResponderIdLookupFunction.java
+++ b/idp-profile-api/src/main/java/net/shibboleth/idp/profile/context/navigate/ResponderIdLookupFunction.java
@@ -39,7 +39,7 @@ public class ResponderIdLookupFunction extends AbstractRelyingPartyLookupFunctio
         if (input != null) {
             final RelyingPartyContext rpc = getRelyingPartyContextLookupStrategy().apply(input);
             if (rpc != null && rpc.getConfiguration() != null) {
-                return rpc.getConfiguration().getResponderId();
+                return rpc.getConfiguration().getResponderId(input);
             }
         }
 
diff --git a/idp-profile-api/src/main/java/net/shibboleth/idp/profile/context/navigate/messaging/AbstractRelyingPartyLookupFunction.java b/idp-profile-api/src/main/java/net/shibboleth/idp/profile/context/navigate/messaging/AbstractRelyingPartyLookupFunction.java
index 450c7f8..0c0d5dc 100644
--- a/idp-profile-api/src/main/java/net/shibboleth/idp/profile/context/navigate/messaging/AbstractRelyingPartyLookupFunction.java
+++ b/idp-profile-api/src/main/java/net/shibboleth/idp/profile/context/navigate/messaging/AbstractRelyingPartyLookupFunction.java
@@ -26,14 +26,16 @@ import org.opensaml.messaging.context.MessageContext;
 import org.opensaml.messaging.context.navigate.ChildContextLookup;
 import org.opensaml.messaging.context.navigate.ContextDataLookupFunction;
 import org.opensaml.messaging.context.navigate.RecursiveTypedParentContextLookup;
+import org.opensaml.profile.context.ProfileRequestContext;
 
 import net.shibboleth.idp.profile.context.RelyingPartyContext;
 import net.shibboleth.utilities.java.support.logic.Constraint;
 
 /**
- * Abstract base class for a function that requires a {@link RelyingPartyContext}
- * obtained via a lookup function, by default a child of the {@link InOutOperationContext} 
- * the parent of the specified {@link MessageContext}.
+ * Abstract base class for a function that requires a {@link ProfileRequestContext} obtained
+ * via a lookup function, by default the parent of the specified {@link MessageContext}, and
+ * a {@link RelyingPartyContext} obtained via a lookup function, by default a child of the
+ * aforementioned parent.
  * 
  * @param <ResultType> return type of function
  */
@@ -44,15 +46,33 @@ public abstract class AbstractRelyingPartyLookupFunction<ResultType>
      * Strategy used to locate the {@link RelyingPartyContext} associated with a given {@link MessageContext}.
      */
     @Nonnull private Function<MessageContext,RelyingPartyContext> relyingPartyContextLookupStrategy;
+
+    /**
+     * Strategy used to locate the {@link ProfileRequestContext} associated with a given {@link MessageContext}.
+     */
+    @Nonnull private Function<MessageContext,ProfileRequestContext> profileRequestContextLookupStrategy;
     
     /** Constructor. */
     public AbstractRelyingPartyLookupFunction() {
+        profileRequestContextLookupStrategy =
+                new RecursiveTypedParentContextLookup<>(ProfileRequestContext.class);
+        
         relyingPartyContextLookupStrategy =
                 new ChildContextLookup<>(RelyingPartyContext.class).compose(
                         new RecursiveTypedParentContextLookup<>(InOutOperationContext.class));
     }
 
     /**
+     * Get the strategy used to locate the {@link RelyingPartyContext} associated with a given
+     * {@link MessageContext}.
+     * 
+     * @return lookup strategy
+     */
+    @Nonnull public Function<MessageContext,RelyingPartyContext> getRelyingPartyContextLookupStrategy() {
+        return relyingPartyContextLookupStrategy;
+    }
+
+    /**
      * Set the strategy used to locate the {@link RelyingPartyContext} associated with a given
      * {@link MessageContext}.
      * 
@@ -65,13 +85,24 @@ public abstract class AbstractRelyingPartyLookupFunction<ResultType>
     }
     
     /**
-     * Get the strategy used to locate the {@link RelyingPartyContext} associated with a given
+     * Get the strategy used to locate the {@link ProfileRequestContext} associated with a given
      * {@link MessageContext}.
      * 
      * @return lookup strategy
      */
-    @Nonnull public Function<MessageContext,RelyingPartyContext> getRelyingPartyContextLookupStrategy() {
-        return relyingPartyContextLookupStrategy;
+    @Nonnull public Function<MessageContext,ProfileRequestContext> getProfileRequestContextLookupStrategy() {
+        return profileRequestContextLookupStrategy;
     }
 
+    /**
+     * Set the strategy used to locate the {@link ProfileRequestContext} associated with a given
+     * {@link MessageContext}.
+     * 
+     * @param strategy lookup strategy
+     */
+    public void setProfileRequestContextLookupStrategy(
+            @Nonnull final Function<MessageContext,ProfileRequestContext> strategy) {
+        profileRequestContextLookupStrategy =
+                Constraint.isNotNull(strategy, "ProfileRequestContext lookup strategy cannot be null");
+    }
 }
\ No newline at end of file
diff --git a/idp-profile-api/src/main/java/net/shibboleth/idp/relyingparty/RelyingPartyConfiguration.java b/idp-profile-api/src/main/java/net/shibboleth/idp/relyingparty/RelyingPartyConfiguration.java
index da73005..4cee8d4 100644
--- a/idp-profile-api/src/main/java/net/shibboleth/idp/relyingparty/RelyingPartyConfiguration.java
+++ b/idp-profile-api/src/main/java/net/shibboleth/idp/relyingparty/RelyingPartyConfiguration.java
@@ -26,7 +26,6 @@ import java.util.function.Predicate;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
-import javax.servlet.ServletRequest;
 
 import net.shibboleth.idp.profile.config.ProfileConfiguration;
 import net.shibboleth.utilities.java.support.annotation.constraint.NonnullElements;
@@ -38,6 +37,7 @@ import net.shibboleth.utilities.java.support.component.ComponentInitializationEx
 import net.shibboleth.utilities.java.support.component.ComponentSupport;
 import net.shibboleth.utilities.java.support.component.IdentifiedComponent;
 import net.shibboleth.utilities.java.support.logic.Constraint;
+import net.shibboleth.utilities.java.support.logic.FunctionSupport;
 import net.shibboleth.utilities.java.support.primitive.StringSupport;
 
 import org.opensaml.profile.context.ProfileRequestContext;
@@ -54,25 +54,16 @@ public class RelyingPartyConfiguration extends AbstractIdentifiableInitializable
     
     /** Class logger. */
     @Nonnull private final Logger log = LoggerFactory.getLogger(RelyingPartyConfiguration.class);
-
-    /** Access to servlet request. */
-    @Nullable private ServletRequest servletRequest;
     
     /** Lookup function to supply {@link #responderId} property. */
-    @Nullable private Function<ProfileRequestContext,String> responderIdLookupStrategy;
-
-    /** Self-referential ID to use when responding to messages. */
-    @Nullable @NotEmpty private String responderId;
+    @Nonnull private Function<ProfileRequestContext,String> responderIdLookupStrategy;
 
     /** Controls whether detailed information about errors should be exposed. */
     @Nonnull private Predicate<ProfileRequestContext> detailedErrorsPredicate;
 
     /** Lookup function to supply {@link #profileConfigurations} property. */
-    @Nullable
+    @Nonnull
     private Function<ProfileRequestContext,Map<String,ProfileConfiguration>> profileConfigurationsLookupStrategy;
-    
-    /** Registered and usable communication profile configurations for this relying party. */
-    @Nonnull @NonnullElements private Map<String,ProfileConfiguration> profileConfigurations;
 
     /** Predicate that must be true for this configuration to be active for a given request. */
     @Nonnull private Predicate<ProfileRequestContext> activationCondition;
@@ -81,31 +72,18 @@ public class RelyingPartyConfiguration extends AbstractIdentifiableInitializable
     public RelyingPartyConfiguration() {
         activationCondition = Predicates.alwaysTrue();
         detailedErrorsPredicate = Predicates.alwaysFalse();
-        profileConfigurations = Collections.emptyMap();
-    }
-    
-    /**
-     * Set the {@link ServletRequest} from which to obtain a reference to the current {@link ProfileRequestContext}.
-     * 
-     * <p>Generally this would be expected to be a proxy to the actual object.</p>
-     * 
-     * @param request servlet request
-     * 
-     * @since 3.3.0
-     */
-    public void setServletRequest(@Nullable final ServletRequest request) {
-        ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
-        
-        servletRequest = request;
+        profileConfigurationsLookupStrategy = FunctionSupport.constant(Collections.emptyMap());
     }
 
     /**
      * Get the self-referential ID to use when responding to requests.
      * 
+     * @param profileRequestContext current profile request context
+     * 
      * @return ID to use when responding
      */
-    @Nonnull @NotEmpty public String getResponderId() {
-        return Constraint.isNotNull(getIndirectProperty(responderIdLookupStrategy, responderId),
+    @Nonnull @NotEmpty public String getResponderId(@Nullable final ProfileRequestContext profileRequestContext) {
+        return Constraint.isNotNull(responderIdLookupStrategy.apply(profileRequestContext),
                 "ResponderId cannot be null");
     }
 
@@ -114,10 +92,12 @@ public class RelyingPartyConfiguration extends AbstractIdentifiableInitializable
      * 
      * @param responder ID to use when responding to messages
      */
-    public void setResponderId(@Nullable final String responder) {
+    public void setResponderId(@Nonnull @NotEmpty final String responder) {
         ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
-
-        responderId = StringSupport.trimOrNull(responder);
+        
+        final String id =
+                Constraint.isNotNull(StringSupport.trimOrNull(responder), "ResponseId cannot be null or empty");
+        responderIdLookupStrategy = FunctionSupport.constant(id);
     }
 
     /**
@@ -125,88 +105,76 @@ public class RelyingPartyConfiguration extends AbstractIdentifiableInitializable
      * 
      * @param strategy  lookup strategy
      * 
-     * @since 3.3.0
+     * @since 3.4.0
      */
-    public void setResponderIdLookupStrategy(@Nullable final Function<ProfileRequestContext,String> strategy) {
+    public void setResponderIdLookupStrategy(@Nonnull final Function<ProfileRequestContext,String> strategy) {
         ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
 
-        responderIdLookupStrategy = strategy;
+        responderIdLookupStrategy = Constraint.isNotNull(strategy, "Lookup strategy cannot be null");
     }
-        
+    
     /**
      * Get whether detailed information about errors should be exposed.
+     * 
+     * @param profileRequestContext current profile request context
      *
      * @return true iff it is acceptable to expose detailed error information
-     *
-     * @deprecated Use {@link #getDetailedErrorsPredicate()} instead.
      */
-    public boolean isDetailedErrors() {
-        return detailedErrorsPredicate.test(getProfileRequestContext());
+    public boolean isDetailedErrors(@Nullable final ProfileRequestContext profileRequestContext) {
+        return detailedErrorsPredicate.test(profileRequestContext);
     }
 
     /**
      * Set whether detailed information about errors should be exposed.
      * 
-     * @param flag flag to set
+     * @param flag  flag to set
      */
     public void setDetailedErrors(final boolean flag) {
         ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
 
-        detailedErrorsPredicate = flag ? Predicates.<ProfileRequestContext>alwaysTrue()
-                : Predicates.<ProfileRequestContext>alwaysFalse();
-    }
-
-    /**
-     * Get a condition to determine whether detailed information about errors should be exposed.
-     *
-     * @return a condition to evaluate
-     * 
-     * @since 3.3.0
-     */
-    @Nonnull public Predicate<ProfileRequestContext> getDetailedErrorsPredicate() {
-        return detailedErrorsPredicate;
+        detailedErrorsPredicate = flag ? Predicates.alwaysTrue() : Predicates.alwaysFalse();
     }
-
+    
     /**
      * Set a condition to determine whether detailed information about errors should be exposed.
      * 
      * @param condition  condition to set
-     * 
-     * @since 3.3.0
      */
     public void setDetailedErrorsPredicate(@Nonnull final Predicate<ProfileRequestContext> condition) {
-        ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
-
-        detailedErrorsPredicate = Constraint.isNotNull(condition, "Detailed errors predicate cannot be null");
+        detailedErrorsPredicate = Constraint.isNotNull(condition, "Condition cannot be null");
     }
     
     /**
      * Get the unmodifiable set of profile configurations for this relying party.
      * 
+     * @param profileRequestContext current profile request context
+     * 
      * @return unmodifiable set of profile configurations for this relying party, never null
      */
-    @Nonnull @NonnullElements @Unmodifiable @NotLive
-    public Map<String,ProfileConfiguration> getProfileConfigurations() {
-        return ImmutableMap.copyOf(getIndirectProperty(profileConfigurationsLookupStrategy, profileConfigurations));
+    @Nonnull @NonnullElements @Unmodifiable @NotLive public Map<String,ProfileConfiguration> getProfileConfigurations(
+            @Nullable final ProfileRequestContext profileRequestContext) {
+        return ImmutableMap.copyOf(profileConfigurationsLookupStrategy.apply(profileRequestContext));
     }
 
     /**
      * Get the profile configuration, for the relying party, for the given profile. This is a convenience method and is
-     * equivalent to calling {@link Map#get(Object)} on the return of {@link #getProfileConfigurations()}. This map
-     * contains no null entries, keys, or values.
+     * equivalent to calling {@link Map#get(Object)} on the return of
+     * {@link #getProfileConfigurations(ProfileRequestContext)}. This map contains no null entries, keys, or values.
      * 
+     * @param profileRequestContext current profile request context
      * @param profileId the ID of the profile
      * 
      * @return the configuration for the profile or null if the profile ID was null or empty or there is no
      *         configuration for the given profile
      */
-    @Nullable public ProfileConfiguration getProfileConfiguration(@Nullable final String profileId) {
+    @Nullable public ProfileConfiguration getProfileConfiguration(
+            @Nullable final ProfileRequestContext profileRequestContext, @Nullable final String profileId) {
         final String trimmedId = StringSupport.trimOrNull(profileId);
         if (trimmedId == null) {
             return null;
         }
 
-        return getProfileConfigurations().get(trimmedId);
+        return getProfileConfigurations(profileRequestContext).get(trimmedId);
     }
 
     /**
@@ -218,15 +186,16 @@ public class RelyingPartyConfiguration extends AbstractIdentifiableInitializable
         ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
         
         if (configs == null) {
-            profileConfigurations = Collections.emptyMap();
+            profileConfigurationsLookupStrategy = FunctionSupport.constant(Collections.emptyMap());
         } else {
-            profileConfigurations = new HashMap<>();
+            final HashMap<String,ProfileConfiguration> map = new HashMap<>();
             for (final ProfileConfiguration config : Collections2.filter(configs, Predicates.notNull())) {
                 final String trimmedId =
                         Constraint.isNotNull(StringSupport.trimOrNull(config.getId()),
                                 "ID of profile configuration class " + config.getClass().getName() + " cannot be null");
-                profileConfigurations.put(trimmedId, config);
+                map.put(trimmedId, config);
             }
+            profileConfigurationsLookupStrategy = FunctionSupport.constant(map);
         }
     }
 
@@ -235,13 +204,13 @@ public class RelyingPartyConfiguration extends AbstractIdentifiableInitializable
      * 
      * @param strategy lookup strategy
      * 
-     * @since 3.3.0
+     * @since 4.0.0
      */
     public void setProfileConfigurationsLookupStrategy(
-            @Nullable final Function<ProfileRequestContext,Map<String,ProfileConfiguration>> strategy) {
+            @Nonnull final Function<ProfileRequestContext,Map<String,ProfileConfiguration>> strategy) {
         ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
 
-        profileConfigurationsLookupStrategy = strategy;
+        profileConfigurationsLookupStrategy = Constraint.isNotNull(strategy, "Lookup strategy cannot be null");
     }
 
     /**
@@ -259,9 +228,9 @@ public class RelyingPartyConfiguration extends AbstractIdentifiableInitializable
     /** {@inheritDoc} */
     @Override protected void doInitialize() throws ComponentInitializationException {
         super.doInitialize();
-
-        if (responderId == null && responderIdLookupStrategy == null) {
-            throw new ComponentInitializationException("Responder ID and lookup strategy cannot both be null");
+    
+        if (responderIdLookupStrategy == null) {
+            throw new ComponentInitializationException("Responder ID lookup strategy cannot be null");
         }
         
     }
@@ -269,54 +238,8 @@ public class RelyingPartyConfiguration extends AbstractIdentifiableInitializable
     /** {@inheritDoc} */
     public boolean test(@Nullable final ProfileRequestContext input) {
         ComponentSupport.ifNotInitializedThrowUninitializedComponentException(this);
-
-        return activationCondition.test(input);
-    }
-
-    /**
-     * Get the current {@link ProfileRequestContext}.
-     * 
-     * @return current profile request context
-     * 
-     * @since 3.3.0
-     */
-    @Nullable protected ProfileRequestContext getProfileRequestContext() {
-        if (servletRequest != null) {
-            final Object object = servletRequest.getAttribute(ProfileRequestContext.BINDING_KEY);
-            if (object instanceof ProfileRequestContext) {
-                return (ProfileRequestContext) object;
-            }
-            log.warn("RelyingPartyConfiguration {}: No ProfileRequestContext in request", getId());
-        } else {
-            log.warn("RelyingPartyConfiguration {}: ServletRequest was null", getId());
-        }
-        return null;
-    }
     
-    /**
-     * Get a property, possibly through indirection via a lookup function.
-     * 
-     * @param <T> type of property
-     * 
-     * @param lookupStrategy lookup strategy function for indirect access
-     * @param staticValue static value to return in the absence of a lookup function or if null is returned
-     * 
-     * @return a dynamic or static result, if any
-     * 
-     * @since 3.3.0
-     */
-    @Nullable protected <T> T getIndirectProperty(@Nullable final Function<ProfileRequestContext,T> lookupStrategy,
-            @Nullable final T staticValue) {
-        ComponentSupport.ifNotInitializedThrowUninitializedComponentException(this);
-        
-        if (lookupStrategy != null) {
-            final T prop = lookupStrategy.apply(getProfileRequestContext());
-            if (prop != null) {
-                return prop;
-            }
-        }
-
-        return staticValue;
+        return activationCondition.test(input);
     }
 
 }
\ No newline at end of file
diff --git a/idp-profile-api/src/test/java/net/shibboleth/idp/profile/RequestContextBuilder.java b/idp-profile-api/src/test/java/net/shibboleth/idp/profile/RequestContextBuilder.java
index 0bc8d14..03a41bf 100644
--- a/idp-profile-api/src/test/java/net/shibboleth/idp/profile/RequestContextBuilder.java
+++ b/idp-profile-api/src/test/java/net/shibboleth/idp/profile/RequestContextBuilder.java
@@ -403,7 +403,7 @@ public class RequestContextBuilder {
 
         final RelyingPartyConfiguration rpConfig = buildRelyingPartyConfiguration();
         rpCtx.setConfiguration(rpConfig);
-        rpCtx.setProfileConfig(selectProfileConfiguration(rpConfig.getProfileConfigurations()));
+        rpCtx.setProfileConfig(selectProfileConfiguration(rpConfig.getProfileConfigurations(profileRequestContext)));
 
         return rpCtx;
     }
diff --git a/idp-profile-api/src/test/java/net/shibboleth/idp/profile/config/AbstractProfileConfigurationTest.java b/idp-profile-api/src/test/java/net/shibboleth/idp/profile/config/AbstractProfileConfigurationTest.java
index ad10a2d..04eab7a 100644
--- a/idp-profile-api/src/test/java/net/shibboleth/idp/profile/config/AbstractProfileConfigurationTest.java
+++ b/idp-profile-api/src/test/java/net/shibboleth/idp/profile/config/AbstractProfileConfigurationTest.java
@@ -21,7 +21,6 @@ import net.shibboleth.idp.relyingparty.MockProfileConfiguration;
 import net.shibboleth.utilities.java.support.logic.ConstraintViolationException;
 
 import net.shibboleth.utilities.java.support.logic.FunctionSupport;
-import org.opensaml.profile.context.ProfileRequestContext;
 import org.testng.Assert;
 import org.testng.annotations.Test;
 
@@ -54,11 +53,11 @@ public class AbstractProfileConfigurationTest {
     @Test
     public void testSecurityConfiguration() {
         final MockProfileConfiguration config = new MockProfileConfiguration("mock");
-        Assert.assertNotNull(config.getSecurityConfiguration());
+        Assert.assertNotNull(config.getSecurityConfiguration(null));
         
         SecurityConfiguration securityConfig = new SecurityConfiguration();
         config.setSecurityConfiguration(securityConfig);
-        Assert.assertSame(config.getSecurityConfiguration(), securityConfig);
+        Assert.assertSame(config.getSecurityConfiguration(null), securityConfig);
     }
 
     @Test
@@ -66,9 +65,8 @@ public class AbstractProfileConfigurationTest {
         final MockProfileConfiguration config = new MockProfileConfiguration("mock");
         config.setSecurityConfiguration(null);
         final SecurityConfiguration securityConfig = new SecurityConfiguration();
-        config.setSecurityConfigurationLookupStrategy(
-                FunctionSupport.<ProfileRequestContext,SecurityConfiguration>constant(securityConfig));
-        Assert.assertSame(config.getSecurityConfiguration(), securityConfig);
+        config.setSecurityConfigurationLookupStrategy(FunctionSupport.constant(securityConfig));
+        Assert.assertSame(config.getSecurityConfiguration(null), securityConfig);
     }
 
     @Test
@@ -76,15 +74,15 @@ public class AbstractProfileConfigurationTest {
         final MockProfileConfiguration config = new MockProfileConfiguration("mock");
         final List<String> flows = Arrays.asList("foo", "bar");
         config.setInboundInterceptorFlows(flows);
-        Assert.assertEquals(config.getInboundInterceptorFlows(), flows);
+        Assert.assertEquals(config.getInboundInterceptorFlows(null), flows);
     }
 
     @Test
     public void testIndirectInboundFlows() {
         final MockProfileConfiguration config = new MockProfileConfiguration("mock");
         final List<String> flows = Arrays.asList("foo", "bar");
-        config.setInboundFlowsLookupStrategy(FunctionSupport.<ProfileRequestContext,List<String>>constant(flows));
-        Assert.assertEquals(config.getInboundInterceptorFlows(), flows);
+        config.setInboundFlowsLookupStrategy(FunctionSupport.constant(flows));
+        Assert.assertEquals(config.getInboundInterceptorFlows(null), flows);
     }
 
     @Test
@@ -92,37 +90,37 @@ public class AbstractProfileConfigurationTest {
         final MockProfileConfiguration config = new MockProfileConfiguration("mock");
         final List<String> flows = Arrays.asList("foo", "bar");
         config.setOutboundInterceptorFlows(flows);
-        Assert.assertEquals(config.getOutboundInterceptorFlows(), flows);
+        Assert.assertEquals(config.getOutboundInterceptorFlows(null), flows);
     }
 
     @Test
     public void testIndirectOutboundFlows() {
         final MockProfileConfiguration config = new MockProfileConfiguration("mock");
         final List<String> flows = Arrays.asList("foo", "bar");
-        config.setOutboundFlowsLookupStrategy(FunctionSupport.<ProfileRequestContext,List<String>>constant(flows));
-        Assert.assertEquals(config.getOutboundInterceptorFlows(), flows);
+        config.setOutboundFlowsLookupStrategy(FunctionSupport.constant(flows));
+        Assert.assertEquals(config.getOutboundInterceptorFlows(null), flows);
     }
 
     @Test
     public void testDisallowedFeatures() {
         final MockProfileConfiguration config = new MockProfileConfiguration("mock");
-        Assert.assertEquals(config.getDisallowedFeatures(), 0);
+        Assert.assertEquals(config.getDisallowedFeatures(null), 0);
 
         config.setDisallowedFeatures(0x1 | 0x4);
-        Assert.assertTrue(config.isFeatureDisallowed(0x1));
-        Assert.assertFalse(config.isFeatureDisallowed(0x2));
-        Assert.assertTrue(config.isFeatureDisallowed(0x4));
+        Assert.assertTrue(config.isFeatureDisallowed(null, 0x1));
+        Assert.assertFalse(config.isFeatureDisallowed(null, 0x2));
+        Assert.assertTrue(config.isFeatureDisallowed(null, 0x4));
     }
 
     @Test
     public void testIndirectDisallowedFeatures() {
         final MockProfileConfiguration config = new MockProfileConfiguration("mock");
-        Assert.assertEquals(config.getDisallowedFeatures(), 0);
+        Assert.assertEquals(config.getDisallowedFeatures(null), 0);
 
-        config.setDisallowedFeaturesLookupStrategy(FunctionSupport.<ProfileRequestContext,Integer>constant(0x1 | 0x4));
-        Assert.assertTrue(config.isFeatureDisallowed(0x1));
-        Assert.assertFalse(config.isFeatureDisallowed(0x2));
-        Assert.assertTrue(config.isFeatureDisallowed(0x4));
+        config.setDisallowedFeaturesLookupStrategy(FunctionSupport.constant(0x1 | 0x4));
+        Assert.assertTrue(config.isFeatureDisallowed(null, 0x1));
+        Assert.assertFalse(config.isFeatureDisallowed(null, 0x2));
+        Assert.assertTrue(config.isFeatureDisallowed(null, 0x4));
     }
 
 }
\ No newline at end of file
diff --git a/idp-profile-api/src/test/java/net/shibboleth/idp/relyingparty/RelyingPartyConfigurationTest.java b/idp-profile-api/src/test/java/net/shibboleth/idp/relyingparty/RelyingPartyConfigurationTest.java
index 8dc4348..e2c2d78 100644
--- a/idp-profile-api/src/test/java/net/shibboleth/idp/relyingparty/RelyingPartyConfigurationTest.java
+++ b/idp-profile-api/src/test/java/net/shibboleth/idp/relyingparty/RelyingPartyConfigurationTest.java
@@ -34,7 +34,6 @@ import org.testng.annotations.Test;
 /** Unit test for {@link RelyingPartyConfiguration}. */
 public class RelyingPartyConfigurationTest {
 
-    @SuppressWarnings("deprecation")
     @Test public void testConstruction() throws ComponentInitializationException {
         RelyingPartyConfiguration config = new RelyingPartyConfiguration();
         config.setId("foo");
@@ -42,10 +41,9 @@ public class RelyingPartyConfigurationTest {
         config.setDetailedErrorsPredicate(Predicates.<ProfileRequestContext>alwaysTrue());
         config.initialize();
         Assert.assertEquals(config.getId(), "foo");
-        Assert.assertEquals(config.getResponderId(), "http://idp.example.org");
-        Assert.assertTrue(config.isDetailedErrors());
-        Assert.assertTrue(config.getDetailedErrorsPredicate().test(null));
-        Assert.assertTrue(config.getProfileConfigurations().isEmpty());
+        Assert.assertEquals(config.getResponderId(null), "http://idp.example.org");
+        Assert.assertTrue(config.isDetailedErrors(null));
+        Assert.assertTrue(config.getProfileConfigurations(null).isEmpty());
 
         config = new RelyingPartyConfiguration();
         config.setId("foo");
@@ -53,10 +51,9 @@ public class RelyingPartyConfigurationTest {
         config.setDetailedErrorsPredicate(Predicates.<ProfileRequestContext>alwaysFalse());
         config.initialize();
         Assert.assertEquals(config.getId(), "foo");
-        Assert.assertEquals(config.getResponderId(), "http://idp.example.org");
-        Assert.assertFalse(config.isDetailedErrors());
-        Assert.assertFalse(config.getDetailedErrorsPredicate().test(null));
-        Assert.assertTrue(config.getProfileConfigurations().isEmpty());
+        Assert.assertEquals(config.getResponderId(null), "http://idp.example.org");
+        Assert.assertFalse(config.isDetailedErrors(null));
+        Assert.assertTrue(config.getProfileConfigurations(null).isEmpty());
 
         ArrayList<ProfileConfiguration> profileConfigs = new ArrayList<>();
         profileConfigs.add(new MockProfileConfiguration("foo"));
@@ -69,8 +66,8 @@ public class RelyingPartyConfigurationTest {
         config.setProfileConfigurations(profileConfigs);
         config.initialize();
         Assert.assertEquals(config.getId(), "foo");
-        Assert.assertEquals(config.getResponderId(), "http://idp.example.org");
-        Assert.assertEquals(config.getProfileConfigurations().size(), 2);
+        Assert.assertEquals(config.getResponderId(null), "http://idp.example.org");
+        Assert.assertEquals(config.getProfileConfigurations(null).size(), 2);
 
         try {
             config = new RelyingPartyConfiguration();
@@ -101,9 +98,9 @@ public class RelyingPartyConfigurationTest {
         config.setProfileConfigurations(profileConfigs);
         config.initialize();
         
-        Assert.assertNotNull(config.getProfileConfiguration("foo"));
-        Assert.assertNotNull(config.getProfileConfiguration("bar"));
-        Assert.assertNull(config.getProfileConfiguration("baz"));
+        Assert.assertNotNull(config.getProfileConfiguration(null, "foo"));
+        Assert.assertNotNull(config.getProfileConfiguration(null, "bar"));
+        Assert.assertNull(config.getProfileConfiguration(null, "baz"));
     }
 
     @Test public void testIndirectProfileConfiguration() throws ComponentInitializationException {
@@ -114,40 +111,38 @@ public class RelyingPartyConfigurationTest {
         RelyingPartyConfiguration config = new RelyingPartyConfiguration();
         config.setId("foo");
         config.setResponderId("http://idp.example.org");
-        config.setProfileConfigurationsLookupStrategy(
-                FunctionSupport.<ProfileRequestContext,Map<String,ProfileConfiguration>>constant(profileConfigs));
+        config.setProfileConfigurationsLookupStrategy(FunctionSupport.constant(profileConfigs));
         config.initialize();
         
-        Assert.assertNotNull(config.getProfileConfiguration("foo"));
-        Assert.assertNotNull(config.getProfileConfiguration("bar"));
-        Assert.assertNull(config.getProfileConfiguration("baz"));
+        Assert.assertNotNull(config.getProfileConfiguration(null, "foo"));
+        Assert.assertNotNull(config.getProfileConfiguration(null, "bar"));
+        Assert.assertNull(config.getProfileConfiguration(null, "baz"));
         
         config = new RelyingPartyConfiguration();
         config.setId("foo");
         config.setResponderId("http://idp.example.org");
         config.setProfileConfigurations(profileConfigs.values());
-        config.setProfileConfigurationsLookupStrategy(
-                FunctionSupport.<ProfileRequestContext,Map<String,ProfileConfiguration>>constant(null));
+        config.setProfileConfigurationsLookupStrategy(FunctionSupport.constant(null));
         config.initialize();
         
-        Assert.assertNotNull(config.getProfileConfiguration("foo"));
-        Assert.assertNotNull(config.getProfileConfiguration("bar"));
-        Assert.assertNull(config.getProfileConfiguration("baz"));
+        Assert.assertNotNull(config.getProfileConfiguration(null, "foo"));
+        Assert.assertNotNull(config.getProfileConfiguration(null, "bar"));
+        Assert.assertNull(config.getProfileConfiguration(null, "baz"));
     }
 
     @Test public void testIndirectResponderId() throws ComponentInitializationException {
         RelyingPartyConfiguration config = new RelyingPartyConfiguration();
         config.setId("foo");
-        config.setResponderIdLookupStrategy(FunctionSupport.<ProfileRequestContext,String>constant("http://idp.example.org"));
+        config.setResponderIdLookupStrategy(FunctionSupport.constant("http://idp.example.org"));
         config.initialize();
-        Assert.assertEquals(config.getResponderId(), "http://idp.example.org");
+        Assert.assertEquals(config.getResponderId(null), "http://idp.example.org");
 
         config = new RelyingPartyConfiguration();
         config.setId("foo");
         config.setResponderId("http://idp.example.org");
-        config.setResponderIdLookupStrategy(FunctionSupport.<ProfileRequestContext,String>constant(null));
+        config.setResponderIdLookupStrategy(FunctionSupport.constant(null));
         config.initialize();
-        Assert.assertEquals(config.getResponderId(), "http://idp.example.org");
+        Assert.assertEquals(config.getResponderId(null), "http://idp.example.org");
     }
 
 }
\ No newline at end of file
diff --git a/idp-profile-impl/src/main/java/net/shibboleth/idp/profile/impl/SelectProfileConfiguration.java b/idp-profile-impl/src/main/java/net/shibboleth/idp/profile/impl/SelectProfileConfiguration.java
index 6797650..b6b4b7b 100644
--- a/idp-profile-impl/src/main/java/net/shibboleth/idp/profile/impl/SelectProfileConfiguration.java
+++ b/idp-profile-impl/src/main/java/net/shibboleth/idp/profile/impl/SelectProfileConfiguration.java
@@ -112,7 +112,8 @@ public class SelectProfileConfiguration extends AbstractProfileAction {
         final String profileId = profileRequestContext.getProfileId();
         final RelyingPartyConfiguration rpConfig = rpCtx.getConfiguration();
 
-        final ProfileConfiguration profileConfiguration = rpConfig.getProfileConfiguration(profileId);
+        final ProfileConfiguration profileConfiguration =
+                rpConfig.getProfileConfiguration(profileRequestContext, profileId);
         if (profileConfiguration == null) {
             log.warn("{} Profile {} is not available for RP configuration {} (RPID {})",
                     new Object[] {getLogPrefix(), profileId, rpConfig.getId(), rpCtx.getRelyingPartyId(),});
diff --git a/idp-profile-impl/src/main/java/net/shibboleth/idp/profile/messaging/impl/SelectProfileConfiguration.java b/idp-profile-impl/src/main/java/net/shibboleth/idp/profile/messaging/impl/SelectProfileConfiguration.java
index 77dabec..21a01db 100644
--- a/idp-profile-impl/src/main/java/net/shibboleth/idp/profile/messaging/impl/SelectProfileConfiguration.java
+++ b/idp-profile-impl/src/main/java/net/shibboleth/idp/profile/messaging/impl/SelectProfileConfiguration.java
@@ -28,6 +28,7 @@ import org.opensaml.messaging.context.navigate.ChildContextLookup;
 import org.opensaml.messaging.context.navigate.RecursiveTypedParentContextLookup;
 import org.opensaml.messaging.handler.AbstractMessageHandler;
 import org.opensaml.messaging.handler.MessageHandlerException;
+import org.opensaml.profile.context.ProfileRequestContext;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -55,6 +56,11 @@ public class SelectProfileConfiguration extends AbstractMessageHandler {
      * Strategy used to locate the {@link RelyingPartyContext} associated with a given {@link MessageContext}.
      */
     @NonnullAfterInit private Function<MessageContext,RelyingPartyContext> relyingPartyContextLookupStrategy;
+
+    /**
+     * Strategy used to locate the {@link ProfileRequestContext} associated with a given {@link MessageContext}.
+     */
+    @Nonnull private Function<MessageContext,ProfileRequestContext> profileRequestContextLookupStrategy;
     
     /**
      * Strategy used to locate the effective profile ID associated with a given {@link MessageContext}.
@@ -66,6 +72,10 @@ public class SelectProfileConfiguration extends AbstractMessageHandler {
     
     /** Constructor. */
     public SelectProfileConfiguration() {
+        
+        profileRequestContextLookupStrategy =
+                new RecursiveTypedParentContextLookup<>(ProfileRequestContext.class);
+
         relyingPartyContextLookupStrategy =
                 new ChildContextLookup<>(RelyingPartyContext.class).compose(
                         new RecursiveTypedParentContextLookup<>(InOutOperationContext.class));
@@ -85,6 +95,28 @@ public class SelectProfileConfiguration extends AbstractMessageHandler {
         relyingPartyContextLookupStrategy = Constraint.isNotNull(strategy,
                 "RelyingPartyContext lookup strategy cannot be null");
     }
+    
+    /**
+     * Get the strategy used to locate the {@link ProfileRequestContext} associated with a given
+     * {@link MessageContext}.
+     * 
+     * @return lookup strategy
+     */
+    @Nonnull public Function<MessageContext,ProfileRequestContext> getProfileRequestContextLookupStrategy() {
+        return profileRequestContextLookupStrategy;
+    }
+
+    /**
+     * Set the strategy used to locate the {@link ProfileRequestContext} associated with a given
+     * {@link MessageContext}.
+     * 
+     * @param strategy lookup strategy
+     */
+    public void setProfileRequestContextLookupStrategy(
+            @Nonnull final Function<MessageContext,ProfileRequestContext> strategy) {
+        profileRequestContextLookupStrategy =
+                Constraint.isNotNull(strategy, "ProfileRequestContext lookup strategy cannot be null");
+    }
 
     /**
      * Set the strategy used to locate the effective profile ID associated with a given
@@ -143,7 +175,8 @@ public class SelectProfileConfiguration extends AbstractMessageHandler {
             throw new MessageHandlerException("Profile ID is not available from message context");
         }
         
-        final ProfileConfiguration profileConfiguration = rpConfig.getProfileConfiguration(profileId);
+        final ProfileConfiguration profileConfiguration =
+                rpConfig.getProfileConfiguration(profileRequestContextLookupStrategy.apply(messageContext), profileId);
         if (profileConfiguration == null) {
             log.warn("{} Profile {} is not available for RP configuration {} (RPID {})",
                     new Object[] {getLogPrefix(), profileId, rpConfig.getId(), rpCtx.getRelyingPartyId(),});
diff --git a/idp-profile-impl/src/main/java/net/shibboleth/idp/relyingparty/impl/CriteriaSelfEntityIDResolver.java b/idp-profile-impl/src/main/java/net/shibboleth/idp/relyingparty/impl/CriteriaSelfEntityIDResolver.java
index 88bd503..ffe4f6c 100644
--- a/idp-profile-impl/src/main/java/net/shibboleth/idp/relyingparty/impl/CriteriaSelfEntityIDResolver.java
+++ b/idp-profile-impl/src/main/java/net/shibboleth/idp/relyingparty/impl/CriteriaSelfEntityIDResolver.java
@@ -22,10 +22,23 @@ import java.util.Collections;
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 
+import org.opensaml.core.criterion.EntityIdCriterion;
+import org.opensaml.profile.context.ProfileRequestContext;
+import org.opensaml.profile.criterion.ProfileRequestContextCriterion;
+import org.opensaml.saml.common.messaging.context.SAMLMetadataContext;
+import org.opensaml.saml.common.messaging.context.SAMLPeerEntityContext;
+import org.opensaml.saml.criterion.RoleDescriptorCriterion;
+import org.opensaml.saml.saml2.metadata.EntityDescriptor;
+import org.opensaml.saml.saml2.metadata.RoleDescriptor;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import net.shibboleth.idp.profile.context.RelyingPartyContext;
 import net.shibboleth.idp.relyingparty.CriteriaRelyingPartyConfigurationResolver;
 import net.shibboleth.idp.relyingparty.RelyingPartyConfiguration;
 import net.shibboleth.utilities.java.support.annotation.constraint.NonnullAfterInit;
 import net.shibboleth.utilities.java.support.annotation.constraint.NonnullElements;
+import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
 import net.shibboleth.utilities.java.support.component.AbstractIdentifiedInitializableComponent;
 import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
 import net.shibboleth.utilities.java.support.component.ComponentSupport;
@@ -46,14 +59,12 @@ import net.shibboleth.utilities.java.support.resolver.ResolverException;
 public class CriteriaSelfEntityIDResolver extends AbstractIdentifiedInitializableComponent
     implements Resolver<String, CriteriaSet>, IdentifiableComponent {
     
+    /** Logger. */
+    @Nonnull private Logger log = LoggerFactory.getLogger(CriteriaSelfEntityIDResolver.class);
+    
     /** The CriteriaRelyingPartyConfigurationResolver to which to delegate. */
     @NonnullAfterInit private CriteriaRelyingPartyConfigurationResolver rpcResolver;
     
-    /** Constructor. */
-    public CriteriaSelfEntityIDResolver() {
-        super();
-    }
-    
     /**
      * Set the {@link CriteriaRelyingPartyConfigurationResolver} instance to which to delegate.
      * 
@@ -66,7 +77,7 @@ public class CriteriaSelfEntityIDResolver extends AbstractIdentifiedInitializabl
     }
 
     /** {@inheritDoc} */
-    @Override public void setId(@Nonnull final String componentId) {
+    @Override public void setId(@Nonnull @NotEmpty final String componentId) {
         super.setId(componentId);
     }
 
@@ -103,13 +114,117 @@ public class CriteriaSelfEntityIDResolver extends AbstractIdentifiedInitializabl
         ComponentSupport.ifNotInitializedThrowUninitializedComponentException(this);
         ComponentSupport.ifDestroyedThrowDestroyedComponentException(this);
         
-        final RelyingPartyConfiguration rpc = rpcResolver.resolveSingle(criteria);
+        final ProfileRequestContext prc = buildContext(criteria);
+        final CriteriaSet prcSet = new CriteriaSet(new ProfileRequestContextCriterion(prc));
+        
+        final RelyingPartyConfiguration rpc = rpcResolver.resolveSingle(prcSet);
         if (rpc != null) {
-            return rpc.getResponderId();
+            return rpc.getResponderId(prc);
         } else {
             return null;
             
         }
     }
 
-}
+    /**
+     * Build and populate the synthetic instance of {@link ProfileRequestContext} which will be passed
+     * in the resolution call to the delegate.
+     * 
+     * @param criteria the input criteria
+     * @return the synthetic context instance, or null if required data is not supplied
+     */
+    @Nullable private ProfileRequestContext buildContext(@Nullable final CriteriaSet criteria) {
+        if (criteria == null) {
+            return null;
+        }
+        
+        if (criteria.contains(ProfileRequestContextCriterion.class)) {
+            return criteria.get(ProfileRequestContextCriterion.class).getProfileRequestContext();
+        }
+
+        final String entityID = resolveEntityID(criteria);
+        log.debug("Resolved effective entityID from criteria: {}", entityID);
+
+        final EntityDescriptor entityDescriptor = resolveEntityDescriptor(criteria);
+        log.debug("Resolved effective entity descriptor from criteria: {}", entityDescriptor);
+
+        final RoleDescriptor roleDescriptor = resolveRoleDescriptor(criteria);
+        log.debug("Resolved effective role descriptor from criteria: {}", roleDescriptor);
+
+        if (entityID != null || entityDescriptor != null || roleDescriptor != null) {
+            final ProfileRequestContext prc = new ProfileRequestContext<>();
+            final RelyingPartyContext rpc = prc.getSubcontext(RelyingPartyContext.class, true);
+            rpc.setVerified(true);
+
+            rpc.setRelyingPartyId(entityID);
+
+            if (entityDescriptor != null || roleDescriptor != null) {
+                final SAMLPeerEntityContext peerContext = prc.getSubcontext(SAMLPeerEntityContext.class, true);
+                rpc.setRelyingPartyIdContextTree(peerContext);
+
+                peerContext.setEntityId(entityID);
+
+                if (roleDescriptor != null) {
+                    peerContext.setRole(roleDescriptor.getSchemaType() != null
+                            ? roleDescriptor.getSchemaType() : roleDescriptor.getElementQName());
+                }
+
+                final SAMLMetadataContext metadataContext = peerContext.getSubcontext(SAMLMetadataContext.class, true);
+                metadataContext.setEntityDescriptor(entityDescriptor);
+                metadataContext.setRoleDescriptor(roleDescriptor);
+            }
+            return prc;
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Resolve the entityID from the criteria.
+     * 
+     * @param criteria the input criteria
+     * @return the input entityID criterion or null if could not be resolved
+     */
+    private String resolveEntityID(@Nonnull final CriteriaSet criteria) {
+        if (criteria.contains(EntityIdCriterion.class)) {
+            return criteria.get(EntityIdCriterion.class).getEntityId();
+        }
+
+        final EntityDescriptor ed = resolveEntityDescriptor(criteria);
+        if (ed != null) {
+            return ed.getEntityID();
+        }
+
+        return null;
+    }
+
+    /**
+     * Resolve the EntityDescriptor from the criteria.
+     *
+     * @param criteria the input criteria
+     * @return the input entity descriptor criterion, or null if could not be resolved
+     */
+    private EntityDescriptor resolveEntityDescriptor(@Nonnull final CriteriaSet criteria) {
+        final RoleDescriptor rd = resolveRoleDescriptor(criteria);
+        if (rd != null && rd.getParent() != null && rd.getParent() instanceof EntityDescriptor) {
+            return (EntityDescriptor)rd.getParent();
+        }
+
+        return null;
+    }
+
+    /**
+     * Resolve the RoleDescriptor from the criteria.
+     *
+     * @param criteria the input criteria
+     * @return the input role descriptor criterion or null if could not be resolved
+     */
+    private RoleDescriptor resolveRoleDescriptor(@Nonnull final CriteriaSet criteria) {
+        if (criteria.contains(RoleDescriptorCriterion.class)) {
+            return criteria.get(RoleDescriptorCriterion.class).getRole();
+        }
+
+        return null;
+    }
+    
+}
\ No newline at end of file
diff --git a/idp-profile-impl/src/main/java/net/shibboleth/idp/relyingparty/impl/DelegatingCriteriaRelyingPartyConfigurationResolver.java b/idp-profile-impl/src/main/java/net/shibboleth/idp/relyingparty/impl/DelegatingCriteriaRelyingPartyConfigurationResolver.java
index 22a2dae..b8a6bd0 100644
--- a/idp-profile-impl/src/main/java/net/shibboleth/idp/relyingparty/impl/DelegatingCriteriaRelyingPartyConfigurationResolver.java
+++ b/idp-profile-impl/src/main/java/net/shibboleth/idp/relyingparty/impl/DelegatingCriteriaRelyingPartyConfigurationResolver.java
@@ -25,6 +25,7 @@ import javax.annotation.Nullable;
 
 import org.opensaml.core.criterion.EntityIdCriterion;
 import org.opensaml.profile.context.ProfileRequestContext;
+import org.opensaml.profile.criterion.ProfileRequestContextCriterion;
 import org.opensaml.saml.common.messaging.context.SAMLMetadataContext;
 import org.opensaml.saml.common.messaging.context.SAMLPeerEntityContext;
 import org.opensaml.saml.criterion.RoleDescriptorCriterion;
@@ -55,6 +56,7 @@ import net.shibboleth.utilities.java.support.resolver.ResolverException;
  * <p>
  * One of the following input criteria is required for resolution based on relying party entityID:
  * <ul>
+ * <li>{@link ProfileRequestContextCriterion}</li>
  * <li>{@link EntityIdCriterion}</li>
  * <li>{@link RoleDescriptorCriterion}</li>
  * </ul>
@@ -64,7 +66,7 @@ public class DelegatingCriteriaRelyingPartyConfigurationResolver extends Abstrac
         implements CriteriaRelyingPartyConfigurationResolver, IdentifiableComponent {
     
     /** Logger. */
-    private Logger log = LoggerFactory.getLogger(DelegatingCriteriaRelyingPartyConfigurationResolver.class);
+    @Nonnull private Logger log = LoggerFactory.getLogger(DelegatingCriteriaRelyingPartyConfigurationResolver.class);
     
     /** The RelyingPartyConfigurationResolver to which to delegate. */
     @NonnullAfterInit private RelyingPartyConfigurationResolver delegate;
@@ -153,6 +155,10 @@ public class DelegatingCriteriaRelyingPartyConfigurationResolver extends Abstrac
         if (criteria == null) {
             return null;
         }
+        
+        if (criteria.contains(ProfileRequestContextCriterion.class)) {
+            return criteria.get(ProfileRequestContextCriterion.class).getProfileRequestContext();
+        }
 
         final String entityID = resolveEntityID(criteria);
         log.debug("Resolved effective entityID from criteria: {}", entityID);
diff --git a/idp-profile-impl/src/test/java/net/shibboleth/idp/profile/impl/SelectRelyingPartyConfigurationTest.java b/idp-profile-impl/src/test/java/net/shibboleth/idp/profile/impl/SelectRelyingPartyConfigurationTest.java
index e6a20ec..19c623b 100644
--- a/idp-profile-impl/src/test/java/net/shibboleth/idp/profile/impl/SelectRelyingPartyConfigurationTest.java
+++ b/idp-profile-impl/src/test/java/net/shibboleth/idp/profile/impl/SelectRelyingPartyConfigurationTest.java
@@ -130,8 +130,8 @@ public class SelectRelyingPartyConfigurationTest {
         final RelyingPartyConfiguration resolvedConfig =
                 prc.getSubcontext(RelyingPartyContext.class).getConfiguration();
         Assert.assertEquals(resolvedConfig.getId(), config.getId());
-        Assert.assertEquals(resolvedConfig.getResponderId(), config.getResponderId());
-        Assert.assertEquals(resolvedConfig.getProfileConfigurations(), config.getProfileConfigurations());
+        Assert.assertEquals(resolvedConfig.getResponderId(prc), config.getResponderId(prc));
+        Assert.assertEquals(resolvedConfig.getProfileConfigurations(prc), config.getProfileConfigurations(prc));
     }
 
     /** A resolver that returns a relying party configuration or throws an exception. */
diff --git a/idp-saml-api/src/main/java/net/shibboleth/idp/saml/profile/config/AbstractMetadataDrivenConfigurationLookupStrategy.java b/idp-saml-api/src/main/java/net/shibboleth/idp/saml/profile/config/AbstractMetadataDrivenConfigurationLookupStrategy.java
index 520e372..7688638 100644
--- a/idp-saml-api/src/main/java/net/shibboleth/idp/saml/profile/config/AbstractMetadataDrivenConfigurationLookupStrategy.java
+++ b/idp-saml-api/src/main/java/net/shibboleth/idp/saml/profile/config/AbstractMetadataDrivenConfigurationLookupStrategy.java
@@ -98,7 +98,10 @@ public abstract class AbstractMetadataDrivenConfigurationLookupStrategy<T> exten
     
     /** Alternative "full" property identifiers to support. */
     @NonnullAfterInit @NonnullElements private Collection<String> propertyAliases;
-        
+    
+    /** Optional default to return in the absence of a property. */
+    @Nullable private T defaultValue;
+    
     /** Strategy for obtaining metadata to check. */
     @Nullable private Function<BaseContext,EntityDescriptor> metadataLookupStrategy;
 
@@ -176,6 +179,17 @@ public abstract class AbstractMetadataDrivenConfigurationLookupStrategy<T> exten
     }
     
     /**
+     * Set a default value to return as the function result in the absence of an explicit property.
+     * 
+     * @param value default value to return 
+     */
+    public void setDefaultValue(@Nullable final T value) {
+        ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+        
+        defaultValue = value;
+    }
+    
+    /**
      * Set lookup strategy for metadata to examine.
      * 
      * @param strategy  lookup strategy
@@ -226,8 +240,8 @@ public abstract class AbstractMetadataDrivenConfigurationLookupStrategy<T> exten
         }
             
         if (entity == null) {
-            log.debug("No metadata available for relying party, no setting returned for '{}'", propertyName);
-            return null;
+            log.debug("No metadata available for relying party, default returned for '{}'", propertyName);
+            return defaultValue;
         }
         
         if (profileIdLookupStrategy != null) {
@@ -263,11 +277,11 @@ public abstract class AbstractMetadataDrivenConfigurationLookupStrategy<T> exten
             }
         }
         
-        log.debug("No applicable tag, no setting returned for '{}'", propertyName);
+        log.debug("No applicable tag, default returned for '{}'", propertyName);
         if (enableCaching) {
-            cacheContext.getPropertyMap().put(propertyName, null);
+            cacheContext.getPropertyMap().put(propertyName, defaultValue);
         }
-        return null;
+        return defaultValue;
     }
 // Checkstyle: CyclomaticComplexity ON
     
diff --git a/idp-saml-api/src/main/java/net/shibboleth/idp/saml/profile/config/AbstractSAMLProfileConfiguration.java b/idp-saml-api/src/main/java/net/shibboleth/idp/saml/profile/config/AbstractSAMLProfileConfiguration.java
index 1ddc275..bb5c856 100644
--- a/idp-saml-api/src/main/java/net/shibboleth/idp/saml/profile/config/AbstractSAMLProfileConfiguration.java
+++ b/idp-saml-api/src/main/java/net/shibboleth/idp/saml/profile/config/AbstractSAMLProfileConfiguration.java
@@ -93,9 +93,10 @@ public abstract class AbstractSAMLProfileConfiguration extends AbstractCondition
 
     /** {@inheritDoc} */
     @Override
-    @Nonnull @NonnullElements @NotLive @Unmodifiable public List<String> getInboundInterceptorFlows() {
+    @Nonnull @NonnullElements @NotLive @Unmodifiable public List<String> getInboundInterceptorFlows(
+            @Nullable final ProfileRequestContext profileRequestContext) {
         
-        final List<String> flows = super.getInboundInterceptorFlows();
+        final List<String> flows = super.getInboundInterceptorFlows(profileRequestContext);
         if (flows.isEmpty()) {
             log.warn("Inbound interceptor collection is empty, this disables default inbound message security checks");
         }
diff --git a/idp-saml-api/src/main/java/net/shibboleth/idp/saml/profile/config/logic/DetailedErrorsProfileConfigPredicate.java b/idp-saml-api/src/main/java/net/shibboleth/idp/saml/profile/config/logic/DetailedErrorsProfileConfigPredicate.java
index fe23269..3bcd03a 100644
--- a/idp-saml-api/src/main/java/net/shibboleth/idp/saml/profile/config/logic/DetailedErrorsProfileConfigPredicate.java
+++ b/idp-saml-api/src/main/java/net/shibboleth/idp/saml/profile/config/logic/DetailedErrorsProfileConfigPredicate.java
@@ -38,7 +38,7 @@ public class DetailedErrorsProfileConfigPredicate extends AbstractRelyingPartyPr
     public boolean test(@Nullable final ProfileRequestContext input) {
         final RelyingPartyContext rpc = getRelyingPartyContextLookupStrategy().apply(input);
         if (rpc != null && rpc.getConfiguration() != null) {
-            return rpc.getConfiguration().getDetailedErrorsPredicate().test(input);
+            return rpc.getConfiguration().isDetailedErrors(input);
         }
         
         return false;
diff --git a/idp-saml-api/src/main/java/net/shibboleth/idp/saml/profile/config/logic/IncludeAttributeStatementPredicate.java b/idp-saml-api/src/main/java/net/shibboleth/idp/saml/profile/config/logic/IncludeAttributeStatementPredicate.java
index 1e1b441..f834abe 100644
--- a/idp-saml-api/src/main/java/net/shibboleth/idp/saml/profile/config/logic/IncludeAttributeStatementPredicate.java
+++ b/idp-saml-api/src/main/java/net/shibboleth/idp/saml/profile/config/logic/IncludeAttributeStatementPredicate.java
@@ -76,11 +76,11 @@ public class IncludeAttributeStatementPredicate extends AbstractRelyingPartyPred
             if (rpc.getProfileConfig()
                     instanceof net.shibboleth.idp.saml.saml1.profile.config.BrowserSSOProfileConfiguration) {
                 return ((net.shibboleth.idp.saml.saml1.profile.config.BrowserSSOProfileConfiguration)
-                        rpc.getProfileConfig()).getIncludeAttributeStatementPredicate().test(input);
+                        rpc.getProfileConfig()).isIncludeAttributeStatement(input);
             } else if (rpc.getProfileConfig()
                     instanceof net.shibboleth.idp.saml.saml2.profile.config.BrowserSSOProfileConfiguration) {
                 return ((net.shibboleth.idp.saml.saml2.profile.config.BrowserSSOProfileConfiguration)
-                        rpc.getProfileConfig()).getIncludeAttributeStatementPredicate().test(input);
+                        rpc.getProfileConfig()).isIncludeAttributeStatement(input);
             } else if (rpc.getProfileConfig()
                     instanceof net.shibboleth.idp.saml.saml1.profile.config.AttributeQueryProfileConfiguration) {
                 return true;
diff --git a/idp-saml-api/src/main/java/net/shibboleth/idp/saml/profile/config/logic/ResolveAttributesProfileConfigPredicate.java b/idp-saml-api/src/main/java/net/shibboleth/idp/saml/profile/config/logic/ResolveAttributesProfileConfigPredicate.java
index 9b940a9..36ba503 100644
--- a/idp-saml-api/src/main/java/net/shibboleth/idp/saml/profile/config/logic/ResolveAttributesProfileConfigPredicate.java
+++ b/idp-saml-api/src/main/java/net/shibboleth/idp/saml/profile/config/logic/ResolveAttributesProfileConfigPredicate.java
@@ -40,11 +40,11 @@ public class ResolveAttributesProfileConfigPredicate extends AbstractRelyingPart
             if (rpc.getProfileConfig()
                     instanceof net.shibboleth.idp.saml.saml1.profile.config.BrowserSSOProfileConfiguration) {
                 return ((net.shibboleth.idp.saml.saml1.profile.config.BrowserSSOProfileConfiguration)
-                        rpc.getProfileConfig()).getResolveAttributesPredicate().test(input);
+                        rpc.getProfileConfig()).isResolveAttributes(input);
             } else if (rpc.getProfileConfig()
                     instanceof net.shibboleth.idp.saml.saml2.profile.config.BrowserSSOProfileConfiguration) {
                 return ((net.shibboleth.idp.saml.saml2.profile.config.BrowserSSOProfileConfiguration)
-                        rpc.getProfileConfig()).getResolveAttributesPredicate().test(input);
+                        rpc.getProfileConfig()).isResolveAttributes(input);
             }
         }
         
diff --git a/idp-saml-api/src/main/java/net/shibboleth/idp/saml/profile/config/navigate/SessionLifetimeLookupFunction.java b/idp-saml-api/src/main/java/net/shibboleth/idp/saml/profile/config/navigate/SessionLifetimeLookupFunction.java
index 37d1a02..fb1d4e1 100644
--- a/idp-saml-api/src/main/java/net/shibboleth/idp/saml/profile/config/navigate/SessionLifetimeLookupFunction.java
+++ b/idp-saml-api/src/main/java/net/shibboleth/idp/saml/profile/config/navigate/SessionLifetimeLookupFunction.java
@@ -43,7 +43,7 @@ public class SessionLifetimeLookupFunction extends AbstractRelyingPartyLookupFun
         if (rpc != null) {
             final ProfileConfiguration pc = rpc.getProfileConfig();
             if (pc != null && pc instanceof BrowserSSOProfileConfiguration) {
-                return ((BrowserSSOProfileConfiguration) pc).getMaximumSPSessionLifetime();
+                return ((BrowserSSOProfileConfiguration) pc).getMaximumSPSessionLifetime(input);
             }
         }
         
diff --git a/idp-saml-api/src/main/java/net/shibboleth/idp/saml/profile/logic/DefaultNameIdentifierFormatStrategy.java b/idp-saml-api/src/main/java/net/shibboleth/idp/saml/profile/logic/DefaultNameIdentifierFormatStrategy.java
index 46b0bc5..c6255b0 100644
--- a/idp-saml-api/src/main/java/net/shibboleth/idp/saml/profile/logic/DefaultNameIdentifierFormatStrategy.java
+++ b/idp-saml-api/src/main/java/net/shibboleth/idp/saml/profile/logic/DefaultNameIdentifierFormatStrategy.java
@@ -114,13 +114,14 @@ public class DefaultNameIdentifierFormatStrategy extends MetadataNameIdentifierF
             
             if (profileId != null) {
                 log.debug("Using overridden profile configuration ID: {}", profileId);
-                profileConfig = relyingPartyCtx.getConfiguration().getProfileConfiguration(profileId);
+                profileConfig = relyingPartyCtx.getConfiguration().getProfileConfiguration(input, profileId);
             } else {
                 profileConfig = relyingPartyCtx.getProfileConfig();
             }
             
             if (profileConfig != null && profileConfig instanceof AuthenticationProfileConfiguration) {
-                fromConfig.addAll(((AuthenticationProfileConfiguration) profileConfig).getNameIDFormatPrecedence());
+                fromConfig.addAll(
+                        ((AuthenticationProfileConfiguration) profileConfig).getNameIDFormatPrecedence(input));
                 log.debug("Configuration specifies the following formats: {}", fromConfig);
             } else {
                 log.debug("No ProfileConfiguraton available (or not an AuthenticationProfileConfiguration)");
diff --git a/idp-saml-api/src/main/java/net/shibboleth/idp/saml/saml1/profile/config/BrowserSSOProfileConfiguration.java b/idp-saml-api/src/main/java/net/shibboleth/idp/saml/saml1/profile/config/BrowserSSOProfileConfiguration.java
index 4f41e9d..ad3809a 100644
--- a/idp-saml-api/src/main/java/net/shibboleth/idp/saml/saml1/profile/config/BrowserSSOProfileConfiguration.java
+++ b/idp-saml-api/src/main/java/net/shibboleth/idp/saml/saml1/profile/config/BrowserSSOProfileConfiguration.java
@@ -20,7 +20,6 @@ package net.shibboleth.idp.saml.saml1.profile.config;
 import java.security.Principal;
 import java.util.ArrayList;
 import java.util.Collection;
-import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
@@ -34,8 +33,6 @@ import org.opensaml.profile.context.ProfileRequestContext;
 
 import com.google.common.base.Predicates;
 import com.google.common.collect.Collections2;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
 
 import net.shibboleth.idp.authn.config.AuthenticationProfileConfiguration;
 import net.shibboleth.idp.saml.authn.principal.AuthenticationMethodPrincipal;
@@ -43,7 +40,9 @@ import net.shibboleth.utilities.java.support.annotation.constraint.NonnullElemen
 import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
 import net.shibboleth.utilities.java.support.annotation.constraint.NotLive;
 import net.shibboleth.utilities.java.support.annotation.constraint.Unmodifiable;
+import net.shibboleth.utilities.java.support.collection.CollectionSupport;
 import net.shibboleth.utilities.java.support.logic.Constraint;
+import net.shibboleth.utilities.java.support.logic.FunctionSupport;
 import net.shibboleth.utilities.java.support.primitive.StringSupport;
 
 /** Configuration for SAML 1 Browser SSO profile requests. */
@@ -51,7 +50,7 @@ public class BrowserSSOProfileConfiguration extends AbstractSAML1ArtifactAwarePr
         implements AuthenticationProfileConfiguration {
 
     /** ID for this profile configuration. */
-    public static final String PROFILE_ID = "http://shibboleth.net/ns/profiles/saml1/sso/browser";
+    @Nonnull @NotEmpty public static final String PROFILE_ID = "http://shibboleth.net/ns/profiles/saml1/sso/browser";
 
     /** Whether attributes should be resolved in the course of the profile. */
     @Nonnull private Predicate<ProfileRequestContext> resolveAttributesPredicate;
@@ -63,29 +62,17 @@ public class BrowserSSOProfileConfiguration extends AbstractSAML1ArtifactAwarePr
     @Nonnull private Predicate<ProfileRequestContext> forceAuthnPredicate;
 
     /** Lookup function to supply {@link #defaultAuthenticationMethods} property. */
-    @Nullable private Function<ProfileRequestContext,Collection<AuthenticationMethodPrincipal>>
+    @Nonnull private Function<ProfileRequestContext,Collection<AuthenticationMethodPrincipal>>
             defaultAuthenticationMethodsLookupStrategy;
 
-    /** Selects, and limits, the authentication methods to use for requests. */
-    @Nonnull @NonnullElements private List<AuthenticationMethodPrincipal> defaultAuthenticationMethods;
-
     /** Lookup function to supply {@link #authenticationFlows} property. */
-    @Nullable private Function<ProfileRequestContext,Set<String>> authenticationFlowsLookupStrategy;
-
-    /** Filters the usable authentication flows. */
-    @Nonnull @NonnullElements private Set<String> authenticationFlows;
+    @Nonnull private Function<ProfileRequestContext,Set<String>> authenticationFlowsLookupStrategy;
 
     /** Lookup function to supply {@link #postAuthenticationFlows} property. */
-    @Nullable private Function<ProfileRequestContext,Collection<String>> postAuthenticationFlowsLookupStrategy;
-
-    /** Enables post-authentication interceptor flows. */
-    @Nonnull @NonnullElements private List<String> postAuthenticationFlows;
+    @Nonnull private Function<ProfileRequestContext,Collection<String>> postAuthenticationFlowsLookupStrategy;
 
     /** Lookup function to supply {@link #nameIDFormatPrecedence} property. */
-    @Nullable private Function<ProfileRequestContext,Collection<String>> nameIDFormatPrecedenceLookupStrategy;
-
-    /** Precedence of name identifier formats to use for requests. */
-    @Nonnull @NonnullElements private List<String> nameIDFormatPrecedence;
+    @Nonnull private Function<ProfileRequestContext,Collection<String>> nameIDFormatPrecedenceLookupStrategy;
     
     /** Constructor. */
     public BrowserSSOProfileConfiguration() {
@@ -99,14 +86,14 @@ public class BrowserSSOProfileConfiguration extends AbstractSAML1ArtifactAwarePr
      */
     protected BrowserSSOProfileConfiguration(@Nonnull @NotEmpty final String profileId) {
         super(profileId);
-        setSignResponses(Predicates.<ProfileRequestContext>alwaysTrue());
+        setSignResponses(Predicates.alwaysTrue());
         resolveAttributesPredicate = Predicates.alwaysTrue();
         includeAttributeStatementPredicate = Predicates.alwaysFalse();
+        authenticationFlowsLookupStrategy = FunctionSupport.constant(null);
+        postAuthenticationFlowsLookupStrategy = FunctionSupport.constant(null);
+        defaultAuthenticationMethodsLookupStrategy = FunctionSupport.constant(null);
+        nameIDFormatPrecedenceLookupStrategy = FunctionSupport.constant(null);
         forceAuthnPredicate = Predicates.alwaysFalse();
-        defaultAuthenticationMethods = Collections.emptyList();
-        authenticationFlows = Collections.emptySet();
-        postAuthenticationFlows = Collections.emptyList();
-        nameIDFormatPrecedence = Collections.emptyList();
     }
 
     /**
@@ -114,41 +101,27 @@ public class BrowserSSOProfileConfiguration extends AbstractSAML1ArtifactAwarePr
      *
      * <p>Default is true</p>
      * 
-     * @return true iff attributes should be resolved
+     * @param profileRequestContext current profile request context
      * 
-     * @deprecated Use {@link #getResolveAttributesPredicate()} instead.
+     * @return true iff attributes should be resolved
      */
-    public boolean resolveAttributes() {
-        return resolveAttributesPredicate.test(getProfileRequestContext());
+    public boolean isResolveAttributes(@Nullable final ProfileRequestContext profileRequestContext) {
+        return resolveAttributesPredicate.test(profileRequestContext);
     }
-    
+
     /**
      * Set whether attributes should be resolved during the profile.
      * 
      * @param flag flag to set
      */
     public void setResolveAttributes(final boolean flag) {
-        resolveAttributesPredicate = flag ? Predicates.<ProfileRequestContext>alwaysTrue()
-                : Predicates.<ProfileRequestContext>alwaysFalse();
-    }
-
-    /**
-     * Get a condition to determine whether attributes should be resolved during the profile.
-     * 
-     * @return condition
-     * 
-     * @since 3.3.0
-     */
-    @Nonnull public Predicate<ProfileRequestContext> getResolveAttributesPredicate() {
-        return resolveAttributesPredicate;
+        resolveAttributesPredicate = flag ? Predicates.alwaysTrue() : Predicates.alwaysFalse();
     }
     
     /**
      * Set a condition to determine whether attributes should be resolved during the profile.
-     *
-     * @param condition  condition to set
      * 
-     * @since 3.3.0
+     * @param condition condition to set
      */
     public void setResolveAttributesPredicate(@Nonnull final Predicate<ProfileRequestContext> condition) {
         resolveAttributesPredicate = Constraint.isNotNull(condition, "Resolve attributes predicate cannot be null");
@@ -158,35 +131,22 @@ public class BrowserSSOProfileConfiguration extends AbstractSAML1ArtifactAwarePr
      * Get whether responses to the authentication request should include an attribute statement.
      *
      * <p>Default is true</p>
+     * 
+     * @param profileRequestContext current profile request context
      *
      * @return whether responses to the authentication request should include an attribute statement
-     * 
-     * @deprecated Use {@link #getIncludeAttributeStatementPredicate()} instead.
      */
-    public boolean includeAttributeStatement() {
-        return includeAttributeStatementPredicate.test(getProfileRequestContext());
+    public boolean isIncludeAttributeStatement(@Nullable final ProfileRequestContext profileRequestContext) {
+        return includeAttributeStatementPredicate.test(profileRequestContext);
     }
 
     /**
      * Set whether responses to the authentication request should include an attribute statement.
-     * 
-     * @param include flag to set
-     */
-    public void setIncludeAttributeStatement(final boolean include) {
-        includeAttributeStatementPredicate = include ? Predicates.<ProfileRequestContext>alwaysTrue()
-                : Predicates.<ProfileRequestContext>alwaysFalse();
-    }
-
-    /**
-     * Get a condition to determine whether responses to the authentication request should include an
-     * attribute statement.
-     * 
-     * @return condition
-     * 
-     * @since 3.3.0
+     *
+     * @param flag flag to set
      */
-    @Nonnull public Predicate<ProfileRequestContext> getIncludeAttributeStatementPredicate() {
-        return includeAttributeStatementPredicate;
+    public void setIncludeAttributeStatement(final boolean flag) {
+        includeAttributeStatementPredicate = flag ? Predicates.alwaysTrue() : Predicates.alwaysFalse();
     }
     
     /**
@@ -194,53 +154,40 @@ public class BrowserSSOProfileConfiguration extends AbstractSAML1ArtifactAwarePr
      * attribute statement.
      *
      * @param condition  condition to set
-     * 
-     * @since 3.3.0
      */
     public void setIncludeAttributeStatementPredicate(@Nonnull final Predicate<ProfileRequestContext> condition) {
         includeAttributeStatementPredicate = Constraint.isNotNull(condition,
                 "Include attribute statement predicate cannot be null");
     }
     
+    /** {@inheritDoc} */
+    public boolean isForceAuthn(@Nullable final ProfileRequestContext profileRequestContext) {
+        return forceAuthnPredicate.test(profileRequestContext);
+    }
+    
     /**
-     * Get a condition to determine whether a fresh user presence proof should be required for this request.
-     * 
-     * @return condition
+     * Set whether a fresh user presence proof should be required for this request.
      * 
-     * @since 3.4.0
+     * @param flag flag to set
      */
-    @Nonnull public Predicate<ProfileRequestContext> getForceAuthnPredicate() {
-        return forceAuthnPredicate;
+    public void setForceAuthn(final boolean flag) {
+        forceAuthnPredicate = flag ? Predicates.alwaysTrue() : Predicates.alwaysFalse();
     }
     
     /**
      * Set a condition to determine whether a fresh user presence proof should be required for this request.
      * 
      * @param condition condition to set
-     * 
-     * @since 3.4.0
      */
     public void setForceAuthnPredicate(@Nonnull final Predicate<ProfileRequestContext> condition) {
         forceAuthnPredicate = Constraint.isNotNull(condition, "Forced authentication predicate cannot be null");
     }
-    
-    /**
-     * Set whether a fresh user presence proof should be required for this request.
-     * 
-     * @param flag flag to set
-     * 
-     * @since 3.4.0
-     */
-    public void setForceAuthn(final boolean flag) {
-        forceAuthnPredicate = flag ? Predicates.<ProfileRequestContext>alwaysTrue()
-                : Predicates.<ProfileRequestContext>alwaysFalse();
-    }
 
     /** {@inheritDoc} */
-    @Override
-    @Nonnull @NonnullElements @NotLive @Unmodifiable public List<Principal> getDefaultAuthenticationMethods() {
-        return ImmutableList.<Principal>copyOf(
-                getIndirectProperty(defaultAuthenticationMethodsLookupStrategy, defaultAuthenticationMethods));
+    @Nonnull @NonnullElements @NotLive @Unmodifiable public List<Principal> getDefaultAuthenticationMethods(
+            @Nullable final ProfileRequestContext profileRequestContext) {
+        return CollectionSupport.buildImmutableList(
+                defaultAuthenticationMethodsLookupStrategy.apply(profileRequestContext));
     }
     
     /**
@@ -252,9 +199,10 @@ public class BrowserSSOProfileConfiguration extends AbstractSAML1ArtifactAwarePr
             @Nullable @NonnullElements final Collection<AuthenticationMethodPrincipal> methods) {
 
         if (methods != null) {
-            defaultAuthenticationMethods = new ArrayList<>(Collections2.filter(methods, Predicates.notNull()));
+            defaultAuthenticationMethodsLookupStrategy =
+                    FunctionSupport.constant(new ArrayList<>(Collections2.filter(methods, Predicates.notNull())));
         } else {
-            defaultAuthenticationMethods = Collections.emptyList();
+            defaultAuthenticationMethodsLookupStrategy = FunctionSupport.constant(null);
         }
     }
 
@@ -266,14 +214,14 @@ public class BrowserSSOProfileConfiguration extends AbstractSAML1ArtifactAwarePr
      * @since 3.3.0
      */
     public void setDefaultAuthenticationMethodsLookupStrategy(
-            @Nullable final Function<ProfileRequestContext,Collection<AuthenticationMethodPrincipal>> strategy) {
-        defaultAuthenticationMethodsLookupStrategy = strategy;
+            @Nonnull final Function<ProfileRequestContext,Collection<AuthenticationMethodPrincipal>> strategy) {
+        defaultAuthenticationMethodsLookupStrategy = Constraint.isNotNull(strategy, "Lookup strategy cannot be null");
     }
 
     /** {@inheritDoc} */
-    @Override
-    @Nonnull @NonnullElements @NotLive @Unmodifiable public Set<String> getAuthenticationFlows() {
-        return ImmutableSet.copyOf(getIndirectProperty(authenticationFlowsLookupStrategy, authenticationFlows));
+    @Nonnull @NonnullElements @NotLive @Unmodifiable public Set<String> getAuthenticationFlows(
+            @Nullable final ProfileRequestContext profileRequestContext) {
+        return CollectionSupport.buildImmutableSet(authenticationFlowsLookupStrategy.apply(profileRequestContext));
     }
 
     /**
@@ -282,11 +230,11 @@ public class BrowserSSOProfileConfiguration extends AbstractSAML1ArtifactAwarePr
      * @param flows   flow identifiers to use
      */
     public void setAuthenticationFlows(@Nullable @NonnullElements final Collection<String> flows) {
-
         if (flows != null) {
-            authenticationFlows = new HashSet<>(StringSupport.normalizeStringCollection(flows));
+            authenticationFlowsLookupStrategy =
+                    FunctionSupport.constant(new HashSet<>(StringSupport.normalizeStringCollection(flows)));
         } else {
-            authenticationFlows = Collections.emptySet();
+            authenticationFlowsLookupStrategy = FunctionSupport.constant(null);
         }
     }
 
@@ -298,15 +246,14 @@ public class BrowserSSOProfileConfiguration extends AbstractSAML1ArtifactAwarePr
      * @since 3.3.0
      */
     public void setAuthenticationFlowsLookupStrategy(
-            @Nullable final Function<ProfileRequestContext,Set<String>> strategy) {
-        authenticationFlowsLookupStrategy = strategy;
+            @Nonnull final Function<ProfileRequestContext,Set<String>> strategy) {
+        authenticationFlowsLookupStrategy = Constraint.isNotNull(strategy, "Lookup strategy cannot be null");
     }
 
     /** {@inheritDoc} */
-    @Override
-    @Nonnull @NonnullElements @NotLive @Unmodifiable public List<String> getPostAuthenticationFlows() {
-        return ImmutableList.copyOf(
-                getIndirectProperty(postAuthenticationFlowsLookupStrategy, postAuthenticationFlows));
+    @Nonnull @NonnullElements @NotLive @Unmodifiable public List<String> getPostAuthenticationFlows(
+            @Nullable final ProfileRequestContext profileRequestContext) {
+        return CollectionSupport.buildImmutableList(postAuthenticationFlowsLookupStrategy.apply(profileRequestContext));
     }
 
     /**
@@ -315,11 +262,11 @@ public class BrowserSSOProfileConfiguration extends AbstractSAML1ArtifactAwarePr
      * @param flows   flow identifiers to enable
      */
     public void setPostAuthenticationFlows(@Nullable @NonnullElements final Collection<String> flows) {
-
         if (flows != null) {
-            postAuthenticationFlows = new ArrayList<>(StringSupport.normalizeStringCollection(flows));
+            postAuthenticationFlowsLookupStrategy =
+                    FunctionSupport.constant(new ArrayList<>(StringSupport.normalizeStringCollection(flows)));
         } else {
-            postAuthenticationFlows = Collections.emptyList();
+            postAuthenticationFlowsLookupStrategy = FunctionSupport.constant(null);
         }
     }
 
@@ -331,14 +278,14 @@ public class BrowserSSOProfileConfiguration extends AbstractSAML1ArtifactAwarePr
      * @since 3.3.0
      */
     public void setPostAuthenticationFlowsLookupStrategy(
-            @Nullable final Function<ProfileRequestContext,Collection<String>> strategy) {
-        postAuthenticationFlowsLookupStrategy = strategy;
+            @Nonnull final Function<ProfileRequestContext,Collection<String>> strategy) {
+        postAuthenticationFlowsLookupStrategy = Constraint.isNotNull(strategy, "Lookup strategy cannot be null");
     }
 
     /** {@inheritDoc} */
-    @Override
-    @Nonnull @NonnullElements @NotLive @Unmodifiable public List<String> getNameIDFormatPrecedence() {
-        return ImmutableList.copyOf(getIndirectProperty(nameIDFormatPrecedenceLookupStrategy, nameIDFormatPrecedence));
+    @Nonnull @NonnullElements @NotLive @Unmodifiable public List<String> getNameIDFormatPrecedence(
+            @Nullable final ProfileRequestContext profileRequestContext) {
+        return CollectionSupport.buildImmutableList(nameIDFormatPrecedenceLookupStrategy.apply(profileRequestContext));
     }
 
     /**
@@ -349,7 +296,8 @@ public class BrowserSSOProfileConfiguration extends AbstractSAML1ArtifactAwarePr
     public void setNameIDFormatPrecedence(@Nonnull @NonnullElements final Collection<String> formats) {
         Constraint.isNotNull(formats, "List of formats cannot be null");
         
-        nameIDFormatPrecedence = new ArrayList<>(StringSupport.normalizeStringCollection(formats));
+        nameIDFormatPrecedenceLookupStrategy =
+                FunctionSupport.constant(new ArrayList<>(StringSupport.normalizeStringCollection(formats)));
     }
 
     /**
@@ -360,8 +308,8 @@ public class BrowserSSOProfileConfiguration extends AbstractSAML1ArtifactAwarePr
      * @since 3.3.0
      */
     public void setNameIDFormatPrecedenceLookupStrategy(
-            @Nullable final Function<ProfileRequestContext,Collection<String>> strategy) {
-        nameIDFormatPrecedenceLookupStrategy = strategy;
+            @Nonnull final Function<ProfileRequestContext,Collection<String>> strategy) {
+        nameIDFormatPrecedenceLookupStrategy = Constraint.isNotNull(strategy, "Lookup strategy cannot be null");
     }
-
+        
 }
\ No newline at end of file
diff --git a/idp-saml-api/src/main/java/net/shibboleth/idp/saml/saml2/profile/config/BrowserSSOProfileConfiguration.java b/idp-saml-api/src/main/java/net/shibboleth/idp/saml/saml2/profile/config/BrowserSSOProfileConfiguration.java
index 505f91c..d569022 100644
--- a/idp-saml-api/src/main/java/net/shibboleth/idp/saml/saml2/profile/config/BrowserSSOProfileConfiguration.java
+++ b/idp-saml-api/src/main/java/net/shibboleth/idp/saml/saml2/profile/config/BrowserSSOProfileConfiguration.java
@@ -21,7 +21,6 @@ import java.security.Principal;
 import java.time.Duration;
 import java.util.ArrayList;
 import java.util.Collection;
-import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
@@ -38,15 +37,15 @@ import net.shibboleth.utilities.java.support.annotation.constraint.NonnullElemen
 import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
 import net.shibboleth.utilities.java.support.annotation.constraint.NotLive;
 import net.shibboleth.utilities.java.support.annotation.constraint.Unmodifiable;
+import net.shibboleth.utilities.java.support.collection.CollectionSupport;
 import net.shibboleth.utilities.java.support.logic.Constraint;
+import net.shibboleth.utilities.java.support.logic.FunctionSupport;
 import net.shibboleth.utilities.java.support.primitive.StringSupport;
 
 import org.opensaml.profile.context.ProfileRequestContext;
 
 import com.google.common.base.Predicates;
 import com.google.common.collect.Collections2;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
 
 /** Configuration support for SAML 2 Browser SSO. */
 public class BrowserSSOProfileConfiguration extends AbstractSAML2ArtifactAwareProfileConfiguration
@@ -71,10 +70,7 @@ public class BrowserSSOProfileConfiguration extends AbstractSAML2ArtifactAwarePr
     @Nonnull private Predicate<ProfileRequestContext> skipEndpointValidationWhenSignedPredicate;
 
     /** Lookup function to supply {@link #maximumSPSessionLifetime} property. */
-    @Nullable private Function<ProfileRequestContext,Duration> maximumSPSessionLifetimeLookupStrategy;
-    
-    /** The maximum amount of time the service provider should maintain a session for the user. */
-    @Nullable private Duration maximumSPSessionLifetime;
+    @Nonnull private Function<ProfileRequestContext,Duration> maximumSPSessionLifetimeLookupStrategy;
 
     /** 
      * The predicate used to determine if produced assertions may be delegated.
@@ -82,35 +78,20 @@ public class BrowserSSOProfileConfiguration extends AbstractSAML2ArtifactAwarePr
     @Nonnull private Predicate<ProfileRequestContext> allowDelegationPredicate;
     
     /** Lookup function to supply {@link #maximumTokenDelegationChainLength} property. */
-    @Nullable private Function<ProfileRequestContext,Long> maximumTokenDelegationChainLengthLookupStrategy;
-    
-    /** Limits the total number of delegates that may be derived from the initial SAML token. Default value: 1. */
-    @NonNegative private long maximumTokenDelegationChainLength;
+    @Nonnull private Function<ProfileRequestContext,Long> maximumTokenDelegationChainLengthLookupStrategy;
 
     /** Lookup function to supply {@link #defaultAuthenticationContexts} property. */
-    @Nullable private Function<ProfileRequestContext,Collection<AuthnContextClassRefPrincipal>>
+    @Nonnull private Function<ProfileRequestContext,Collection<AuthnContextClassRefPrincipal>>
             defaultAuthenticationContextsLookupStrategy;
     
-    /** Selects, and limits, the authentication contexts to use for requests. */
-    @Nonnull @NonnullElements private List<AuthnContextClassRefPrincipal> defaultAuthenticationContexts;
-
     /** Lookup function to supply {@link #authenticationFlows} property. */
-    @Nullable private Function<ProfileRequestContext,Set<String>> authenticationFlowsLookupStrategy;
-
-    /** Filters the usable authentication flows. */
-    @Nonnull @NonnullElements private Set<String> authenticationFlows;
+    @Nonnull private Function<ProfileRequestContext,Set<String>> authenticationFlowsLookupStrategy;
     
     /** Lookup function to supply {@link #postAuthenticationFlows} property. */
-    @Nullable private Function<ProfileRequestContext,Collection<String>> postAuthenticationFlowsLookupStrategy;
-    
-    /** Enables post-authentication interceptor flows. */
-    @Nonnull @NonnullElements private List<String> postAuthenticationFlows;
+    @Nonnull private Function<ProfileRequestContext,Collection<String>> postAuthenticationFlowsLookupStrategy;
     
     /** Lookup function to supply {@link #nameIDFormatPrecedence} property. */
-    @Nullable private Function<ProfileRequestContext,Collection<String>> nameIDFormatPrecedenceLookupStrategy;
-    
-    /** Precedence of name identifier formats to use for requests. */
-    @Nonnull @NonnullElements private List<String> nameIDFormatPrecedence;
+    @Nonnull private Function<ProfileRequestContext,Collection<String>> nameIDFormatPrecedenceLookupStrategy;
     
     /** Constructor. */
     public BrowserSSOProfileConfiguration() {
@@ -124,72 +105,72 @@ public class BrowserSSOProfileConfiguration extends AbstractSAML2ArtifactAwarePr
      */
     protected BrowserSSOProfileConfiguration(@Nonnull @NotEmpty final String profileId) {
         super(profileId);
-        setSignResponses(Predicates.<ProfileRequestContext>alwaysTrue());
-        setEncryptAssertions(Predicates.<ProfileRequestContext>alwaysTrue());
+        setSignResponses(Predicates.alwaysTrue());
+        setEncryptAssertions(Predicates.alwaysTrue());
         resolveAttributesPredicate = Predicates.alwaysTrue();
         includeAttributeStatementPredicate = Predicates.alwaysTrue();
         forceAuthnPredicate = Predicates.alwaysFalse();
         skipEndpointValidationWhenSignedPredicate = Predicates.alwaysFalse();
-        maximumTokenDelegationChainLength = 1;
-        allowDelegationPredicate = Predicates.<ProfileRequestContext>alwaysFalse();
-        defaultAuthenticationContexts = Collections.emptyList();
-        authenticationFlows = Collections.emptySet();
-        postAuthenticationFlows = Collections.emptyList();
-        nameIDFormatPrecedence = Collections.emptyList();
+        maximumSPSessionLifetimeLookupStrategy = FunctionSupport.constant(null);
+        maximumTokenDelegationChainLengthLookupStrategy = FunctionSupport.constant(1L);
+        allowDelegationPredicate = Predicates.alwaysFalse();
+        authenticationFlowsLookupStrategy = FunctionSupport.constant(null);
+        postAuthenticationFlowsLookupStrategy = FunctionSupport.constant(null);
+        defaultAuthenticationContextsLookupStrategy = FunctionSupport.constant(null);
+        nameIDFormatPrecedenceLookupStrategy = FunctionSupport.constant(null);
     }
     
     /**
-     * Set whether attributes should be resolved during the profile.
+     * Get whether attributes should be resolved during the profile.
+     *
+     * <p>Default is true</p>
      * 
-     * @param flag flag to set
+     * @param profileRequestContext current profile request context
+     * 
+     * @return true iff attributes should be resolved
      */
-    public void setResolveAttributes(final boolean flag) {
-        resolveAttributesPredicate = flag ? Predicates.<ProfileRequestContext>alwaysTrue()
-                : Predicates.<ProfileRequestContext>alwaysFalse();
+    public boolean isResolveAttributes(@Nullable final ProfileRequestContext profileRequestContext) {
+        return resolveAttributesPredicate.test(profileRequestContext);
     }
-
+    
     /**
-     * Get a condition to determine whether attributes should be resolved during the profile.
-     * 
-     * @return condition
+     * Set whether attributes should be resolved during the profile.
      * 
-     * @since 3.3.0
+     * @param flag flag to set
      */
-    @Nonnull public Predicate<ProfileRequestContext> getResolveAttributesPredicate() {
-        return resolveAttributesPredicate;
+    public void setResolveAttributes(final boolean flag) {
+        resolveAttributesPredicate = flag ? Predicates.alwaysTrue() : Predicates.alwaysFalse();
     }
     
     /**
      * Set a condition to determine whether attributes should be resolved during the profile.
-     *
-     * @param condition  condition to set
      * 
-     * @since 3.3.0
+     * @param condition condition to set
      */
     public void setResolveAttributesPredicate(@Nonnull final Predicate<ProfileRequestContext> condition) {
         resolveAttributesPredicate = Constraint.isNotNull(condition, "Resolve attributes predicate cannot be null");
     }
 
     /**
-     * Set whether responses to the authentication request should include an attribute statement.
+     * Get whether responses to the authentication request should include an attribute statement.
+     *
+     * <p>Default is true</p>
      * 
-     * @param include flag to set
+     * @param profileRequestContext current profile request context
+     *
+     * @return whether responses to the authentication request should include an attribute statement
      */
-    public void setIncludeAttributeStatement(final boolean include) {
-        includeAttributeStatementPredicate = include ? Predicates.<ProfileRequestContext>alwaysTrue()
-                : Predicates.<ProfileRequestContext>alwaysFalse();
+    public boolean isIncludeAttributeStatement(@Nullable final ProfileRequestContext profileRequestContext) {
+        return includeAttributeStatementPredicate.test(profileRequestContext);
     }
 
     /**
-     * Get a condition to determine whether responses to the authentication request should include an
-     * attribute statement.
-     * 
-     * @return condition
-     * 
-     * @since 3.3.0
+     * Set whether responses to the authentication request should include an attribute statement.
+     *
+     * @param flag flag to set
      */
-    @Nonnull public Predicate<ProfileRequestContext> getIncludeAttributeStatementPredicate() {
-        return includeAttributeStatementPredicate;
+    public void setIncludeAttributeStatement(final boolean flag) {
+        includeAttributeStatementPredicate = flag ? Predicates.alwaysTrue() : Predicates.alwaysFalse();
     }
     
     /**
@@ -197,90 +178,81 @@ public class BrowserSSOProfileConfiguration extends AbstractSAML2ArtifactAwarePr
      * attribute statement.
      *
      * @param condition  condition to set
-     * 
-     * @since 3.3.0
      */
     public void setIncludeAttributeStatementPredicate(@Nonnull final Predicate<ProfileRequestContext> condition) {
         includeAttributeStatementPredicate = Constraint.isNotNull(condition,
                 "Include attribute statement predicate cannot be null");
     }
-
+    
+    /** {@inheritDoc} */
+    public boolean isForceAuthn(@Nullable final ProfileRequestContext profileRequestContext) {
+        return forceAuthnPredicate.test(profileRequestContext);
+    }
+    
     /**
-     * Get a condition to determine whether a fresh user presence proof should be required for this request.
-     * 
-     * @return condition
+     * Set whether a fresh user presence proof should be required for this request.
      * 
-     * @since 3.4.0
+     * @param flag flag to set
      */
-    @Nonnull public Predicate<ProfileRequestContext> getForceAuthnPredicate() {
-        return forceAuthnPredicate;
+    public void setForceAuthn(final boolean flag) {
+        forceAuthnPredicate = flag ? Predicates.alwaysTrue() : Predicates.alwaysFalse();
     }
     
     /**
      * Set a condition to determine whether a fresh user presence proof should be required for this request.
      * 
      * @param condition condition to set
-     * 
-     * @since 3.4.0
      */
     public void setForceAuthnPredicate(@Nonnull final Predicate<ProfileRequestContext> condition) {
         forceAuthnPredicate = Constraint.isNotNull(condition, "Forced authentication predicate cannot be null");
     }
     
     /**
-     * Set whether a fresh user presence proof should be required for this request.
+     * Get condition to determine whether the response endpoint should be validated if the request is signed.
      * 
-     * @param flag flag to set
+     * @param profileRequestContext current profile request context
      * 
-     * @since 3.4.0
-     */
-    public void setForceAuthn(final boolean flag) {
-        forceAuthnPredicate = flag ? Predicates.<ProfileRequestContext>alwaysTrue()
-                : Predicates.<ProfileRequestContext>alwaysFalse();
-    }
-    
-    /**
-     * Set whether the response endpoint should be validated if the request is signed.
+     * @return condition
      * 
-     * @param skip whether the response endpoint should be validated if the request is signed
+     * @since 4.0.0
      */
-    public void setSkipEndpointValidationWhenSigned(final boolean skip) {
-        skipEndpointValidationWhenSignedPredicate = skip ? Predicates.<ProfileRequestContext>alwaysTrue()
-                : Predicates.<ProfileRequestContext>alwaysFalse();
+    public boolean isSkipEndpointValidationWhenSigned(@Nullable final ProfileRequestContext profileRequestContext) {
+        return skipEndpointValidationWhenSignedPredicate.test(profileRequestContext);
     }
     
     /**
-     * Get condition to determine whether the response endpoint should be validated if the request is signed.
+     * Set whether the response endpoint should be validated if the request is signed.
      * 
-     * @return condition
+     * @param flag flag to set
      * 
-     * @since 3.3.0
+     * @since 3.4.0
      */
-    @Nonnull public Predicate<ProfileRequestContext> getSkipEndpointValidationWhenSignedPredicate() {
-        return skipEndpointValidationWhenSignedPredicate;
+    public void setSkipEndpointValidationWhenSigned(final boolean flag) {
+        skipEndpointValidationWhenSignedPredicate = flag ? Predicates.alwaysTrue() : Predicates.alwaysFalse();
     }
-
+    
     /**
      * Set condition to determine whether the response endpoint should be validated if the request is signed.
      * 
      * @param condition condition to set
      * 
-     * @since 3.3.0
+     * @since 3.4.0
      */
     public void setSkipEndpointValidationWhenSignedPredicate(
             @Nonnull final Predicate<ProfileRequestContext> condition) {
-        skipEndpointValidationWhenSignedPredicate = Constraint.isNotNull(condition,
-                "Skip endpoint validation predicate cannot be null");
+        skipEndpointValidationWhenSignedPredicate = Constraint.isNotNull(condition, "Condition cannot be null");
     }
 
     /**
      * Get the maximum amount of time the service provider should maintain a session for the user
      * based on the authentication assertion. A null or 0 is interpreted as an unlimited lifetime.
      * 
+     * @param profileRequestContext current profile request context
+     * 
      * @return max lifetime of service provider should maintain a session
      */
-    @Nullable public Duration getMaximumSPSessionLifetime() {
-        return getIndirectProperty(maximumSPSessionLifetimeLookupStrategy, maximumSPSessionLifetime);
+    @Nullable public Duration getMaximumSPSessionLifetime(@Nullable final ProfileRequestContext profileRequestContext) {
+        return maximumSPSessionLifetimeLookupStrategy.apply(profileRequestContext);
     }
 
     /**
@@ -293,7 +265,7 @@ public class BrowserSSOProfileConfiguration extends AbstractSAML2ArtifactAwarePr
         Constraint.isFalse(lifetime != null && lifetime.isNegative(),
                 "Maximum SP session lifetime must be greater than or equal to 0");
         
-        maximumSPSessionLifetime = lifetime;
+        maximumSPSessionLifetimeLookupStrategy = FunctionSupport.constant(lifetime);
     }
     
     /**
@@ -301,39 +273,55 @@ public class BrowserSSOProfileConfiguration extends AbstractSAML2ArtifactAwarePr
      * 
      * @param strategy  lookup strategy
      * 
-     * @since 3.3.0
+     * @since 3.4.0
      */
     public void setMaximumSPSessionLifetimeLookupStrategy(
-            @Nullable final Function<ProfileRequestContext,Duration> strategy) {
-        maximumSPSessionLifetimeLookupStrategy = strategy;
+            @Nonnull final Function<ProfileRequestContext,Duration> strategy) {
+        maximumSPSessionLifetimeLookupStrategy = Constraint.isNotNull(strategy, "Lookup strategy cannot be null");
     }
     
     /**
      * Get the predicate used to determine if produced assertions may be delegated.
      * 
+     * @param profileRequestContext current profile request context
+     * 
      * @return predicate used to determine if produced assertions may be delegated
      */
-    @Nonnull public Predicate<ProfileRequestContext> getAllowDelegation() {
-        return allowDelegationPredicate;
+    @Nonnull public boolean isAllowDelegation(@Nullable final ProfileRequestContext profileRequestContext) {
+        return allowDelegationPredicate.test(profileRequestContext);
     }
+    
+
+    /**
+     * Set whether produced assertions may be delegated.
+     * 
+     * @param  flag flag to set
+     */
+    public void setAllowDelegation(final boolean flag) {
+        allowDelegationPredicate = flag ? Predicates.alwaysTrue() : Predicates.alwaysFalse();
+    }    
 
     /**
      * Set the predicate used to determine if produced assertions may be delegated.
      * 
      * @param  predicate used to determine if produced assertions may be delegated
      */
-    public void setAllowDelegation(@Nonnull final Predicate<ProfileRequestContext> predicate) {
+    public void setAllowDelegationPredicate(@Nonnull final Predicate<ProfileRequestContext> predicate) {
         allowDelegationPredicate = Constraint.isNotNull(predicate, "Allow delegation predicate cannot be null");
     }
 
     /**
      * Get the limits on the total number of delegates that may be derived from the initial SAML token.
      * 
+     * @param profileRequestContext current profile request context
+     * 
      * @return the limit on the total number of delegates that may be derived from the initial SAML token
      */
-    @NonNegative public long getMaximumTokenDelegationChainLength() {
-        return Constraint.isGreaterThanOrEqual(0,
-                getIndirectProperty(maximumTokenDelegationChainLengthLookupStrategy, maximumTokenDelegationChainLength),
+    @NonNegative public long getMaximumTokenDelegationChainLength(
+            @Nullable final ProfileRequestContext profileRequestContext) {
+        
+        final Long len = maximumTokenDelegationChainLengthLookupStrategy.apply(profileRequestContext);
+        return Constraint.isGreaterThanOrEqual(0, len != null ? len : 1L,
                 "Delegation chain length must be greater than or equal to 0");
     }
 
@@ -343,8 +331,9 @@ public class BrowserSSOProfileConfiguration extends AbstractSAML2ArtifactAwarePr
      * @param length the limit on the total number of delegates that may be derived from the initial SAML token
      */
     public void setMaximumTokenDelegationChainLength(@NonNegative final long length) {
-        maximumTokenDelegationChainLength = Constraint.isGreaterThanOrEqual(0, length,
-                "Delegation chain length must be greater than or equal to 0");
+        Constraint.isGreaterThanOrEqual(0, length, "Delegation chain length must be greater than or equal to 0");
+        
+        maximumTokenDelegationChainLengthLookupStrategy = FunctionSupport.constant(length);
     }
     
     /**
@@ -352,18 +341,19 @@ public class BrowserSSOProfileConfiguration extends AbstractSAML2ArtifactAwarePr
      * 
      * @param strategy  lookup strategy
      * 
-     * @since 3.3.0
+     * @since 3.4.0
      */
     public void setMaximumTokenDelegationChainLengthLookupStrategy(
-            @Nullable final Function<ProfileRequestContext,Long> strategy) {
-        maximumTokenDelegationChainLengthLookupStrategy = strategy;
+            @Nonnull final Function<ProfileRequestContext,Long> strategy) {
+        maximumTokenDelegationChainLengthLookupStrategy =
+                Constraint.isNotNull(strategy, "Lookup strategy cannot be null");
     }
 
     /** {@inheritDoc} */
-    @Override
-    @Nonnull @NonnullElements @NotLive @Unmodifiable public List<Principal> getDefaultAuthenticationMethods() {
-        return ImmutableList.<Principal>copyOf(getIndirectProperty(defaultAuthenticationContextsLookupStrategy,
-                defaultAuthenticationContexts));
+    @Nonnull @NonnullElements @NotLive @Unmodifiable public List<Principal> getDefaultAuthenticationMethods(
+            @Nullable final ProfileRequestContext profileRequestContext) {
+        return CollectionSupport.buildImmutableList(
+                defaultAuthenticationContextsLookupStrategy.apply(profileRequestContext));
     }
         
     /**
@@ -374,28 +364,29 @@ public class BrowserSSOProfileConfiguration extends AbstractSAML2ArtifactAwarePr
     public void setDefaultAuthenticationMethods(
             @Nullable @NonnullElements final Collection<AuthnContextClassRefPrincipal> contexts) {
         if (contexts != null) {
-            defaultAuthenticationContexts = new ArrayList<>(Collections2.filter(contexts, Predicates.notNull()));
+            defaultAuthenticationContextsLookupStrategy =
+                    FunctionSupport.constant(new ArrayList<>(Collections2.filter(contexts, Predicates.notNull())));
         } else {
-            defaultAuthenticationContexts = Collections.emptyList();
+            defaultAuthenticationContextsLookupStrategy = FunctionSupport.constant(null);
         }
     }
-    
+
     /**
-     * Set a lookup strategy for the <code>defaultAuthenticationMethods</code> property.
+     * Set a lookup strategy for the {@link #defaultAuthenticationContexts} property.
      *
      * @param strategy  lookup strategy
      * 
      * @since 3.3.0
      */
     public void setDefaultAuthenticationMethodsLookupStrategy(
-            @Nullable final Function<ProfileRequestContext,Collection<AuthnContextClassRefPrincipal>> strategy) {
-        defaultAuthenticationContextsLookupStrategy = strategy;
+            @Nonnull final Function<ProfileRequestContext,Collection<AuthnContextClassRefPrincipal>> strategy) {
+        defaultAuthenticationContextsLookupStrategy = Constraint.isNotNull(strategy, "Lookup strategy cannot be null");
     }
 
     /** {@inheritDoc} */
-    @Override
-    @Nonnull @NonnullElements @NotLive @Unmodifiable public Set<String> getAuthenticationFlows() {
-        return ImmutableSet.copyOf(getIndirectProperty(authenticationFlowsLookupStrategy, authenticationFlows));
+    @Nonnull @NonnullElements @NotLive @Unmodifiable public Set<String> getAuthenticationFlows(
+            @Nullable final ProfileRequestContext profileRequestContext) {
+        return CollectionSupport.buildImmutableSet(authenticationFlowsLookupStrategy.apply(profileRequestContext));
     }
 
     /**
@@ -404,31 +395,30 @@ public class BrowserSSOProfileConfiguration extends AbstractSAML2ArtifactAwarePr
      * @param flows   flow identifiers to use
      */
     public void setAuthenticationFlows(@Nullable @NonnullElements final Collection<String> flows) {
-
         if (flows != null) {
-            authenticationFlows = new HashSet<>(StringSupport.normalizeStringCollection(flows));
+            authenticationFlowsLookupStrategy =
+                    FunctionSupport.constant(new HashSet<>(StringSupport.normalizeStringCollection(flows)));
         } else {
-            authenticationFlows = Collections.emptySet();
+            authenticationFlowsLookupStrategy = FunctionSupport.constant(null);
         }
     }
 
     /**
-     * Set a lookup strategy for the <code>authenticationFlows</code> property.
+     * Set a lookup strategy for the {@link #authenticationFlows} property.
      *
      * @param strategy  lookup strategy
      * 
      * @since 3.3.0
      */
     public void setAuthenticationFlowsLookupStrategy(
-            @Nullable final Function<ProfileRequestContext,Set<String>> strategy) {
-        authenticationFlowsLookupStrategy = strategy;
+            @Nonnull final Function<ProfileRequestContext,Set<String>> strategy) {
+        authenticationFlowsLookupStrategy = Constraint.isNotNull(strategy, "Lookup strategy cannot be null");
     }
 
     /** {@inheritDoc} */
-    @Override
-    @Nonnull @NonnullElements @NotLive @Unmodifiable public List<String> getPostAuthenticationFlows() {
-        return ImmutableList.copyOf(
-                getIndirectProperty(postAuthenticationFlowsLookupStrategy, postAuthenticationFlows));
+    @Nonnull @NonnullElements @NotLive @Unmodifiable public List<String> getPostAuthenticationFlows(
+            @Nullable final ProfileRequestContext profileRequestContext) {
+        return CollectionSupport.buildImmutableList(postAuthenticationFlowsLookupStrategy.apply(profileRequestContext));
     }
 
     /**
@@ -437,11 +427,11 @@ public class BrowserSSOProfileConfiguration extends AbstractSAML2ArtifactAwarePr
      * @param flows   flow identifiers to enable
      */
     public void setPostAuthenticationFlows(@Nullable @NonnullElements final Collection<String> flows) {
-
         if (flows != null) {
-            postAuthenticationFlows = new ArrayList<>(StringSupport.normalizeStringCollection(flows));
+            postAuthenticationFlowsLookupStrategy =
+                    FunctionSupport.constant(new ArrayList<>(StringSupport.normalizeStringCollection(flows)));
         } else {
-            postAuthenticationFlows = Collections.emptyList();
+            postAuthenticationFlowsLookupStrategy = FunctionSupport.constant(null);
         }
     }
 
@@ -453,14 +443,14 @@ public class BrowserSSOProfileConfiguration extends AbstractSAML2ArtifactAwarePr
      * @since 3.3.0
      */
     public void setPostAuthenticationFlowsLookupStrategy(
-            @Nullable final Function<ProfileRequestContext,Collection<String>> strategy) {
-        postAuthenticationFlowsLookupStrategy = strategy;
+            @Nonnull final Function<ProfileRequestContext,Collection<String>> strategy) {
+        postAuthenticationFlowsLookupStrategy = Constraint.isNotNull(strategy, "Lookup strategy cannot be null");
     }
 
     /** {@inheritDoc} */
-    @Override
-    @Nonnull @NonnullElements @NotLive @Unmodifiable public List<String> getNameIDFormatPrecedence() {
-        return ImmutableList.copyOf(getIndirectProperty(nameIDFormatPrecedenceLookupStrategy, nameIDFormatPrecedence));
+    @Nonnull @NonnullElements @NotLive @Unmodifiable public List<String> getNameIDFormatPrecedence(
+            @Nullable final ProfileRequestContext profileRequestContext) {
+        return CollectionSupport.buildImmutableList(nameIDFormatPrecedenceLookupStrategy.apply(profileRequestContext));
     }
 
     /**
@@ -471,7 +461,8 @@ public class BrowserSSOProfileConfiguration extends AbstractSAML2ArtifactAwarePr
     public void setNameIDFormatPrecedence(@Nonnull @NonnullElements final Collection<String> formats) {
         Constraint.isNotNull(formats, "List of formats cannot be null");
         
-        nameIDFormatPrecedence = new ArrayList<>(StringSupport.normalizeStringCollection(formats));
+        nameIDFormatPrecedenceLookupStrategy =
+                FunctionSupport.constant(new ArrayList<>(StringSupport.normalizeStringCollection(formats)));
     }
 
     /**
@@ -482,8 +473,8 @@ public class BrowserSSOProfileConfiguration extends AbstractSAML2ArtifactAwarePr
      * @since 3.3.0
      */
     public void setNameIDFormatPrecedenceLookupStrategy(
-            @Nullable final Function<ProfileRequestContext,Collection<String>> strategy) {
-        nameIDFormatPrecedenceLookupStrategy = strategy;
+            @Nonnull final Function<ProfileRequestContext,Collection<String>> strategy) {
+        nameIDFormatPrecedenceLookupStrategy = Constraint.isNotNull(strategy, "Lookup strategy cannot be null");
     }
-    
+
 }
\ No newline at end of file
diff --git a/idp-saml-api/src/test/java/net/shibboleth/idp/saml/saml1/profile/SAML1ActionSupportTest.java b/idp-saml-api/src/test/java/net/shibboleth/idp/saml/saml1/profile/SAML1ActionSupportTest.java
index e268919..7158075 100644
--- a/idp-saml-api/src/test/java/net/shibboleth/idp/saml/saml1/profile/SAML1ActionSupportTest.java
+++ b/idp-saml-api/src/test/java/net/shibboleth/idp/saml/saml1/profile/SAML1ActionSupportTest.java
@@ -67,13 +67,13 @@ public class SAML1ActionSupportTest extends OpenSAMLInitBaseTestCase {
 
         Assert.assertEquals(response.getAssertions().size(), 0, "Expected zarro assertions before insert");
         Assertion assertion = SAML1ActionSupport.addAssertionToResponse(action, response,
-                relyingPartyCtx.getProfileConfig().getSecurityConfiguration().getIdGenerator(),
-                relyingPartyCtx.getConfiguration().getResponderId());
+                relyingPartyCtx.getProfileConfig().getSecurityConfiguration(profileRequestContext).getIdGenerator(),
+                relyingPartyCtx.getConfiguration().getResponderId(profileRequestContext));
         Assert.assertEquals(response.getAssertions().size(), 1, "Expected but one assertion after insert");
         Assert.assertTrue(response.getAssertions().contains(assertion), "Inserted assertion should be there");
         Assertion second = SAML1ActionSupport.addAssertionToResponse(action, response,
-                relyingPartyCtx.getProfileConfig().getSecurityConfiguration().getIdGenerator(),
-                relyingPartyCtx.getConfiguration().getResponderId());
+                relyingPartyCtx.getProfileConfig().getSecurityConfiguration(profileRequestContext).getIdGenerator(),
+                relyingPartyCtx.getConfiguration().getResponderId(profileRequestContext));
         Assert.assertEquals(response.getAssertions().size(), 2, "Expected two assertions after two inserts");
         Assert.assertTrue(response.getAssertions().contains(assertion), "Inserted assertion should be there");
         Assert.assertNotSame(second, assertion, "Two separate assertions should have been added");
diff --git a/idp-saml-api/src/test/java/net/shibboleth/idp/saml/saml1/profile/SAML1ActionTestingSupport.java b/idp-saml-api/src/test/java/net/shibboleth/idp/saml/saml1/profile/SAML1ActionTestingSupport.java
index c1f4ad2..27685a1 100644
--- a/idp-saml-api/src/test/java/net/shibboleth/idp/saml/saml1/profile/SAML1ActionTestingSupport.java
+++ b/idp-saml-api/src/test/java/net/shibboleth/idp/saml/saml1/profile/SAML1ActionTestingSupport.java
@@ -74,7 +74,7 @@ public final class SAML1ActionTestingSupport extends org.opensaml.saml.saml1.pro
 
         RelyingPartyContext subcontext = parent.getSubcontext(RelyingPartyContext.class, true);
         subcontext.setRelyingPartyId(id);
-        subcontext.setProfileConfig(rpConfig.getProfileConfiguration(BrowserSSOProfileConfiguration.PROFILE_ID));
+        subcontext.setProfileConfig(rpConfig.getProfileConfiguration(null, BrowserSSOProfileConfiguration.PROFILE_ID));
         subcontext.setConfiguration(rpConfig);
 
         return subcontext;
diff --git a/idp-saml-api/src/test/java/net/shibboleth/idp/saml/saml1/profile/config/BrowserSSOProfileConfigurationTest.java b/idp-saml-api/src/test/java/net/shibboleth/idp/saml/saml1/profile/config/BrowserSSOProfileConfigurationTest.java
index f34113e..f596247 100644
--- a/idp-saml-api/src/test/java/net/shibboleth/idp/saml/saml1/profile/config/BrowserSSOProfileConfigurationTest.java
+++ b/idp-saml-api/src/test/java/net/shibboleth/idp/saml/saml1/profile/config/BrowserSSOProfileConfigurationTest.java
@@ -42,42 +42,38 @@ public class BrowserSSOProfileConfigurationTest {
         Assert.assertEquals(config.getId(), BrowserSSOProfileConfiguration.PROFILE_ID);
     }
     
-    @SuppressWarnings("deprecation")
     @Test
     public void testResolveAttributes(){
         final BrowserSSOProfileConfiguration config = new BrowserSSOProfileConfiguration();
-        Assert.assertTrue(config.resolveAttributes());
+        Assert.assertTrue(config.isResolveAttributes(null));
         
         config.setResolveAttributes(false);
-        Assert.assertFalse(config.resolveAttributes());
+        Assert.assertFalse(config.isResolveAttributes(null));
     }
 
-    @SuppressWarnings("deprecation")
     @Test
     public void testIndirectResolveAttributes(){
         final BrowserSSOProfileConfiguration config = new BrowserSSOProfileConfiguration();
 
-        config.setResolveAttributesPredicate(Predicates.<ProfileRequestContext>alwaysFalse());
-        Assert.assertFalse(config.resolveAttributes());
+        config.setResolveAttributesPredicate(Predicates.alwaysFalse());
+        Assert.assertFalse(config.isResolveAttributes(null));
     }
 
-    @SuppressWarnings("deprecation")
     @Test
     public void testIncludeAttributeStatement(){
         final BrowserSSOProfileConfiguration config = new BrowserSSOProfileConfiguration();
-        Assert.assertFalse(config.includeAttributeStatement());
+        Assert.assertFalse(config.isIncludeAttributeStatement(null));
 
         config.setIncludeAttributeStatement(true);
-        Assert.assertTrue(config.includeAttributeStatement());
+        Assert.assertTrue(config.isIncludeAttributeStatement(null));
     }
 
-    @SuppressWarnings("deprecation")
     @Test
     public void testIndirectIncludeAttributeStatement(){
         final BrowserSSOProfileConfiguration config = new BrowserSSOProfileConfiguration();
 
-        config.setIncludeAttributeStatementPredicate(Predicates.<ProfileRequestContext>alwaysTrue());
-        Assert.assertTrue(config.includeAttributeStatement());
+        config.setIncludeAttributeStatementPredicate(Predicates.alwaysTrue());
+        Assert.assertTrue(config.isIncludeAttributeStatement(null));
     }
 
     @Test
@@ -105,14 +101,14 @@ public class BrowserSSOProfileConfigurationTest {
     @Test
     public void testDefaultAuthenticationMethods() {
         final BrowserSSOProfileConfiguration config = new BrowserSSOProfileConfiguration();
-        Assert.assertTrue(config.getDefaultAuthenticationMethods().isEmpty());
+        Assert.assertTrue(config.getDefaultAuthenticationMethods(null).isEmpty());
 
         final List<AuthenticationMethodPrincipal> principals = new ArrayList<>();
         principals.add(new AuthenticationMethodPrincipal("foo"));
         principals.add(new AuthenticationMethodPrincipal("bar"));
 
         config.setDefaultAuthenticationMethods(principals);
-        Assert.assertEquals(config.getDefaultAuthenticationMethods(), principals);
+        Assert.assertEquals(config.getDefaultAuthenticationMethods(null), principals);
     }
 
     @Test
@@ -123,22 +119,21 @@ public class BrowserSSOProfileConfigurationTest {
         principals.add(new AuthenticationMethodPrincipal("foo"));
         principals.add(new AuthenticationMethodPrincipal("bar"));
 
-        config.setDefaultAuthenticationMethodsLookupStrategy(
-                FunctionSupport.<ProfileRequestContext,Collection<AuthenticationMethodPrincipal>>constant(principals));
-        Assert.assertEquals(config.getDefaultAuthenticationMethods(), principals);
+        config.setDefaultAuthenticationMethodsLookupStrategy(FunctionSupport.constant(principals));
+        Assert.assertEquals(config.getDefaultAuthenticationMethods(null), principals);
     }
 
     @Test
     public void testAuthenticationFlows() {
         final BrowserSSOProfileConfiguration config = new BrowserSSOProfileConfiguration();
-        Assert.assertTrue(config.getAuthenticationFlows().isEmpty());
+        Assert.assertTrue(config.getAuthenticationFlows(null).isEmpty());
 
         final Set<String> flows = new HashSet<>();
         flows.add("foo");
         flows.add("bar");
 
         config.setAuthenticationFlows(flows);
-        Assert.assertEquals(config.getAuthenticationFlows(), flows);
+        Assert.assertEquals(config.getAuthenticationFlows(null), flows);
     }
 
     @Test
@@ -149,22 +144,21 @@ public class BrowserSSOProfileConfigurationTest {
         flows.add("foo");
         flows.add("bar");
 
-        config.setAuthenticationFlowsLookupStrategy(
-                FunctionSupport.<ProfileRequestContext,Set<String>>constant(flows));
-        Assert.assertEquals(config.getAuthenticationFlows(), flows);
+        config.setAuthenticationFlowsLookupStrategy(FunctionSupport.constant(flows));
+        Assert.assertEquals(config.getAuthenticationFlows(null), flows);
     }
 
     @Test
     public void testPostAuthenticationFlows() {
         final BrowserSSOProfileConfiguration config = new BrowserSSOProfileConfiguration();
-        Assert.assertTrue(config.getPostAuthenticationFlows().isEmpty());
+        Assert.assertTrue(config.getPostAuthenticationFlows(null).isEmpty());
 
         final List<String> flows = new ArrayList<>();
         flows.add("foo");
         flows.add("bar");
 
         config.setPostAuthenticationFlows(flows);
-        Assert.assertEquals(config.getPostAuthenticationFlows(), flows);
+        Assert.assertEquals(config.getPostAuthenticationFlows(null), flows);
     }
 
     @Test
@@ -175,22 +169,21 @@ public class BrowserSSOProfileConfigurationTest {
         flows.add("foo");
         flows.add("bar");
 
-        config.setPostAuthenticationFlowsLookupStrategy(
-                FunctionSupport.<ProfileRequestContext,Collection<String>>constant(flows));
-        Assert.assertEquals(config.getPostAuthenticationFlows(), flows);
+        config.setPostAuthenticationFlowsLookupStrategy(FunctionSupport.constant(flows));
+        Assert.assertEquals(config.getPostAuthenticationFlows(null), flows);
     }
 
     @Test
     public void testNameIDFormatPrecedence() {
         final BrowserSSOProfileConfiguration config = new BrowserSSOProfileConfiguration();
-        Assert.assertTrue(config.getNameIDFormatPrecedence().isEmpty());
+        Assert.assertTrue(config.getNameIDFormatPrecedence(null).isEmpty());
 
         final List<String> formats = new ArrayList<>();
         formats.add("foo");
         formats.add("bar");
 
         config.setNameIDFormatPrecedence(formats);
-        Assert.assertEquals(config.getNameIDFormatPrecedence(), formats);
+        Assert.assertEquals(config.getNameIDFormatPrecedence(null), formats);
     }
 
     @Test
@@ -201,9 +194,8 @@ public class BrowserSSOProfileConfigurationTest {
         formats.add("foo");
         formats.add("bar");
 
-        config.setNameIDFormatPrecedenceLookupStrategy(
-                FunctionSupport.<ProfileRequestContext,Collection<String>>constant(formats));
-        Assert.assertEquals(config.getNameIDFormatPrecedence(), formats);
+        config.setNameIDFormatPrecedenceLookupStrategy(FunctionSupport.constant(formats));
+        Assert.assertEquals(config.getNameIDFormatPrecedence(null), formats);
     }
 
 }
\ No newline at end of file
diff --git a/idp-saml-api/src/test/java/net/shibboleth/idp/saml/saml2/profile/SAML2ActionSupportTest.java b/idp-saml-api/src/test/java/net/shibboleth/idp/saml/saml2/profile/SAML2ActionSupportTest.java
index 3854873..b51c9c8 100644
--- a/idp-saml-api/src/test/java/net/shibboleth/idp/saml/saml2/profile/SAML2ActionSupportTest.java
+++ b/idp-saml-api/src/test/java/net/shibboleth/idp/saml/saml2/profile/SAML2ActionSupportTest.java
@@ -67,13 +67,13 @@ public class SAML2ActionSupportTest extends OpenSAMLInitBaseTestCase {
 
         Assert.assertEquals(response.getAssertions().size(), 0, "Expected zarro assertions before insert");
         Assertion assertion = SAML2ActionSupport.addAssertionToResponse(action, response,
-                relyingPartyCtx.getProfileConfig().getSecurityConfiguration().getIdGenerator(),
-                relyingPartyCtx.getConfiguration().getResponderId());
+                relyingPartyCtx.getProfileConfig().getSecurityConfiguration(profileRequestContext).getIdGenerator(),
+                relyingPartyCtx.getConfiguration().getResponderId(profileRequestContext));
         Assert.assertEquals(response.getAssertions().size(), 1, "Expected but one assertion after insert");
         Assert.assertTrue(response.getAssertions().contains(assertion), "Inserted assertion should be there");
         Assertion second = SAML2ActionSupport.addAssertionToResponse(action, response,
-                relyingPartyCtx.getProfileConfig().getSecurityConfiguration().getIdGenerator(),
-                relyingPartyCtx.getConfiguration().getResponderId());
+                relyingPartyCtx.getProfileConfig().getSecurityConfiguration(profileRequestContext).getIdGenerator(),
+                relyingPartyCtx.getConfiguration().getResponderId(profileRequestContext));
         Assert.assertEquals(response.getAssertions().size(), 2, "Expected two assertions after two inserts");
         Assert.assertTrue(response.getAssertions().contains(assertion), "Inserted assertion should be there");
         Assert.assertNotSame(second, assertion, "Two separate assertions should have been added");
diff --git a/idp-saml-api/src/test/java/net/shibboleth/idp/saml/saml2/profile/SAML2ActionTestingSupport.java b/idp-saml-api/src/test/java/net/shibboleth/idp/saml/saml2/profile/SAML2ActionTestingSupport.java
index 3a2fae7..a6d712b 100644
--- a/idp-saml-api/src/test/java/net/shibboleth/idp/saml/saml2/profile/SAML2ActionTestingSupport.java
+++ b/idp-saml-api/src/test/java/net/shibboleth/idp/saml/saml2/profile/SAML2ActionTestingSupport.java
@@ -74,7 +74,7 @@ public final class SAML2ActionTestingSupport extends org.opensaml.saml.saml2.pro
 
         RelyingPartyContext subcontext = parent.getSubcontext(RelyingPartyContext.class, true);
         subcontext.setRelyingPartyId(id);
-        subcontext.setProfileConfig(rpConfig.getProfileConfiguration(BrowserSSOProfileConfiguration.PROFILE_ID));
+        subcontext.setProfileConfig(rpConfig.getProfileConfiguration(null, BrowserSSOProfileConfiguration.PROFILE_ID));
         subcontext.setConfiguration(rpConfig);
 
         return subcontext;
diff --git a/idp-saml-api/src/test/java/net/shibboleth/idp/saml/saml2/profile/config/BrowserSSOProfileConfigurationTest.java b/idp-saml-api/src/test/java/net/shibboleth/idp/saml/saml2/profile/config/BrowserSSOProfileConfigurationTest.java
index 89428da..b7b1135 100644
--- a/idp-saml-api/src/test/java/net/shibboleth/idp/saml/saml2/profile/config/BrowserSSOProfileConfigurationTest.java
+++ b/idp-saml-api/src/test/java/net/shibboleth/idp/saml/saml2/profile/config/BrowserSSOProfileConfigurationTest.java
@@ -25,7 +25,6 @@ import net.shibboleth.utilities.java.support.logic.FunctionSupport;
 
 import java.time.Duration;
 import java.util.ArrayList;
-import java.util.Collection;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
@@ -52,10 +51,10 @@ public class BrowserSSOProfileConfigurationTest {
     @Test
     public void testResolveAttributes(){
         final BrowserSSOProfileConfiguration config = new BrowserSSOProfileConfiguration();
-        Assert.assertTrue(config.getResolveAttributesPredicate().test(null));
+        Assert.assertTrue(config.isResolveAttributes(null));
         
         config.setResolveAttributes(false);
-        Assert.assertFalse(config.getResolveAttributesPredicate().test(null));
+        Assert.assertFalse(config.isResolveAttributes(null));
     }
 
     @Test
@@ -63,16 +62,16 @@ public class BrowserSSOProfileConfigurationTest {
         final BrowserSSOProfileConfiguration config = new BrowserSSOProfileConfiguration();
 
         config.setResolveAttributesPredicate(Predicates.alwaysFalse());
-        Assert.assertFalse(config.getResolveAttributesPredicate().test(null));
+        Assert.assertFalse(config.isResolveAttributes(null));
     }
 
     @Test
     public void testIncludeAttributeStatement(){
         final BrowserSSOProfileConfiguration config = new BrowserSSOProfileConfiguration();
-        Assert.assertTrue(config.getIncludeAttributeStatementPredicate().test(null));
+        Assert.assertTrue(config.isIncludeAttributeStatement(null));
 
         config.setIncludeAttributeStatement(false);
-        Assert.assertFalse(config.getIncludeAttributeStatementPredicate().test(null));
+        Assert.assertFalse(config.isIncludeAttributeStatement(null));
     }
 
     @Test
@@ -80,16 +79,16 @@ public class BrowserSSOProfileConfigurationTest {
         final BrowserSSOProfileConfiguration config = new BrowserSSOProfileConfiguration();
 
         config.setIncludeAttributeStatementPredicate(Predicates.alwaysFalse());
-        Assert.assertFalse(config.getIncludeAttributeStatementPredicate().test(null));
+        Assert.assertFalse(config.isIncludeAttributeStatement(null));
     }
 
     @Test
     public void testSkipEndpointValidationWhenSigned() {
         BrowserSSOProfileConfiguration config = new BrowserSSOProfileConfiguration();
-        Assert.assertFalse(config.getSkipEndpointValidationWhenSignedPredicate().test(null));
+        Assert.assertFalse(config.isSkipEndpointValidationWhenSigned(null));
 
         config.setSkipEndpointValidationWhenSigned(true);
-        Assert.assertTrue(config.getSkipEndpointValidationWhenSignedPredicate().test(null));
+        Assert.assertTrue(config.isSkipEndpointValidationWhenSigned(null));
     }
 
     @Test
@@ -97,16 +96,16 @@ public class BrowserSSOProfileConfigurationTest {
         final BrowserSSOProfileConfiguration config = new BrowserSSOProfileConfiguration();
 
         config.setSkipEndpointValidationWhenSignedPredicate(Predicates.alwaysTrue());
-        Assert.assertTrue(config.getSkipEndpointValidationWhenSignedPredicate().test(null));
+        Assert.assertTrue(config.isSkipEndpointValidationWhenSigned(null));
     }
     
     @Test
     public void testMaximumSPSessionLifeTime() {
         final BrowserSSOProfileConfiguration config = new BrowserSSOProfileConfiguration();
-        Assert.assertNull(config.getMaximumSPSessionLifetime());
+        Assert.assertNull(config.getMaximumSPSessionLifetime(null));
 
         config.setMaximumSPSessionLifetime(Duration.ofSeconds(1));
-        Assert.assertEquals(config.getMaximumSPSessionLifetime(), Duration.ofSeconds(1));
+        Assert.assertEquals(config.getMaximumSPSessionLifetime(null), Duration.ofSeconds(1));
     }
     
     @Test
@@ -114,21 +113,20 @@ public class BrowserSSOProfileConfigurationTest {
         final BrowserSSOProfileConfiguration config = new BrowserSSOProfileConfiguration();
 
         config.setMaximumSPSessionLifetimeLookupStrategy(FunctionSupport.constant(Duration.ofSeconds(1)));
-        Assert.assertEquals(config.getMaximumSPSessionLifetime(), Duration.ofSeconds(1));
+        Assert.assertEquals(config.getMaximumSPSessionLifetime(null), Duration.ofSeconds(1));
     }
     
     @Test
     public void testAllowDelegation() {
-        // Note: testing the newer predicate variant
         final BrowserSSOProfileConfiguration config = new BrowserSSOProfileConfiguration();
-        Assert.assertNotNull(config.getAllowDelegation());
+        Assert.assertFalse(config.isAllowDelegation(null));
         
         final Predicate<ProfileRequestContext> predicate = Predicates.alwaysTrue();
-        config.setAllowDelegation(predicate);
-        Assert.assertSame(config.getAllowDelegation(), predicate);
+        config.setAllowDelegationPredicate(predicate);
+        Assert.assertTrue(config.isAllowDelegation(null));
         
         try {
-            config.setAllowDelegation(null);
+            config.setAllowDelegationPredicate(null);
             Assert.fail("Null predicate should not have been allowed");
         } catch (ConstraintViolationException e) {
             // expected, do nothing 
@@ -138,18 +136,18 @@ public class BrowserSSOProfileConfigurationTest {
     @Test
     public void testMaximumTokenDelegationChainLength(){
         final BrowserSSOProfileConfiguration config = new BrowserSSOProfileConfiguration();
-        Assert.assertEquals(config.getMaximumTokenDelegationChainLength(), 1);
+        Assert.assertEquals(config.getMaximumTokenDelegationChainLength(null), 1);
         
         config.setMaximumTokenDelegationChainLength(10);
-        Assert.assertEquals(config.getMaximumTokenDelegationChainLength(), 10);
+        Assert.assertEquals(config.getMaximumTokenDelegationChainLength(null), 10);
     }
     
     @Test
     public void testIndirectMaximumTokenDelegationChainLength(){
         final BrowserSSOProfileConfiguration config = new BrowserSSOProfileConfiguration();
         
-        config.setMaximumTokenDelegationChainLengthLookupStrategy(FunctionSupport.<ProfileRequestContext,Long>constant(10L));
-        Assert.assertEquals(config.getMaximumTokenDelegationChainLength(), 10);
+        config.setMaximumTokenDelegationChainLengthLookupStrategy(FunctionSupport.constant(10L));
+        Assert.assertEquals(config.getMaximumTokenDelegationChainLength(null), 10);
     }
 
     @Test
@@ -177,14 +175,14 @@ public class BrowserSSOProfileConfigurationTest {
     @Test
     public void testDefaultAuthenticationMethods() {
         final BrowserSSOProfileConfiguration config = new BrowserSSOProfileConfiguration();
-        Assert.assertTrue(config.getDefaultAuthenticationMethods().isEmpty());
+        Assert.assertTrue(config.getDefaultAuthenticationMethods(null).isEmpty());
 
         final List<AuthnContextClassRefPrincipal> principals = new ArrayList<>();
         principals.add(new AuthnContextClassRefPrincipal("foo"));
         principals.add(new AuthnContextClassRefPrincipal("bar"));
 
         config.setDefaultAuthenticationMethods(principals);
-        Assert.assertEquals(config.getDefaultAuthenticationMethods(), principals);
+        Assert.assertEquals(config.getDefaultAuthenticationMethods(null), principals);
     }
 
     @Test
@@ -195,22 +193,21 @@ public class BrowserSSOProfileConfigurationTest {
         principals.add(new AuthnContextClassRefPrincipal("foo"));
         principals.add(new AuthnContextClassRefPrincipal("bar"));
 
-        config.setDefaultAuthenticationMethodsLookupStrategy(
-                FunctionSupport.<ProfileRequestContext,Collection<AuthnContextClassRefPrincipal>>constant(principals));
-        Assert.assertEquals(config.getDefaultAuthenticationMethods(), principals);
+        config.setDefaultAuthenticationMethodsLookupStrategy(FunctionSupport.constant(principals));
+        Assert.assertEquals(config.getDefaultAuthenticationMethods(null), principals);
     }
 
     @Test
     public void testAuthenticationFlows() {
         final BrowserSSOProfileConfiguration config = new BrowserSSOProfileConfiguration();
-        Assert.assertTrue(config.getAuthenticationFlows().isEmpty());
+        Assert.assertTrue(config.getAuthenticationFlows(null).isEmpty());
 
         final Set<String> flows = new HashSet<>();
         flows.add("foo");
         flows.add("bar");
 
         config.setAuthenticationFlows(flows);
-        Assert.assertEquals(config.getAuthenticationFlows(), flows);
+        Assert.assertEquals(config.getAuthenticationFlows(null), flows);
     }
 
     @Test
@@ -221,22 +218,21 @@ public class BrowserSSOProfileConfigurationTest {
         flows.add("foo");
         flows.add("bar");
 
-        config.setAuthenticationFlowsLookupStrategy(
-                FunctionSupport.<ProfileRequestContext,Set<String>>constant(flows));
-        Assert.assertEquals(config.getAuthenticationFlows(), flows);
+        config.setAuthenticationFlowsLookupStrategy(FunctionSupport.constant(flows));
+        Assert.assertEquals(config.getAuthenticationFlows(null), flows);
     }
 
     @Test
     public void testPostAuthenticationFlows() {
         final BrowserSSOProfileConfiguration config = new BrowserSSOProfileConfiguration();
-        Assert.assertTrue(config.getPostAuthenticationFlows().isEmpty());
+        Assert.assertTrue(config.getPostAuthenticationFlows(null).isEmpty());
 
         final List<String> flows = new ArrayList<>();
         flows.add("foo");
         flows.add("bar");
 
         config.setPostAuthenticationFlows(flows);
-        Assert.assertEquals(config.getPostAuthenticationFlows(), flows);
+        Assert.assertEquals(config.getPostAuthenticationFlows(null), flows);
     }
 
     @Test
@@ -247,22 +243,21 @@ public class BrowserSSOProfileConfigurationTest {
         flows.add("foo");
         flows.add("bar");
 
-        config.setPostAuthenticationFlowsLookupStrategy(
-                FunctionSupport.<ProfileRequestContext,Collection<String>>constant(flows));
-        Assert.assertEquals(config.getPostAuthenticationFlows(), flows);
+        config.setPostAuthenticationFlowsLookupStrategy(FunctionSupport.constant(flows));
+        Assert.assertEquals(config.getPostAuthenticationFlows(null), flows);
     }
 
     @Test
     public void testNameIDFormatPrecedence() {
         final BrowserSSOProfileConfiguration config = new BrowserSSOProfileConfiguration();
-        Assert.assertTrue(config.getNameIDFormatPrecedence().isEmpty());
+        Assert.assertTrue(config.getNameIDFormatPrecedence(null).isEmpty());
 
         final List<String> formats = new ArrayList<>();
         formats.add("foo");
         formats.add("bar");
 
         config.setNameIDFormatPrecedence(formats);
-        Assert.assertEquals(config.getNameIDFormatPrecedence(), formats);
+        Assert.assertEquals(config.getNameIDFormatPrecedence(null), formats);
     }
 
     @Test
@@ -273,9 +268,8 @@ public class BrowserSSOProfileConfigurationTest {
         formats.add("foo");
         formats.add("bar");
 
-        config.setNameIDFormatPrecedenceLookupStrategy(
-                FunctionSupport.<ProfileRequestContext,Collection<String>>constant(formats));
-        Assert.assertEquals(config.getNameIDFormatPrecedence(), formats);
+        config.setNameIDFormatPrecedenceLookupStrategy(FunctionSupport.constant(formats));
+        Assert.assertEquals(config.getNameIDFormatPrecedence(null), formats);
     }
     
     @Test
@@ -283,15 +277,15 @@ public class BrowserSSOProfileConfigurationTest {
         final BrowserSSOProfileConfiguration config = new BrowserSSOProfileConfiguration();
         
         config.setSignArtifactRequests(Predicates.<MessageContext>alwaysTrue());
-        Assert.assertSame(config.getSignArtifactRequests(), Predicates.<MessageContext>alwaysTrue());
+        Assert.assertSame(config.getSignArtifactRequests(), Predicates.alwaysTrue());
     }
      
     @Test
     public void testClientTLSArtifactRequests() {
         final BrowserSSOProfileConfiguration config = new BrowserSSOProfileConfiguration();
         
-        config.setClientTLSArtifactRequests(Predicates.<MessageContext>alwaysTrue());
-        Assert.assertSame(config.getClientTLSArtifactRequests(), Predicates.<MessageContext>alwaysTrue());
+        config.setClientTLSArtifactRequests(Predicates.alwaysTrue());
+        Assert.assertSame(config.getClientTLSArtifactRequests(), Predicates.alwaysTrue());
     }
      
 
diff --git a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/profile/impl/InitializeAuthenticationContext.java b/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/profile/impl/InitializeAuthenticationContext.java
index 5a909fd..d3add6e 100644
--- a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/profile/impl/InitializeAuthenticationContext.java
+++ b/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/profile/impl/InitializeAuthenticationContext.java
@@ -23,9 +23,9 @@ import java.util.function.Predicate;
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 
+import net.shibboleth.idp.authn.config.navigate.ForceAuthnProfileConfigPredicate;
 import net.shibboleth.idp.authn.context.AuthenticationContext;
 import net.shibboleth.idp.profile.AbstractProfileAction;
-import net.shibboleth.idp.saml.profile.config.logic.ForceAuthnProfileConfigPredicate;
 import net.shibboleth.utilities.java.support.component.ComponentSupport;
 import net.shibboleth.utilities.java.support.logic.Constraint;
 
diff --git a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/profile/impl/PopulateBindingAndEndpointContexts.java b/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/profile/impl/PopulateBindingAndEndpointContexts.java
index 793bf4f..f44561f 100644
--- a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/profile/impl/PopulateBindingAndEndpointContexts.java
+++ b/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/profile/impl/PopulateBindingAndEndpointContexts.java
@@ -347,8 +347,8 @@ public class PopulateBindingAndEndpointContexts extends AbstractProfileAction {
                 }
                 if (profileConfiguration instanceof BrowserSSOProfileConfiguration) {
                     skipValidationSinceSigned =
-                            ((BrowserSSOProfileConfiguration) profileConfiguration)
-                                .getSkipEndpointValidationWhenSignedPredicate().test(profileRequestContext)
+                            ((BrowserSSOProfileConfiguration) profileConfiguration).isSkipEndpointValidationWhenSigned(
+                                    profileRequestContext)
                             && inboundMessage instanceof AuthnRequest
                             && SAMLBindingSupport.isMessageSigned(profileRequestContext.getInboundMessageContext()); 
                 }
diff --git a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/saml2/profile/delegation/impl/AddDelegationPolicyToAssertion.java b/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/saml2/profile/delegation/impl/AddDelegationPolicyToAssertion.java
index 511850c..4850cc6 100644
--- a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/saml2/profile/delegation/impl/AddDelegationPolicyToAssertion.java
+++ b/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/saml2/profile/delegation/impl/AddDelegationPolicyToAssertion.java
@@ -190,7 +190,7 @@ public class AddDelegationPolicyToAssertion extends AbstractProfileAction {
             if (relyingPartyContext != null) {
                 if (relyingPartyContext.getProfileConfig() instanceof BrowserSSOProfileConfiguration) {
                     return ((BrowserSSOProfileConfiguration) relyingPartyContext.getProfileConfig())
-                            .getMaximumTokenDelegationChainLength();
+                            .getMaximumTokenDelegationChainLength(profileRequestContext);
                 } else {
                     log.debug("Profile config was not BrowserSSOProfileConfiguration, can't evaluate: {}", 
                             relyingPartyContext.getProfileConfig() != null ? 
diff --git a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/saml2/profile/delegation/impl/DecorateDelegatedAssertion.java b/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/saml2/profile/delegation/impl/DecorateDelegatedAssertion.java
index 8abaaf1..5568bf1 100644
--- a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/saml2/profile/delegation/impl/DecorateDelegatedAssertion.java
+++ b/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/saml2/profile/delegation/impl/DecorateDelegatedAssertion.java
@@ -325,7 +325,7 @@ public class DecorateDelegatedAssertion extends AbstractProfileAction {
         }
         
         // This is @Nonnull
-        responderId = relyingPartyContext.getConfiguration().getResponderId();
+        responderId = relyingPartyContext.getConfiguration().getResponderId(profileRequestContext);
         
         return true;
     }
diff --git a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/saml2/profile/delegation/impl/PopulateDelegationContext.java b/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/saml2/profile/delegation/impl/PopulateDelegationContext.java
index 45758c1..36e640d 100644
--- a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/saml2/profile/delegation/impl/PopulateDelegationContext.java
+++ b/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/saml2/profile/delegation/impl/PopulateDelegationContext.java
@@ -341,7 +341,7 @@ public class PopulateDelegationContext extends AbstractProfileAction {
         if (relyingPartyContext.getProfileConfig() instanceof BrowserSSOProfileConfiguration) {
             final BrowserSSOProfileConfiguration config = 
                     (BrowserSSOProfileConfiguration) relyingPartyContext.getProfileConfig();
-            delegationAllowed = config.getAllowDelegation().test(profileRequestContext);
+            delegationAllowed = config.isAllowDelegation(profileRequestContext);
         } else {
             log.debug("ProfileConfiguration does not support delegation: {}", 
                     relyingPartyContext.getProfileConfig().getClass().getName());
@@ -349,7 +349,7 @@ public class PopulateDelegationContext extends AbstractProfileAction {
         }
         
         // This is @Nonnull
-        responderId = relyingPartyContext.getConfiguration().getResponderId();
+        responderId = relyingPartyContext.getConfiguration().getResponderId(profileRequestContext);
         
         return true;
     }
diff --git a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/saml2/profile/impl/ProcessRequestedAuthnContext.java b/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/saml2/profile/impl/ProcessRequestedAuthnContext.java
index 86c703c..477b772 100644
--- a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/saml2/profile/impl/ProcessRequestedAuthnContext.java
+++ b/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/saml2/profile/impl/ProcessRequestedAuthnContext.java
@@ -177,7 +177,7 @@ public class ProcessRequestedAuthnContext extends AbstractAuthenticationAction {
         if (rpContext != null && rpContext.getProfileConfig() != null
                 && rpContext.getProfileConfig() instanceof BrowserSSOProfileConfiguration) {
             if (((BrowserSSOProfileConfiguration) rpContext.getProfileConfig()).isFeatureDisallowed(
-                    BrowserSSOProfileConfiguration.FEATURE_AUTHNCONTEXT)) {
+                    profileRequestContext, BrowserSSOProfileConfiguration.FEATURE_AUTHNCONTEXT)) {
                 log.warn("{} Incoming RequestedAuthnContext disallowed by profile configuration", getLogPrefix());
                 ActionSupport.buildEvent(profileRequestContext, AuthnEventIds.INVALID_AUTHN_CTX);
                 return;
diff --git a/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/nameid/impl/AttributeSourcedSAML1NameIdentifierGeneratorTest.java b/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/nameid/impl/AttributeSourcedSAML1NameIdentifierGeneratorTest.java
index 4055181..055777d 100644
--- a/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/nameid/impl/AttributeSourcedSAML1NameIdentifierGeneratorTest.java
+++ b/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/nameid/impl/AttributeSourcedSAML1NameIdentifierGeneratorTest.java
@@ -196,7 +196,7 @@ public class AttributeSourcedSAML1NameIdentifierGeneratorTest extends OpenSAMLIn
         Assert.assertEquals(outputNameId.getValue(), NAME_1);
         Assert.assertEquals(outputNameId.getFormat(), NameIdentifier.X509_SUBJECT);
         Assert.assertEquals(outputNameId.getNameQualifier(), prc.getSubcontext(RelyingPartyContext.class)
-                .getConfiguration().getResponderId());
+                .getConfiguration().getResponderId(prc));
     }
 
     @Test public void testScopeValued() throws Exception {
@@ -216,6 +216,6 @@ public class AttributeSourcedSAML1NameIdentifierGeneratorTest extends OpenSAMLIn
         Assert.assertEquals(outputNameId.getValue(), NAME_1 + '@' + QUALIFIER);
         Assert.assertEquals(outputNameId.getFormat(), NameIdentifier.X509_SUBJECT);
         Assert.assertEquals(outputNameId.getNameQualifier(), prc.getSubcontext(RelyingPartyContext.class)
-                .getConfiguration().getResponderId());
+                .getConfiguration().getResponderId(prc));
     }
 }
\ No newline at end of file
diff --git a/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/nameid/impl/AttributeSourcedSAML2NameIDGeneratorTest.java b/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/nameid/impl/AttributeSourcedSAML2NameIDGeneratorTest.java
index 3da57c7..4afc037 100644
--- a/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/nameid/impl/AttributeSourcedSAML2NameIDGeneratorTest.java
+++ b/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/nameid/impl/AttributeSourcedSAML2NameIDGeneratorTest.java
@@ -199,7 +199,7 @@ public class AttributeSourcedSAML2NameIDGeneratorTest extends OpenSAMLInitBaseTe
         Assert.assertEquals(outputNameId.getValue(), NAME_1);
         Assert.assertEquals(outputNameId.getFormat(), NameID.X509_SUBJECT);
         Assert.assertEquals(outputNameId.getNameQualifier(),
-                prc.getSubcontext(RelyingPartyContext.class).getConfiguration().getResponderId());
+                prc.getSubcontext(RelyingPartyContext.class).getConfiguration().getResponderId(prc));
     }
 
     @Test public void testScopeValued() throws Exception {
@@ -219,7 +219,7 @@ public class AttributeSourcedSAML2NameIDGeneratorTest extends OpenSAMLInitBaseTe
         Assert.assertEquals(outputNameId.getValue(), NAME_1 + '@' + QUALIFIER);
         Assert.assertEquals(outputNameId.getFormat(), NameID.X509_SUBJECT);
         Assert.assertEquals(outputNameId.getNameQualifier(),
-                prc.getSubcontext(RelyingPartyContext.class).getConfiguration().getResponderId());
+                prc.getSubcontext(RelyingPartyContext.class).getConfiguration().getResponderId(prc));
         Assert.assertEquals(outputNameId.getSPNameQualifier(),
                 prc.getSubcontext(RelyingPartyContext.class).getRelyingPartyId());
     }
diff --git a/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/nameid/impl/CryptoTransientSAML1NameIdentifierGeneratorTest.java b/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/nameid/impl/CryptoTransientSAML1NameIdentifierGeneratorTest.java
index 9201894..3880739 100644
--- a/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/nameid/impl/CryptoTransientSAML1NameIdentifierGeneratorTest.java
+++ b/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/nameid/impl/CryptoTransientSAML1NameIdentifierGeneratorTest.java
@@ -119,7 +119,7 @@ public class CryptoTransientSAML1NameIdentifierGeneratorTest extends OpenSAMLIni
         
         Assert.assertNotNull(name);
         Assert.assertEquals(name.getFormat(), generator.getFormat());
-        Assert.assertEquals(name.getNameQualifier(), rpc.getConfiguration().getResponderId());
+        Assert.assertEquals(name.getNameQualifier(), rpc.getConfiguration().getResponderId(prc));
 
         final String val = name.getValue();
 
diff --git a/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/nameid/impl/CryptoTransientSAML2NameIDGeneratorTest.java b/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/nameid/impl/CryptoTransientSAML2NameIDGeneratorTest.java
index dfa8ed5..5a366fd 100644
--- a/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/nameid/impl/CryptoTransientSAML2NameIDGeneratorTest.java
+++ b/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/nameid/impl/CryptoTransientSAML2NameIDGeneratorTest.java
@@ -120,7 +120,7 @@ public class CryptoTransientSAML2NameIDGeneratorTest extends OpenSAMLInitBaseTes
         
         Assert.assertNotNull(name);
         Assert.assertEquals(name.getFormat(), generator.getFormat());
-        Assert.assertEquals(name.getNameQualifier(), rpc.getConfiguration().getResponderId());
+        Assert.assertEquals(name.getNameQualifier(), rpc.getConfiguration().getResponderId(prc));
 
         final String val = name.getValue();
 
diff --git a/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/nameid/impl/StoredTransientSAML1NameIdentifierGeneratorTest.java b/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/nameid/impl/StoredTransientSAML1NameIdentifierGeneratorTest.java
index 14d7706..7e533cf 100644
--- a/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/nameid/impl/StoredTransientSAML1NameIdentifierGeneratorTest.java
+++ b/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/nameid/impl/StoredTransientSAML1NameIdentifierGeneratorTest.java
@@ -94,7 +94,7 @@ public class StoredTransientSAML1NameIdentifierGeneratorTest extends OpenSAMLIni
         
         Assert.assertNotNull(name);
         Assert.assertEquals(name.getFormat(), generator.getFormat());
-        Assert.assertEquals(name.getNameQualifier(), rpc.getConfiguration().getResponderId());
+        Assert.assertEquals(name.getNameQualifier(), rpc.getConfiguration().getResponderId(prc));
 
         String val = name.getValue();
 
diff --git a/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/nameid/impl/StoredTransientSAML2NameIDGeneratorTest.java b/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/nameid/impl/StoredTransientSAML2NameIDGeneratorTest.java
index 812089e..332ecce 100644
--- a/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/nameid/impl/StoredTransientSAML2NameIDGeneratorTest.java
+++ b/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/nameid/impl/StoredTransientSAML2NameIDGeneratorTest.java
@@ -95,7 +95,7 @@ public class StoredTransientSAML2NameIDGeneratorTest extends OpenSAMLInitBaseTes
         
         Assert.assertNotNull(name);
         Assert.assertEquals(name.getFormat(), generator.getFormat());
-        Assert.assertEquals(name.getNameQualifier(), rpc.getConfiguration().getResponderId());
+        Assert.assertEquals(name.getNameQualifier(), rpc.getConfiguration().getResponderId(prc));
         Assert.assertEquals(name.getSPNameQualifier(), rpc.getRelyingPartyId());
 
         String val = name.getValue();
diff --git a/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/saml2/profile/delegation/impl/PopulateDelegationContextTest.java b/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/saml2/profile/delegation/impl/PopulateDelegationContextTest.java
index 89b4243..4b15b19 100644
--- a/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/saml2/profile/delegation/impl/PopulateDelegationContextTest.java
+++ b/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/saml2/profile/delegation/impl/PopulateDelegationContextTest.java
@@ -313,7 +313,7 @@ public class PopulateDelegationContextTest extends OpenSAMLInitBaseTestCase {
         samlMetadataContext.getSubcontext(AttributeConsumingServiceContext.class, true).setAttributeConsumingService(
                 buildDelegationRequestAttributeConsumingService(false));
         
-        browserSSOProfileConfig.setAllowDelegation(Predicates.<ProfileRequestContext>alwaysTrue());
+        browserSSOProfileConfig.setAllowDelegation(true);
         
         action.initialize();
         final Event result = action.execute(rc);
@@ -332,7 +332,7 @@ public class PopulateDelegationContextTest extends OpenSAMLInitBaseTestCase {
         samlMetadataContext.getSubcontext(AttributeConsumingServiceContext.class, true).setAttributeConsumingService(
                 buildDelegationRequestAttributeConsumingService(true));
         
-        browserSSOProfileConfig.setAllowDelegation(Predicates.<ProfileRequestContext>alwaysTrue());
+        browserSSOProfileConfig.setAllowDelegation(true);
         
         action.initialize();
         final Event result = action.execute(rc);
@@ -362,7 +362,7 @@ public class PopulateDelegationContextTest extends OpenSAMLInitBaseTestCase {
     public void testRequestedViaConditionsAllowed() throws Exception {
         authnRequest.setConditions(buildDelegationRequestConditions());
         
-        browserSSOProfileConfig.setAllowDelegation(Predicates.<ProfileRequestContext>alwaysTrue());
+        browserSSOProfileConfig.setAllowDelegation(true);
         
         action.initialize();
         final Event result = action.execute(rc);
@@ -383,7 +383,7 @@ public class PopulateDelegationContextTest extends OpenSAMLInitBaseTestCase {
         
         authnRequest.setConditions(buildDelegationRequestConditions());
         
-        browserSSOProfileConfig.setAllowDelegation(Predicates.<ProfileRequestContext>alwaysTrue());
+        browserSSOProfileConfig.setAllowDelegation(true);
 
         
         action.initialize();
@@ -401,7 +401,7 @@ public class PopulateDelegationContextTest extends OpenSAMLInitBaseTestCase {
         samlMetadataContext.getSubcontext(AttributeConsumingServiceContext.class, true).setAttributeConsumingService(
                 buildDelegationRequestAttributeConsumingService(false));
         
-        browserSSOProfileConfig.setAllowDelegation(Predicates.<ProfileRequestContext>alwaysTrue());
+        browserSSOProfileConfig.setAllowDelegation(true);
         
         action.initialize();
         final Event result = action.execute(rc);
@@ -416,7 +416,7 @@ public class PopulateDelegationContextTest extends OpenSAMLInitBaseTestCase {
     
     private Conditions buildDelegationRequestConditions() {
         Audience audience = (Audience) XMLObjectSupport.buildXMLObject(Audience.DEFAULT_ELEMENT_NAME);
-        audience.setAudienceURI(prc.getSubcontext(RelyingPartyContext.class).getConfiguration().getResponderId());
+        audience.setAudienceURI(prc.getSubcontext(RelyingPartyContext.class).getConfiguration().getResponderId(prc));
         AudienceRestriction ar = (AudienceRestriction) XMLObjectSupport.buildXMLObject(AudienceRestriction.DEFAULT_ELEMENT_NAME);
         ar.getAudiences().add(audience);
         Conditions conditions = (Conditions) XMLObjectSupport.buildXMLObject(Conditions.DEFAULT_ELEMENT_NAME);

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


More information about the commits mailing list