[java-shib-profile] branch main updated: JSPROF-1 - Move RelyingParty "layer" into java-shib-profile
Scott Cantor
cantor.2 at osu.edu
Wed Feb 15 20:20:49 UTC 2023
This is an automated email from the git hooks/post-receive script.
scantor pushed a commit to branch main
in repository java-shib-profile.
View the commit online:
http://git.shibboleth.net/view/?p=java-shib-profile.git;a=commit;h=0872ac3c68b369e732ffc0707f8ecf4592b278af
The following commit(s) were added to refs/heads/main by this push:
new 0872ac3 JSPROF-1 - Move RelyingParty "layer" into java-shib-profile
0872ac3 is described below
commit 0872ac3c68b369e732ffc0707f8ecf4592b278af
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Wed Feb 15 15:20:46 2023 -0500
JSPROF-1 - Move RelyingParty "layer" into java-shib-profile
https://shibboleth.atlassian.net/browse/JSPROF-1
Initial migration of SAML classes.
Bare-bones SAMLProfileConfiguration base interface.
---
pom.xml | 2 +-
shib-profile-bom/pom.xml | 2 +-
.../audit/impl/AttributesAuditExtractor.java | 100 +++++++
.../profile/audit/impl/package-info.java | 21 ++
.../DefaultRelyingPartyConfigurationResolver.java | 3 +-
shib-saml-profile-api/pom.xml | 11 +
.../shibboleth/saml/binding/BindingDescriptor.java | 51 ++++
.../net/shibboleth/saml/binding/package-info.java | 21 ++
.../SAMLArtifactConsumerProfileConfiguration.java | 48 ++++
.../profile/config/SAMLProfileConfiguration.java | 47 ++++
.../config/logic/SignRequestsPredicate.java | 108 ++++++++
.../config/logic/SignResponsesPredicate.java | 46 ++++
.../ClientTLSArtifactRequestsPredicate.java | 46 ++++
.../messaging/SignArtifactRequestsPredicate.java | 46 ++++
.../config/logic/messaging/package-info.java | 21 ++
.../saml/profile/config/logic/package-info.java | 21 ++
.../saml/profile/config/package-info.java | 21 ++
.../logic/MappedEntityAttributesPredicate.java | 302 +++++++++++++++++++++
.../saml/profile/context/logic/package-info.java | 21 ++
.../SAMLMetadataContextLookupFunction.java | 51 ++++
.../profile/context/navigate/package-info.java | 21 ++
.../logic/EntityAttributesPredicateTest.java | 182 +++++++++++++
.../context/logic/attribute-mapping-metadata.xml | 63 +++++
.../context/logic/attribute-registry-service.xml | 41 +++
.../profile/context/logic/attribute-registry.xml | 28 ++
.../saml/profile/context/logic/rules/subjectid.txt | 3 +
.../saml/profile/context/logic/rules/zorkmids.txt | 4 +
27 files changed, 1328 insertions(+), 3 deletions(-)
diff --git a/pom.xml b/pom.xml
index 0227b39..ce757e2 100644
--- a/pom.xml
+++ b/pom.xml
@@ -22,7 +22,7 @@
<modules>
<module>shib-profile-api</module>
-<!-- <module>shib-saml-profile-api</module>-->
+ <module>shib-saml-profile-api</module>
<module>shib-profile-impl</module>
<!-- <module>shib-saml-profile-impl</module>-->
diff --git a/shib-profile-bom/pom.xml b/shib-profile-bom/pom.xml
index fe7c7ce..af5e860 100644
--- a/shib-profile-bom/pom.xml
+++ b/shib-profile-bom/pom.xml
@@ -33,12 +33,12 @@
<artifactId>shib-profile-impl</artifactId>
<version>${project.version}</version>
</dependency>
- <!--
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>shib-saml-profile-api</artifactId>
<version>${project.version}</version>
</dependency>
+ <!--
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>shib-saml-profile-impl</artifactId>
diff --git a/shib-profile-impl/src/main/java/net/shibboleth/profile/audit/impl/AttributesAuditExtractor.java b/shib-profile-impl/src/main/java/net/shibboleth/profile/audit/impl/AttributesAuditExtractor.java
new file mode 100644
index 0000000..ce7f324
--- /dev/null
+++ b/shib-profile-impl/src/main/java/net/shibboleth/profile/audit/impl/AttributesAuditExtractor.java
@@ -0,0 +1,100 @@
+/*
+ * 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.profile.audit.impl;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.function.Function;
+import java.util.function.Predicate;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.opensaml.messaging.context.navigate.ChildContextLookup;
+import org.opensaml.profile.context.ProfileRequestContext;
+
+import net.shibboleth.idp.attribute.context.AttributeContext;
+import net.shibboleth.profile.context.RelyingPartyContext;
+import net.shibboleth.shared.logic.Constraint;
+
+/** {@link Function} that returns the attribute IDs from an {@link AttributeContext}. */
+public class AttributesAuditExtractor implements Function<ProfileRequestContext,Collection<String>> {
+
+ /** Extract the unfiltered attribute list instead of the filtered list. */
+ private boolean useUnfiltered;
+
+ /** A predicate to control whether attributes should be extracted for logging. */
+ @Nullable private Predicate<ProfileRequestContext> activationCondition;
+
+ /** Lookup strategy for AttributeContext to read from. */
+ @Nonnull private final Function<ProfileRequestContext,AttributeContext> attributeContextLookupStrategy;
+
+ /** Constructor. */
+ public AttributesAuditExtractor() {
+ // Defaults to ProfileRequestContext -> RelyingPartyContext -> AttributeContext.
+ attributeContextLookupStrategy = new ChildContextLookup<>(AttributeContext.class).compose(
+ new ChildContextLookup<>(RelyingPartyContext.class));
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param strategy lookup strategy for {@link AttributeContext}
+ */
+ public AttributesAuditExtractor(@Nonnull final Function<ProfileRequestContext,AttributeContext> strategy) {
+ attributeContextLookupStrategy = Constraint.isNotNull(strategy,
+ "AttributeContext lookup strategy cannot be null");
+ }
+
+ /**
+ * Set whether to extract the list of unfiltered attributes instead of the filtered attributes.
+ *
+ * @param flag flag to set
+ */
+ public void setUseUnfiltered(final boolean flag) {
+ useUnfiltered = flag;
+ }
+
+ /**
+ * Set a condition to evaluate to control whether attributes are extracted for logging.
+ *
+ * <p>This is used primarily to prevent logging of attributes for profiles in which attributes
+ * may be resolved, but not actually disclosed to a relying party.</p>
+ *
+ * @param condition condition to evaluate
+ */
+ public void setActivationCondition(@Nullable final Predicate<ProfileRequestContext> condition) {
+ activationCondition = condition;
+ }
+
+ /** {@inheritDoc} */
+ @Nullable public Collection<String> apply(@Nullable final ProfileRequestContext input) {
+
+ if (activationCondition != null && !activationCondition.test(input)) {
+ return Collections.emptyList();
+ }
+
+ final AttributeContext attributeCtx = attributeContextLookupStrategy.apply(input);
+ if (attributeCtx != null) {
+ return (useUnfiltered ? attributeCtx.getUnfilteredIdPAttributes()
+ : attributeCtx.getIdPAttributes()).keySet();
+ }
+ return Collections.emptyList();
+ }
+
+}
\ No newline at end of file
diff --git a/shib-profile-impl/src/main/java/net/shibboleth/profile/audit/impl/package-info.java b/shib-profile-impl/src/main/java/net/shibboleth/profile/audit/impl/package-info.java
new file mode 100644
index 0000000..018eaf7
--- /dev/null
+++ b/shib-profile-impl/src/main/java/net/shibboleth/profile/audit/impl/package-info.java
@@ -0,0 +1,21 @@
+/*
+ * 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.
+ */
+
+/**
+ * Audit implementation classes.
+ */
+package net.shibboleth.profile.audit.impl;
\ No newline at end of file
diff --git a/shib-profile-impl/src/main/java/net/shibboleth/profile/relyingparty/impl/DefaultRelyingPartyConfigurationResolver.java b/shib-profile-impl/src/main/java/net/shibboleth/profile/relyingparty/impl/DefaultRelyingPartyConfigurationResolver.java
index e248705..e0e29da 100644
--- a/shib-profile-impl/src/main/java/net/shibboleth/profile/relyingparty/impl/DefaultRelyingPartyConfigurationResolver.java
+++ b/shib-profile-impl/src/main/java/net/shibboleth/profile/relyingparty/impl/DefaultRelyingPartyConfigurationResolver.java
@@ -240,7 +240,8 @@ public class DefaultRelyingPartyConfigurationResolver extends AbstractIdentifiab
if (matches.isEmpty()) {
log.debug("No matching relying party configuration applicable, returning default: {}",
getDefaultConfiguration().getId());
- return CollectionSupport.singleton(getDefaultConfiguration());
+ assert defaultRelyingPartyConfiguration != null;
+ return CollectionSupport.singleton(defaultRelyingPartyConfiguration);
}
return matches;
}
diff --git a/shib-saml-profile-api/pom.xml b/shib-saml-profile-api/pom.xml
index 2699c73..4f397ad 100644
--- a/shib-saml-profile-api/pom.xml
+++ b/shib-saml-profile-api/pom.xml
@@ -28,6 +28,11 @@
<version>${project.version}</version>
</dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>shib-saml-attribute-impl</artifactId>
+ </dependency>
+
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>shib-metadata-api</artifactId>
@@ -56,6 +61,12 @@
<!-- Runtime Dependencies -->
<!-- Test Dependencies -->
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>shib-attribute-impl</artifactId>
+ <scope>test</scope>
+ </dependency>
+
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>shib-metadata-impl</artifactId>
diff --git a/shib-saml-profile-api/src/main/java/net/shibboleth/saml/binding/BindingDescriptor.java b/shib-saml-profile-api/src/main/java/net/shibboleth/saml/binding/BindingDescriptor.java
new file mode 100644
index 0000000..3d4eff2
--- /dev/null
+++ b/shib-saml-profile-api/src/main/java/net/shibboleth/saml/binding/BindingDescriptor.java
@@ -0,0 +1,51 @@
+/*
+ * 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.saml.binding;
+
+import javax.annotation.Nullable;
+
+import net.shibboleth.shared.primitive.StringSupport;
+
+/**
+ * Subclass that adds awareness of a Spring bean ID for a binding's
+ * {@link org.opensaml.messaging.encoder.MessageEncoder}.
+ */
+public class BindingDescriptor extends org.opensaml.saml.common.binding.BindingDescriptor {
+
+ /** Spring bean ID of message encoder. */
+ @Nullable private String encoderBeanId;
+
+ /**
+ * Get the Spring bean ID of the binding's {@link org.opensaml.messaging.encoder.MessageEncoder}.
+ *
+ * @return bean ID of message encoder
+ */
+ @Nullable public String getEncoderBeanId() {
+ return encoderBeanId;
+ }
+
+ /**
+ * Set the Spring bean ID of the binding's {@link org.opensaml.messaging.encoder.MessageEncoder}.
+ *
+ * @param id bean ID of message encoder
+ */
+ public void setEncoderBeanId(@Nullable final String id) {
+ encoderBeanId = StringSupport.trimOrNull(id);
+ }
+
+}
\ No newline at end of file
diff --git a/shib-saml-profile-api/src/main/java/net/shibboleth/saml/binding/package-info.java b/shib-saml-profile-api/src/main/java/net/shibboleth/saml/binding/package-info.java
new file mode 100644
index 0000000..1ec56b0
--- /dev/null
+++ b/shib-saml-profile-api/src/main/java/net/shibboleth/saml/binding/package-info.java
@@ -0,0 +1,21 @@
+/*
+ * 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.
+ */
+
+/**
+ * Classes related to SAML bindings.
+ */
+package net.shibboleth.saml.binding;
\ No newline at end of file
diff --git a/shib-saml-profile-api/src/main/java/net/shibboleth/saml/profile/config/SAMLArtifactConsumerProfileConfiguration.java b/shib-saml-profile-api/src/main/java/net/shibboleth/saml/profile/config/SAMLArtifactConsumerProfileConfiguration.java
new file mode 100644
index 0000000..6c8c63c
--- /dev/null
+++ b/shib-saml-profile-api/src/main/java/net/shibboleth/saml/profile/config/SAMLArtifactConsumerProfileConfiguration.java
@@ -0,0 +1,48 @@
+/*
+ * 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.saml.profile.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.
+ */
+public interface SAMLArtifactConsumerProfileConfiguration extends SAMLProfileConfiguration {
+
+ /**
+ * 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/shib-saml-profile-api/src/main/java/net/shibboleth/saml/profile/config/SAMLProfileConfiguration.java b/shib-saml-profile-api/src/main/java/net/shibboleth/saml/profile/config/SAMLProfileConfiguration.java
new file mode 100644
index 0000000..ca7ad64
--- /dev/null
+++ b/shib-saml-profile-api/src/main/java/net/shibboleth/saml/profile/config/SAMLProfileConfiguration.java
@@ -0,0 +1,47 @@
+/*
+ * 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.saml.profile.config;
+
+import javax.annotation.Nullable;
+
+import org.opensaml.profile.context.ProfileRequestContext;
+
+import net.shibboleth.profile.config.ProfileConfiguration;
+
+/** Common interface for SAML profile configurations. */
+public interface SAMLProfileConfiguration extends ProfileConfiguration {
+
+ /**
+ * 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);
+
+}
\ No newline at end of file
diff --git a/shib-saml-profile-api/src/main/java/net/shibboleth/saml/profile/config/logic/SignRequestsPredicate.java b/shib-saml-profile-api/src/main/java/net/shibboleth/saml/profile/config/logic/SignRequestsPredicate.java
new file mode 100644
index 0000000..0b09855
--- /dev/null
+++ b/shib-saml-profile-api/src/main/java/net/shibboleth/saml/profile/config/logic/SignRequestsPredicate.java
@@ -0,0 +1,108 @@
+/*
+ * 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.saml.profile.config.logic;
+
+import java.util.function.Function;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import net.shibboleth.profile.config.ProfileConfiguration;
+import net.shibboleth.profile.context.RelyingPartyContext;
+import net.shibboleth.profile.context.logic.AbstractRelyingPartyPredicate;
+import net.shibboleth.saml.profile.context.navigate.SAMLMetadataContextLookupFunction;
+import net.shibboleth.saml.profile.config.SAMLProfileConfiguration;
+import net.shibboleth.shared.logic.Constraint;
+
+import org.opensaml.profile.context.ProfileRequestContext;
+import org.opensaml.saml.common.messaging.context.SAMLMetadataContext;
+import org.opensaml.saml.saml2.metadata.IDPSSODescriptor;
+import org.opensaml.saml.saml2.metadata.RoleDescriptor;
+
+/**
+ * A predicate implementation that forwards to
+ * {@link SAMLProfileConfiguration#isSignRequests(ProfileRequestContext)}
+ * or follows {@link IDPSSODescriptor#getWantAuthnRequestsSigned()} if so configured.
+ */
+public class SignRequestsPredicate extends AbstractRelyingPartyPredicate {
+
+ /** Whether to override the result based on the WantAuthnRequestsSigned flag in SAML metadata. */
+ private boolean honorMetadata;
+
+ /** Lookup strategy for {@link SAMLMetadataContext}. */
+ private Function<ProfileRequestContext,SAMLMetadataContext> metadataContextLookupStrategy;
+
+ /** Constructor. */
+ public SignRequestsPredicate() {
+ metadataContextLookupStrategy = new SAMLMetadataContextLookupFunction();
+ }
+
+ /**
+ * Set whether to override the result based on the WantAuthnRequestsSigned flag in SAML metadata.
+ *
+ * <p>Defaults to false.</p>
+ *
+ * @param flag flag to set
+ *
+ * @since 4.0.0
+ */
+ public void setHonorMetadata(final boolean flag) {
+ honorMetadata = flag;
+ }
+
+ /**
+ * Set lookup strategy for {@link SAMLMetadataContext}.
+ *
+ * @param strategy lookup strategy
+ *
+ * @since 4.0.0
+ */
+ public void setMetadataContextLookupStrategy(
+ @Nonnull final Function<ProfileRequestContext,SAMLMetadataContext> strategy) {
+ metadataContextLookupStrategy = Constraint.isNotNull(strategy,
+ "SAMLMetadataContext lookup strategy cannot be null");
+ }
+
+ /** {@inheritDoc} */
+ public boolean test(@Nullable final ProfileRequestContext input) {
+
+ if (honorMetadata) {
+ final SAMLMetadataContext metadataCtx = metadataContextLookupStrategy.apply(input);
+ if (metadataCtx != null) {
+ final RoleDescriptor role = metadataCtx.getRoleDescriptor();
+ if (role instanceof IDPSSODescriptor) {
+ final Boolean flag = ((IDPSSODescriptor) role).getWantAuthnRequestsSigned();
+ if (flag != null && flag.booleanValue()) {
+ return true;
+ }
+ }
+ }
+ }
+
+ final RelyingPartyContext rpc = getRelyingPartyContext(input);
+ if (rpc != null) {
+ final ProfileConfiguration pc = rpc.getProfileConfig();
+ if (pc != null && pc instanceof SAMLProfileConfiguration) {
+ return ((SAMLProfileConfiguration) pc).isSignRequests(input);
+ }
+ }
+
+ return false;
+ }
+
+}
\ No newline at end of file
diff --git a/shib-saml-profile-api/src/main/java/net/shibboleth/saml/profile/config/logic/SignResponsesPredicate.java b/shib-saml-profile-api/src/main/java/net/shibboleth/saml/profile/config/logic/SignResponsesPredicate.java
new file mode 100644
index 0000000..01b6fc4
--- /dev/null
+++ b/shib-saml-profile-api/src/main/java/net/shibboleth/saml/profile/config/logic/SignResponsesPredicate.java
@@ -0,0 +1,46 @@
+/*
+ * 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.saml.profile.config.logic;
+
+import javax.annotation.Nullable;
+
+import net.shibboleth.profile.config.ProfileConfiguration;
+import net.shibboleth.profile.context.RelyingPartyContext;
+import net.shibboleth.profile.context.logic.AbstractRelyingPartyPredicate;
+import net.shibboleth.saml.profile.config.SAMLProfileConfiguration;
+
+import org.opensaml.profile.context.ProfileRequestContext;
+
+/** A predicate implementation that forwards
+ * to {@link SAMLProfileConfiguration#isSignResponses(ProfileRequestContext)}. */
+public class SignResponsesPredicate extends AbstractRelyingPartyPredicate {
+
+ /** {@inheritDoc} */
+ public boolean test(@Nullable final ProfileRequestContext input) {
+ final RelyingPartyContext rpc = getRelyingPartyContext(input);
+ if (rpc != null) {
+ final ProfileConfiguration pc = rpc.getProfileConfig();
+ if (pc instanceof SAMLProfileConfiguration) {
+ return ((SAMLProfileConfiguration) pc).isSignResponses(input);
+ }
+ }
+
+ return false;
+ }
+
+}
\ No newline at end of file
diff --git a/shib-saml-profile-api/src/main/java/net/shibboleth/saml/profile/config/logic/messaging/ClientTLSArtifactRequestsPredicate.java b/shib-saml-profile-api/src/main/java/net/shibboleth/saml/profile/config/logic/messaging/ClientTLSArtifactRequestsPredicate.java
new file mode 100644
index 0000000..0d030cb
--- /dev/null
+++ b/shib-saml-profile-api/src/main/java/net/shibboleth/saml/profile/config/logic/messaging/ClientTLSArtifactRequestsPredicate.java
@@ -0,0 +1,46 @@
+/*
+ * 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.saml.profile.config.logic.messaging;
+
+import javax.annotation.Nullable;
+
+import org.opensaml.messaging.context.MessageContext;
+
+import net.shibboleth.profile.config.ProfileConfiguration;
+import net.shibboleth.profile.context.RelyingPartyContext;
+import net.shibboleth.profile.context.logic.messaging.AbstractRelyingPartyPredicate;
+import net.shibboleth.saml.profile.config.SAMLArtifactConsumerProfileConfiguration;
+
+/** A predicate implementation that forwards to
+ * {@link SAMLArtifactConsumerProfileConfiguration#isClientTLSArtifactRequests(MessageContext)}. */
+public class ClientTLSArtifactRequestsPredicate extends AbstractRelyingPartyPredicate {
+
+ /** {@inheritDoc} */
+ public boolean test(@Nullable final MessageContext input) {
+ final RelyingPartyContext rpc = getRelyingPartyContext(input);
+ if (rpc != null) {
+ final ProfileConfiguration pc = rpc.getProfileConfig();
+ if (pc != null && pc instanceof SAMLArtifactConsumerProfileConfiguration) {
+ return ((SAMLArtifactConsumerProfileConfiguration) pc).isClientTLSArtifactRequests(input);
+ }
+ }
+
+ return false;
+ }
+
+}
\ No newline at end of file
diff --git a/shib-saml-profile-api/src/main/java/net/shibboleth/saml/profile/config/logic/messaging/SignArtifactRequestsPredicate.java b/shib-saml-profile-api/src/main/java/net/shibboleth/saml/profile/config/logic/messaging/SignArtifactRequestsPredicate.java
new file mode 100644
index 0000000..4c2e230
--- /dev/null
+++ b/shib-saml-profile-api/src/main/java/net/shibboleth/saml/profile/config/logic/messaging/SignArtifactRequestsPredicate.java
@@ -0,0 +1,46 @@
+/*
+ * 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.saml.profile.config.logic.messaging;
+
+import javax.annotation.Nullable;
+
+import org.opensaml.messaging.context.MessageContext;
+
+import net.shibboleth.profile.config.ProfileConfiguration;
+import net.shibboleth.profile.context.RelyingPartyContext;
+import net.shibboleth.profile.context.logic.messaging.AbstractRelyingPartyPredicate;
+import net.shibboleth.saml.profile.config.SAMLArtifactConsumerProfileConfiguration;
+
+/** A predicate implementation that forwards to
+ * {@link SAMLArtifactConsumerProfileConfiguration#isSignArtifactRequests(MessageContext)}. */
+public class SignArtifactRequestsPredicate extends AbstractRelyingPartyPredicate {
+
+ /** {@inheritDoc} */
+ public boolean test(@Nullable final MessageContext input) {
+ final RelyingPartyContext rpc = getRelyingPartyContext(input);
+ if (rpc != null) {
+ final ProfileConfiguration pc = rpc.getProfileConfig();
+ if (pc != null && pc instanceof SAMLArtifactConsumerProfileConfiguration) {
+ return ((SAMLArtifactConsumerProfileConfiguration) pc).isSignArtifactRequests(input);
+ }
+ }
+
+ return false;
+ }
+
+}
\ No newline at end of file
diff --git a/shib-saml-profile-api/src/main/java/net/shibboleth/saml/profile/config/logic/messaging/package-info.java b/shib-saml-profile-api/src/main/java/net/shibboleth/saml/profile/config/logic/messaging/package-info.java
new file mode 100644
index 0000000..4e058f5
--- /dev/null
+++ b/shib-saml-profile-api/src/main/java/net/shibboleth/saml/profile/config/logic/messaging/package-info.java
@@ -0,0 +1,21 @@
+/*
+ * 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.
+ */
+
+/**
+ * Predicates based on message contexts and SAML profile configuration.
+ */
+package net.shibboleth.saml.profile.config.logic.messaging;
\ No newline at end of file
diff --git a/shib-saml-profile-api/src/main/java/net/shibboleth/saml/profile/config/logic/package-info.java b/shib-saml-profile-api/src/main/java/net/shibboleth/saml/profile/config/logic/package-info.java
new file mode 100644
index 0000000..b75813e
--- /dev/null
+++ b/shib-saml-profile-api/src/main/java/net/shibboleth/saml/profile/config/logic/package-info.java
@@ -0,0 +1,21 @@
+/*
+ * 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.
+ */
+
+/**
+ * Predicates based on SAML profile configuration.
+ */
+package net.shibboleth.saml.profile.config.logic;
\ No newline at end of file
diff --git a/shib-saml-profile-api/src/main/java/net/shibboleth/saml/profile/config/package-info.java b/shib-saml-profile-api/src/main/java/net/shibboleth/saml/profile/config/package-info.java
new file mode 100644
index 0000000..7262525
--- /dev/null
+++ b/shib-saml-profile-api/src/main/java/net/shibboleth/saml/profile/config/package-info.java
@@ -0,0 +1,21 @@
+/*
+ * 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.
+ */
+
+/**
+ * Generic SAML profile configuration.
+ */
+package net.shibboleth.saml.profile.config;
\ No newline at end of file
diff --git a/shib-saml-profile-api/src/main/java/net/shibboleth/saml/profile/context/logic/MappedEntityAttributesPredicate.java b/shib-saml-profile-api/src/main/java/net/shibboleth/saml/profile/context/logic/MappedEntityAttributesPredicate.java
new file mode 100644
index 0000000..7576340
--- /dev/null
+++ b/shib-saml-profile-api/src/main/java/net/shibboleth/saml/profile/context/logic/MappedEntityAttributesPredicate.java
@@ -0,0 +1,302 @@
+/*
+ * 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.saml.profile.context.logic;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.regex.Pattern;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.opensaml.core.xml.XMLObject;
+import org.opensaml.saml.common.profile.logic.EntityAttributesPredicate;
+import org.opensaml.saml.common.profile.logic.EntityAttributesPredicate.Candidate;
+import org.opensaml.saml.saml2.metadata.EntitiesDescriptor;
+import org.opensaml.saml.saml2.metadata.EntityDescriptor;
+import org.slf4j.Logger;
+
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Multimap;
+
+import net.shibboleth.idp.attribute.AttributesMapContainer;
+import net.shibboleth.idp.attribute.EmptyAttributeValue;
+import net.shibboleth.idp.attribute.EmptyAttributeValue.EmptyType;
+import net.shibboleth.shared.annotation.ParameterName;
+import net.shibboleth.shared.annotation.constraint.NonnullElements;
+import net.shibboleth.shared.annotation.constraint.NotEmpty;
+import net.shibboleth.shared.logic.Constraint;
+import net.shibboleth.shared.primitive.LoggerFactory;
+import net.shibboleth.shared.primitive.StringSupport;
+import net.shibboleth.idp.attribute.IdPAttribute;
+import net.shibboleth.idp.attribute.IdPAttributeValue;
+import net.shibboleth.idp.attribute.ScopedStringAttributeValue;
+import net.shibboleth.idp.attribute.StringAttributeValue;
+
+import java.util.function.Predicate;
+
+/**
+ * Extended version of EntityAttributes-driven predicate that uses an optimization to check
+ * for mapped attributes in an {@link AttributesMapContainer} structure.
+ */
+public class MappedEntityAttributesPredicate extends EntityAttributesPredicate {
+
+ /** Class logger. */
+ @Nonnull private final Logger log = LoggerFactory.getLogger(MappedEntityAttributesPredicate.class);
+
+ /** Delimiter to build string form of scoped values. */
+ @Nonnull @NotEmpty private String scopeDelimiter = "@";
+
+ /**
+ * Constructor.
+ *
+ * @param candidates the {@link Candidate} criteria to check for
+ */
+ public MappedEntityAttributesPredicate(
+ @Nonnull @NonnullElements @ParameterName(name="candidates") final Collection<Candidate> candidates) {
+ super(candidates);
+
+ Constraint.isTrue(Iterables.all(candidates, c -> c.getNameFormat() == null),
+ "Use of nameFormat property is impermissible with MappedEntityAttributesPredicate");
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param candidates the {@link Candidate} criteria to check for
+ * @param trim true iff the values found in the metadata should be trimmed before comparison
+ */
+ public MappedEntityAttributesPredicate(
+ @Nonnull @NonnullElements @ParameterName(name="candidates") final Collection<Candidate> candidates,
+ @ParameterName(name="trim") final boolean trim) {
+ super(candidates, trim);
+
+ Constraint.isTrue(Iterables.all(candidates, c -> c.getNameFormat() == null),
+ "Use of nameFormat property is impermissible with MappedEntityAttributesPredicate");
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param candidates the {@link Candidate} criteria to check for
+ * @param trim true iff the values found in the metadata should be trimmed before comparison
+ * @param all true iff all the criteria must match to be a successful test
+ */
+ public MappedEntityAttributesPredicate(
+ @Nonnull @NonnullElements @ParameterName(name="candidates") final Collection<Candidate> candidates,
+ @ParameterName(name="trim") final boolean trim,
+ @ParameterName(name="all") final boolean all) {
+ super(candidates, trim, all);
+
+ Constraint.isTrue(Iterables.all(candidates, c -> c.getNameFormat() == null),
+ "Use of nameFormat property is impermissible with MappedEntityAttributesPredicate");
+ }
+
+ /**
+ * Set delimiter for constructing scoped values for comparison.
+ *
+ * <p>Defaults to '@'.</p>
+ *
+ * @param delimiter delimiter to use
+ */
+ public void setScopeDelimiter(@Nonnull @NotEmpty final String delimiter) {
+ scopeDelimiter = Constraint.isNotNull(StringSupport.trimOrNull(delimiter),
+ "Scope delimiter cannot be null or empty");
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean test(@Nullable final EntityDescriptor input) {
+
+ if (getCandidates().isEmpty()) {
+ return true;
+ } else if (input == null) {
+ return false;
+ }
+
+ final Collection<Candidate> candidates = new ArrayList<>(getCandidates());
+
+ if (doTest(input, input.getEntityID(), candidates)) {
+
+ // At least one match. Check if sufficient.
+ if (!getMatchAll() || candidates.isEmpty()) {
+ return true;
+ }
+ }
+
+ XMLObject parent = input.getParent();
+ while (parent instanceof EntitiesDescriptor) {
+ if (doTest(parent, ((EntitiesDescriptor) parent).getName(), candidates)) {
+
+ // At least one match. Check if sufficient.
+ if (!getMatchAll() || candidates.isEmpty()) {
+ return true;
+ }
+ }
+ parent = parent.getParent();
+ }
+
+ return false;
+ }
+
+ /**
+ * Evaluate the input object's attached object metadata against the supplied candidates.
+ *
+ * <p>Any candidates that match will be removed from the input collection.</p>
+ *
+ * @param input input object
+ * @param name label for logging
+ * @param candidates candidates to check
+ *
+ * @return true iff the attached object metadata matched at least one input candidate
+ */
+ private boolean doTest(@Nonnull final XMLObject input, @Nullable final String name,
+ @Nonnull @NonnullElements final Collection<Candidate> candidates) {
+ final List<AttributesMapContainer> containerList =
+ input.getObjectMetadata().get(AttributesMapContainer.class);
+ if (null == containerList || containerList.isEmpty() || containerList.get(0).get() == null ||
+ containerList.get(0).get().isEmpty()) {
+ log.trace("No mapped Entity Attributes for {}", name);
+ return false;
+ }
+
+ final Multimap<String,? extends IdPAttribute> entityAttributes = containerList.get(0).get();
+
+ log.trace("Checking for match against {} Entity Attributes for {}", entityAttributes.size(),
+ name);
+
+ // Remove each candidate that matches. Tag values are OR'd for matching purposes.
+ // Return true iff at least one candidate matches.
+ return candidates.removeIf(new EntityAttributesMatcher(entityAttributes));
+ }
+
+ /**
+ * Determines whether an {@link Candidate} criterion is satisfied by the mapped
+ * attributes in an entity's metadata.
+ */
+ private class EntityAttributesMatcher implements Predicate<Candidate> {
+
+ /** Population to evaluate for a match. */
+ @Nonnull private final Multimap<String,? extends IdPAttribute> attributes;
+
+ /**
+ * Constructor.
+ *
+ * @param attrs population to evaluate for a match
+ */
+ public EntityAttributesMatcher(@Nonnull @NonnullElements final Multimap<String,? extends IdPAttribute> attrs) {
+ attributes = Constraint.isNotNull(attrs, "Extension attributes cannot be null");
+ }
+
+// Checkstyle: CyclomaticComplexity OFF
+ /** {@inheritDoc} */
+ public boolean test(@Nullable final Candidate input) {
+
+ if (input == null || input.getNameFormat() != null) {
+ return false;
+ }
+
+ final List<String> tagvals = input.getValues();
+ final List<Pattern> tagexps = input.getRegexps();
+
+ // Track whether we've found every match we need (possibly with arrays of 0 size).
+ final boolean[] valflags = new boolean[tagvals.size()];
+ final boolean[] expflags = new boolean[tagexps.size()];
+
+ // Check each attribute/tag in the populated set.
+ for (final IdPAttribute a : attributes.get(input.getName())) {
+
+ // Check each tag value's simple content for a value match.
+ for (int tagindex = 0; tagindex < tagvals.size(); ++tagindex) {
+ final String tagvalstr = tagvals.get(tagindex);
+
+ for (final IdPAttributeValue cval : a.getValues()) {
+ assert cval != null;
+ final String cvalstr = attributeValueToString(cval);
+ if (tagvalstr != null && cvalstr != null) {
+ if (tagvalstr.equals(cvalstr)) {
+ log.trace("Matched mapped Entity Attribute ({}) value {}", a.getId(), tagvalstr);
+ valflags[tagindex] = true;
+ break;
+ } else if (getTrimTags()) {
+ if (tagvalstr.equals(cvalstr.trim())) {
+ log.trace("Matched mapped Entity Attribute ({}) value {}", a.getId(), tagvalstr);
+ valflags[tagindex] = true;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ // Check each tag regular expression for a match.
+ for (int tagindex = 0; tagindex < tagexps.size(); ++tagindex) {
+
+ for (final IdPAttributeValue cval : a.getValues()) {
+ assert cval != null;
+ final String cvalstr = attributeValueToString(cval);
+ if (tagexps.get(tagindex) != null && cvalstr != null) {
+ if (tagexps.get(tagindex).matcher(cvalstr).matches()) {
+ log.trace("Matched mapped Entity Attribute ({}) value {}", a.getId(), cvalstr);
+ expflags[tagindex] = true;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ for (final boolean flag : valflags) {
+ if (!flag) {
+ return false;
+ }
+ }
+
+ for (final boolean flag : expflags) {
+ if (!flag) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+// Checkstyle: CyclomaticComplexity ON
+
+ /**
+ * Convert an IdPAttributeValue to a String if the type is recognized.
+ *
+ * @param value object to convert
+ * @return the converted value, or null
+ */
+ @Nullable private String attributeValueToString(@Nonnull final IdPAttributeValue value) {
+
+ if (value instanceof ScopedStringAttributeValue) {
+ return ((ScopedStringAttributeValue) value).getValue() + scopeDelimiter +
+ ((ScopedStringAttributeValue) value).getScope();
+ } else if (value instanceof StringAttributeValue) {
+ return ((StringAttributeValue) value).getValue();
+ } else if (value instanceof EmptyAttributeValue) {
+ final EmptyType empty = ((EmptyAttributeValue) value).getValue();
+ return EmptyType.ZERO_LENGTH_VALUE.equals(empty) ? "" : null;
+ }
+ return null;
+ }
+ }
+
+}
diff --git a/shib-saml-profile-api/src/main/java/net/shibboleth/saml/profile/context/logic/package-info.java b/shib-saml-profile-api/src/main/java/net/shibboleth/saml/profile/context/logic/package-info.java
new file mode 100644
index 0000000..c0e1ba0
--- /dev/null
+++ b/shib-saml-profile-api/src/main/java/net/shibboleth/saml/profile/context/logic/package-info.java
@@ -0,0 +1,21 @@
+/*
+ * 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.
+ */
+
+/**
+ * Predicates operating against SAML contexts.
+ */
+package net.shibboleth.saml.profile.context.logic;
\ No newline at end of file
diff --git a/shib-saml-profile-api/src/main/java/net/shibboleth/saml/profile/context/navigate/SAMLMetadataContextLookupFunction.java b/shib-saml-profile-api/src/main/java/net/shibboleth/saml/profile/context/navigate/SAMLMetadataContextLookupFunction.java
new file mode 100644
index 0000000..29a0607
--- /dev/null
+++ b/shib-saml-profile-api/src/main/java/net/shibboleth/saml/profile/context/navigate/SAMLMetadataContextLookupFunction.java
@@ -0,0 +1,51 @@
+/*
+ * 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.saml.profile.context.navigate;
+
+import javax.annotation.Nullable;
+
+import net.shibboleth.profile.context.RelyingPartyContext;
+import net.shibboleth.profile.context.navigate.AbstractRelyingPartyLookupFunction;
+
+import org.opensaml.messaging.context.BaseContext;
+import org.opensaml.profile.context.ProfileRequestContext;
+import org.opensaml.saml.common.messaging.context.SAMLMetadataContext;
+
+/**
+ * A function to access a {@link SAMLMetadataContext} underlying a {@link RelyingPartyContext} located via a
+ * lookup function, by default a child of the profile request context.
+ */
+public class SAMLMetadataContextLookupFunction extends AbstractRelyingPartyLookupFunction<SAMLMetadataContext> {
+
+ /** {@inheritDoc} */
+ @Nullable public SAMLMetadataContext apply(@Nullable final ProfileRequestContext input) {
+ final RelyingPartyContext rpCtx = getRelyingPartyContext(input);
+ if (rpCtx != null) {
+ final BaseContext peer = rpCtx.getRelyingPartyIdContextTree();
+ if (peer != null) {
+ if (peer instanceof SAMLMetadataContext) {
+ return (SAMLMetadataContext) peer;
+ }
+ return peer.getSubcontext(SAMLMetadataContext.class);
+ }
+ }
+
+ return null;
+ }
+
+}
\ No newline at end of file
diff --git a/shib-saml-profile-api/src/main/java/net/shibboleth/saml/profile/context/navigate/package-info.java b/shib-saml-profile-api/src/main/java/net/shibboleth/saml/profile/context/navigate/package-info.java
new file mode 100644
index 0000000..dd1d585
--- /dev/null
+++ b/shib-saml-profile-api/src/main/java/net/shibboleth/saml/profile/context/navigate/package-info.java
@@ -0,0 +1,21 @@
+/*
+ * 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.
+ */
+
+/**
+ * Context lookup functions related to SAML contexts.
+ */
+package net.shibboleth.saml.profile.context.navigate;
\ No newline at end of file
diff --git a/shib-saml-profile-api/src/test/java/net/shibboleth/saml/profile/context/logic/EntityAttributesPredicateTest.java b/shib-saml-profile-api/src/test/java/net/shibboleth/saml/profile/context/logic/EntityAttributesPredicateTest.java
new file mode 100644
index 0000000..f44019b
--- /dev/null
+++ b/shib-saml-profile-api/src/test/java/net/shibboleth/saml/profile/context/logic/EntityAttributesPredicateTest.java
@@ -0,0 +1,182 @@
+/*
+ * 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.saml.profile.context.logic;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.opensaml.core.criterion.EntityIdCriterion;
+import org.opensaml.core.testing.XMLObjectBaseTestCase;
+import org.opensaml.saml.common.profile.logic.EntityAttributesPredicate;
+import org.opensaml.saml.common.profile.logic.EntityAttributesPredicate.Candidate;
+import org.opensaml.saml.metadata.resolver.MetadataResolver;
+import org.opensaml.saml.metadata.resolver.filter.MetadataNodeProcessor;
+import org.opensaml.saml.metadata.resolver.filter.impl.NodeProcessingMetadataFilter;
+import org.opensaml.saml.metadata.resolver.impl.DOMMetadataResolver;
+import org.opensaml.saml.saml2.core.Attribute;
+import org.opensaml.saml.saml2.metadata.EntityDescriptor;
+import org.springframework.context.support.ConversionServiceFactoryBean;
+import org.springframework.context.support.GenericApplicationContext;
+import org.testng.Assert;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+import org.w3c.dom.Document;
+
+import net.shibboleth.idp.attribute.transcoding.AttributeTranscoderRegistry;
+import net.shibboleth.idp.saml.attribute.impl.AttributeMappingNodeProcessor;
+import net.shibboleth.shared.annotation.constraint.NotEmpty;
+import net.shibboleth.shared.collection.CollectionSupport;
+import net.shibboleth.shared.resolver.CriteriaSet;
+import net.shibboleth.shared.resolver.ResolverException;
+import net.shibboleth.shared.service.ReloadableService;
+import net.shibboleth.shared.spring.config.StringToDurationConverter;
+import net.shibboleth.shared.spring.custom.SchemaTypeAwareXMLBeanDefinitionReader;
+
+/**
+ * Unit test for {@link EntityAttributesPredicate} and {@link MappedEntityAttributesPredicate}.
+ */
+ at SuppressWarnings("javadoc")
+public class EntityAttributesPredicateTest extends XMLObjectBaseTestCase {
+
+ @Nonnull @NotEmpty private String fooEntityID = "http://foo.example.org/shibboleth";
+
+ @Nonnull @NotEmpty private String barEntityID = "http://bar.example.org/shibboleth";
+
+ @Nonnull @NotEmpty private String bazEntityID = "http://baz.example.org/shibboleth";
+
+ @Nullable private GenericApplicationContext pendingTeardownContext;
+
+ @Nullable private MetadataResolver resolver;
+
+ @BeforeClass
+ protected void setUp() throws Exception {
+ final String mdFileName = "/net/shibboleth/saml/profile/context/logic/attribute-mapping-metadata.xml";
+
+ final Document mdDoc = parserPool.parse(getClass().getResourceAsStream(mdFileName));
+ final DOMMetadataResolver mdProvider = new DOMMetadataResolver(mdDoc.getDocumentElement());
+
+ final ArrayList<MetadataNodeProcessor> processors = new ArrayList<>();
+ processors.add(new AttributeMappingNodeProcessor(getService()));
+
+ final NodeProcessingMetadataFilter nodeFilter = new NodeProcessingMetadataFilter();
+ nodeFilter.setNodeProcessors(processors);
+ nodeFilter.initialize();
+
+ mdProvider.setMetadataFilter(nodeFilter);
+ mdProvider.setId("Test");
+ mdProvider.initialize();
+
+ resolver = mdProvider;
+ }
+
+ @AfterClass public void tearDownTestContext() {
+ if (null != pendingTeardownContext) {
+ pendingTeardownContext.close();
+ pendingTeardownContext = null;
+ }
+ }
+
+ private void setTestContext(GenericApplicationContext context) {
+ tearDownTestContext();
+ pendingTeardownContext = context;
+ }
+
+ private EntityDescriptor getEntity(@Nonnull final String entityID) throws ResolverException {
+ assert resolver != null;
+ return resolver.resolveSingle(new CriteriaSet(new EntityIdCriterion(entityID)));
+ }
+
+ private ReloadableService<AttributeTranscoderRegistry> getService() {
+ final GenericApplicationContext context = new GenericApplicationContext();
+ setTestContext(context);
+ context.setDisplayName("ApplicationContext: ");
+
+ final ConversionServiceFactoryBean service = new ConversionServiceFactoryBean();
+ service.setConverters(new HashSet<>(CollectionSupport.listOf(new StringToDurationConverter())));
+ service.afterPropertiesSet();
+
+ context.getBeanFactory().setConversionService(service.getObject());
+
+ final SchemaTypeAwareXMLBeanDefinitionReader beanDefinitionReader =
+ new SchemaTypeAwareXMLBeanDefinitionReader(context);
+
+ beanDefinitionReader.loadBeanDefinitions("/net/shibboleth/saml/profile/context/logic/attribute-registry-service.xml");
+ context.refresh();
+
+ return context.getBean(ReloadableService.class);
+ }
+
+ @Test
+ public void testSimpleMatch() throws ResolverException {
+
+ final Candidate tag = new Candidate("zorkmids", Attribute.BASIC);
+ tag.setValues(CollectionSupport.singletonList("10"));
+
+ final EntityAttributesPredicate predicate = new EntityAttributesPredicate(CollectionSupport.singletonList(tag));
+ Assert.assertFalse(predicate.test(getEntity(fooEntityID)));
+ Assert.assertTrue(predicate.test(getEntity(barEntityID)));
+ Assert.assertFalse(predicate.test(getEntity(bazEntityID)));
+ }
+
+ @Test
+ public void testMultiLevelMatch() throws ResolverException {
+ final Candidate tag1 = new Candidate("http://macedir.org/entity-category", Attribute.URI_REFERENCE);
+ tag1.setValues(CollectionSupport.singletonList("http://refeds.org/category/research-and-scholarship"));
+
+ final Candidate tag2 = new Candidate("urn:oasis:names:tc:SAML:profiles:subject-id:req", Attribute.URI_REFERENCE);
+ tag2.setValues(CollectionSupport.singletonList("none"));
+
+ final EntityAttributesPredicate predicate =
+ new EntityAttributesPredicate(CollectionSupport.listOf(tag1, tag2), false, true);
+ Assert.assertTrue(predicate.test(getEntity(fooEntityID)));
+ Assert.assertFalse(predicate.test(getEntity(barEntityID)));
+ Assert.assertFalse(predicate.test(getEntity(bazEntityID)));
+ }
+
+ @Test
+ public void testSimpleMatchMapped() throws ResolverException {
+
+ final Candidate tag = new Candidate("zorkmids");
+ tag.setValues(CollectionSupport.singletonList("10"));
+
+ final MappedEntityAttributesPredicate predicate = new MappedEntityAttributesPredicate(CollectionSupport.singletonList(tag));
+ Assert.assertFalse(predicate.test(getEntity(fooEntityID)));
+ Assert.assertTrue(predicate.test(getEntity(barEntityID)));
+ Assert.assertFalse(predicate.test(getEntity(bazEntityID)));
+ }
+
+ @Test
+ public void testMultiLevelMappedMatch() throws ResolverException {
+ final Candidate tag1 = new Candidate("http://macedir.org/entity-category");
+ tag1.setValues(CollectionSupport.singletonList("http://refeds.org/category/research-and-scholarship"));
+
+ final Candidate tag2 = new Candidate("subject-id-req");
+ tag2.setValues(CollectionSupport.singletonList("none"));
+
+ final MappedEntityAttributesPredicate predicate =
+ new MappedEntityAttributesPredicate(CollectionSupport.listOf(tag1, tag2), false, true);
+ Assert.assertTrue(predicate.test(getEntity(fooEntityID)));
+ Assert.assertFalse(predicate.test(getEntity(barEntityID)));
+ Assert.assertFalse(predicate.test(getEntity(bazEntityID)));
+ }
+
+}
\ No newline at end of file
diff --git a/shib-saml-profile-api/src/test/resources/net/shibboleth/saml/profile/context/logic/attribute-mapping-metadata.xml b/shib-saml-profile-api/src/test/resources/net/shibboleth/saml/profile/context/logic/attribute-mapping-metadata.xml
new file mode 100644
index 0000000..a9850f5
--- /dev/null
+++ b/shib-saml-profile-api/src/test/resources/net/shibboleth/saml/profile/context/logic/attribute-mapping-metadata.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<EntitiesDescriptor Name="example.org"
+ xmlns="urn:oasis:names:tc:SAML:2.0:metadata"
+ xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
+ xmlns:mdattr="urn:oasis:names:tc:SAML:metadata:attribute">
+
+ <Extensions>
+ <mdattr:EntityAttributes>
+ <saml:Attribute Name="http://macedir.org/entity-category"
+ NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri">
+ <saml:AttributeValue>http://refeds.org/category/research-and-scholarship</saml:AttributeValue>
+ </saml:Attribute>
+ </mdattr:EntityAttributes>
+ </Extensions>
+
+ <EntityDescriptor entityID="http://foo.example.org/shibboleth">
+
+ <Extensions>
+ <mdattr:EntityAttributes>
+ <saml:Attribute Name="urn:oasis:names:tc:SAML:profiles:subject-id:req"
+ NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri">
+ <saml:AttributeValue>none</saml:AttributeValue>
+ </saml:Attribute>
+ </mdattr:EntityAttributes>
+ </Extensions>
+
+ <IDPSSODescriptor protocolSupportEnumeration="foo">
+ <SingleSignOnService Binding="urn:mace:shibboleth:1.0:profiles:AuthnRequest" Location="https://foo.example.org/shibboleth/SSO_BAR"/>
+ </IDPSSODescriptor>
+
+ </EntityDescriptor>
+
+
+ <EntityDescriptor entityID="http://bar.example.org/shibboleth">
+
+ <Extensions>
+ <mdattr:EntityAttributes>
+ <saml:Attribute Name="zorkmids"
+ NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
+ <saml:AttributeValue>10</saml:AttributeValue>
+ </saml:Attribute>
+ <saml:Attribute Name="babelfish"
+ NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
+ <saml:AttributeValue>10</saml:AttributeValue>
+ </saml:Attribute>
+ </mdattr:EntityAttributes>
+ </Extensions>
+
+ <SPSSODescriptor protocolSupportEnumeration="foo">
+ <AssertionConsumerService Binding="urn:oasis:names:tc:SAML:1.0:profiles:browser-post" Location="https://bar.example.org/Shibboleth.sso/POST" index="0"/>
+ </SPSSODescriptor>
+
+ </EntityDescriptor>
+
+ <EntityDescriptor entityID="http://baz.example.org/shibboleth">
+
+ <SPSSODescriptor protocolSupportEnumeration="foo">
+ <AssertionConsumerService Binding="urn:oasis:names:tc:SAML:1.0:profiles:browser-post" Location="https://baz.example.org/Shibboleth.sso/POST" index="0"/>
+ </SPSSODescriptor>
+
+ </EntityDescriptor>
+
+</EntitiesDescriptor>
diff --git a/shib-saml-profile-api/src/test/resources/net/shibboleth/saml/profile/context/logic/attribute-registry-service.xml b/shib-saml-profile-api/src/test/resources/net/shibboleth/saml/profile/context/logic/attribute-registry-service.xml
new file mode 100644
index 0000000..6046385
--- /dev/null
+++ b/shib-saml-profile-api/src/test/resources/net/shibboleth/saml/profile/context/logic/attribute-registry-service.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans"
+ xmlns:context="http://www.springframework.org/schema/context"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:util="http://www.springframework.org/schema/util"
+ xmlns:p="http://www.springframework.org/schema/p"
+ xmlns:c="http://www.springframework.org/schema/c"
+ xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
+ http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
+ http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"
+ default-init-method="initialize"
+ default-destroy-method="destroy">
+
+ <!-- Needed to allow for auto-wiring of descriptors and other componnents. -->
+ <context:annotation-config />
+
+ <bean id="SAML2NamingFunction" destroy-method=""
+ class="net.shibboleth.idp.attribute.transcoding.BasicNamingFunction"
+ c:claz="org.opensaml.saml.saml2.core.Attribute">
+ <constructor-arg name="function">
+ <bean destroy-method=""
+ class="net.shibboleth.idp.saml.attribute.transcoding.AbstractSAML2AttributeTranscoder.NamingFunction" />
+ </constructor-arg>
+ </bean>
+
+ <bean id="RegistryServiceStrategy" class="net.shibboleth.idp.attribute.transcoding.impl.AttributeRegistryServiceStrategy"
+ p:id="shibboleth.AttributeRegistryService" />
+
+ <bean id="shibboleth.AttributeRegistryService" class="net.shibboleth.shared.spring.service.ReloadableSpringService"
+ c:claz="net.shibboleth.idp.attribute.transcoding.AttributeTranscoderRegistry"
+ c:strategy-ref="RegistryServiceStrategy"
+ p:failFast="true"
+ p:reloadCheckDelay="0">
+ <property name="serviceConfigurations">
+ <util:list>
+ <value>net/shibboleth/saml/profile/context/logic/attribute-registry.xml</value>
+ </util:list>
+ </property>
+ </bean>
+
+</beans>
\ No newline at end of file
diff --git a/shib-saml-profile-api/src/test/resources/net/shibboleth/saml/profile/context/logic/attribute-registry.xml b/shib-saml-profile-api/src/test/resources/net/shibboleth/saml/profile/context/logic/attribute-registry.xml
new file mode 100644
index 0000000..137c7f1
--- /dev/null
+++ b/shib-saml-profile-api/src/test/resources/net/shibboleth/saml/profile/context/logic/attribute-registry.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans"
+ xmlns:context="http://www.springframework.org/schema/context"
+ xmlns:util="http://www.springframework.org/schema/util"
+ xmlns:p="http://www.springframework.org/schema/p"
+ xmlns:c="http://www.springframework.org/schema/c"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
+ http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
+ http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"
+
+ default-init-method="initialize"
+ default-destroy-method="destroy">
+
+ <bean id="SAML2StringTranscoder"
+ class="net.shibboleth.idp.saml.attribute.transcoding.impl.SAML2StringAttributeTranscoder" />
+ <bean id="SAML2ScopedStringTranscoder"
+ class="net.shibboleth.idp.saml.attribute.transcoding.impl.SAML2ScopedStringAttributeTranscoder" />
+ <bean id="SAML2ByteTranscoder"
+ class="net.shibboleth.idp.saml.attribute.transcoding.impl.SAML2ByteAttributeTranscoder" />
+ <bean id="SAML2XMLObjectTranscoder"
+ class="net.shibboleth.idp.saml.attribute.transcoding.impl.SAML2XMLObjectAttributeTranscoder" />
+
+ <bean id="shibboleth.TranscodingRuleLoader" destroy-method=""
+ class="net.shibboleth.idp.attribute.transcoding.impl.TranscodingRuleLoader"
+ c:dir="net/shibboleth/saml/profile/context/logic/rules" />
+
+</beans>
diff --git a/shib-saml-profile-api/src/test/resources/net/shibboleth/saml/profile/context/logic/rules/subjectid.txt b/shib-saml-profile-api/src/test/resources/net/shibboleth/saml/profile/context/logic/rules/subjectid.txt
new file mode 100644
index 0000000..17d1ceb
--- /dev/null
+++ b/shib-saml-profile-api/src/test/resources/net/shibboleth/saml/profile/context/logic/rules/subjectid.txt
@@ -0,0 +1,3 @@
+id = subject-id-req
+transcoder = SAML2StringTranscoder
+saml2.name = urn:oasis:names:tc:SAML:profiles:subject-id:req
diff --git a/shib-saml-profile-api/src/test/resources/net/shibboleth/saml/profile/context/logic/rules/zorkmids.txt b/shib-saml-profile-api/src/test/resources/net/shibboleth/saml/profile/context/logic/rules/zorkmids.txt
new file mode 100644
index 0000000..1b25004
--- /dev/null
+++ b/shib-saml-profile-api/src/test/resources/net/shibboleth/saml/profile/context/logic/rules/zorkmids.txt
@@ -0,0 +1,4 @@
+id = zorkmids
+transcoder = SAML2StringTranscoder
+saml2.name = zorkmids
+saml2.nameFormat = urn:oasis:names:tc:SAML:2.0:attrname-format:basic
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list