[java-sp-server] branch main updated: Initial set of profile configuration classes.

Scott Cantor cantor.2 at osu.edu
Fri Feb 3 19:15:02 UTC 2023


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

scantor pushed a commit to branch main
in repository java-sp-server.

View the commit online:
http://git.shibboleth.net/view/?p=java-sp-server.git;a=commit;h=d8d9ef99d176aea7b4cc1fcefa6063c1a010ef87

The following commit(s) were added to refs/heads/main by this push:
     new d8d9ef9  Initial set of profile configuration classes.
d8d9ef9 is described below

commit d8d9ef99d176aea7b4cc1fcefa6063c1a010ef87
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Fri Feb 3 14:15:00 2023 -0500

    Initial set of profile configuration classes.
---
 ...tSAML2ArtifactConsumerProfileConfiguration.java | 103 +++++
 ...SAML2AssertionConsumerProfileConfiguration.java | 160 +++++++
 .../config/AbstractSAML2ProfileConfiguration.java  | 183 ++++++++
 .../config/BrowserSSOProfileConfiguration.java     | 501 +++++++++++++++++++++
 .../SAML2ArtifactConsumerProfileConfiguration.java |  50 ++
 ...SAML2AssertionConsumerProfileConfiguration.java |  66 +++
 .../sp/saml2/config/SAML2ProfileConfiguration.java |  81 ++++
 .../shibboleth/sp/saml2/config/package-info.java   |  25 +-
 .../sp/config/AbstractProfileConfiguration.java    |  36 ++
 .../shibboleth/sp/config/ProfileConfiguration.java |  21 +
 10 files changed, 1203 insertions(+), 23 deletions(-)

diff --git a/sp-saml-api/src/main/java/net/shibboleth/sp/saml2/config/AbstractSAML2ArtifactConsumerProfileConfiguration.java b/sp-saml-api/src/main/java/net/shibboleth/sp/saml2/config/AbstractSAML2ArtifactConsumerProfileConfiguration.java
new file mode 100644
index 0000000..1f8e654
--- /dev/null
+++ b/sp-saml-api/src/main/java/net/shibboleth/sp/saml2/config/AbstractSAML2ArtifactConsumerProfileConfiguration.java
@@ -0,0 +1,103 @@
+/*
+ * 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.sp.saml2.config;
+
+import java.util.function.Predicate;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.opensaml.messaging.context.MessageContext;
+import org.opensaml.messaging.logic.NoIntegrityMessageChannelPredicate;
+
+import net.shibboleth.shared.annotation.constraint.NotEmpty;
+import net.shibboleth.shared.logic.Constraint;
+import net.shibboleth.shared.logic.PredicateSupport;
+
+/**
+ * Configuration support for artifact-consuming profiles.
+ */
+public abstract class AbstractSAML2ArtifactConsumerProfileConfiguration extends AbstractSAML2ProfileConfiguration
+        implements SAML2ArtifactConsumerProfileConfiguration {
+    
+    /** Predicate used to determine if artifact resolution requests should be signed. */
+    @Nonnull private Predicate<MessageContext> signArtifactRequestsPredicate;
+    
+    /** Predicate used to determine if artifact resolution requests should use client TLS. */
+    @Nonnull private Predicate<MessageContext> clientTLSArtifactRequestsPredicate;
+
+    /**
+     * Constructor.
+     * 
+     * @param profileId unique ID for this profile
+     */
+    protected AbstractSAML2ArtifactConsumerProfileConfiguration(@Nonnull @NotEmpty final String profileId) {
+        super(profileId);
+        signArtifactRequestsPredicate = new NoIntegrityMessageChannelPredicate();
+        clientTLSArtifactRequestsPredicate = new NoIntegrityMessageChannelPredicate().negate();
+    }
+
+    /** {@inheritDoc} */
+    public boolean isSignArtifactRequests(@Nullable final MessageContext messageContext) {
+        return signArtifactRequestsPredicate.test(messageContext);
+    }
+
+    /**
+     * Set whether artifact resolution requests should be signed.
+     * 
+     * @param flag flag to set
+     */
+    public void setSignArtifactRequests(final boolean flag) {
+        signArtifactRequestsPredicate = PredicateSupport.constant(flag);
+    }
+    
+    /**
+     * Set the predicate used to determine if artifact resolution requests should be signed.
+     * 
+     * @param predicate the predicate
+     */
+    public void setSignArtifactRequestsPredicate(@Nonnull final Predicate<MessageContext> predicate) {
+        signArtifactRequestsPredicate = Constraint.isNotNull(predicate, 
+                "Predicate used to determine artifact request signing may not be null");
+    }
+
+    /** {@inheritDoc} */
+    public boolean isClientTLSArtifactRequests(@Nullable final MessageContext messageContext) {
+        return clientTLSArtifactRequestsPredicate.test(messageContext);
+    }
+
+    /**
+     * Set whether artifact resolution requests should use client TLS.
+     * 
+     * @param flag flag to set
+     */
+    public void setClientTLSArtifactRequests(final boolean flag) {
+        clientTLSArtifactRequestsPredicate = PredicateSupport.constant(flag);
+    }
+    
+    /**
+     * Set the predicate used to determine if artifact resolution requests should use client TLS.
+     * 
+     * @param predicate the predicate
+     */
+    public void setClientTLSArtifactRequestsPredicate(@Nonnull final Predicate<MessageContext> predicate) {
+        clientTLSArtifactRequestsPredicate = Constraint.isNotNull(predicate, 
+                "Predicate used to determine artifact client TLS use may not be null");
+    }
+
+}
\ No newline at end of file
diff --git a/sp-saml-api/src/main/java/net/shibboleth/sp/saml2/config/AbstractSAML2AssertionConsumerProfileConfiguration.java b/sp-saml-api/src/main/java/net/shibboleth/sp/saml2/config/AbstractSAML2AssertionConsumerProfileConfiguration.java
new file mode 100644
index 0000000..cf822bf
--- /dev/null
+++ b/sp-saml-api/src/main/java/net/shibboleth/sp/saml2/config/AbstractSAML2AssertionConsumerProfileConfiguration.java
@@ -0,0 +1,160 @@
+/*
+ * 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.sp.saml2.config;
+
+import java.time.Duration;
+import java.util.Collection;
+import java.util.Set;
+import java.util.function.Function;
+import java.util.function.Predicate;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import net.shibboleth.shared.annotation.constraint.NonNegative;
+import net.shibboleth.shared.annotation.constraint.NonnullElements;
+import net.shibboleth.shared.annotation.constraint.NotEmpty;
+import net.shibboleth.shared.annotation.constraint.NotLive;
+import net.shibboleth.shared.collection.CollectionSupport;
+import net.shibboleth.shared.logic.Constraint;
+import net.shibboleth.shared.logic.FunctionSupport;
+import net.shibboleth.shared.logic.PredicateSupport;
+import net.shibboleth.shared.primitive.StringSupport;
+
+import org.opensaml.profile.context.ProfileRequestContext;
+
+/** Base class for SAML profile configurations. */
+public abstract class AbstractSAML2AssertionConsumerProfileConfiguration
+        extends AbstractSAML2ArtifactConsumerProfileConfiguration
+        implements SAML2AssertionConsumerProfileConfiguration {
+    
+    /** Whether to require signed assertions. */
+    @Nonnull private Predicate<ProfileRequestContext> requireSignedAssertionsPredicate;
+    
+    /** Lookup function to supply assertionLifetime property. */
+    @Nonnull private Function<ProfileRequestContext,Duration> assertionLifetimeLookupStrategy;
+
+    /** Lookup function to supply additionalAudiences property. */
+    @Nonnull private Function<ProfileRequestContext,Set<String>> additionalAudiencesLookupStrategy;
+    
+    /**
+     * Constructor.
+     * 
+     * @param profileId ID of the communication profile
+     */
+    public AbstractSAML2AssertionConsumerProfileConfiguration(@Nonnull @NotEmpty final String profileId) {
+        super(profileId);
+        
+        requireSignedAssertionsPredicate = PredicateSupport.alwaysFalse();
+        assertionLifetimeLookupStrategy = FunctionSupport.constant(null);
+        additionalAudiencesLookupStrategy = FunctionSupport.constant(null);
+    }
+
+    /** {@inheritDoc} */
+    public boolean isRequireSignedAssertions(@Nullable final ProfileRequestContext profileRequestContext) {
+        return requireSignedAssertionsPredicate.test(profileRequestContext);
+    }
+    
+    /**
+     * Set whether to require signed assertions.
+     * 
+     * @param flag flag to set
+     */
+    public void setRequireSignedAssertions(final boolean flag) {
+        requireSignedAssertionsPredicate = PredicateSupport.constant(flag);
+    }
+    
+    /**
+     * Set condition to determine whether to require signed assertions.
+     * 
+     * @param condition condition to set
+     */
+    public void setRequireSignedAssertionsPredicate(@Nonnull final Predicate<ProfileRequestContext> condition) {
+        requireSignedAssertionsPredicate = Constraint.isNotNull(condition, "Condition cannot be null");
+    }
+
+    /** {@inheritDoc} */
+    @Nullable @NonNegative public Duration getAssertionLifetime(@Nullable final ProfileRequestContext profileRequestContext) {
+        final Duration lifetime = assertionLifetimeLookupStrategy.apply(profileRequestContext);
+        if (lifetime != null) {
+            Constraint.isFalse(lifetime.isNegative(), "Assertion lifetime must be non-negative");
+        }
+        return lifetime;
+    }
+
+    /**
+     * Set the maximum lifetime of an assertion.
+     * 
+     * @param lifetime lifetime of an assertion
+     */
+    public void setAssertionLifetime(@Nullable @NonNegative final Duration lifetime) {
+        if (lifetime != null) {
+            Constraint.isFalse(lifetime.isNegative(), "Assertion lifetime must be non-negative");
+        }
+        
+        assertionLifetimeLookupStrategy = FunctionSupport.constant(lifetime);
+    }
+
+    /**
+     * Set a lookup strategy for the maximum lifetime of an assertion.
+     *
+     * @param strategy  lookup strategy
+     */
+    public void setAssertionLifetimeLookupStrategy(@Nonnull final Function<ProfileRequestContext,Duration> strategy) {
+        assertionLifetimeLookupStrategy = Constraint.isNotNull(strategy, "Lookup strategy cannot be null");
+    }
+
+    /** {@inheritDoc} */
+    @Nonnull @NonnullElements @NotLive public Set<String> getAdditionalAudiences(
+            @Nullable final ProfileRequestContext profileRequestContext) {
+        
+        final Set<String> audiences = additionalAudiencesLookupStrategy.apply(profileRequestContext);
+        if (audiences != null) {
+            return CollectionSupport.copyToSet(audiences);
+        }
+        return CollectionSupport.emptySet();
+    }
+
+    /**
+     * Set the set of audiences, in addition to our entityID, to validate the assertion against.
+     * 
+     * @param audiences the additional audiences
+     */
+    public void setAdditionalAudiences(@Nullable @NonnullElements final Collection<String> audiences) {
+
+        if (audiences == null || audiences.isEmpty()) {
+            additionalAudiencesLookupStrategy = FunctionSupport.constant(null);
+        } else {
+            additionalAudiencesLookupStrategy = FunctionSupport.constant(
+                    CollectionSupport.copyToSet(StringSupport.normalizeStringCollection(audiences)));
+        }
+    }
+
+    /**
+     * Set a lookup strategy for the set of audiences, in addition to our entityID, to validate the assertion against.
+     *
+     * @param strategy  lookup strategy
+     * 
+     * @since 4.0.0
+     */
+    public void setAdditionalAudiencesLookupStrategy(
+            @Nonnull final Function<ProfileRequestContext,Set<String>> strategy) {
+        additionalAudiencesLookupStrategy = Constraint.isNotNull(strategy, "Lookup strategy cannot be null");
+    }
+
+}
\ No newline at end of file
diff --git a/sp-saml-api/src/main/java/net/shibboleth/sp/saml2/config/AbstractSAML2ProfileConfiguration.java b/sp-saml-api/src/main/java/net/shibboleth/sp/saml2/config/AbstractSAML2ProfileConfiguration.java
new file mode 100644
index 0000000..677ed74
--- /dev/null
+++ b/sp-saml-api/src/main/java/net/shibboleth/sp/saml2/config/AbstractSAML2ProfileConfiguration.java
@@ -0,0 +1,183 @@
+/*
+ * 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.sp.saml2.config;
+
+import java.util.function.Function;
+import java.util.function.Predicate;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import net.shibboleth.shared.annotation.constraint.NotEmpty;
+import net.shibboleth.shared.logic.Constraint;
+import net.shibboleth.shared.logic.FunctionSupport;
+import net.shibboleth.shared.logic.PredicateSupport;
+import net.shibboleth.sp.config.AbstractConditionalProfileConfiguration;
+
+import org.opensaml.profile.context.ProfileRequestContext;
+
+/** Base class for SAML profile configurations. */
+public abstract class AbstractSAML2ProfileConfiguration extends AbstractConditionalProfileConfiguration implements
+        SAML2ProfileConfiguration {
+    
+    /** Function used to obtain our entityID. */
+    @Nonnull private Function<ProfileRequestContext,String> entityIDLookupStrategy;
+    
+    /** Predicate used to determine if the generated request should be signed. Default returns false. */
+    @Nonnull private Predicate<ProfileRequestContext> signRequestsPredicate;
+
+    /** Predicate used to determine if the generated response should be signed. Default returns false. */
+    @Nonnull private Predicate<ProfileRequestContext> signResponsesPredicate;
+
+    /** Whether encryption is optional in the face of no key, etc. */
+    @Nonnull private Predicate<ProfileRequestContext> encryptionOptionalPredicate;
+    
+    /** Predicate used to determine if name identifiers should be encrypted. */
+    @Nonnull private Predicate<ProfileRequestContext> encryptNameIDsPredicate;
+    
+    /**
+     * Constructor.
+     * 
+     * @param profileId ID of the communication profile
+     */
+    public AbstractSAML2ProfileConfiguration(@Nonnull @NotEmpty final String profileId) {
+        super(profileId);
+
+        entityIDLookupStrategy = FunctionSupport.constant(null);
+        signRequestsPredicate = PredicateSupport.alwaysFalse();
+        signResponsesPredicate = PredicateSupport.alwaysFalse();
+        encryptionOptionalPredicate = PredicateSupport.alwaysFalse();
+        encryptNameIDsPredicate = PredicateSupport.alwaysFalse();
+    }
+    
+    /** {@inheritDoc} */
+    @Nullable @NotEmpty public String getEntityID(@Nullable final ProfileRequestContext profileRequestContext) {
+        return entityIDLookupStrategy.apply(profileRequestContext);
+    }
+    
+    /**
+     * Set the entityID of this system.
+     * 
+     * @param id entityID
+     */
+    public void setEntityID(@Nullable @NotEmpty final String id) {
+        entityIDLookupStrategy = FunctionSupport.constant(id);
+    }
+    
+    /**
+     * Set the lookup strategy for the entityID of this system
+     * 
+     * @param strategy lookup strategy
+     */
+    public void setEntityIDLookupStrategy(@Nonnull final Function<ProfileRequestContext,String> strategy) {
+        entityIDLookupStrategy = Constraint.isNotNull(strategy, "EntityID lookup strategy cannot be null");
+    }
+
+    /** {@inheritDoc} */
+    public boolean isSignRequests(@Nullable final ProfileRequestContext profileRequestContext) {
+        return signRequestsPredicate.test(profileRequestContext);
+    }
+
+    /**
+     * Set whether generated requests should be signed.
+     * 
+     * @param flag flag to set
+     */
+    public void setSignRequests(final boolean flag) {
+        signRequestsPredicate = PredicateSupport.constant(flag);
+    }
+    
+    /**
+     * Set the predicate used to determine if generated requests should be signed.
+     * 
+     * @param predicate predicate used to determine if generated requests should be signed
+     */
+    public void setSignRequestsPredicate(@Nonnull final Predicate<ProfileRequestContext> predicate) {
+        signRequestsPredicate = Constraint.isNotNull(predicate, "Condition cannot be null");
+    }
+
+    /** {@inheritDoc} */
+    public boolean isSignResponses(@Nullable final ProfileRequestContext profileRequestContext) {
+        return signResponsesPredicate.test(profileRequestContext);
+    }
+
+    /**
+     * Set whether generated responses should be signed.
+     * 
+     * @param flag flag to set
+     */
+    public void setSignResponses(final boolean flag) {
+        signResponsesPredicate = PredicateSupport.constant(flag);
+    }
+    
+    /**
+     * Set the predicate used to determine if generated responses should be signed.
+     * 
+     * @param predicate predicate used to determine if generated responses should be signed
+     */
+    public void setSignResponsesPredicate(@Nonnull final Predicate<ProfileRequestContext> predicate) {
+        signResponsesPredicate = Constraint.isNotNull(predicate, "Condition cannot be null");
+    }
+
+    /** {@inheritDoc} */
+    public boolean isEncryptionOptional(@Nullable final ProfileRequestContext profileRequestContext) {
+        return encryptionOptionalPredicate.test(profileRequestContext);
+    }
+    
+    /**
+     * Set whether encryption is optional in the face of a missing key, etc.
+     * 
+     * @param flag  flag to set
+     */
+    public void setEncryptionOptional(final boolean flag) {
+        encryptionOptionalPredicate = PredicateSupport.constant(flag);
+    }
+
+    /**
+     * Set a condition to determine whether encryption is optional in the face of a missing key, etc.
+     *
+     * @param condition condition to set
+     */
+    public void setEncryptionOptionalPredicate(@Nonnull final Predicate<ProfileRequestContext> condition) {
+        encryptionOptionalPredicate = Constraint.isNotNull(condition, "Encryption optional predicate cannot be null");
+    }
+
+    /** {@inheritDoc} */
+    public boolean isEncryptNameIDs(@Nullable final ProfileRequestContext profileRequestContext) {
+        return encryptNameIDsPredicate.test(profileRequestContext);
+    }
+
+    /**
+     * Set whether name identifiers should be encrypted.
+     * 
+     * @param flag  flag to set
+     */
+    public void setEncryptNameIDs(final boolean flag) {
+        encryptNameIDsPredicate = PredicateSupport.constant(flag);
+    }
+
+    /**
+     * Set the predicate used to determine if name identifiers should be encrypted.
+     * 
+     * @param predicate predicate used to determine if name identifiers should be encrypted
+     */
+    public void setEncryptNameIDsPredicate(@Nonnull final Predicate<ProfileRequestContext> predicate) {
+        encryptNameIDsPredicate = Constraint.isNotNull(predicate, "Condition cannot be null");
+    }
+
+}
\ No newline at end of file
diff --git a/sp-saml-api/src/main/java/net/shibboleth/sp/saml2/config/BrowserSSOProfileConfiguration.java b/sp-saml-api/src/main/java/net/shibboleth/sp/saml2/config/BrowserSSOProfileConfiguration.java
new file mode 100644
index 0000000..73d6578
--- /dev/null
+++ b/sp-saml-api/src/main/java/net/shibboleth/sp/saml2/config/BrowserSSOProfileConfiguration.java
@@ -0,0 +1,501 @@
+/*
+ * 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.sp.saml2.config;
+
+import java.time.Duration;
+import java.util.Collection;
+import java.util.List;
+import java.util.function.BiConsumer;
+import java.util.function.Function;
+import java.util.function.Predicate;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import net.shibboleth.shared.annotation.constraint.NonNegative;
+import net.shibboleth.shared.annotation.constraint.NonnullElements;
+import net.shibboleth.shared.annotation.constraint.NotEmpty;
+import net.shibboleth.shared.annotation.constraint.NotLive;
+import net.shibboleth.shared.annotation.constraint.Unmodifiable;
+import net.shibboleth.shared.collection.CollectionSupport;
+import net.shibboleth.shared.logic.Constraint;
+import net.shibboleth.shared.logic.FunctionSupport;
+import net.shibboleth.shared.logic.PredicateSupport;
+
+import org.opensaml.profile.context.ProfileRequestContext;
+import org.opensaml.saml.saml2.core.AuthnContextClassRef;
+import org.opensaml.saml.saml2.core.AuthnContextComparisonTypeEnumeration;
+import org.opensaml.saml.saml2.core.AuthnRequest;
+import org.opensaml.saml.saml2.core.SubjectLocality;
+import org.opensaml.saml.saml2.metadata.RequestedAttribute;
+
+/** Configuration support for SAML 2 Browser SSO. */
+public class BrowserSSOProfileConfiguration extends AbstractSAML2AssertionConsumerProfileConfiguration
+        implements SAML2ArtifactConsumerProfileConfiguration {
+    
+    /** ID for this profile configuration. */
+    @Nonnull @NotEmpty public static final String PROFILE_ID = "http://shibboleth.net/ns/profiles/saml2/sso/browser";
+    
+    /** Bit constant for RequestedAuthnContext feature. */
+    public static final int FEATURE_AUTHNCONTEXT = 0x1;
+    
+    /** Bit constant for NameIDPolicy Format feature. */
+    public static final int FEATURE_NAMEIDFORMAT = 0x2;
+
+    /** Bit constant for NameIDPolicy SPNameQualifier feature. */
+    public static final int FEATURE_SPNAMEQUALIFIER = 0x4;
+
+    /** Bit constant for ForceAuthn feature. */
+    public static final int FEATURE_FORCEAUTHN = 0x8;
+
+    /** Whether to mandate forced authentication for the request. */
+    @Nonnull private Predicate<ProfileRequestContext> forceAuthnPredicate;
+
+    /** Whether to compare client and assertion addresses on inbound SSO. */
+    @Nonnull private Predicate<ProfileRequestContext> checkAddressPredicate;
+    
+    /** Lookup function to supply maximum time since inbound AuthnInstant. */
+    @Nonnull private Function<ProfileRequestContext,Duration> maximumTimeSinceAuthnLookupStrategy;
+
+    /** Lookup function to supply ProxyCount. */
+    @Nonnull private Function<ProfileRequestContext,Integer> proxyCountLookupStrategy;
+    
+    /** Lookup function for requested AC operator. */
+    @Nonnull private Function<ProfileRequestContext,String> authnContextComparisonLookupStrategy;
+    
+    /** Lookup function to supply default authentication methods. */
+    @Nonnull private Function<ProfileRequestContext,Collection<String>> authnContextClassRefLookupStrategy;
+    
+    /** Lookup function to supply NameID format. */
+    @Nonnull private Function<ProfileRequestContext,String> nameIDFormatLookupStrategy;
+
+    /** Lookup function to supply SPNameQualifier. */
+    @Nonnull private Function<ProfileRequestContext,String> nameQualifierLookupStrategy;
+
+    /** Lookup function to supply AttributeConsumingServiceIndex. */
+    @Nonnull private Function<ProfileRequestContext,String> attributeIndexLookupStrategy;
+
+    /** Lookup function to supply RequestedAttributes. */
+    @Nonnull private Function<ProfileRequestContext,Collection<RequestedAttribute>> requestedAttributesLookupStrategy;
+    
+    /** Lookup function to supply a decorator for the {@link AuthnRequest}. */
+    @Nonnull private Function<ProfileRequestContext,BiConsumer<ProfileRequestContext,AuthnRequest>>
+    requestDecoratorLookupStrategy;
+
+    /** Constructor. */
+    public BrowserSSOProfileConfiguration() {
+        this(PROFILE_ID);
+    }
+
+    /**
+     * Constructor.
+     * 
+     * @param profileId unique ID for this profile
+     */
+    protected BrowserSSOProfileConfiguration(@Nonnull @NotEmpty final String profileId) {
+        super(profileId);
+        setEncryptNameIDs(true);
+        forceAuthnPredicate = PredicateSupport.alwaysFalse();
+        checkAddressPredicate = PredicateSupport.alwaysTrue();
+        maximumTimeSinceAuthnLookupStrategy = FunctionSupport.constant(null);
+        proxyCountLookupStrategy = FunctionSupport.constant(null);
+        authnContextComparisonLookupStrategy = FunctionSupport.constant(null);
+        authnContextClassRefLookupStrategy = FunctionSupport.constant(null);
+        nameIDFormatLookupStrategy = FunctionSupport.constant(null);
+        nameQualifierLookupStrategy = FunctionSupport.constant(null);
+        attributeIndexLookupStrategy = FunctionSupport.constant(null);
+        requestedAttributesLookupStrategy = FunctionSupport.constant(null);
+        requestDecoratorLookupStrategy = FunctionSupport.constant(null);
+    }
+
+    /**
+     * Get whether a fresh user presence proof should be required for this request.
+     * 
+     * @param profileRequestContext current profile request context
+     * 
+     * @return true iff a fresh user presence proof should be required for this request
+     */
+    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 = PredicateSupport.constant(flag);
+    }
+    
+    /**
+     * 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");
+    }
+
+    /**
+     * Get whether the client's address must match the address in an inbound {@link SubjectLocality}
+     * element during inbound SSO.
+     * 
+     * @param profileRequestContext current profile request context
+     * 
+     * @return whether to compare addresses
+     */
+    public boolean isCheckAddress(@Nullable final ProfileRequestContext profileRequestContext) {
+        return checkAddressPredicate.test(profileRequestContext);
+    }
+    
+    /**
+     * Set whether the client's address must match the address in an inbound {@link SubjectLocality}
+     * element during inbound SSO.
+     * 
+     * @param flag flag to set
+     */
+    public void setCheckAddress(final boolean flag) {
+        checkAddressPredicate = PredicateSupport.constant(flag);
+    }
+    
+    /**
+     * Set a condition to determine whether the client's address must match the address in an inbound
+     * {@link SubjectLocality} element during inbound SSO.
+     * 
+     * @param condition condition to set
+     */
+    public void setCheckAddressPredicate(@Nonnull final Predicate<ProfileRequestContext> condition) {
+        checkAddressPredicate = Constraint.isNotNull(condition, "Address checking predicate cannot be null");
+    }
+    
+    /**
+     * Get the maximum amount of time allowed to have elapsed since an incoming AuthnInstant.
+     * 
+     * <p>A null or 0 is interpreted as an unlimited amount.</p>
+     * 
+     * @param profileRequestContext current profile request context
+     * 
+     * @return max time since inbound AuthnInstant
+     */
+    @Nullable public Duration getMaximumTimeSinceAuthn(@Nullable final ProfileRequestContext profileRequestContext) {
+        final Duration amount = maximumTimeSinceAuthnLookupStrategy.apply(profileRequestContext);
+        Constraint.isFalse(amount != null && amount.isNegative(),
+                "Maximum time since authentication must be greater than or equal to 0");
+        return amount;
+    }
+
+    /**
+     * Set the maximum amount of time allowed to have elapsed since an incoming AuthnInstant.
+     * 
+     * <p>A null or 0 is interpreted as an unlimited amount.</p>
+     * 
+     * @param amount max time to allow
+     */
+    public void setMaximumTimeSinceAuthn(@Nullable final Duration amount) {
+        Constraint.isFalse(amount != null && amount.isNegative(),
+                "Maximum time since authentication must be greater than or equal to 0");
+        
+        maximumTimeSinceAuthnLookupStrategy = FunctionSupport.constant(amount);
+    }
+    
+    /**
+     * Set a lookup strategy for the maximum amount of time allowed to have elapsed since an incoming AuthnInstant.
+     * 
+     * @param strategy  lookup strategy
+     */
+    public void setMaximumTimeSinceAuthnLookupStrategy(
+            @Nonnull final Function<ProfileRequestContext,Duration> strategy) {
+        maximumTimeSinceAuthnLookupStrategy = Constraint.isNotNull(strategy, "Lookup strategy cannot be null");
+    }
+
+    /**
+     * Gets the maximum number of times an assertion may be proxied to signal in the SAML request.
+     * 
+     * @param profileRequestContext current profile request context
+     * 
+     * @return maximum number of times an assertion may be proxied
+     */
+    @NonNegative @Nullable Integer getProxyCount(@Nullable final ProfileRequestContext profileRequestContext) {
+        final Integer count = proxyCountLookupStrategy.apply(profileRequestContext);
+        if (count != null) {
+            Constraint.isGreaterThanOrEqual(0, count, "Proxy count must be greater than or equal to 0");
+        }
+        return count;
+    }
+    
+    /**
+     * Set the maximum number of times an assertion may be proxied to signal in the SAML request.
+     * 
+     * @param count maximum number of times an assertion may be proxied
+     */
+    public void setProxyCount(@Nullable @NonNegative final Integer count) {
+        if (count != null) {
+            Constraint.isGreaterThanOrEqual(0, count, "Proxy count must be greater than or equal to 0");
+        }
+        proxyCountLookupStrategy = FunctionSupport.constant(count);
+    }
+
+    /**
+     * Set a lookup strategy for the maximum number of times an assertion may be proxied to signal
+     * in the SAML request.
+     *
+     * @param strategy  lookup strategy
+     */
+    public void setProxyCountLookupStrategy(@Nonnull final Function<ProfileRequestContext,Integer> strategy) {
+        proxyCountLookupStrategy = Constraint.isNotNull(strategy, "Lookup strategy cannot be null");
+    }
+    
+    /**
+     * Get the comparison operator to use when issuing SAML requests containing requested context classes.
+     * 
+     * @param profileRequestContext profile request context
+     * 
+     * @return comparison value or null
+     */
+    @Nullable public AuthnContextComparisonTypeEnumeration getAuthnContextComparison(
+            @Nullable final ProfileRequestContext profileRequestContext) {
+        
+        final String comparison = authnContextComparisonLookupStrategy.apply(profileRequestContext);
+        if (comparison != null) {
+            return AuthnContextComparisonTypeEnumeration.valueOf(comparison.toUpperCase());
+        }
+        
+        return null;
+    }
+    
+    /**
+     * Set the comparison operator to use when issuing SAML requests containing requested context classes.
+     * 
+     * @param comparison comparison value or null
+     * 
+     * @since 4.0.0
+     */
+    public void setAuthnContextComparison(@Nullable final AuthnContextComparisonTypeEnumeration comparison) {
+        authnContextComparisonLookupStrategy =
+                FunctionSupport.constant(comparison != null ? comparison.toString() : null);
+    }
+
+    /**
+     * Set a lookup strategy for the comparison operator to use when issuing SAML requests containing
+     * requested context classes.
+     * 
+     * @param strategy lookup strategy
+     */
+    public void setAuthnContextComparisonLookupStrategy(
+            @Nonnull final Function<ProfileRequestContext,String> strategy) {
+        authnContextComparisonLookupStrategy = Constraint.isNotNull(strategy, "Lookup strategy cannot be null");
+    }
+
+    /**
+     * Get the {@link AuthnContextClassRef} values to include in SAML request.
+     * 
+     * @param profileRequestContext current profile request context
+     * 
+     * @return list of class references
+     */
+    @Nonnull @NonnullElements @NotLive @Unmodifiable public List<String> getAuthnContextClassRefs(
+            @Nullable final ProfileRequestContext profileRequestContext) {
+        final Collection<String> refs = authnContextClassRefLookupStrategy.apply(profileRequestContext);
+        if (refs != null) {
+            return CollectionSupport.copyToList(refs);
+        }
+        return CollectionSupport.emptyList();
+    }
+        
+    /**
+     * Set the {@link AuthnContextClassRef} values to include in SAML request.
+     * 
+     * @param contexts default authentication context class references to use
+     */
+    public void setAuthnContextClassRefs(@Nullable @NonnullElements final Collection<String> contexts) {
+        if (contexts != null) {
+            authnContextClassRefLookupStrategy = FunctionSupport.constant(CollectionSupport.copyToList(contexts));
+        } else {
+            authnContextClassRefLookupStrategy = FunctionSupport.constant(null);
+        }
+    }
+
+    /**
+     * Set a lookup strategy for the {@link AuthnContextClassRef} values to include in SAML request.
+     *
+     * @param strategy  lookup strategy
+     */
+    public void setAuthnContextClassRefsLookupStrategy(
+            @Nonnull final Function<ProfileRequestContext,Collection<String>> strategy) {
+        authnContextClassRefLookupStrategy = Constraint.isNotNull(strategy, "Lookup strategy cannot be null");
+    }
+
+    /**
+     * Get the name identifier format to require via the SAML request.
+     * 
+     * @param profileRequestContext current profile request context
+     * 
+     * @return required format
+     */
+    @Nullable public String getNameIDFormat(@Nullable final ProfileRequestContext profileRequestContext) {
+        return nameIDFormatLookupStrategy.apply(profileRequestContext);
+    }
+
+    /**
+     * Set the name identifier format to require via the SAML request.
+     * 
+     * @param format required format
+     */
+    public void setNameIDFormat(@Nullable final String format) {
+        nameIDFormatLookupStrategy = FunctionSupport.constant(format);
+    }
+
+    /**
+     * Set a lookup strategy for the name identifier format to require via the SAML request.
+     *
+     * @param strategy  lookup strategy
+     */
+    public void setNameIDFormatLookupStrategy(
+            @Nonnull final Function<ProfileRequestContext,String> strategy) {
+        nameIDFormatLookupStrategy = Constraint.isNotNull(strategy, "Lookup strategy cannot be null");
+    }
+
+    /**
+     * Get the SPNameQualifier to include in the SAML request.
+     * 
+     * @param profileRequestContext current profile request context
+     * 
+     * @return requested SPNameQualifier
+     */
+    @Nullable public String getNameQualifier(@Nullable final ProfileRequestContext profileRequestContext) {
+        return nameQualifierLookupStrategy.apply(profileRequestContext);
+    }
+
+    /**
+     * Set the SPNameQualifier to include in the SAML request.
+     * 
+     * @param qualifier requested SPNameQualifier
+     */
+    public void setNameQualifier(@Nullable final String qualifier) {
+        nameQualifierLookupStrategy = FunctionSupport.constant(qualifier);
+    }
+
+    /**
+     * Set a lookup strategy for the SPNameQualifier to include in the SAML request.
+     *
+     * @param strategy  lookup strategy
+     */
+    public void setNameQualifierLookupStrategy(
+            @Nonnull final Function<ProfileRequestContext,String> strategy) {
+        nameQualifierLookupStrategy = Constraint.isNotNull(strategy, "Lookup strategy cannot be null");
+    }
+    
+    /**
+     * Get the AttributeConsumingServiceIndex to include in the SAML request.
+     * 
+     * @param profileRequestContext current profile request context
+     * 
+     * @return the AttributeConsumingServiceIndex
+     */
+    @Nullable public String getAttributeIndex(@Nullable final ProfileRequestContext profileRequestContext) {
+        return attributeIndexLookupStrategy.apply(profileRequestContext);
+    }
+
+    /**
+     * Set the AttributeConsumingServiceIndex to include in the SAML request.
+     * 
+     * @param index the AttributeConsumingServiceIndex
+     */
+    public void setAttributeIndex(@Nullable final String index) {
+        attributeIndexLookupStrategy = FunctionSupport.constant(index);
+    }
+
+    /**
+     * Set a lookup strategy for the AttributeConsumingServiceIndex to include in the SAML request.
+     *
+     * @param strategy  lookup strategy
+     */
+    public void setAttributeIndexLookupStrategy(@Nonnull final Function<ProfileRequestContext,String> strategy) {
+        attributeIndexLookupStrategy = Constraint.isNotNull(strategy, "Lookup strategy cannot be null");
+    }
+    
+    /**
+     * Get the list of {@link RequestedAttribute} objects to include in the SAML request (via extension).
+     * 
+     * @param profileRequestContext current profile request context
+     * 
+     * @return the requested attributes
+     */
+    @Nonnull @NonnullElements @Unmodifiable @NotLive public Collection<RequestedAttribute> getRequestedAttributes(
+            @Nullable final ProfileRequestContext profileRequestContext) {
+        final Collection<RequestedAttribute> attrs = requestedAttributesLookupStrategy.apply(profileRequestContext);
+        if (attrs != null) {
+            return CollectionSupport.copyToList(attrs);
+        } else {
+            return CollectionSupport.emptyList();
+        }
+    }
+    
+    /**
+     * Set the list of {@link RequestedAttribute} objects to include in the SAML request (via extension).
+     * 
+     * @param attrs requested attributes
+     */
+    public void setRequestedAttributes(@Nullable @NonnullElements final Collection<RequestedAttribute> attrs) {
+        requestedAttributesLookupStrategy = FunctionSupport.constant(attrs);
+    }
+    
+    /**
+     * Set a lookup strategy for the list of {@link RequestedAttribute} objects to include in the SAML request
+     * (via extension).
+     * 
+     * @param strategy lookup strategy
+     */
+    public void setRequestedAttributesLookupStrategy(
+            @Nonnull final Function<ProfileRequestContext,Collection<RequestedAttribute>> strategy) {
+        requestedAttributesLookupStrategy = Constraint.isNotNull(strategy, "Lookup strategy cannot be null");
+    }
+    
+    /**
+     * Get a decorator for the SAML request.
+     * 
+     * @param profileRequestContext current profile request context
+     * 
+     * @return request decorator
+     */
+    @Nullable public BiConsumer<ProfileRequestContext,AuthnRequest> getRequestDecorator(
+            @Nullable final ProfileRequestContext profileRequestContext) {
+        return requestDecoratorLookupStrategy.apply(profileRequestContext);
+    }
+    
+    /**
+     * Set a decorator for the SAML request.
+     * 
+     * @param decorator request decorator
+     */
+    public void setRequestDecorator(@Nullable final BiConsumer<ProfileRequestContext,AuthnRequest> decorator) {
+        requestDecoratorLookupStrategy = FunctionSupport.constant(decorator);
+    }
+    
+    /**
+     * Set a lookup strategy for a decorator for the SAML request.
+     * 
+     * @param strategy lookup strategy
+     */
+    public void setRequestDecoratorLookupStrategy(
+            @Nonnull final Function<ProfileRequestContext,BiConsumer<ProfileRequestContext,AuthnRequest>> strategy) {
+        requestDecoratorLookupStrategy = Constraint.isNotNull(strategy, "Lookup strategy cannot be null");
+    }
+    
+}
\ No newline at end of file
diff --git a/sp-saml-api/src/main/java/net/shibboleth/sp/saml2/config/SAML2ArtifactConsumerProfileConfiguration.java b/sp-saml-api/src/main/java/net/shibboleth/sp/saml2/config/SAML2ArtifactConsumerProfileConfiguration.java
new file mode 100644
index 0000000..558b3e7
--- /dev/null
+++ b/sp-saml-api/src/main/java/net/shibboleth/sp/saml2/config/SAML2ArtifactConsumerProfileConfiguration.java
@@ -0,0 +1,50 @@
+/*
+ * 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.sp.saml2.config;
+
+import javax.annotation.Nullable;
+
+import org.opensaml.messaging.context.MessageContext;
+
+/**
+ * Common interface for SAML profile configurations involving artifact consumption, for example artifact
+ * resolution requests.
+ * 
+ * <p>This is {@link MessageContext}-driven.</p>
+ */
+public interface SAML2ArtifactConsumerProfileConfiguration extends SAML2ProfileConfiguration {
+    
+    /**
+     * Get whether artifact resolution requests should be signed.
+     * 
+     * @param messageContext current message context
+     * 
+     * @return whether artifact resolution requests should be signed
+     */
+    boolean isSignArtifactRequests(@Nullable final MessageContext messageContext); 
+
+    /**
+     * Get whether artifact resolution requests should use client TLS.
+     * 
+     * @param messageContext current message context
+     * 
+     * @return whether artifact resolution requests should use client TLS
+     */
+    boolean isClientTLSArtifactRequests(@Nullable final MessageContext messageContext); 
+
+}
\ No newline at end of file
diff --git a/sp-saml-api/src/main/java/net/shibboleth/sp/saml2/config/SAML2AssertionConsumerProfileConfiguration.java b/sp-saml-api/src/main/java/net/shibboleth/sp/saml2/config/SAML2AssertionConsumerProfileConfiguration.java
new file mode 100644
index 0000000..f505491
--- /dev/null
+++ b/sp-saml-api/src/main/java/net/shibboleth/sp/saml2/config/SAML2AssertionConsumerProfileConfiguration.java
@@ -0,0 +1,66 @@
+/*
+ * 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.sp.saml2.config;
+
+import java.time.Duration;
+import java.util.Set;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.opensaml.profile.context.ProfileRequestContext;
+
+import net.shibboleth.shared.annotation.constraint.NonNegative;
+import net.shibboleth.shared.annotation.constraint.NonnullElements;
+import net.shibboleth.shared.annotation.constraint.NotLive;
+import net.shibboleth.shared.annotation.constraint.Unmodifiable;
+
+/**
+ * Interface for configuration of profiles that consume SAML Assertions.
+ */
+public interface SAML2AssertionConsumerProfileConfiguration extends SAML2ProfileConfiguration {
+
+    /**
+     * Get the predicate used to determine if assertions must be signed.
+     * 
+     * @param profileRequestContext current profile request context
+     * 
+     * @return predicate used to determine if assertions must be signed
+     */
+    boolean isRequireSignedAssertions(@Nullable final ProfileRequestContext profileRequestContext);
+
+    /**
+     * Get the maximum lifetime of the assertions.
+     * 
+     * @param profileRequestContext current profile request context
+     * 
+     * @return maximum lifetime of the assertions
+     */
+    @Nullable @NonNegative Duration getAssertionLifetime(@Nullable final ProfileRequestContext profileRequestContext);
+    
+    /**
+     * Get set of audiences to include when validating assertion, in addition to our own entityID.
+     * 
+     * @param profileRequestContext current profile request context
+     * 
+     * @return additional audiences
+     */
+    @Nonnull @NonnullElements @NotLive @Unmodifiable Set<String> getAdditionalAudiences(
+            @Nullable final ProfileRequestContext profileRequestContext);
+
+}
\ No newline at end of file
diff --git a/sp-saml-api/src/main/java/net/shibboleth/sp/saml2/config/SAML2ProfileConfiguration.java b/sp-saml-api/src/main/java/net/shibboleth/sp/saml2/config/SAML2ProfileConfiguration.java
new file mode 100644
index 0000000..3511804
--- /dev/null
+++ b/sp-saml-api/src/main/java/net/shibboleth/sp/saml2/config/SAML2ProfileConfiguration.java
@@ -0,0 +1,81 @@
+/*
+ * 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.sp.saml2.config;
+
+import javax.annotation.Nullable;
+
+import org.opensaml.profile.context.ProfileRequestContext;
+
+import net.shibboleth.shared.annotation.constraint.NotEmpty;
+import net.shibboleth.sp.config.ProfileConfiguration;
+
+/** Common interface for SAML 2.0 profile configurations. */
+public interface SAML2ProfileConfiguration extends ProfileConfiguration {
+
+    /**
+     * Get the entityID assigned to this system.
+     * 
+     * @param profileRequestContext current profile request context
+     * 
+     * @return our own entityID
+     */
+    @Nullable @NotEmpty String getEntityID(@Nullable final ProfileRequestContext profileRequestContext);
+    
+    /**
+     * Get the predicate used to determine if generated requests should be signed.
+     * 
+     * @param profileRequestContext current profile request context
+     * 
+     * @return predicate used to determine if generated requests should be signed
+     */
+    boolean isSignRequests(@Nullable final ProfileRequestContext profileRequestContext);
+
+    /**
+     * Get the predicate used to determine if generated responses should be signed.
+     * 
+     * @param profileRequestContext current profile request context
+     * 
+     * @return predicate used to determine if generated responses should be signed
+     */
+    boolean isSignResponses(@Nullable final ProfileRequestContext profileRequestContext);
+    
+    /**
+     * Gets whether to ignore an inability to encrypt due to external factors.
+     * 
+     *  <p>This allows a deployer to signal that encryption is "best effort" and
+     *  can be omitted if an asserting party doesn't possess a key, support a compatible
+     *  algorithm, etc.</p>
+     *  
+     *  <p>Defaults to false.</p>
+     *  
+     * @param profileRequestContext current profile request context
+     * 
+     * @return true iff encryption should be treated as optional
+     */
+    boolean isEncryptionOptional(@Nullable final ProfileRequestContext profileRequestContext);
+
+    /**
+     * Gets the predicate used to determine if name identifiers should be encrypted.
+     * 
+     * @param profileRequestContext current profile request context
+     * 
+     * @return predicate used to determine if name identifiers should be encrypted
+     */
+    boolean isEncryptNameIDs(@Nullable final ProfileRequestContext profileRequestContext);
+    
+}
\ No newline at end of file
diff --git a/sp-server-api/src/main/java/net/shibboleth/sp/config/ProfileConfiguration.java b/sp-saml-api/src/main/java/net/shibboleth/sp/saml2/config/package-info.java
similarity index 53%
copy from sp-server-api/src/main/java/net/shibboleth/sp/config/ProfileConfiguration.java
copy to sp-saml-api/src/main/java/net/shibboleth/sp/saml2/config/package-info.java
index 0f5f78c..09937f8 100644
--- a/sp-server-api/src/main/java/net/shibboleth/sp/config/ProfileConfiguration.java
+++ b/sp-saml-api/src/main/java/net/shibboleth/sp/saml2/config/package-info.java
@@ -15,28 +15,7 @@
  * limitations under the License.
  */
 
-package net.shibboleth.sp.config;
-
-import javax.annotation.Nullable;
-
-import org.opensaml.profile.context.ProfileRequestContext;
-import org.opensaml.security.config.SecurityConfiguration;
-
-import net.shibboleth.shared.component.IdentifiedComponent;
-
 /**
- * Interface for profile-specific configuration used to customize SP behavior.
+ * Configuration of SAML support in SP.
  */
-public interface ProfileConfiguration extends IdentifiedComponent {
-
-    /**
-     * Gets the applicable {@link SecurityConfiguration}.
-     * 
-     * @param profileRequestContext profile request context 
-     * 
-     * @return the profile's security configuration
-     */
-    @Nullable SecurityConfiguration getSecurityConfiguration(
-            @Nullable final ProfileRequestContext profileRequestContext);
-    
-}
\ No newline at end of file
+package net.shibboleth.sp.saml2.config;
\ No newline at end of file
diff --git a/sp-server-api/src/main/java/net/shibboleth/sp/config/AbstractProfileConfiguration.java b/sp-server-api/src/main/java/net/shibboleth/sp/config/AbstractProfileConfiguration.java
index 9b7567a..2a0b713 100644
--- a/sp-server-api/src/main/java/net/shibboleth/sp/config/AbstractProfileConfiguration.java
+++ b/sp-server-api/src/main/java/net/shibboleth/sp/config/AbstractProfileConfiguration.java
@@ -36,9 +36,15 @@ import org.opensaml.security.config.SecurityConfiguration;
 public abstract class AbstractProfileConfiguration extends AbstractIdentifiableInitializableComponent
         implements ProfileConfiguration {
 
+    /** Default value for disallowedFeatures property. */
+    @Nonnull public static final Integer DEFAULT_DISALLOWED_FEATURES = 0; 
+
     /** Lookup function to supply securityConfiguration property. */
     @Nonnull private Function<ProfileRequestContext,SecurityConfiguration> securityConfigurationLookupStrategy;
 
+    /** Lookup function to return a bitmask of request features to disallow. */
+    @Nonnull private Function<ProfileRequestContext,Integer> disallowedFeaturesLookupStrategy;
+
     /**
      * Constructor.
      * 
@@ -47,6 +53,7 @@ public abstract class AbstractProfileConfiguration extends AbstractIdentifiableI
     public AbstractProfileConfiguration(@Nonnull @NotEmpty @ParameterName(name="id") final String id) {
         setId(id);
         securityConfigurationLookupStrategy = FunctionSupport.constant(null);
+        disallowedFeaturesLookupStrategy = FunctionSupport.constant(DEFAULT_DISALLOWED_FEATURES);
     }
 
     /** {@inheritDoc} */
@@ -76,6 +83,35 @@ public abstract class AbstractProfileConfiguration extends AbstractIdentifiableI
         securityConfigurationLookupStrategy = Constraint.isNotNull(strategy, "Lookup strategy cannot be null");
     }
     
+    /** {@inheritDoc} */
+    public boolean isFeatureDisallowed(@Nullable final ProfileRequestContext profileRequestContext, final int feature) {
+        return (getDisallowedFeatures(profileRequestContext) & feature) == feature;
+    }
+    
+    /** {@inheritDoc} */
+    public int getDisallowedFeatures(@Nullable final ProfileRequestContext profileRequestContext) {
+        final Integer mask = disallowedFeaturesLookupStrategy.apply(profileRequestContext); 
+        return mask != null ? mask : DEFAULT_DISALLOWED_FEATURES;
+    }
+    
+    /**
+     * Set a bitmask of disallowed features to block.
+     * 
+     * @param mask a bitmask of features to block
+     */
+    public void setDisallowedFeatures(final int mask) {
+        disallowedFeaturesLookupStrategy = FunctionSupport.constant(mask);
+    }
+    
+    /**
+     * Set a lookup strategy for the bitmask of disallowed features to block. 
+     * 
+     * @param strategy lookup strategy
+     */
+    public void setDisallowedFeaturesLookupStrategy(@Nonnull final Function<ProfileRequestContext,Integer> strategy) {
+        disallowedFeaturesLookupStrategy = Constraint.isNotNull(strategy, "Lookup strategy cannot be null");
+    }
+    
     /** {@inheritDoc} */
     @Override
     public int hashCode() {
diff --git a/sp-server-api/src/main/java/net/shibboleth/sp/config/ProfileConfiguration.java b/sp-server-api/src/main/java/net/shibboleth/sp/config/ProfileConfiguration.java
index 0f5f78c..13bc699 100644
--- a/sp-server-api/src/main/java/net/shibboleth/sp/config/ProfileConfiguration.java
+++ b/sp-server-api/src/main/java/net/shibboleth/sp/config/ProfileConfiguration.java
@@ -38,5 +38,26 @@ public interface ProfileConfiguration extends IdentifiedComponent {
      */
     @Nullable SecurityConfiguration getSecurityConfiguration(
             @Nullable final ProfileRequestContext profileRequestContext);
+ 
+    /**
+     * Get a bitmask of disallowed features to block.
+     * 
+     * <p>Individual profiles define their own feature constants.</p>
+     * 
+     * @param profileRequestContext current profile request context
+     * 
+     * @return bitmask of features to block
+     */
+    public int getDisallowedFeatures(@Nullable final ProfileRequestContext profileRequestContext);
+
+    /**
+     * 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
+     */
+    public boolean isFeatureDisallowed(@Nullable final ProfileRequestContext profileRequestContext, final int feature);
     
 }
\ No newline at end of file

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


More information about the commits mailing list