[java-sp-server] branch main updated: First cut of AssertingPartyResolver and ported tests.
Scott Cantor
cantor.2 at osu.edu
Mon Feb 6 20:17:48 UTC 2023
This is an automated email from the git hooks/post-receive script.
scantor pushed a commit to branch main
in repository java-sp-server.
View the commit online:
http://git.shibboleth.net/view/?p=java-sp-server.git;a=commit;h=843be0d4da3a2f1688a5a4bef3d858e1a17d4323
The following commit(s) were added to refs/heads/main by this push:
new 843be0d First cut of AssertingPartyResolver and ported tests.
843be0d is described below
commit 843be0d4da3a2f1688a5a4bef3d858e1a17d4323
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Mon Feb 6 15:17:46 2023 -0500
First cut of AssertingPartyResolver and ported tests.
---
pom.xml | 1 +
sp-bom/pom.xml | 7 +
sp-server-api/pom.xml | 7 -
.../net/shibboleth/sp/config/AssertingParty.java | 15 +-
.../sp/config/AssertingPartyResolver.java | 50 ++++
.../net/shibboleth/sp/config/CredentialHolder.java | 63 +++++
sp-server-impl/pom.xml | 10 +-
.../sp/config/impl/BasicAssertingParty.java | 147 ++++++++++
.../config/impl/DefaultAssertingPartyResolver.java | 304 +++++++++++++++++++++
.../shibboleth/sp/config/impl/package-info.java | 21 ++
.../sp/config/impl/BasicAssertingPartyTest.java | 119 ++++++++
.../impl/DefaultAssertingPartyResolverTest.java | 154 +++++++++++
sp-testing/.checkstyle | 10 +
sp-testing/.gitignore | 2 +
{sp-server-api => sp-testing}/pom.xml | 47 ++--
.../profile/testing/MockProfileConfiguration.java | 41 +++
.../sp/profile/testing/package-info.java | 22 ++
17 files changed, 986 insertions(+), 34 deletions(-)
diff --git a/pom.xml b/pom.xml
index 4f58701..525989f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -68,6 +68,7 @@
<module>sp-server-impl</module>
<module>sp-session-api</module>
<module>sp-session-impl</module>
+ <module>sp-testing</module>
</modules>
<dependencies>
diff --git a/sp-bom/pom.xml b/sp-bom/pom.xml
index 9ddf6af..4a76d6a 100644
--- a/sp-bom/pom.xml
+++ b/sp-bom/pom.xml
@@ -60,6 +60,13 @@
<version>${project.version}</version>
</dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>sp-testing</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ </dependency>
+
</dependencies>
</dependencyManagement>
diff --git a/sp-server-api/pom.xml b/sp-server-api/pom.xml
index 07d2442..63a6a04 100644
--- a/sp-server-api/pom.xml
+++ b/sp-server-api/pom.xml
@@ -24,39 +24,32 @@
<dependency>
<groupId>net.shibboleth</groupId>
<artifactId>shib-attribute-resolver-api</artifactId>
- <scope>compile</scope>
</dependency>
<dependency>
<groupId>net.shibboleth</groupId>
<artifactId>shib-attribute-filter-api</artifactId>
- <scope>compile</scope>
</dependency>
<dependency>
<groupId>net.shibboleth</groupId>
<artifactId>shib-metadata-api</artifactId>
- <scope>compile</scope>
</dependency>
<dependency>
<groupId>net.shibboleth</groupId>
<artifactId>shib-service</artifactId>
- <scope>compile</scope>
</dependency>
<dependency>
<groupId>net.shibboleth</groupId>
<artifactId>shib-support</artifactId>
- <scope>compile</scope>
</dependency>
<dependency>
<groupId>${spring.groupId}</groupId>
<artifactId>spring-beans</artifactId>
- <scope>compile</scope>
</dependency>
<dependency>
<groupId>${spring.groupId}</groupId>
<artifactId>spring-context</artifactId>
- <scope>compile</scope>
</dependency>
<!-- Provided dependencies -->
diff --git a/sp-server-api/src/main/java/net/shibboleth/sp/config/AssertingParty.java b/sp-server-api/src/main/java/net/shibboleth/sp/config/AssertingParty.java
index b5b9960..d24e1c2 100644
--- a/sp-server-api/src/main/java/net/shibboleth/sp/config/AssertingParty.java
+++ b/sp-server-api/src/main/java/net/shibboleth/sp/config/AssertingParty.java
@@ -27,6 +27,7 @@ import org.opensaml.profile.context.ProfileRequestContext;
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.component.IdentifiedComponent;
/**
* Package of options exposed for configuring behavior when dealing with particular sources
@@ -34,7 +35,7 @@ import net.shibboleth.shared.annotation.constraint.Unmodifiable;
*
* <p>Historically referred to as a "relying party", renamed for better accuracy.</p>
*/
-public interface AssertingParty {
+public interface AssertingParty extends IdentifiedComponent {
// TODO: This is entirely speculative but I lean toward this being pretty minimal and not
// particularly connected to the "existing" <RelyingParty> settings/concept in the SP.
@@ -52,4 +53,16 @@ public interface AssertingParty {
@Nonnull @NonnullElements @NotLive @Unmodifiable Map<String,ProfileConfiguration> getProfileConfigurations(
@Nullable final ProfileRequestContext profileRequestContext);
+ /**
+ * Get the profile configuration, for the asserting party, for the given profile.
+ *
+ * @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);
+
}
\ No newline at end of file
diff --git a/sp-server-api/src/main/java/net/shibboleth/sp/config/AssertingPartyResolver.java b/sp-server-api/src/main/java/net/shibboleth/sp/config/AssertingPartyResolver.java
new file mode 100644
index 0000000..a0aef23
--- /dev/null
+++ b/sp-server-api/src/main/java/net/shibboleth/sp/config/AssertingPartyResolver.java
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements. See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID licenses this file to You under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.shibboleth.sp.config;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.opensaml.profile.criterion.ProfileRequestContextCriterion;
+import org.opensaml.security.config.SecurityConfiguration;
+
+import net.shibboleth.shared.annotation.constraint.NotEmpty;
+import net.shibboleth.shared.resolver.CriteriaSet;
+import net.shibboleth.shared.resolver.Resolver;
+
+/**
+ * Interface to a resolution service that identifies the applicable {@link AssertingParty}
+ * 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>
+ */
+public interface AssertingPartyResolver extends Resolver<AssertingParty,CriteriaSet> {
+
+ /**
+ * Return the default security configuration for the profile.
+ *
+ * @param profileId the profile ID
+ *
+ * @return the default configuration for the profile
+ */
+ @Nullable SecurityConfiguration getDefaultSecurityConfiguration(@Nonnull @NotEmpty final String profileId);
+
+}
\ No newline at end of file
diff --git a/sp-server-api/src/main/java/net/shibboleth/sp/config/CredentialHolder.java b/sp-server-api/src/main/java/net/shibboleth/sp/config/CredentialHolder.java
new file mode 100644
index 0000000..efb5770
--- /dev/null
+++ b/sp-server-api/src/main/java/net/shibboleth/sp/config/CredentialHolder.java
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements. See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID licenses this file to You under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.shibboleth.sp.config;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.opensaml.security.credential.Credential;
+
+import net.shibboleth.shared.annotation.constraint.NonnullElements;
+
+/**
+ * This is a utility class used as an auto-wiring source for collections of
+ * signing and encryption {@link Credential} objects so that other layers of the
+ * system can gain access to the complete set of them.
+ */
+public class CredentialHolder {
+
+ /** Credentials to expose. */
+ @Nonnull @NonnullElements private final List<Credential> credentials;
+
+ /**
+ * Constructor.
+ *
+ * @param creds credentials to expose to other components
+ */
+ public CredentialHolder(@Nullable @NonnullElements final Collection<Credential> creds) {
+ if (creds != null) {
+ credentials = List.copyOf(creds);
+ } else {
+ credentials = Collections.emptyList();
+ }
+ }
+
+ /**
+ * Get the credentials to expose to other components.
+ *
+ * @return credentials to expose
+ */
+ @Nonnull @NonnullElements public Collection<Credential> getCredentials() {
+ return credentials;
+ }
+
+}
\ No newline at end of file
diff --git a/sp-server-impl/pom.xml b/sp-server-impl/pom.xml
index eb3352f..2a6ab6d 100644
--- a/sp-server-impl/pom.xml
+++ b/sp-server-impl/pom.xml
@@ -69,7 +69,7 @@
<artifactId>spring-integration-ip</artifactId>
</dependency>
- <!-- provided dependencies -->
+ <!-- Provided dependencies -->
<dependency>
<groupId>${slf4j.groupId}</groupId>
<artifactId>jcl-over-slf4j</artifactId>
@@ -85,7 +85,15 @@
<artifactId>jcommander</artifactId>
<scope>provided</scope>
</dependency>
+
<!-- Test Dependencies -->
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>sp-testing</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ </dependency>
+
<dependency>
<groupId>${spring.groupId}</groupId>
<artifactId>spring-test</artifactId>
diff --git a/sp-server-impl/src/main/java/net/shibboleth/sp/config/impl/BasicAssertingParty.java b/sp-server-impl/src/main/java/net/shibboleth/sp/config/impl/BasicAssertingParty.java
new file mode 100644
index 0000000..90dc6ee
--- /dev/null
+++ b/sp-server-impl/src/main/java/net/shibboleth/sp/config/impl/BasicAssertingParty.java
@@ -0,0 +1,147 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements. See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID licenses this file to You under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.shibboleth.sp.config.impl;
+
+import java.util.Collection;
+import java.util.HashMap;
+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.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.logic.Constraint;
+import net.shibboleth.shared.logic.FunctionSupport;
+import net.shibboleth.shared.logic.PredicateSupport;
+import net.shibboleth.shared.primitive.StringSupport;
+import net.shibboleth.sp.config.AssertingParty;
+import net.shibboleth.sp.config.ProfileConfiguration;
+
+/**
+ * Concrete implementation of {@link AssertingParty} interface to support the default implementation of
+ * a Spring-based configuration resolver.
+ */
+public class BasicAssertingParty extends AbstractIdentifiableInitializableComponent implements AssertingParty,
+ 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 BasicAssertingParty() {
+ activationCondition = PredicateSupport.alwaysTrue();
+ profileConfigurationsLookupStrategy = FunctionSupport.constant(null);
+ }
+
+
+ /** {@inheritDoc} */
+ @Nonnull @NonnullElements @Unmodifiable @NotLive public Map<String,ProfileConfiguration> getProfileConfigurations(
+ @Nullable final ProfileRequestContext profileRequestContext) {
+ checkComponentActive();
+
+ final Map<String,ProfileConfiguration> map = profileConfigurationsLookupStrategy.apply(profileRequestContext);
+ if (map != null) {
+ return CollectionSupport.copyToMap(map);
+ }
+ return CollectionSupport.emptyMap();
+ }
+
+ /** {@inheritDoc} */
+ @Nullable public ProfileConfiguration getProfileConfiguration(
+ @Nullable final ProfileRequestContext profileRequestContext, @Nullable final String profileId) {
+ checkComponentActive();
+
+ final String trimmedId = StringSupport.trimOrNull(profileId);
+ if (trimmedId == null) {
+ return null;
+ }
+
+ final Map<String,ProfileConfiguration> configs = profileConfigurationsLookupStrategy.apply(profileRequestContext);
+ if (configs != null) {
+ return configs.get(trimmedId);
+ }
+
+ return null;
+ }
+
+ /**
+ * 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 : 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);
+ }
+ }
+
+ /**
+ * Set a lookup strategy for the <code>profileConfigurations</code> property.
+ *
+ * @param strategy lookup strategy
+ */
+ 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/sp-server-impl/src/main/java/net/shibboleth/sp/config/impl/DefaultAssertingPartyResolver.java b/sp-server-impl/src/main/java/net/shibboleth/sp/config/impl/DefaultAssertingPartyResolver.java
new file mode 100644
index 0000000..dfdd5ff
--- /dev/null
+++ b/sp-server-impl/src/main/java/net/shibboleth/sp/config/impl/DefaultAssertingPartyResolver.java
@@ -0,0 +1,304 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements. See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID licenses this file to You under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.shibboleth.sp.config.impl;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.opensaml.profile.context.ProfileRequestContext;
+import org.opensaml.profile.criterion.ProfileRequestContextCriterion;
+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.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.sp.config.AssertingParty;
+import net.shibboleth.sp.config.AssertingPartyResolver;
+import net.shibboleth.sp.config.CredentialHolder;
+
+/**
+ * Retrieves a per-asserting party configuration for a given profile request based on the
+ * supplied {@link CriteriaSet}.
+ *
+ * <p>Supported {@link Criterion}:</p>
+ * <ul>
+ * <li>{@link ProfileRequestContextCriterion}</li>
+ * </ul>
+ *
+ * <p>
+ * Note that this resolver does not permit more than one {@link AssertingParty} with the same ID.
+ * </p>
+ */
+public class DefaultAssertingPartyResolver extends AbstractIdentifiableInitializableComponent
+ implements AssertingPartyResolver {
+
+ /** Class logger. */
+ @Nonnull private final Logger log = LoggerFactory.getLogger(DefaultAssertingPartyResolver.class);
+
+ /** Registered relying party configurations. */
+ @Nonnull private List<BasicAssertingParty> assertingParties;
+
+ /** Default asserting party, used if no other verified instance matches. */
+ @NonnullAfterInit private BasicAssertingParty defaultAssertingParty;
+
+ /** The predicate which decides if this request is "verified". */
+ @NonnullAfterInit private Predicate<ProfileRequestContext> verificationPredicate;
+
+ /** 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 DefaultAssertingPartyResolver() {
+ assertingParties = 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<BasicAssertingParty> getAssertingParties() {
+ return assertingParties;
+ }
+
+ /**
+ * Set the verified relying party configurations.
+ *
+ * @param configs list of verified relying party configurations
+ */
+ public void setAssertingParties(@Nullable @NonnullElements final Collection<BasicAssertingParty> configs) {
+ checkSetterPreconditions();
+
+ if (configs != null) {
+ assertingParties = CollectionSupport.copyToList(configs);
+ } else {
+ assertingParties = CollectionSupport.emptyList();
+ }
+ }
+
+ /**
+ * Get the {@link AssertingParty} to use if no other configuration is applicable.
+ *
+ * @return default configuration
+ */
+ @NonnullAfterInit public BasicAssertingParty getDefaultConfiguration() {
+ return defaultAssertingParty;
+ }
+
+ /**
+ * Set the {@link AssertingParty} to use if no other configuration is applicable.
+ *
+ * @param configuration default configuration
+ */
+ public void setDefaultConfiguration(@Nonnull final BasicAssertingParty configuration) {
+ checkSetterPreconditions();
+ defaultAssertingParty = Constraint.isNotNull(configuration, "Default AssertingParty cannot be null");
+ }
+
+ /**
+ * Set the global default {@link SecurityConfiguration}.
+ *
+ * @param config global default
+ */
+ public void setDefaultSecurityConfiguration(@Nullable final SecurityConfiguration config) {
+ checkSetterPreconditions();
+ defaultSecurityConfiguration = config;
+ }
+
+ /** {@inheritDoc} */
+ @Override protected void doInitialize() throws ComponentInitializationException {
+ super.doInitialize();
+
+ final HashSet<String> configIds = new HashSet<>(assertingParties.size());
+ for (final AssertingParty config : assertingParties) {
+ if (configIds.contains(config.getId())) {
+ throw new ComponentInitializationException("Multiple AssertingParty configurations with ID "
+ + config.getId() + " detected, IDs must be unique.");
+ }
+ configIds.add(config.getId());
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Nonnull @NonnullElements public Iterable<AssertingParty> resolve(@Nullable final CriteriaSet criteria)
+ throws ResolverException {
+ checkComponentActive();
+
+ final ProfileRequestContext context = getProfileRequestContext(criteria);
+ if (context == null) {
+ return CollectionSupport.emptyList();
+ }
+
+ log.debug("Resolving asserting party configuration");
+
+ final ArrayList<AssertingParty> matches = new ArrayList<>();
+
+ for (final BasicAssertingParty configuration : assertingParties) {
+ log.debug("Checking if asserting party configuration {} is applicable", configuration.getId());
+ if (configuration.test(context)) {
+ log.debug("Asserting party configuration {} is applicable", configuration.getId());
+ matches.add(configuration);
+ } else {
+ log.debug("Asserting party configuration {} is not applicable", configuration.getId());
+ }
+ }
+
+ if (matches.isEmpty()) {
+ log.debug("No matching asserting party configuration applicable, returning default: {}",
+ getDefaultConfiguration().getId());
+ return CollectionSupport.singleton(getDefaultConfiguration());
+ }
+ return matches;
+ }
+
+ /** {@inheritDoc} */
+ @Nullable public AssertingParty resolveSingle(@Nullable final CriteriaSet criteria) throws ResolverException {
+ checkComponentActive();
+
+ final ProfileRequestContext context = getProfileRequestContext(criteria);
+ if (context == null) {
+ return null;
+ }
+
+ log.debug("Resolving asserting party configuration");
+
+ for (final BasicAssertingParty configuration : assertingParties) {
+ log.debug("Checking if asserting party configuration {} is applicable", configuration.getId());
+ if (configuration.test(context)) {
+ log.debug("Asserting party configuration {} is applicable", configuration.getId());
+ return configuration;
+ }
+ log.debug("Asserting party configuration {} is not applicable", configuration.getId());
+ }
+
+ log.debug("No asserting party configurations applicable, returning default: {}",
+ getDefaultConfiguration().getId());
+ return getDefaultConfiguration();
+ }
+
+ /** {@inheritDoc} */
+ @Nullable public SecurityConfiguration getDefaultSecurityConfiguration(@Nonnull @NotEmpty final String profileId) {
+ return defaultSecurityConfiguration;
+ }
+
+ /**
+ * Get the list of all configured signing credentials.
+ *
+ * @return the list of signing credentials
+ */
+ @Nonnull @NonnullElements @Unmodifiable @NotLive public List<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();
+ }
+ }
+
+ /**
+ * Get the list of all configured encryption credentials.
+ *
+ * @return the list of encryption credentials
+ */
+ @Nonnull @NonnullElements @Unmodifiable @NotLive public List<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(@Nullable final CriteriaSet criteria) {
+ if (criteria != null) {
+ final ProfileRequestContextCriterion prcCriterion = criteria.get(ProfileRequestContextCriterion.class);
+ if (prcCriterion != null) {
+ return prcCriterion.getProfileRequestContext();
+ }
+ }
+
+ return null;
+ }
+
+}
\ No newline at end of file
diff --git a/sp-server-impl/src/main/java/net/shibboleth/sp/config/impl/package-info.java b/sp-server-impl/src/main/java/net/shibboleth/sp/config/impl/package-info.java
new file mode 100644
index 0000000..180de26
--- /dev/null
+++ b/sp-server-impl/src/main/java/net/shibboleth/sp/config/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 SP-specific configuration.
+ */
+package net.shibboleth.sp.config.impl;
\ No newline at end of file
diff --git a/sp-server-impl/src/test/java/net/shibboleth/sp/config/impl/BasicAssertingPartyTest.java b/sp-server-impl/src/test/java/net/shibboleth/sp/config/impl/BasicAssertingPartyTest.java
new file mode 100644
index 0000000..1802969
--- /dev/null
+++ b/sp-server-impl/src/test/java/net/shibboleth/sp/config/impl/BasicAssertingPartyTest.java
@@ -0,0 +1,119 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements. See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID licenses this file to You under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.shibboleth.sp.config.impl;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+
+import net.shibboleth.shared.component.ComponentInitializationException;
+import net.shibboleth.shared.logic.ConstraintViolationException;
+import net.shibboleth.shared.logic.FunctionSupport;
+import net.shibboleth.sp.config.ProfileConfiguration;
+import net.shibboleth.sp.profile.testing.MockProfileConfiguration;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+/** Unit test for {@link BasicAssertingParty}. */
+ at SuppressWarnings("javadoc")
+public class BasicAssertingPartyTest {
+
+ @Test public void testConstruction() throws ComponentInitializationException {
+ BasicAssertingParty config = new BasicAssertingParty();
+ config.setId("foo");
+ config.initialize();
+ Assert.assertEquals(config.getId(), "foo");
+ Assert.assertTrue(config.getProfileConfigurations(null).isEmpty());
+
+ config = new BasicAssertingParty();
+ 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 BasicAssertingParty();
+ config.setId("foo");
+ config.setProfileConfigurations(profileConfigs);
+ config.initialize();
+ Assert.assertEquals(config.getId(), "foo");
+ Assert.assertEquals(config.getProfileConfigurations(null).size(), 2);
+
+ try {
+ config = new BasicAssertingParty();
+ config.initialize();
+ Assert.fail();
+ } catch (final ComponentInitializationException e) {
+ // expected this
+ }
+
+ try {
+ config = new BasicAssertingParty();
+ 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 BasicAssertingParty config = new BasicAssertingParty();
+ 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"));
+
+ BasicAssertingParty config = new BasicAssertingParty();
+ 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 BasicAssertingParty();
+ 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/sp-server-impl/src/test/java/net/shibboleth/sp/config/impl/DefaultAssertingPartyResolverTest.java b/sp-server-impl/src/test/java/net/shibboleth/sp/config/impl/DefaultAssertingPartyResolverTest.java
new file mode 100644
index 0000000..9a2f6aa
--- /dev/null
+++ b/sp-server-impl/src/test/java/net/shibboleth/sp/config/impl/DefaultAssertingPartyResolverTest.java
@@ -0,0 +1,154 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements. See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID licenses this file to You under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.shibboleth.sp.config.impl;
+
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+
+import net.shibboleth.shared.component.ComponentInitializationException;
+import net.shibboleth.shared.logic.PredicateSupport;
+import net.shibboleth.shared.resolver.CriteriaSet;
+import net.shibboleth.sp.config.AssertingParty;
+
+import org.opensaml.profile.context.ProfileRequestContext;
+import org.opensaml.profile.criterion.ProfileRequestContextCriterion;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+/** Unit test for {@link DefaultAssertingPartyResolver}. */
+ at SuppressWarnings("javadoc")
+public class DefaultAssertingPartyResolverTest {
+
+ @Test public void testConstruction() throws ComponentInitializationException {
+ final BasicAssertingParty one = new BasicAssertingParty();
+ one.setId("one");
+ one.initialize();
+
+ final BasicAssertingParty two = new BasicAssertingParty();
+ two.setId("two");
+ two.setActivationCondition(PredicateSupport.alwaysFalse());
+ two.initialize();
+
+ final BasicAssertingParty three = new BasicAssertingParty();
+ three.setId("three");
+ three.initialize();
+
+ final List<BasicAssertingParty> apConfigs = Arrays.asList(one, two, three);
+
+ DefaultAssertingPartyResolver resolver = new DefaultAssertingPartyResolver();
+ resolver.setId("test");
+ resolver.setAssertingParties(apConfigs);
+ Assert.assertEquals(resolver.getId(), "test");
+ Assert.assertEquals(resolver.getAssertingParties().size(), 3);
+
+ resolver = new DefaultAssertingPartyResolver();
+ resolver.setId("test");
+ Assert.assertEquals(resolver.getId(), "test");
+ Assert.assertEquals(resolver.getAssertingParties().size(), 0);
+
+ resolver = new DefaultAssertingPartyResolver();
+ resolver.setId("test");
+ Assert.assertEquals(resolver.getId(), "test");
+ Assert.assertEquals(resolver.getAssertingParties().size(), 0);
+ }
+
+ @Test public void testDefault() throws Exception {
+ final ProfileRequestContext prc = new ProfileRequestContext();
+ final ProfileRequestContextCriterion crit = new ProfileRequestContextCriterion(prc);
+
+ final BasicAssertingParty anonRP = new BasicAssertingParty();
+ anonRP.setId("anonRPId");
+ anonRP.initialize();
+
+ final BasicAssertingParty defaultRP = new BasicAssertingParty();
+ defaultRP.setId("defaultRPId");
+ defaultRP.initialize();
+
+ final DefaultAssertingPartyResolver resolver = new DefaultAssertingPartyResolver();
+ resolver.setId("test");
+ resolver.setDefaultConfiguration(defaultRP);
+ resolver.initialize();
+
+ final Iterable<AssertingParty> results = resolver.resolve(new CriteriaSet(crit));
+ Assert.assertNotNull(results);
+
+ final Iterator<AssertingParty> resultItr = results.iterator();
+ Assert.assertTrue(resultItr.hasNext());
+ Assert.assertSame(resultItr.next(), defaultRP);
+ Assert.assertFalse(resultItr.hasNext());
+
+ Assert.assertSame(resolver.resolveSingle(new CriteriaSet(crit)), defaultRP);
+ }
+
+ @Test public void testResolve() throws Exception {
+ final ProfileRequestContext prc = new ProfileRequestContext();
+ final ProfileRequestContextCriterion crit = new ProfileRequestContextCriterion(prc);
+
+ final BasicAssertingParty anonRP = new BasicAssertingParty();
+ anonRP.setId("anonRPId");
+ anonRP.initialize();
+
+ final BasicAssertingParty defaultRP = new BasicAssertingParty();
+ defaultRP.setId("defaultRPId");
+ defaultRP.initialize();
+
+ final BasicAssertingParty one = new BasicAssertingParty();
+ one.setId("one");
+ one.initialize();
+
+ final BasicAssertingParty two = new BasicAssertingParty();
+ two.setId("two");
+ two.setActivationCondition(PredicateSupport.alwaysFalse());
+ two.initialize();
+
+ final BasicAssertingParty three = new BasicAssertingParty();
+ three.setId("three");
+ three.initialize();
+
+ final List<BasicAssertingParty> apConfigs = Arrays.asList(one, two, three);
+
+ final DefaultAssertingPartyResolver resolver = new DefaultAssertingPartyResolver();
+ resolver.setId("test");
+ resolver.setAssertingParties(apConfigs);
+ resolver.setDefaultConfiguration(defaultRP);
+ resolver.initialize();
+
+ Iterable<AssertingParty> results = resolver.resolve(new CriteriaSet(crit));
+ Assert.assertNotNull(results);
+
+ Iterator<AssertingParty> 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());
+
+ AssertingParty result = resolver.resolveSingle(new CriteriaSet(crit));
+ 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/sp-testing/.checkstyle b/sp-testing/.checkstyle
new file mode 100644
index 0000000..5bae456
--- /dev/null
+++ b/sp-testing/.checkstyle
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<fileset-config file-format-version="1.2.0" simple-config="true" sync-formatter="false">
+ <local-check-config name="Shibboleth Checkstyle" location="/java-sp-server/resources/checkstyle.xml" type="project" description="">
+ <additional-data name="protect-config-file" value="false"/>
+ </local-check-config>
+ <fileset name="all" enabled="true" check-config-name="Shibboleth Checkstyle" local="true">
+ <file-match-pattern match-pattern="." include-pattern="true"/>
+ </fileset>
+</fileset-config>
diff --git a/sp-testing/.gitignore b/sp-testing/.gitignore
new file mode 100644
index 0000000..1df25bf
--- /dev/null
+++ b/sp-testing/.gitignore
@@ -0,0 +1,2 @@
+/test-output
+/target
diff --git a/sp-server-api/pom.xml b/sp-testing/pom.xml
similarity index 65%
copy from sp-server-api/pom.xml
copy to sp-testing/pom.xml
index 07d2442..843aa7f 100644
--- a/sp-server-api/pom.xml
+++ b/sp-testing/pom.xml
@@ -9,53 +9,55 @@
<version>0.0.1-SNAPSHOT</version>
</parent>
- <artifactId>sp-server-api</artifactId>
- <description>SP processing hub/service API.</description>
- <name>Shibboleth SP :: Processing Hub :: Service API</name>
+ <artifactId>sp-testing</artifactId>
+ <name>Shibboleth SP :: Processing Hub :: Testing API</name>
+ <description>Testing APIs for SP components</description>
<packaging>jar</packaging>
<properties>
<checkstyle.configLocation>${project.basedir}/../resources/checkstyle.xml</checkstyle.configLocation>
- <automatic.module.name>net.shibboleth.sp.server</automatic.module.name>
+ <automatic.module.name>net.shibboleth.sp.testing</automatic.module.name>
</properties>
<dependencies>
<!-- Compile dependencies -->
<dependency>
- <groupId>net.shibboleth</groupId>
- <artifactId>shib-attribute-resolver-api</artifactId>
- <scope>compile</scope>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>sp-server-api</artifactId>
+ <version>${project.version}</version>
</dependency>
+
<dependency>
- <groupId>net.shibboleth</groupId>
- <artifactId>shib-attribute-filter-api</artifactId>
- <scope>compile</scope>
+ <groupId>org.opensaml</groupId>
+ <artifactId>opensaml-security-api</artifactId>
</dependency>
+
+ <!-- Normally test scope. -->
<dependency>
- <groupId>net.shibboleth</groupId>
- <artifactId>shib-metadata-api</artifactId>
+ <groupId>org.opensaml</groupId>
+ <artifactId>opensaml-testing</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>net.shibboleth</groupId>
- <artifactId>shib-service</artifactId>
- <scope>compile</scope>
+ <artifactId>shib-support</artifactId>
</dependency>
<dependency>
<groupId>net.shibboleth</groupId>
- <artifactId>shib-support</artifactId>
- <scope>compile</scope>
+ <artifactId>shib-testing</artifactId>
</dependency>
-
+
+ <!-- Normally test scope. -->
<dependency>
- <groupId>${spring.groupId}</groupId>
- <artifactId>spring-beans</artifactId>
+ <groupId>org.testng</groupId>
+ <artifactId>testng</artifactId>
<scope>compile</scope>
</dependency>
+
<dependency>
<groupId>${spring.groupId}</groupId>
- <artifactId>spring-context</artifactId>
+ <artifactId>spring-test</artifactId>
<scope>compile</scope>
</dependency>
@@ -72,11 +74,6 @@
</dependency>
<!-- Test Dependencies -->
- <dependency>
- <groupId>${spring.groupId}</groupId>
- <artifactId>spring-test</artifactId>
- <scope>test</scope>
- </dependency>
</dependencies>
</project>
diff --git a/sp-testing/src/main/java/net/shibboleth/sp/profile/testing/MockProfileConfiguration.java b/sp-testing/src/main/java/net/shibboleth/sp/profile/testing/MockProfileConfiguration.java
new file mode 100644
index 0000000..cbc5240
--- /dev/null
+++ b/sp-testing/src/main/java/net/shibboleth/sp/profile/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.sp.profile.testing;
+
+import javax.annotation.Nonnull;
+
+import org.opensaml.security.config.BasicSecurityConfiguration;
+
+import net.shibboleth.shared.annotation.constraint.NotEmpty;
+import net.shibboleth.sp.config.AbstractProfileConfiguration;
+import net.shibboleth.sp.config.ProfileConfiguration;
+
+/** Mock implementation of {@link ProfileConfiguration}. */
+public class MockProfileConfiguration extends AbstractProfileConfiguration {
+
+ /**
+ * 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/sp-testing/src/main/java/net/shibboleth/sp/profile/testing/package-info.java b/sp-testing/src/main/java/net/shibboleth/sp/profile/testing/package-info.java
new file mode 100644
index 0000000..bde6abd
--- /dev/null
+++ b/sp-testing/src/main/java/net/shibboleth/sp/profile/testing/package-info.java
@@ -0,0 +1,22 @@
+/*
+ * 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.
+ */
+
+/**
+ * Testing utility classes.
+ */
+
+package net.shibboleth.sp.profile.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