[java-shib-profile] branch main updated: JSPROF-1 - Move RelyingParty "layer" into java-shib-profile
Scott Cantor
cantor.2 at osu.edu
Tue Feb 14 13:25:09 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=72ef0a9218f204f3f7266b7917c6042420c55bbe
The following commit(s) were added to refs/heads/main by this push:
new 72ef0a9 JSPROF-1 - Move RelyingParty "layer" into java-shib-profile
72ef0a9 is described below
commit 72ef0a9218f204f3f7266b7917c6042420c55bbe
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Tue Feb 14 08:25:06 2023 -0500
JSPROF-1 - Move RelyingParty "layer" into java-shib-profile
Migrate in RelayingParty classes and resolver.
Collapse out criteria-based reslver.
Add VerifiedProfileCriterion.
Add testing module.
---
pom.xml | 4 +-
.../profile/context/RelyingPartyContext.java | 228 +++++++++++
.../shibboleth/profile/context/package-info.java | 21 +
.../relyingparty/RelyingPartyConfiguration.java | 157 ++++++++
.../RelyingPartyConfigurationResolver.java | 75 ++++
.../relyingparty/VerifiedProfileCriterion.java | 87 ++++
.../profile/relyingparty/package-info.java | 21 +
shib-profile-bom/pom.xml | 10 +-
shib-profile-impl/pom.xml | 12 +
.../DefaultRelyingPartyConfigurationResolver.java | 440 +++++++++++++++++++++
.../profile/relyingparty/impl/package-info.java | 21 +
...faultRelyingPartyConfigurationResolverTest.java | 183 +++++++++
.../impl/RelyingPartyConfigurationTest.java | 120 ++++++
.../pom.xml | 47 +--
.../config/testing/MockProfileConfiguration.java | 41 ++
.../profile/config/testing/package-info.java | 21 +
16 files changed, 1463 insertions(+), 25 deletions(-)
diff --git a/pom.xml b/pom.xml
index dd9604e..0227b39 100644
--- a/pom.xml
+++ b/pom.xml
@@ -24,9 +24,11 @@
<module>shib-profile-api</module>
<!-- <module>shib-saml-profile-api</module>-->
-<!-- <module>shib-profile-impl</module>-->
+ <module>shib-profile-impl</module>
<!-- <module>shib-saml-profile-impl</module>-->
+ <module>shib-profile-testing</module>
+
<module>shib-profile-bom</module>
</modules>
diff --git a/shib-profile-api/src/main/java/net/shibboleth/profile/context/RelyingPartyContext.java b/shib-profile-api/src/main/java/net/shibboleth/profile/context/RelyingPartyContext.java
new file mode 100644
index 0000000..e39b2ee
--- /dev/null
+++ b/shib-profile-api/src/main/java/net/shibboleth/profile/context/RelyingPartyContext.java
@@ -0,0 +1,228 @@
+/*
+ * 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.context;
+
+import java.util.function.Function;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import net.shibboleth.profile.config.ProfileConfiguration;
+import net.shibboleth.profile.relyingparty.RelyingPartyConfiguration;
+import net.shibboleth.shared.logic.Constraint;
+import net.shibboleth.shared.primitive.StringSupport;
+
+import org.opensaml.messaging.context.BaseContext;
+
+/**
+ * {@link BaseContext} containing relying party specific information, usually a
+ * subcontext of {@link org.opensaml.profile.context.ProfileRequestContext}.
+ */
+public final class RelyingPartyContext extends BaseContext {
+
+ /** Optional flag indicating whether verification was done. */
+ @Nullable private Boolean verified;
+
+ /** The identifier for the relying party. */
+ @Nullable private String relyingPartyId;
+
+ /** A pointer to a context tree containing identifying material for the relying party. */
+ @Nullable private BaseContext relyingPartyIdContextTree;
+
+ /** A lookup strategy for deriving verification based on the context. */
+ @Nullable private Function<RelyingPartyContext,Boolean> verificationLookupStrategy;
+
+ /** A lookup strategy for deriving a relying party ID based on contained information. */
+ @Nullable private Function<RelyingPartyContext,String> relyingPartyIdLookupStrategy;
+
+ /** The relying party configuration. */
+ @Nullable private RelyingPartyConfiguration relyingPartyConfiguration;
+
+ /** Profile configuration that is in use. */
+ @Nullable private ProfileConfiguration profileConfiguration;
+
+ /**
+ * Get whether the relying party was verified in some fashion.
+ *
+ * @return true iff the relying party's identity was verified
+ */
+ public boolean isVerified() {
+ if (verified != null) {
+ return verified;
+ } else if (verificationLookupStrategy != null) {
+ final Boolean flag = verificationLookupStrategy.apply(this);
+ if (flag != null) {
+ return flag;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Set whether the relying party was verified in some fashion.
+ *
+ * @param flag explicit value for the verified setting
+ *
+ * @return this context
+ */
+ @Nonnull public RelyingPartyContext setVerified(@Nullable final Boolean flag) {
+ verified = flag;
+ return this;
+ }
+
+ /**
+ * Get the unique identifier of the relying party.
+ *
+ * @return unique identifier of the relying party
+ */
+ @Nullable public String getRelyingPartyId() {
+
+ if (relyingPartyId != null) {
+ return relyingPartyId;
+ } else if (relyingPartyIdLookupStrategy != null) {
+ return relyingPartyIdLookupStrategy.apply(this);
+ } else {
+ return null;
+ }
+ }
+
+
+ /**
+ * Set the unique identifier of the relying party.
+ *
+ * @param rpId the relying party identifier, or null
+ *
+ * @return this context
+ */
+ @Nonnull public RelyingPartyContext setRelyingPartyId(@Nullable final String rpId) {
+ relyingPartyId = StringSupport.trimOrNull(rpId);
+ return this;
+ }
+
+ /**
+ * Get the context tree containing identifying information for this relying party.
+ *
+ * <p>The subtree root may, but need not, be an actual subcontext of this context.</p>
+ *
+ * @return context tree
+ */
+ @Nullable public BaseContext getRelyingPartyIdContextTree() {
+ return relyingPartyIdContextTree;
+ }
+
+ /**
+ * Set the context tree containing identifying information for this relying party.
+ *
+ * <p>The subtree root may, but need not, be an actual subcontext of this context.</p>
+ *
+ * @param root root of context tree
+ *
+ * @return this context
+ */
+ @Nonnull public RelyingPartyContext setRelyingPartyIdContextTree(@Nullable final BaseContext root) {
+ relyingPartyIdContextTree = root;
+ return this;
+ }
+
+ /**
+ * Get the lookup strategy for a non-explicit verification determination.
+ *
+ * @return lookup strategy
+ */
+ @Nullable Function<RelyingPartyContext,Boolean> getVerificationLookupStrategy() {
+ return verificationLookupStrategy;
+ }
+
+ /**
+ * Set the lookup strategy for a non-explicit verification determination.
+ *
+ * @param strategy lookup strategy
+ *
+ * @return this context
+ */
+ @Nonnull public RelyingPartyContext setVerificationLookupStrategy(
+ @Nonnull final Function<RelyingPartyContext,Boolean> strategy) {
+ verificationLookupStrategy = Constraint.isNotNull(strategy, "Lookup strategy cannot be null");
+ return this;
+ }
+
+ /**
+ * Get the lookup strategy for a non-explicit relying party ID.
+ *
+ * @return lookup strategy
+ */
+ @Nullable Function<RelyingPartyContext,String> getRelyingPartyIdLookupStrategy() {
+ return relyingPartyIdLookupStrategy;
+ }
+
+ /**
+ * Set the lookup strategy for a non-explicit relying party ID.
+ *
+ * @param strategy lookup strategy
+ *
+ * @return this context
+ */
+ @Nonnull public RelyingPartyContext setRelyingPartyIdLookupStrategy(
+ @Nonnull final Function<RelyingPartyContext,String> strategy) {
+ relyingPartyIdLookupStrategy = Constraint.isNotNull(strategy, "Lookup strategy cannot be null");
+ return this;
+ }
+
+ /**
+ * Get the relying party configuration.
+ *
+ * @return the relying party configuration, or null
+ */
+ @Nullable public RelyingPartyConfiguration getConfiguration() {
+ return relyingPartyConfiguration;
+ }
+
+ /**
+ * Set the configuration to use when processing requests for this relying party.
+ *
+ * @param config configuration to use when processing requests for this relying party, or null
+ *
+ * @return this context
+ */
+ @Nonnull public RelyingPartyContext setConfiguration(@Nullable final RelyingPartyConfiguration config) {
+ relyingPartyConfiguration = config;
+ return this;
+ }
+
+ /**
+ * Get the configuration for the request profile currently being processed.
+ *
+ * @return profile configuration for the request profile currently being processed, or null
+ */
+ @Nullable public ProfileConfiguration getProfileConfig() {
+ return profileConfiguration;
+ }
+
+ /**
+ * Set the configuration for the request profile currently being processed.
+ *
+ * @param config configuration for the request profile currently being processed, or null
+ *
+ * @return this context
+ */
+ @Nonnull public RelyingPartyContext setProfileConfig(@Nullable final ProfileConfiguration config) {
+ profileConfiguration = config;
+ return this;
+ }
+
+}
\ No newline at end of file
diff --git a/shib-profile-api/src/main/java/net/shibboleth/profile/context/package-info.java b/shib-profile-api/src/main/java/net/shibboleth/profile/context/package-info.java
new file mode 100644
index 0000000..329b652
--- /dev/null
+++ b/shib-profile-api/src/main/java/net/shibboleth/profile/context/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 classes used in profile handling.
+ */
+package net.shibboleth.profile.context;
\ No newline at end of file
diff --git a/shib-profile-api/src/main/java/net/shibboleth/profile/relyingparty/RelyingPartyConfiguration.java b/shib-profile-api/src/main/java/net/shibboleth/profile/relyingparty/RelyingPartyConfiguration.java
new file mode 100644
index 0000000..a802c6e
--- /dev/null
+++ b/shib-profile-api/src/main/java/net/shibboleth/profile/relyingparty/RelyingPartyConfiguration.java
@@ -0,0 +1,157 @@
+/*
+ * 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.relyingparty;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
+import java.util.function.Predicate;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.opensaml.profile.context.ProfileRequestContext;
+
+import net.shibboleth.profile.config.ProfileConfiguration;
+import net.shibboleth.shared.annotation.constraint.NonnullElements;
+import net.shibboleth.shared.annotation.constraint.NotLive;
+import net.shibboleth.shared.annotation.constraint.Unmodifiable;
+import net.shibboleth.shared.collection.CollectionSupport;
+import net.shibboleth.shared.component.AbstractIdentifiableInitializableComponent;
+import net.shibboleth.shared.component.IdentifiedComponent;
+import net.shibboleth.shared.logic.Constraint;
+import net.shibboleth.shared.logic.FunctionSupport;
+import net.shibboleth.shared.logic.PredicateSupport;
+import net.shibboleth.shared.primitive.StringSupport;
+
+/**
+ * The configuration that applies to a peer with which the software is communicating.
+ *
+ * <p>The name "Relying Party" is historical and encompasses both sources and consumers
+ * of identity information.</p>
+ *
+ * @since 5.0.0
+ */
+public class RelyingPartyConfiguration extends AbstractIdentifiableInitializableComponent implements
+ IdentifiedComponent, Predicate<ProfileRequestContext> {
+
+ /** Lookup function to supply <code>profileConfigurations</code> property. */
+ @Nonnull
+ private Function<ProfileRequestContext,Map<String,ProfileConfiguration>> profileConfigurationsLookupStrategy;
+
+ /** Predicate that must be true for this configuration to be active for a given request. */
+ @Nonnull private Predicate<ProfileRequestContext> activationCondition;
+
+ /** Constructor. */
+ public RelyingPartyConfiguration() {
+ activationCondition = PredicateSupport.alwaysTrue();
+ profileConfigurationsLookupStrategy = FunctionSupport.constant(null);
+ }
+
+ /**
+ * Get the unmodifiable set of profile configurations for this relying party.
+ *
+ * @param profileRequestContext current profile request context
+ *
+ * @return unmodifiable set of profile configurations for this relying party, never null
+ */
+ @Nonnull @NonnullElements @Unmodifiable @NotLive public Map<String,ProfileConfiguration> getProfileConfigurations(
+ @Nullable final ProfileRequestContext profileRequestContext) {
+
+ final Map<String,ProfileConfiguration> map = profileConfigurationsLookupStrategy.apply(profileRequestContext);
+ if (map != null) {
+ return CollectionSupport.copyToMap(map);
+ }
+ return CollectionSupport.emptyMap();
+ }
+
+ /**
+ * Get the profile configuration, for the relying party, for the given profile. This is a convenience method and is
+ * equivalent to calling {@link Map#get(Object)} on the return of
+ * {@link #getProfileConfigurations(ProfileRequestContext)}. This map contains no null entries, keys, or values.
+ *
+ * @param profileRequestContext current profile request context
+ * @param profileId the ID of the profile
+ *
+ * @return the configuration for the profile or null if the profile ID was null or empty or there is no
+ * configuration for the given profile
+ */
+ @Nullable public ProfileConfiguration getProfileConfiguration(
+ @Nullable final ProfileRequestContext profileRequestContext, @Nullable final String profileId) {
+ final String trimmedId = StringSupport.trimOrNull(profileId);
+ if (trimmedId == null) {
+ return null;
+ }
+
+ return getProfileConfigurations(profileRequestContext).get(trimmedId);
+ }
+
+ /**
+ * Set the profile configurations for this relying party.
+ *
+ * @param configs the configurations to set
+ */
+ public void setProfileConfigurations(@Nullable @NonnullElements final Collection<ProfileConfiguration> configs) {
+ checkSetterPreconditions();
+ if (configs == null) {
+ profileConfigurationsLookupStrategy = FunctionSupport.constant(null);
+ } else {
+ final HashMap<String,ProfileConfiguration> map = new HashMap<>();
+ for (final ProfileConfiguration config : List.copyOf(configs)) {
+ final String trimmedId =
+ Constraint.isNotNull(StringSupport.trimOrNull(config.getId()),
+ "ID of profile configuration class " + config.getClass().getName() + " cannot be null");
+ map.put(trimmedId, config);
+ }
+ profileConfigurationsLookupStrategy = FunctionSupport.constant(Map.copyOf(map));
+ }
+ }
+
+ /**
+ * Set a lookup strategy for the <code>profileConfigurations</code> property.
+ *
+ * @param strategy lookup strategy
+ *
+ * @since 4.0.0
+ */
+ public void setProfileConfigurationsLookupStrategy(
+ @Nonnull final Function<ProfileRequestContext,Map<String,ProfileConfiguration>> strategy) {
+ checkSetterPreconditions();
+ profileConfigurationsLookupStrategy = Constraint.isNotNull(strategy, "Lookup strategy cannot be null");
+ }
+
+ /**
+ * Set the condition under which the relying party configuration should be active.
+ *
+ * @param condition the activation condition
+ */
+ public void setActivationCondition(@Nonnull final Predicate<ProfileRequestContext> condition) {
+ checkSetterPreconditions();
+ activationCondition =
+ Constraint.isNotNull(condition, "Relying party configuration activation condition cannot be null");
+ }
+
+ /** {@inheritDoc} */
+ public boolean test(@Nullable final ProfileRequestContext input) {
+ checkComponentActive();
+ return activationCondition.test(input);
+ }
+
+}
\ No newline at end of file
diff --git a/shib-profile-api/src/main/java/net/shibboleth/profile/relyingparty/RelyingPartyConfigurationResolver.java b/shib-profile-api/src/main/java/net/shibboleth/profile/relyingparty/RelyingPartyConfigurationResolver.java
new file mode 100644
index 0000000..9b9d255
--- /dev/null
+++ b/shib-profile-api/src/main/java/net/shibboleth/profile/relyingparty/RelyingPartyConfigurationResolver.java
@@ -0,0 +1,75 @@
+/*
+ * 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.relyingparty;
+
+import java.util.Collection;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.opensaml.profile.criterion.ProfileRequestContextCriterion;
+import org.opensaml.security.config.SecurityConfiguration;
+import org.opensaml.security.credential.Credential;
+
+import net.shibboleth.profile.config.ProfileConfiguration;
+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.component.IdentifiedComponent;
+import net.shibboleth.shared.resolver.CriteriaSet;
+import net.shibboleth.shared.resolver.Resolver;
+
+/**
+ * Interface to a resolution service that identifies the applicable {@link RelyingPartyConfiguration}
+ * instance for a request based on extensible criteria.
+ *
+ * <p>The {@link ProfileRequestContextCriterion} criterion type MUST be supported; other
+ * types are optional.</p>
+ *
+ * <p>This service must also expose a default security configuration for supported profiles.</p>
+ *
+ * @since 5.0.0
+ */
+public interface RelyingPartyConfigurationResolver extends Resolver<RelyingPartyConfiguration,CriteriaSet>,
+ IdentifiedComponent {
+
+ /**
+ * Return the default security configuration for a profile.
+ *
+ * @param profileId the profile ID (available via {@link ProfileConfiguration#getId()}
+ *
+ * @return the configured default configuration
+ */
+ @Nullable SecurityConfiguration getDefaultSecurityConfiguration(@Nonnull @NotEmpty final String profileId);
+
+ /**
+ * Directly expose any configured signing credentials.
+ *
+ * @return signing credentials
+ */
+ @Nonnull @NonnullElements @Unmodifiable @NotLive public Collection<Credential> getSigningCredentials();
+
+ /**
+ * Directly expose any configured encryption (really decryption) credentials.
+ *
+ * @return signing credentials
+ */
+ @Nonnull @NonnullElements @Unmodifiable @NotLive public Collection<Credential> getEncryptionCredentials();
+
+}
\ No newline at end of file
diff --git a/shib-profile-api/src/main/java/net/shibboleth/profile/relyingparty/VerifiedProfileCriterion.java b/shib-profile-api/src/main/java/net/shibboleth/profile/relyingparty/VerifiedProfileCriterion.java
new file mode 100644
index 0000000..6de30d1
--- /dev/null
+++ b/shib-profile-api/src/main/java/net/shibboleth/profile/relyingparty/VerifiedProfileCriterion.java
@@ -0,0 +1,87 @@
+/*
+ * 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.relyingparty;
+
+import javax.annotation.Nonnull;
+
+import net.shibboleth.shared.resolver.Criterion;
+
+/**
+ * {@link Criterion} indicating whether a relying party has been verified in a
+ * profile-specific fashion.
+ *
+ * @since 5.0.0
+ */
+public final class VerifiedProfileCriterion implements Criterion {
+
+ /** Verified flag. */
+ @Nonnull private final boolean verified;
+
+ /**
+ * Constructor.
+ *
+ * @param flag flag to set
+ */
+ public VerifiedProfileCriterion(final boolean flag) {
+ verified = flag;
+ }
+
+ /**
+ * Gets the profile request context.
+ *
+ * @return the profile request context
+ */
+ public boolean isVerified() {
+ return verified;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String toString() {
+ final StringBuilder builder = new StringBuilder();
+ builder.append("VerifiedProfileCriterion [verified=");
+ builder.append(verified);
+ builder.append("]");
+ return builder.toString();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int hashCode() {
+ return Boolean.valueOf(verified).hashCode();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean equals(final Object obj) {
+ if (this == obj) {
+ return true;
+ }
+
+ if (obj == null) {
+ return false;
+ }
+
+ if (obj instanceof VerifiedProfileCriterion) {
+ return verified == ((VerifiedProfileCriterion) obj).isVerified();
+ }
+
+ return false;
+ }
+
+}
\ No newline at end of file
diff --git a/shib-profile-api/src/main/java/net/shibboleth/profile/relyingparty/package-info.java b/shib-profile-api/src/main/java/net/shibboleth/profile/relyingparty/package-info.java
new file mode 100644
index 0000000..e3947e9
--- /dev/null
+++ b/shib-profile-api/src/main/java/net/shibboleth/profile/relyingparty/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.
+ */
+
+/**
+ * Shared RelyingPartyConfiguration and resolver APIs.
+ */
+package net.shibboleth.profile.relyingparty;
\ No newline at end of file
diff --git a/shib-profile-bom/pom.xml b/shib-profile-bom/pom.xml
index f231d5e..fe7c7ce 100644
--- a/shib-profile-bom/pom.xml
+++ b/shib-profile-bom/pom.xml
@@ -27,12 +27,13 @@
<artifactId>shib-profile-api</artifactId>
<version>${project.version}</version>
</dependency>
- <!--
+
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>shib-profile-impl</artifactId>
<version>${project.version}</version>
</dependency>
+ <!--
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>shib-saml-profile-api</artifactId>
@@ -44,6 +45,13 @@
<version>${project.version}</version>
</dependency>
-->
+
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>shib-profile-testing</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ </dependency>
</dependencies>
</dependencyManagement>
diff --git a/shib-profile-impl/pom.xml b/shib-profile-impl/pom.xml
index 958d164..bf13f73 100644
--- a/shib-profile-impl/pom.xml
+++ b/shib-profile-impl/pom.xml
@@ -28,6 +28,12 @@
<version>${project.version}</version>
</dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>shib-metadata-spring</artifactId>
+ <version>${shib-metadata.version}</version>
+ </dependency>
+
<dependency>
<groupId>${opensaml.groupId}</groupId>
<artifactId>opensaml-profile-api</artifactId>
@@ -66,6 +72,12 @@
<!-- Runtime Dependencies -->
<!-- Test Dependencies -->
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>shib-profile-testing</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ </dependency>
<dependency>
<groupId>${shib-shared.groupId}</groupId>
<artifactId>shib-testing</artifactId>
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
new file mode 100644
index 0000000..e248705
--- /dev/null
+++ b/shib-profile-impl/src/main/java/net/shibboleth/profile/relyingparty/impl/DefaultRelyingPartyConfigurationResolver.java
@@ -0,0 +1,440 @@
+/*
+ * 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.relyingparty.impl;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.opensaml.core.criterion.EntityIdCriterion;
+import org.opensaml.profile.context.ProfileRequestContext;
+import org.opensaml.profile.criterion.ProfileRequestContextCriterion;
+import org.opensaml.saml.common.messaging.context.SAMLMetadataContext;
+import org.opensaml.saml.common.messaging.context.SAMLPeerEntityContext;
+import org.opensaml.saml.criterion.RoleDescriptorCriterion;
+import org.opensaml.saml.saml2.metadata.EntityDescriptor;
+import org.opensaml.saml.saml2.metadata.RoleDescriptor;
+import org.opensaml.security.config.SecurityConfiguration;
+import org.opensaml.security.credential.Credential;
+import org.slf4j.Logger;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+
+import net.shibboleth.profile.context.RelyingPartyContext;
+import net.shibboleth.profile.relyingparty.RelyingPartyConfiguration;
+import net.shibboleth.profile.relyingparty.RelyingPartyConfigurationResolver;
+import net.shibboleth.profile.relyingparty.VerifiedProfileCriterion;
+import net.shibboleth.shared.annotation.constraint.NonnullAfterInit;
+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.component.AbstractIdentifiableInitializableComponent;
+import net.shibboleth.shared.component.ComponentInitializationException;
+import net.shibboleth.shared.logic.Constraint;
+import net.shibboleth.shared.primitive.LoggerFactory;
+import net.shibboleth.shared.resolver.CriteriaSet;
+import net.shibboleth.shared.resolver.Criterion;
+import net.shibboleth.shared.resolver.ResolverException;
+import net.shibboleth.spring.security.CredentialHolder;
+
+/**
+ * Retrieves a per-relying party configuration for a given profile request based on the
+ * supplied {@link CriteriaSet}.
+ *
+ * <p>Supported {@link Criterion}:</p>
+ * <ul>
+ * <li>{@link ProfileRequestContextCriterion}</li>
+ * <li>{@link EntityIdCriterion}</li>
+ * <li>{@link RoleDescriptorCriterion}</li>
+ * <li>{@link VerifiedProfileCriterion}</li>
+ * </ul>
+ *
+ * <p>
+ * Note that this resolver does not permit more than one {@link RelyingPartyConfiguration} with the same ID.
+ * </p>
+ *
+ * @since 5.0.0
+ */
+public class DefaultRelyingPartyConfigurationResolver extends AbstractIdentifiableInitializableComponent
+ implements RelyingPartyConfigurationResolver {
+
+ /** Class logger. */
+ @Nonnull private final Logger log = LoggerFactory.getLogger(DefaultRelyingPartyConfigurationResolver.class);
+
+ /** Registered relying party configurations. */
+ @Nonnull private List<RelyingPartyConfiguration> rpConfigurations;
+
+ /** Default relying party, used if no other verified instance matches. */
+ @NonnullAfterInit private RelyingPartyConfiguration defaultRelyingPartyConfiguration;
+
+ /** Unverified relying party configuration, used if the request is unverified. */
+ @Nullable private RelyingPartyConfiguration unverifiedConfiguration;
+
+ /** A global default security configuration. */
+ @Nullable private SecurityConfiguration defaultSecurityConfiguration;
+
+ /** The global list of all configured signing credentials. */
+ @Nonnull private List<Credential> signingCredentials;
+
+ /** The global list of all configured encryption credentials. */
+ @Nonnull private List<Credential> encryptionCredentials;
+
+ /** Constructor. */
+ public DefaultRelyingPartyConfigurationResolver() {
+ rpConfigurations = CollectionSupport.emptyList();
+ signingCredentials = CollectionSupport.emptyList();
+ encryptionCredentials = CollectionSupport.emptyList();
+ }
+
+ /**
+ * Get an unmodifiable list of verified relying party configurations.
+ *
+ * @return unmodifiable list of verified relying party configurations
+ */
+ @Nonnull @NonnullElements @Unmodifiable @NotLive
+ public Collection<? extends RelyingPartyConfiguration> getRelyingPartyConfigurations() {
+ return rpConfigurations;
+ }
+
+ /**
+ * Set the verified relying party configurations.
+ *
+ * @param configs list of verified relying party configurations
+ */
+ public void setRelyingPartyConfigurations(
+ @Nullable @NonnullElements final Collection<? extends RelyingPartyConfiguration> configs) {
+ checkSetterPreconditions();
+
+ if (configs != null) {
+ rpConfigurations = CollectionSupport.copyToList(configs);
+ } else {
+ rpConfigurations = CollectionSupport.emptyList();
+ }
+ }
+
+ /**
+ * Get the {@link RelyingPartyConfiguration} to use if no other configuration is applicable.
+ *
+ * @return default configuration
+ */
+ @NonnullAfterInit public RelyingPartyConfiguration getDefaultConfiguration() {
+ return defaultRelyingPartyConfiguration;
+ }
+
+ /**
+ * Set the {@link RelyingPartyConfiguration} to use if no other configuration is applicable.
+ *
+ * @param configuration default configuration
+ */
+ public void setDefaultConfiguration(@Nonnull final RelyingPartyConfiguration configuration) {
+ checkSetterPreconditions();
+
+ defaultRelyingPartyConfiguration = Constraint.isNotNull(configuration, "Default RelyingPartyConfiguration cannot be null");
+ }
+
+ /**
+ * Set the global default {@link SecurityConfiguration}.
+ *
+ * @param config global default
+ */
+ public void setDefaultSecurityConfiguration(@Nullable final SecurityConfiguration config) {
+ checkSetterPreconditions();
+
+ defaultSecurityConfiguration = config;
+ }
+
+ /**
+ * Get the {@link RelyingPartyConfiguration} to use if the configuration is found to be "unverified"
+ * (via use of {@link VerifiedProfileCriterion}).
+ *
+ * @return unverified configuration
+ */
+ @Nullable public RelyingPartyConfiguration getUnverifiedConfiguration() {
+ return unverifiedConfiguration;
+ }
+
+ /**
+ * Set the {@link RelyingPartyConfiguration} to use if the configuration is found to be "unverified"
+ * (via use of {@link VerifiedProfileCriterion}).
+ *
+ * @param configuration unverified configuration
+ */
+ public void setUnverifiedConfiguration(@Nullable final RelyingPartyConfiguration configuration) {
+ checkSetterPreconditions();
+
+ unverifiedConfiguration = configuration;
+ }
+
+ /** {@inheritDoc} */
+ @Override protected void doInitialize() throws ComponentInitializationException {
+ super.doInitialize();
+
+ final HashSet<String> configIds = new HashSet<>(rpConfigurations.size());
+ for (final RelyingPartyConfiguration config : rpConfigurations) {
+ if (configIds.contains(config.getId())) {
+ throw new ComponentInitializationException("Multiple RelyingPartyConfiguration configurations with ID "
+ + config.getId() + " detected, IDs must be unique.");
+ }
+ configIds.add(config.getId());
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Nonnull @NonnullElements public Iterable<RelyingPartyConfiguration> resolve(@Nullable final CriteriaSet criteria)
+ throws ResolverException {
+ checkComponentActive();
+
+ log.debug("Resolving relying party configuration");
+
+ if (criteria == null) {
+ return CollectionSupport.emptyList();
+ }
+
+ final VerifiedProfileCriterion vpc = criteria.get(VerifiedProfileCriterion.class);
+ if (vpc == null || !vpc.isVerified()) {
+ final RelyingPartyConfiguration uvc = getUnverifiedConfiguration();
+ if (uvc == null) {
+ log.warn("Profile request was unverified, but no such configuration is available");
+ return CollectionSupport.emptyList();
+ }
+ log.debug("Profile request is unverified, returning configuration {}", uvc.getId());
+ return CollectionSupport.singleton(uvc);
+ }
+
+ final ArrayList<RelyingPartyConfiguration> matches = new ArrayList<>();
+
+ final ProfileRequestContext context = getProfileRequestContext(criteria);
+
+ for (final RelyingPartyConfiguration configuration : rpConfigurations) {
+ log.debug("Checking if relying party configuration {} is applicable", configuration.getId());
+ if (configuration.test(context)) {
+ log.debug("Relying party configuration {} is applicable", configuration.getId());
+ matches.add(configuration);
+ } else {
+ log.debug("Relying party configuration {} is not applicable", configuration.getId());
+ }
+ }
+
+ if (matches.isEmpty()) {
+ log.debug("No matching relying party configuration applicable, returning default: {}",
+ getDefaultConfiguration().getId());
+ return CollectionSupport.singleton(getDefaultConfiguration());
+ }
+ return matches;
+ }
+
+ /** {@inheritDoc} */
+ @Nullable public RelyingPartyConfiguration resolveSingle(@Nullable final CriteriaSet criteria) throws ResolverException {
+ checkComponentActive();
+
+ log.debug("Resolving relying party configuration");
+
+ if (criteria == null) {
+ return null;
+ }
+
+ final VerifiedProfileCriterion vpc = criteria.get(VerifiedProfileCriterion.class);
+ if (vpc == null || !vpc.isVerified()) {
+ final RelyingPartyConfiguration uvc = getUnverifiedConfiguration();
+ if (uvc == null) {
+ log.warn("Profile request was unverified, but no such configuration is available");
+ return null;
+ }
+ log.debug("Profile request is unverified, returning configuration {}", uvc.getId());
+ return uvc;
+ }
+
+ final ProfileRequestContext context = getProfileRequestContext(criteria);
+
+ for (final RelyingPartyConfiguration configuration : rpConfigurations) {
+ log.debug("Checking if relying party configuration {} is applicable", configuration.getId());
+ if (configuration.test(context)) {
+ log.debug("Relying party configuration {} is applicable", configuration.getId());
+ return configuration;
+ }
+ log.debug("Relying party configuration {} is not applicable", configuration.getId());
+ }
+
+ log.debug("No relying party configurations applicable, returning default: {}",
+ getDefaultConfiguration().getId());
+ return getDefaultConfiguration();
+ }
+
+ /** {@inheritDoc} */
+ @Nullable public SecurityConfiguration getDefaultSecurityConfiguration(@Nonnull @NotEmpty final String profileId) {
+ return defaultSecurityConfiguration;
+ }
+
+ /** {@inheritDoc} */
+ @Nonnull @NonnullElements @Unmodifiable @NotLive public Collection<Credential> getSigningCredentials() {
+ return signingCredentials;
+ }
+
+ /**
+ * Set the list of all configured signing credentials.
+ *
+ * @param credentials the list of signing credentials, may be null
+ */
+ @Autowired
+ @Qualifier("signing")
+ public void setSigningCredentials(
+ @Nullable @NonnullElements final List<CredentialHolder> credentials) {
+ checkSetterPreconditions();
+
+ if (credentials != null) {
+ signingCredentials = credentials.stream()
+ .flatMap(h -> h.getCredentials().stream())
+ .collect(CollectionSupport.nonnullCollector(Collectors.toUnmodifiableList())).get();
+ } else {
+ signingCredentials = CollectionSupport.emptyList();
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Nonnull @NonnullElements @Unmodifiable @NotLive public Collection<Credential> getEncryptionCredentials() {
+ return encryptionCredentials;
+ }
+
+ /**
+ * Set the list of all configured encryption credentials.
+ *
+ * @param credentials the list of encryption credentials, may be null
+ */
+ @Autowired
+ @Qualifier("encryption")
+ public void setEncryptionCredentials(
+ @Nullable @NonnullElements final List<CredentialHolder> credentials) {
+ checkSetterPreconditions();
+
+ if (credentials != null) {
+ encryptionCredentials = credentials.stream()
+ .flatMap(h -> h.getCredentials().stream())
+ .collect(CollectionSupport.nonnullCollector(Collectors.toUnmodifiableList())).get();
+ } else {
+ encryptionCredentials = CollectionSupport.emptyList();
+ }
+ }
+
+ /**
+ * Get the {@link ProfileRequestContext} included in the input criteria, if any.
+ *
+ * @param criteria input criteria
+ *
+ * @return embedded profile request context or null
+ */
+ @Nullable private ProfileRequestContext getProfileRequestContext(@Nonnull final CriteriaSet criteria) {
+
+ final ProfileRequestContextCriterion prcCriterion = criteria.get(ProfileRequestContextCriterion.class);
+ if (prcCriterion != null) {
+ return prcCriterion.getProfileRequestContext();
+ }
+
+ final String entityID = resolveEntityID(criteria);
+ log.debug("Resolved effective entityID from criteria: {}", entityID);
+
+ final EntityDescriptor entityDescriptor = resolveEntityDescriptor(criteria);
+ log.debug("Resolved effective entity descriptor from criteria: {}", entityDescriptor);
+
+ final RoleDescriptor roleDescriptor = resolveRoleDescriptor(criteria);
+ log.debug("Resolved effective role descriptor from criteria: {}", roleDescriptor);
+
+ if (entityID != null || entityDescriptor != null || roleDescriptor != null) {
+ final ProfileRequestContext prc = new ProfileRequestContext();
+ final RelyingPartyContext rpc = prc.getOrCreateSubcontext(RelyingPartyContext.class);
+ rpc.setVerified(true);
+
+ rpc.setRelyingPartyId(entityID);
+
+ if (entityDescriptor != null || roleDescriptor != null) {
+ final SAMLPeerEntityContext peerContext = prc.getOrCreateSubcontext(SAMLPeerEntityContext.class);
+ rpc.setRelyingPartyIdContextTree(peerContext);
+
+ peerContext.setEntityId(entityID);
+
+ if (roleDescriptor != null) {
+ peerContext.setRole(roleDescriptor.getSchemaType() != null
+ ? roleDescriptor.getSchemaType() : roleDescriptor.getElementQName());
+ }
+
+ final SAMLMetadataContext metadataContext = peerContext.getOrCreateSubcontext(SAMLMetadataContext.class);
+ metadataContext.setEntityDescriptor(entityDescriptor);
+ metadataContext.setRoleDescriptor(roleDescriptor);
+ }
+ return prc;
+ }
+ return null;
+ }
+
+ /**
+ * Resolve the entityID from the criteria.
+ *
+ * @param criteria the input criteria
+ * @return the input entityID criterion or null if could not be resolved
+ */
+ @Nullable private String resolveEntityID(@Nonnull final CriteriaSet criteria) {
+ final EntityIdCriterion eic = criteria.get(EntityIdCriterion.class);
+ if (eic != null) {
+ return eic.getEntityId();
+ }
+
+ final EntityDescriptor ed = resolveEntityDescriptor(criteria);
+ if (ed != null) {
+ return ed.getEntityID();
+ }
+
+ return null;
+ }
+
+ /**
+ * Resolve the EntityDescriptor from the criteria.
+ *
+ * @param criteria the input criteria
+ * @return the input entity descriptor criterion, or null if could not be resolved
+ */
+ @Nullable private EntityDescriptor resolveEntityDescriptor(@Nonnull final CriteriaSet criteria) {
+ final RoleDescriptor rd = resolveRoleDescriptor(criteria);
+ if (rd != null && rd.getParent() != null && rd.getParent() instanceof EntityDescriptor) {
+ return (EntityDescriptor)rd.getParent();
+ }
+
+ return null;
+ }
+
+ /**
+ * Resolve the RoleDescriptor from the criteria.
+ *
+ * @param criteria the input criteria
+ * @return the input role descriptor criterion or null if could not be resolved
+ */
+ @Nullable private RoleDescriptor resolveRoleDescriptor(@Nonnull final CriteriaSet criteria) {
+ final RoleDescriptorCriterion rdc = criteria.get(RoleDescriptorCriterion.class);
+ if (rdc != null) {
+ return rdc.getRole();
+ }
+
+ return null;
+ }
+
+}
\ No newline at end of file
diff --git a/shib-profile-impl/src/main/java/net/shibboleth/profile/relyingparty/impl/package-info.java b/shib-profile-impl/src/main/java/net/shibboleth/profile/relyingparty/impl/package-info.java
new file mode 100644
index 0000000..a394c02
--- /dev/null
+++ b/shib-profile-impl/src/main/java/net/shibboleth/profile/relyingparty/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.
+ */
+
+/**
+ * Implementation of relying party resolution.
+ */
+package net.shibboleth.profile.relyingparty.impl;
\ No newline at end of file
diff --git a/shib-profile-impl/src/test/java/net/shibboleth/profile/relyingparty/impl/DefaultRelyingPartyConfigurationResolverTest.java b/shib-profile-impl/src/test/java/net/shibboleth/profile/relyingparty/impl/DefaultRelyingPartyConfigurationResolverTest.java
new file mode 100644
index 0000000..594b984
--- /dev/null
+++ b/shib-profile-impl/src/test/java/net/shibboleth/profile/relyingparty/impl/DefaultRelyingPartyConfigurationResolverTest.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.profile.relyingparty.impl;
+
+import java.util.Iterator;
+import java.util.List;
+
+import net.shibboleth.profile.relyingparty.RelyingPartyConfiguration;
+import net.shibboleth.profile.relyingparty.VerifiedProfileCriterion;
+import net.shibboleth.shared.collection.CollectionSupport;
+import net.shibboleth.shared.component.ComponentInitializationException;
+import net.shibboleth.shared.logic.PredicateSupport;
+import net.shibboleth.shared.resolver.CriteriaSet;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+/** Unit test for {@link DefaultRelyingPartyConfigurationResolver}. */
+ at SuppressWarnings("javadoc")
+public class DefaultRelyingPartyConfigurationResolverTest {
+
+ @Test public void testConstruction() throws ComponentInitializationException {
+ final RelyingPartyConfiguration one = new RelyingPartyConfiguration();
+ one.setId("one");
+ one.initialize();
+
+ final RelyingPartyConfiguration two = new RelyingPartyConfiguration();
+ two.setId("two");
+ two.setActivationCondition(PredicateSupport.alwaysFalse());
+ two.initialize();
+
+ final RelyingPartyConfiguration three = new RelyingPartyConfiguration();
+ three.setId("three");
+ three.initialize();
+
+ final List<RelyingPartyConfiguration> rpConfigs = CollectionSupport.listOf(one, two, three);
+
+ DefaultRelyingPartyConfigurationResolver resolver = new DefaultRelyingPartyConfigurationResolver();
+ resolver.setId("test");
+ resolver.setRelyingPartyConfigurations(rpConfigs);
+ Assert.assertEquals(resolver.getId(), "test");
+ Assert.assertEquals(resolver.getRelyingPartyConfigurations().size(), 3);
+
+ resolver = new DefaultRelyingPartyConfigurationResolver();
+ resolver.setId("test");
+ Assert.assertEquals(resolver.getId(), "test");
+ Assert.assertEquals(resolver.getRelyingPartyConfigurations().size(), 0);
+
+ resolver = new DefaultRelyingPartyConfigurationResolver();
+ resolver.setId("test");
+ Assert.assertEquals(resolver.getId(), "test");
+ Assert.assertEquals(resolver.getRelyingPartyConfigurations().size(), 0);
+ }
+
+ @Test public void testDefault() throws Exception {
+ final RelyingPartyConfiguration anonRP = new RelyingPartyConfiguration();
+ anonRP.setId("anonRPId");
+ anonRP.initialize();
+
+ final RelyingPartyConfiguration defaultRP = new RelyingPartyConfiguration();
+ defaultRP.setId("defaultRPId");
+ defaultRP.initialize();
+
+ final DefaultRelyingPartyConfigurationResolver resolver = new DefaultRelyingPartyConfigurationResolver();
+ resolver.setId("test");
+ resolver.setUnverifiedConfiguration(anonRP);
+ resolver.setDefaultConfiguration(defaultRP);
+ resolver.initialize();
+
+ final CriteriaSet criteria = new CriteriaSet();
+ criteria.add(new VerifiedProfileCriterion(true));
+
+ final Iterable<RelyingPartyConfiguration> results = resolver.resolve(criteria);
+ Assert.assertNotNull(results);
+
+ final Iterator<RelyingPartyConfiguration> resultItr = results.iterator();
+ Assert.assertTrue(resultItr.hasNext());
+ Assert.assertSame(resultItr.next(), defaultRP);
+ Assert.assertFalse(resultItr.hasNext());
+
+ Assert.assertSame(resolver.resolveSingle(criteria), defaultRP);
+ }
+
+ @Test public void testAnon() throws Exception {
+
+ final RelyingPartyConfiguration anonRP = new RelyingPartyConfiguration();
+ anonRP.setId("anonRPId");
+ anonRP.initialize();
+
+ final RelyingPartyConfiguration defaultRP = new RelyingPartyConfiguration();
+ defaultRP.setId("defaultRPId");
+ defaultRP.initialize();
+
+ final DefaultRelyingPartyConfigurationResolver resolver = new DefaultRelyingPartyConfigurationResolver();
+ resolver.setId("test");
+ resolver.setUnverifiedConfiguration(anonRP);
+ resolver.setDefaultConfiguration(defaultRP);
+ resolver.initialize();
+
+ final Iterable<RelyingPartyConfiguration> results = resolver.resolve(new CriteriaSet());
+ Assert.assertNotNull(results);
+
+ final Iterator<RelyingPartyConfiguration> resultItr = results.iterator();
+ Assert.assertTrue(resultItr.hasNext());
+ Assert.assertSame(resultItr.next(), anonRP);
+ Assert.assertFalse(resultItr.hasNext());
+
+ Assert.assertSame(resolver.resolveSingle(new CriteriaSet()), anonRP);
+ }
+
+ @Test public void testResolve() throws Exception {
+ final RelyingPartyConfiguration anonRP = new RelyingPartyConfiguration();
+ anonRP.setId("anonRPId");
+ anonRP.initialize();
+
+ final RelyingPartyConfiguration defaultRP = new RelyingPartyConfiguration();
+ defaultRP.setId("defaultRPId");
+ defaultRP.initialize();
+
+ final RelyingPartyConfiguration one = new RelyingPartyConfiguration();
+ one.setId("one");
+ one.initialize();
+
+ final RelyingPartyConfiguration two = new RelyingPartyConfiguration();
+ two.setId("two");
+ two.setActivationCondition(PredicateSupport.alwaysFalse());
+ two.initialize();
+
+ final RelyingPartyConfiguration three = new RelyingPartyConfiguration();
+ three.setId("three");
+ three.initialize();
+
+ final List<RelyingPartyConfiguration> rpConfigs = CollectionSupport.listOf(one, two, three);
+
+ final DefaultRelyingPartyConfigurationResolver resolver = new DefaultRelyingPartyConfigurationResolver();
+ resolver.setId("test");
+ resolver.setRelyingPartyConfigurations(rpConfigs);
+ resolver.setUnverifiedConfiguration(anonRP);
+ resolver.setDefaultConfiguration(defaultRP);
+ resolver.initialize();
+
+ final CriteriaSet criteria = new CriteriaSet();
+ criteria.add(new VerifiedProfileCriterion(true));
+
+ Iterable<RelyingPartyConfiguration> results = resolver.resolve(criteria);
+ Assert.assertNotNull(results);
+
+ Iterator<RelyingPartyConfiguration> resultItr = results.iterator();
+ Assert.assertTrue(resultItr.hasNext());
+ Assert.assertSame(resultItr.next(), one);
+ Assert.assertTrue(resultItr.hasNext());
+ Assert.assertSame(resultItr.next(), three);
+ Assert.assertFalse(resultItr.hasNext());
+
+ RelyingPartyConfiguration result = resolver.resolveSingle(criteria);
+ Assert.assertSame(result, one);
+
+ results = resolver.resolve(null);
+ Assert.assertNotNull(results);
+
+ resultItr = results.iterator();
+ Assert.assertFalse(resultItr.hasNext());
+
+ result = resolver.resolveSingle(null);
+ Assert.assertNull(result);
+ }
+
+}
\ No newline at end of file
diff --git a/shib-profile-impl/src/test/java/net/shibboleth/profile/relyingparty/impl/RelyingPartyConfigurationTest.java b/shib-profile-impl/src/test/java/net/shibboleth/profile/relyingparty/impl/RelyingPartyConfigurationTest.java
new file mode 100644
index 0000000..a2fd530
--- /dev/null
+++ b/shib-profile-impl/src/test/java/net/shibboleth/profile/relyingparty/impl/RelyingPartyConfigurationTest.java
@@ -0,0 +1,120 @@
+/*
+ * 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.relyingparty.impl;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+
+import net.shibboleth.profile.config.ProfileConfiguration;
+import net.shibboleth.profile.config.testing.MockProfileConfiguration;
+import net.shibboleth.profile.relyingparty.RelyingPartyConfiguration;
+import net.shibboleth.shared.component.ComponentInitializationException;
+import net.shibboleth.shared.logic.ConstraintViolationException;
+import net.shibboleth.shared.logic.FunctionSupport;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+/** Unit test for {@link RelyingPartyConfiguration}. */
+ at SuppressWarnings("javadoc")
+public class RelyingPartyConfigurationTest {
+
+ @Test public void testConstruction() throws ComponentInitializationException {
+ RelyingPartyConfiguration config = new RelyingPartyConfiguration();
+ config.setId("foo");
+ config.initialize();
+ Assert.assertEquals(config.getId(), "foo");
+ Assert.assertTrue(config.getProfileConfigurations(null).isEmpty());
+
+ config = new RelyingPartyConfiguration();
+ config.setId("foo");
+ config.initialize();
+ Assert.assertEquals(config.getId(), "foo");
+ Assert.assertTrue(config.getProfileConfigurations(null).isEmpty());
+
+ ArrayList<ProfileConfiguration> profileConfigs = new ArrayList<>();
+ profileConfigs.add(new MockProfileConfiguration("foo"));
+ profileConfigs.add(new MockProfileConfiguration("bar"));
+
+ config = new RelyingPartyConfiguration();
+ config.setId("foo");
+ config.setProfileConfigurations(profileConfigs);
+ config.initialize();
+ Assert.assertEquals(config.getId(), "foo");
+ Assert.assertEquals(config.getProfileConfigurations(null).size(), 2);
+
+ try {
+ config = new RelyingPartyConfiguration();
+ config.initialize();
+ Assert.fail();
+ } catch (final ComponentInitializationException e) {
+ // expected this
+ }
+
+ try {
+ config = new RelyingPartyConfiguration();
+ config.setId("");
+ config.initialize();
+ Assert.fail();
+ } catch (final ConstraintViolationException e) {
+ // expected this
+ }
+ }
+
+ @Test public void testProfileConfiguration() throws ComponentInitializationException {
+ final ArrayList<ProfileConfiguration> profileConfigs = new ArrayList<>();
+ profileConfigs.add(new MockProfileConfiguration("foo"));
+ profileConfigs.add(new MockProfileConfiguration("bar"));
+
+ final RelyingPartyConfiguration config = new RelyingPartyConfiguration();
+ config.setId("foo");
+ config.setProfileConfigurations(profileConfigs);
+ config.initialize();
+
+ Assert.assertNotNull(config.getProfileConfiguration(null, "foo"));
+ Assert.assertNotNull(config.getProfileConfiguration(null, "bar"));
+ Assert.assertNull(config.getProfileConfiguration(null, "baz"));
+ }
+
+ @Test public void testIndirectProfileConfiguration() throws ComponentInitializationException {
+ final Map<String,ProfileConfiguration> profileConfigs = new HashMap<>();
+ profileConfigs.put("foo", new MockProfileConfiguration("foo"));
+ profileConfigs.put("bar", new MockProfileConfiguration("bar"));
+
+ RelyingPartyConfiguration config = new RelyingPartyConfiguration();
+ config.setId("foo");
+ config.setProfileConfigurationsLookupStrategy(FunctionSupport.constant(profileConfigs));
+ config.initialize();
+
+ Assert.assertNotNull(config.getProfileConfiguration(null, "foo"));
+ Assert.assertNotNull(config.getProfileConfiguration(null, "bar"));
+ Assert.assertNull(config.getProfileConfiguration(null, "baz"));
+
+ config = new RelyingPartyConfiguration();
+ config.setId("foo");
+ config.setProfileConfigurations(profileConfigs.values());
+ config.setProfileConfigurationsLookupStrategy(FunctionSupport.constant(null));
+ config.initialize();
+
+ Assert.assertNull(config.getProfileConfiguration(null, "foo"));
+ Assert.assertNull(config.getProfileConfiguration(null, "bar"));
+ Assert.assertNull(config.getProfileConfiguration(null, "baz"));
+ }
+
+}
\ No newline at end of file
diff --git a/shib-profile-impl/pom.xml b/shib-profile-testing/pom.xml
similarity index 73%
copy from shib-profile-impl/pom.xml
copy to shib-profile-testing/pom.xml
index 958d164..9ab4a6e 100644
--- a/shib-profile-impl/pom.xml
+++ b/shib-profile-testing/pom.xml
@@ -10,14 +10,14 @@
<version>5.0.0-SNAPSHOT</version>
</parent>
- <name>Shibboleth Profile :: Profile Implementation</name>
- <description>Core Profile Implementation</description>
- <artifactId>shib-profile-impl</artifactId>
+ <name>Shibboleth Profile :: Testing API</name>
+ <description>Core Profile Testing API</description>
+ <artifactId>shib-profile-testing</artifactId>
<packaging>jar</packaging>
<properties>
<checkstyle.configLocation>${project.basedir}/../resources/checkstyle/checkstyle.xml</checkstyle.configLocation>
- <automatic.module.name>net.shibboleth.profile.impl</automatic.module.name>
+ <automatic.module.name>net.shibboleth.profile.config.testing</automatic.module.name>
</properties>
<dependencies>
@@ -27,50 +27,51 @@
<artifactId>shib-profile-api</artifactId>
<version>${project.version}</version>
</dependency>
-
+
+ <dependency>
+ <groupId>${opensaml.groupId}</groupId>
+ <artifactId>opensaml-core-api</artifactId>
+ </dependency>
<dependency>
<groupId>${opensaml.groupId}</groupId>
<artifactId>opensaml-profile-api</artifactId>
</dependency>
+ <dependency>
+ <groupId>${opensaml.groupId}</groupId>
+ <artifactId>opensaml-messaging-api</artifactId>
+ </dependency>
+ <!-- Normally test scope. -->
<dependency>
- <groupId>${spring.groupId}</groupId>
- <artifactId>spring-beans</artifactId>
+ <groupId>${opensaml.groupId}</groupId>
+ <artifactId>opensaml-testing</artifactId>
+ <scope>compile</scope>
</dependency>
<dependency>
- <groupId>${spring.groupId}</groupId>
- <artifactId>spring-context</artifactId>
+ <groupId>${shib-shared.groupId}</groupId>
+ <artifactId>shib-testing</artifactId>
+ <scope>compile</scope>
</dependency>
+
<dependency>
<groupId>${spring.groupId}</groupId>
<artifactId>spring-core</artifactId>
</dependency>
-
<dependency>
- <groupId>${shib-shared.groupId}</groupId>
- <artifactId>shib-service</artifactId>
+ <groupId>${spring.groupId}</groupId>
+ <artifactId>spring-context</artifactId>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</dependency>
-
+
<!-- Provided Dependencies -->
- <dependency>
- <groupId>jakarta.servlet</groupId>
- <artifactId>jakarta.servlet-api</artifactId>
- <scope>provided</scope>
- </dependency>
<!-- Runtime Dependencies -->
<!-- Test Dependencies -->
- <dependency>
- <groupId>${shib-shared.groupId}</groupId>
- <artifactId>shib-testing</artifactId>
- <scope>test</scope>
- </dependency>
</dependencies>
diff --git a/shib-profile-testing/src/main/java/net/shibboleth/profile/config/testing/MockProfileConfiguration.java b/shib-profile-testing/src/main/java/net/shibboleth/profile/config/testing/MockProfileConfiguration.java
new file mode 100644
index 0000000..ff220f9
--- /dev/null
+++ b/shib-profile-testing/src/main/java/net/shibboleth/profile/config/testing/MockProfileConfiguration.java
@@ -0,0 +1,41 @@
+/*
+ * 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.config.testing;
+
+import javax.annotation.Nonnull;
+
+import org.opensaml.security.config.BasicSecurityConfiguration;
+
+import net.shibboleth.profile.config.AbstractConditionalProfileConfiguration;
+import net.shibboleth.profile.config.ProfileConfiguration;
+import net.shibboleth.shared.annotation.constraint.NotEmpty;
+
+/** Mock implementation of {@link ProfileConfiguration}. */
+public class MockProfileConfiguration extends AbstractConditionalProfileConfiguration {
+
+ /**
+ * Constructor.
+ *
+ * @param id ID of this profile
+ */
+ public MockProfileConfiguration(@Nonnull @NotEmpty final String id) {
+ super(id);
+ setSecurityConfiguration(new BasicSecurityConfiguration());
+ }
+
+}
\ No newline at end of file
diff --git a/shib-profile-testing/src/main/java/net/shibboleth/profile/config/testing/package-info.java b/shib-profile-testing/src/main/java/net/shibboleth/profile/config/testing/package-info.java
new file mode 100644
index 0000000..b54ca69
--- /dev/null
+++ b/shib-profile-testing/src/main/java/net/shibboleth/profile/config/testing/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.
+ */
+
+/**
+ * Profile testing APIs.
+ */
+package net.shibboleth.profile.config.testing;
\ 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