[java-opensaml] 02/02: OSJ-181: Enhance dynamic metadata resolvers to support non-entityID criteria
Brent Putman
putmanb at georgetown.edu
Mon Oct 1 18:09:29 EDT 2018
This is an automated email from the git hooks/post-receive script.
putmanb pushed a commit to branch master
in repository java-opensaml.
View the commit online:
http://git.shibboleth.net/view/?p=java-opensaml.git;a=commit;h=23e8004daf7e5734104b4a34673d5e277a466c51
commit 23e8004daf7e5734104b4a34673d5e277a466c51
Author: Brent Putman <putmanb at georgetown.edu>
AuthorDate: Sun Sep 23 18:58:04 2018 -0400
OSJ-181: Enhance dynamic metadata resolvers to support non-entityID criteria
---
.../impl/AbstractDynamicMetadataResolver.java | 420 ++++++++++++++++++---
.../DefaultLocalDynamicSourceKeyGenerator.java | 90 +++++
.../resolver/impl/EntityIDDigestGenerator.java | 31 +-
.../FunctionDrivenDynamicHTTPMetadataResolver.java | 25 +-
.../impl/HTTPEntityIDRequestURLBuilder.java | 17 +-
.../impl/LocalDynamicMetadataResolver.java | 7 +-
.../MetadataQueryProtocolRequestURLBuilder.java | 144 ++++++-
.../impl/MetadataQueryProtocolSHA1Transformer.java | 61 ---
.../resolver/impl/RegexRequestURLBuilder.java | 17 +-
.../resolver/impl/SAMLArtifactURLBuilder.java | 67 ++++
.../resolver/impl/TemplateRequestURLBuilder.java | 15 +-
.../index/impl/LockableMetadataIndexManager.java | 75 ++++
.../AbstractDynamicHTTPMetadataResolverTest.java | 4 +-
.../impl/AbstractDynamicMetadataResolverTest.java | 214 +++++++++--
.../DefaultLocalDynamicSourceKeyGeneratorTest.java | 126 +++++++
...ctionDrivenDynamicHTTPMetadataResolverTest.java | 69 +++-
.../impl/HTTPEntityIDRequestURLBuilderTest.java | 18 +-
...MetadataQueryProtocolRequestURLBuilderTest.java | 63 +++-
.../MetadataQueryProtocolSHA1TransformerTest.java | 31 --
.../resolver/impl/RegexRequestURLBuilderTest.java | 15 +-
.../resolver/impl/SAMLArtifactURLBuilderTest.java | 85 +++++
.../impl/TemplateRequestURLBuilderTest.java | 18 +-
22 files changed, 1332 insertions(+), 280 deletions(-)
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/resolver/impl/AbstractDynamicMetadataResolver.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/resolver/impl/AbstractDynamicMetadataResolver.java
index daae4fb..5814ac0 100644
--- a/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/resolver/impl/AbstractDynamicMetadataResolver.java
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/resolver/impl/AbstractDynamicMetadataResolver.java
@@ -19,10 +19,13 @@ package org.opensaml.saml.metadata.resolver.impl;
import java.io.IOException;
import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
import java.util.Collections;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
+import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ConcurrentHashMap;
@@ -45,9 +48,11 @@ import org.opensaml.core.xml.util.XMLObjectSupport;
import org.opensaml.core.xml.util.XMLObjectSupport.CloneOutputOption;
import org.opensaml.saml.metadata.resolver.ClearableMetadataResolver;
import org.opensaml.saml.metadata.resolver.DynamicMetadataResolver;
-import org.opensaml.saml.metadata.resolver.MetadataResolver;
import org.opensaml.saml.metadata.resolver.filter.FilterException;
+import org.opensaml.saml.metadata.resolver.index.MetadataIndex;
+import org.opensaml.saml.metadata.resolver.index.impl.LockableMetadataIndexManager;
import org.opensaml.saml.saml2.common.SAML2Support;
+import org.opensaml.saml.saml2.metadata.EntitiesDescriptor;
import org.opensaml.saml.saml2.metadata.EntityDescriptor;
import org.opensaml.security.crypto.JCAConstants;
import org.slf4j.Logger;
@@ -59,20 +64,26 @@ import com.codahale.metrics.RatioGauge;
import com.codahale.metrics.Timer.Context;
import com.google.common.base.Function;
import com.google.common.base.MoreObjects;
+import com.google.common.base.Optional;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
-import com.google.common.base.Strings;
+import com.google.common.collect.Collections2;
+import com.google.common.collect.ImmutableSet;
import net.shibboleth.utilities.java.support.annotation.Duration;
import net.shibboleth.utilities.java.support.annotation.constraint.NonnullAfterInit;
import net.shibboleth.utilities.java.support.annotation.constraint.NonnullElements;
+import net.shibboleth.utilities.java.support.annotation.constraint.NotLive;
import net.shibboleth.utilities.java.support.annotation.constraint.Positive;
+import net.shibboleth.utilities.java.support.annotation.constraint.Unmodifiable;
import net.shibboleth.utilities.java.support.codec.StringDigester;
import net.shibboleth.utilities.java.support.codec.StringDigester.OutputFormat;
import net.shibboleth.utilities.java.support.collection.Pair;
import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
import net.shibboleth.utilities.java.support.component.ComponentSupport;
import net.shibboleth.utilities.java.support.logic.Constraint;
+import net.shibboleth.utilities.java.support.primitive.DeprecationSupport;
+import net.shibboleth.utilities.java.support.primitive.DeprecationSupport.ObjectType;
import net.shibboleth.utilities.java.support.primitive.StringSupport;
import net.shibboleth.utilities.java.support.primitive.TimerSupport;
import net.shibboleth.utilities.java.support.resolver.CriteriaSet;
@@ -170,6 +181,9 @@ public abstract class AbstractDynamicMetadataResolver extends AbstractMetadataRe
/** Object tracking metrics related to the persistent cache initialization. */
@NonnullAfterInit private PersistentCacheInitializationMetrics persistentCacheInitMetrics;
+ /** The set of indexes configured. */
+ private Set<MetadataIndex> indexes;
+
/** Flag used to track state of whether currently initializing or not. */
private boolean initializing;
@@ -181,6 +195,8 @@ public abstract class AbstractDynamicMetadataResolver extends AbstractMetadataRe
public AbstractDynamicMetadataResolver(@Nullable final Timer backgroundTaskTimer) {
super();
+ indexes = Collections.emptySet();
+
if (backgroundTaskTimer == null) {
taskTimer = new Timer(TimerSupport.getTimerName(this), true);
createdOwnTaskTimer = true;
@@ -529,6 +545,34 @@ public abstract class AbstractDynamicMetadataResolver extends AbstractMetadataRe
metricsBaseName = StringSupport.trimOrNull(baseName);
}
+ /**
+ * Get the configured indexes.
+ *
+ * @return the set of configured indexes
+ */
+ @Nonnull @NonnullElements @Unmodifiable @NotLive public Set<MetadataIndex> getIndexes() {
+ return ImmutableSet.copyOf(indexes);
+ }
+
+ /**
+ * Set the configured indexes.
+ *
+ * @param newIndexes the new indexes to set
+ */
+ public void setIndexes(@Nullable final Set<MetadataIndex> newIndexes) {
+ ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+ if (newIndexes == null) {
+ indexes = Collections.emptySet();
+ } else {
+ indexes = new HashSet<>();
+ indexes.addAll(Collections2.filter(newIndexes, Predicates.notNull()));
+ }
+ }
+
+ protected boolean indexesEnabled() {
+ return ! getBackingStore().getSecondaryIndexManager().getIndexes().isEmpty();
+ }
+
/** {@inheritDoc} */
public void clear() throws ResolverException {
final DynamicEntityBackingStore backingStore = getBackingStore();
@@ -573,48 +617,48 @@ public abstract class AbstractDynamicMetadataResolver extends AbstractMetadataRe
final Context contextResolve = MetricsSupport.startTimer(timerResolve);
try {
- final EntityIdCriterion entityIdCriterion = criteria.get(EntityIdCriterion.class);
- if (entityIdCriterion == null || Strings.isNullOrEmpty(entityIdCriterion.getEntityId())) {
- log.info("{} Entity Id was not supplied in criteria set, skipping resolution", getLogPrefix());
- return Collections.emptySet();
- }
-
- final String entityID = StringSupport.trimOrNull(criteria.get(EntityIdCriterion.class).getEntityId());
- log.debug("{} Attempting to resolve metadata for entityID: {}", getLogPrefix(), entityID);
-
- final EntityManagementData mgmtData = getBackingStore().getManagementData(entityID);
- final Lock readLock = mgmtData.getReadWriteLock().readLock();
Iterable<EntityDescriptor> candidates = null;
- try {
- readLock.lock();
+
+ final String entityID = resolveEntityID(criteria);
+ if (entityID != null) {
+ log.debug("{} Resolved criteria to entityID: {}", getLogPrefix(), entityID);
- final List<EntityDescriptor> descriptors = lookupEntityID(entityID);
- if (descriptors.isEmpty()) {
- if (mgmtData.isNegativeLookupCacheActive()) {
- log.debug("{} Did not find requested metadata in backing store, "
- + "and negative lookup cache is active, returning empty result",
- getLogPrefix());
- return Collections.emptyList();
- } else {
- log.debug("{} Did not find requested metadata in backing store, "
- + "attempting to resolve dynamically",
- getLogPrefix());
- }
- } else {
- if (shouldAttemptRefresh(mgmtData)) {
- log.debug("{} Metadata was indicated to be refreshed based on refresh trigger time",
- getLogPrefix());
+ final EntityManagementData mgmtData = getBackingStore().getManagementData(entityID);
+ final Lock readLock = mgmtData.getReadWriteLock().readLock();
+ try {
+ readLock.lock();
+
+ final List<EntityDescriptor> descriptors = lookupEntityID(entityID);
+ if (descriptors.isEmpty()) {
+ if (mgmtData.isNegativeLookupCacheActive()) {
+ log.debug("{} Did not find requested metadata in backing store, "
+ + "and negative lookup cache is active, returning empty result",
+ getLogPrefix());
+ return Collections.emptyList();
+ } else {
+ log.debug("{} Did not find requested metadata in backing store, "
+ + "attempting to resolve dynamically",
+ getLogPrefix());
+ }
} else {
- log.debug("{} Found requested metadata in backing store", getLogPrefix());
- candidates = descriptors;
+ if (shouldAttemptRefresh(mgmtData)) {
+ log.debug("{} Metadata was indicated to be refreshed based on refresh trigger time",
+ getLogPrefix());
+ } else {
+ log.debug("{} Found requested metadata in backing store", getLogPrefix());
+ candidates = descriptors;
+ }
}
+ } finally {
+ readLock.unlock();
}
- } finally {
- readLock.unlock();
+ } else {
+ log.debug("{} Single entityID unresolveable from criteria, will resolve from origin by criteria only",
+ getLogPrefix());
}
if (candidates == null) {
- candidates = resolveFromOriginSource(criteria);
+ candidates = resolveFromOriginSource(criteria, entityID);
}
return predicateFilterCandidates(candidates, criteria, false);
@@ -624,17 +668,137 @@ public abstract class AbstractDynamicMetadataResolver extends AbstractMetadataRe
}
/**
+ * Attempt to resolve the single entityID for the operation from the criteria set.
+ *
+ * <p>
+ * If an {@link EntityIdCriterion} is present, that will be used. If not present, then a single
+ * entityID will be resolved via the secondary index manager of the backing store.
+ * </p>
+ *
+ * @param criteria the criteria set on which to operate
+ * @return the resolve entityID, or null if a single entityID could not be resolved
+ */
+ @Nullable protected String resolveEntityID(@Nonnull final CriteriaSet criteria) {
+ final Set<String> entityIDs = resolveEntityIDs(criteria);
+ if (entityIDs.size() == 1) {
+ return entityIDs.iterator().next();
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ *
+ * Attempt to resolve all the entityIDs represented by the criteria set.
+ *
+ * <p>
+ * If an {@link EntityIdCriterion} is present, that will be used. If not present, then
+ * entityIDs will be resolved via the secondary index manager of the backing store.
+ * </p>
+ *
+ * @param criteria the criteria set on which to operate
+ * @return the resolved entityIDs, may be empty
+ */
+ @Nonnull protected Set<String> resolveEntityIDs(@Nonnull final CriteriaSet criteria) {
+ final EntityIdCriterion entityIdCriterion = criteria.get(EntityIdCriterion.class);
+ if (entityIdCriterion != null) {
+ log.debug("{} Found entityID in criteria: {}", getLogPrefix(), entityIdCriterion.getEntityId());
+ return Collections.singleton(entityIdCriterion.getEntityId());
+ } else {
+ log.debug("{} EntityID was not supplied in criteria, processing criteria with secondary indexes",
+ getLogPrefix());
+ }
+
+ if (!indexesEnabled()) {
+ log.trace("Indexes not enabled, skipping secondary index processing");
+ return Collections.emptySet();
+ }
+
+ Optional<Set<String>> indexedResult = null;
+ final Lock readLock = getBackingStore().getSecondaryIndexManager().getReadWriteLock().readLock();
+ try {
+ readLock.lock();
+ indexedResult = getBackingStore().getSecondaryIndexManager().lookupIndexedItems(criteria);
+ } finally {
+ readLock.unlock();
+ }
+
+ if (indexedResult.isPresent()) {
+ final Set<String> entityIDs = indexedResult.get();
+ if (entityIDs.isEmpty()) {
+ log.debug("{} No entityIDs resolved from secondary indexes (Optional 'present' with empty set)",
+ getLogPrefix());
+ return Collections.emptySet();
+ } else if (entityIDs.size() > 1) {
+ log.debug("{} Multiple entityIDs resolved from secondary indexes: {}",
+ getLogPrefix(), entityIDs);
+ return new HashSet<>(entityIDs);
+ } else {
+ final String entityID = entityIDs.iterator().next();
+ log.debug("{} Resolved 1 entityID from secondary indexes: {}", getLogPrefix(), entityID);
+ return Collections.singleton(entityID);
+ }
+ } else {
+ log.debug("{} No entityIDs resolved from secondary indexes (Optional 'absent').", getLogPrefix());
+ return null;
+ }
+ }
+
+ /**
* Fetch metadata from an origin source based on the input criteria, store it in the backing store
* and then return it.
*
* @param criteria the input criteria set
* @return the resolved metadata
* @throws ResolverException if there is a fatal error attempting to resolve the metadata
+ *
+ * @deprecated instead use {@link #resolveFromOriginSource(CriteriaSet, String)}
*/
- @Nonnull @NonnullElements protected Iterable<EntityDescriptor> resolveFromOriginSource(
+ @Deprecated
+ @Nonnull @NonnullElements
+ protected Iterable<EntityDescriptor> resolveFromOriginSource(
@Nonnull final CriteriaSet criteria) throws ResolverException {
- final String entityID = StringSupport.trimOrNull(criteria.get(EntityIdCriterion.class).getEntityId());
+ DeprecationSupport.warnOnce(ObjectType.METHOD, "resolveFromOriginSource", null, "2-arg same-named method");
+
+ return resolveFromOriginSource(criteria, resolveEntityID(criteria));
+ }
+
+ /**
+ * Fetch metadata from an origin source based on the input criteria, store it in the backing store
+ * and then return it.
+ *
+ * @param criteria the input criteria set
+ * @param entityID the previously resolved single entityID
+ * @return the resolved metadata
+ * @throws ResolverException if there is a fatal error attempting to resolve the metadata
+ */
+ @Nonnull @NonnullElements protected Iterable<EntityDescriptor> resolveFromOriginSource(
+ @Nonnull final CriteriaSet criteria, @Nullable final String entityID) throws ResolverException {
+
+ if (entityID != null) {
+ log.debug("{} Resolving from origin source based on entityID: {}", getLogPrefix(), entityID);
+ return resolveFromOriginSourceWithEntityID(criteria, entityID);
+ } else {
+ log.debug("{} Resolving from origin source based on non-entityID criteria", getLogPrefix());
+ return resolveFromOriginSourceWithoutEntityID(criteria);
+ }
+
+ }
+
+ /**
+ * Fetch metadata from an origin source based on the input criteria when the entityID is known,
+ * store it in the backing store and then return it.
+ *
+ * @param criteria the input criteria set
+ * @param entityID the entityID known to be represented by the criteria set
+ * @return the resolved metadata
+ * @throws ResolverException if there is a fatal error attempting to resolve the metadata
+ */
+ @Nonnull @NonnullElements
+ protected Iterable<EntityDescriptor> resolveFromOriginSourceWithEntityID(
+ @Nonnull final CriteriaSet criteria, @Nonnull final String entityID) throws ResolverException {
+
final EntityManagementData mgmtData = getBackingStore().getManagementData(entityID);
final Lock writeLock = mgmtData.getReadWriteLock().writeLock();
@@ -690,6 +854,120 @@ public abstract class AbstractDynamicMetadataResolver extends AbstractMetadataRe
}
}
+
+ /**
+ * Fetch metadata from an origin source based on the input criteria when the entityID is not known,
+ * store it in the backing store and then return it.
+ *
+ * @param criteria the input criteria set
+ * @return the resolved metadata
+ * @throws ResolverException if there is a fatal error attempting to resolve the metadata
+ */
+ @Nonnull @NonnullElements
+ protected Iterable<EntityDescriptor> resolveFromOriginSourceWithoutEntityID(@Nonnull final CriteriaSet criteria)
+ throws ResolverException {
+
+ XMLObject root = null;
+ final Context contextFetchFromOriginSource = MetricsSupport.startTimer(timerFetchFromOriginSource);
+ try {
+ root = fetchFromOriginSource(criteria);
+ } catch (final IOException e) {
+ log.error("{} Error fetching metadata from origin source", getLogPrefix(), e);
+ return lookupCriteria(criteria);
+ } finally {
+ MetricsSupport.stopTimer(contextFetchFromOriginSource);
+ }
+
+ if (root == null) {
+ log.debug("{} No metadata was fetched from the origin source", getLogPrefix());
+ return lookupCriteria(criteria);
+ } else if (root instanceof EntityDescriptor){
+ log.debug("{} Fetched EntityDescriptor from the origin source", getLogPrefix());
+ return processNonEntityIDFetchedEntityDescriptor((EntityDescriptor) root);
+ } else if (root instanceof EntitiesDescriptor) {
+ log.debug("{} Fetched EntitiesDescriptor from the origin source", getLogPrefix());
+ return processNonEntityIDFetchedEntittiesDescriptor((EntitiesDescriptor) root);
+ } else {
+ log.warn("{} Fetched metadata was of an unsupported type: {}", getLogPrefix(), root.getClass().getName());
+ return lookupCriteria(criteria);
+ }
+ }
+
+ /**
+ * Lookup and return all EntityDescriptors currently available in the resolver cache
+ * which match either entityID or secondary-indexed criteria.
+ *
+ * @param criteria the input criteria set
+ * @return the resolved metadata
+ * @throws ResolverException if there is a fatal error attempting to resolve the metadata
+ */
+ @Nonnull @NonnullElements
+ protected Iterable<EntityDescriptor> lookupCriteria(@Nonnull final CriteriaSet criteria) throws ResolverException {
+ final List<EntityDescriptor> entities = new ArrayList<>();
+ final Set<String> entityIDs = resolveEntityIDs(criteria);
+ for (final String entityID : entityIDs) {
+ final EntityManagementData mgmtData = getBackingStore().getManagementData(entityID);
+ final Lock readLock = mgmtData.getReadWriteLock().readLock();
+ try {
+ readLock.lock();
+
+ entities.addAll(lookupEntityID(entityID));
+ } finally {
+ readLock.unlock();
+ }
+ }
+ return entities;
+ }
+
+ /**
+ * Process an EntitiesDescriptor received from a non-entityID-based fetch.
+ *
+ * @param entities the metadata to process
+ * @return the resolved descriptor(s)
+ * @throws ResolverException if there is a fatal error attempting to resolve the metadata
+ */
+ @Nullable protected List<EntityDescriptor> processNonEntityIDFetchedEntittiesDescriptor(
+ @Nonnull final EntitiesDescriptor entities) throws ResolverException {
+
+ final List<EntityDescriptor> returnedEntities = new ArrayList<>();
+
+ for (final EntitiesDescriptor childEntities : entities.getEntitiesDescriptors()) {
+ returnedEntities.addAll(processNonEntityIDFetchedEntittiesDescriptor(childEntities));
+ }
+
+ for (final EntityDescriptor entity : entities.getEntityDescriptors()) {
+ returnedEntities.addAll(processNonEntityIDFetchedEntityDescriptor(entity));
+ }
+
+ return returnedEntities;
+ }
+
+ /**
+ * Process an EntityDescriptor received from a non-entityID-based fetch.
+ *
+ * @param entity the metadata to process
+ * @return the resolved descriptor(s)
+ * @throws ResolverException if there is a fatal error attempting to resolve the metadata
+ */
+ @Nullable protected List<EntityDescriptor> processNonEntityIDFetchedEntityDescriptor(
+ @Nonnull final EntityDescriptor entity) throws ResolverException {
+
+ final String entityID = entity.getEntityID();
+ final EntityManagementData mgmtData = getBackingStore().getManagementData(entityID);
+ final Lock writeLock = mgmtData.getReadWriteLock().writeLock();
+ try {
+ writeLock.lock();
+ mgmtData.clearNegativeLookupCache();
+ processNewMetadata(entity, entityID);
+ return lookupEntityID(entityID);
+ } catch (final FilterException e) {
+ log.error("{} Metadata filtering problem processing non-entityID fetched EntityDescriptor",
+ getLogPrefix(), e);
+ return lookupEntityID(entityID);
+ } finally {
+ writeLock.unlock();
+ }
+ }
/**
* Fetch the metadata from the origin source.
@@ -928,7 +1206,7 @@ public abstract class AbstractDynamicMetadataResolver extends AbstractMetadataRe
/** {@inheritDoc} */
@Override
@Nonnull protected DynamicEntityBackingStore createNewBackingStore() {
- return new DynamicEntityBackingStore();
+ return new DynamicEntityBackingStore(getIndexes());
}
/** {@inheritDoc} */
@@ -1137,10 +1415,23 @@ public abstract class AbstractDynamicMetadataResolver extends AbstractMetadataRe
/** {@inheritDoc} */
@Override
protected void removeByEntityID(final String entityID, final EntityBackingStore backingStore) {
- if (isPersistentCachingEnabled()) {
- final List<EntityDescriptor> descriptors = backingStore.getIndexedDescriptors().get(entityID);
- if (descriptors != null) {
- for (final EntityDescriptor descriptor : descriptors) {
+ final List<EntityDescriptor> descriptors = backingStore.getIndexedDescriptors().get(entityID);
+ if (descriptors != null) {
+ for (final EntityDescriptor descriptor : descriptors) {
+
+ if (indexesEnabled()) {
+ final DynamicEntityBackingStore dynamicStore = (DynamicEntityBackingStore) backingStore;
+
+ final Lock writeLock = dynamicStore.getSecondaryIndexManager().getReadWriteLock().writeLock();
+ try {
+ writeLock.lock();
+ dynamicStore.getSecondaryIndexManager().deindexEntityDescriptor(descriptor);
+ } finally {
+ writeLock.unlock();
+ }
+ }
+
+ if (isPersistentCachingEnabled()) {
final String key = getPersistentCacheKeyGenerator().apply(descriptor);
try {
getPersistentCacheManager().remove(key);
@@ -1149,6 +1440,7 @@ public abstract class AbstractDynamicMetadataResolver extends AbstractMetadataRe
getLogPrefix(), descriptor.getEntityID(), key);
}
}
+
}
}
@@ -1188,6 +1480,24 @@ public abstract class AbstractDynamicMetadataResolver extends AbstractMetadataRe
super.doDestroy();
}
+ /** {@inheritDoc} */
+ @Override protected void indexEntityDescriptor(@Nonnull final EntityDescriptor entityDescriptor,
+ @Nonnull final EntityBackingStore backingStore) {
+ super.indexEntityDescriptor(entityDescriptor, backingStore);
+
+ if (indexesEnabled()) {
+ final DynamicEntityBackingStore dynamicStore = (DynamicEntityBackingStore) backingStore;
+
+ final Lock writeLock = dynamicStore.getSecondaryIndexManager().getReadWriteLock().writeLock();
+ try {
+ writeLock.lock();
+ dynamicStore.getSecondaryIndexManager().indexEntityDescriptor(entityDescriptor);
+ } finally {
+ writeLock.unlock();
+ }
+ }
+ }
+
/**
* Specialized entity backing store implementation for dynamic metadata resolvers.
*/
@@ -1196,10 +1506,30 @@ public abstract class AbstractDynamicMetadataResolver extends AbstractMetadataRe
/** Map holding management data for each entityID. */
private Map<String, EntityManagementData> mgmtDataMap;
- /** Constructor. */
- protected DynamicEntityBackingStore() {
+ /** Manager for secondary indexes. */
+ private LockableMetadataIndexManager<String> secondaryIndexManager;
+
+ /**
+ * Constructor.
+ *
+ * @param initIndexes secondary indexes for which to initialize storage
+ */
+ protected DynamicEntityBackingStore(
+ @Nullable @NonnullElements @Unmodifiable @NotLive final Set<MetadataIndex> initIndexes) {
super();
mgmtDataMap = new ConcurrentHashMap<>();
+ secondaryIndexManager = new LockableMetadataIndexManager(initIndexes,
+ new LockableMetadataIndexManager.EntityIDExtractionFunction());
+
+ }
+
+ /**
+ * Get the secondary index manager.
+ *
+ * @return the manager for secondary indexes
+ */
+ public LockableMetadataIndexManager<String> getSecondaryIndexManager() {
+ return secondaryIndexManager;
}
/**
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/resolver/impl/DefaultLocalDynamicSourceKeyGenerator.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/resolver/impl/DefaultLocalDynamicSourceKeyGenerator.java
new file mode 100644
index 0000000..05044e0
--- /dev/null
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/resolver/impl/DefaultLocalDynamicSourceKeyGenerator.java
@@ -0,0 +1,90 @@
+/*
+ * 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 org.opensaml.saml.metadata.resolver.impl;
+
+import javax.annotation.Nullable;
+
+import org.opensaml.core.criterion.EntityIdCriterion;
+import org.opensaml.saml.common.binding.artifact.SAMLArtifact;
+import org.opensaml.saml.common.binding.artifact.SAMLSourceIDArtifact;
+import org.opensaml.saml.criterion.ArtifactCriterion;
+
+import com.google.common.base.Function;
+import com.google.common.io.BaseEncoding;
+
+import net.shibboleth.utilities.java.support.codec.StringDigester;
+import net.shibboleth.utilities.java.support.resolver.CriteriaSet;
+
+/**
+ * A default implementation of {@link Function} for use as a source key generator
+ * with {@link LocalDynamicMetadataResolver}.
+ *
+ * <p>
+ * This is a simple subclass of {@link EntityIDDigestGenerator} which defaults in the {@link StringDigester}
+ * to use lower-case hex encoding of the SHA-1 digest of the entity ID from {@link EntityIdCriterion}.
+ * Since this is the same representation typically used for the SAML SourceID used in artifacts,
+ * this implementation adds in support for understanding {@link ArtifactCriterion} carrying a
+ * {@link SAMLSourceIDArtifact}.
+ * </p>
+ */
+public class DefaultLocalDynamicSourceKeyGenerator extends EntityIDDigestGenerator {
+
+ /** Hex encoder. */
+ private static final BaseEncoding HEX = BaseEncoding.base16().lowerCase();
+
+ /**
+ * Constructor.
+ *
+ */
+ public DefaultLocalDynamicSourceKeyGenerator() {
+ super();
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param keyPrefix optional prefix for the digested value
+ * @param keySuffix optional suffix for the digested value
+ * @param valueSeparator optional separator between the prefix, digest and suffix values
+ */
+ public DefaultLocalDynamicSourceKeyGenerator(@Nullable final String keyPrefix, @Nullable final String keySuffix,
+ @Nullable final String valueSeparator) {
+ super(null, keyPrefix, keySuffix, valueSeparator);
+ }
+
+ /** {@inheritDoc} */
+ public String apply(@Nullable final CriteriaSet criteria) {
+ if (criteria == null) {
+ return null;
+ }
+
+ if (criteria.contains(EntityIdCriterion.class)) {
+ return super.apply(criteria);
+ }
+
+ if (criteria.contains(ArtifactCriterion.class)) {
+ final SAMLArtifact artifact = criteria.get(ArtifactCriterion.class).getArtifact();
+ if (artifact instanceof SAMLSourceIDArtifact) {
+ return buildKey(HEX.encode(((SAMLSourceIDArtifact)artifact).getSourceID()));
+ }
+ }
+
+ return null;
+ }
+
+}
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/resolver/impl/EntityIDDigestGenerator.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/resolver/impl/EntityIDDigestGenerator.java
index e273a9e..2d25762 100644
--- a/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/resolver/impl/EntityIDDigestGenerator.java
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/resolver/impl/EntityIDDigestGenerator.java
@@ -87,25 +87,26 @@ public class EntityIDDigestGenerator implements Function<CriteriaSet, String> {
/** {@inheritDoc} */
@Override
- public String apply(final CriteriaSet input) {
- if (input == null) {
+ public String apply(final CriteriaSet criteria) {
+ if (criteria == null || !criteria.contains(EntityIdCriterion.class)) {
return null;
}
- final EntityIdCriterion entityIDCrit = input.get(EntityIdCriterion.class);
- if (entityIDCrit == null) {
- return null;
- }
-
- final String entityID = StringSupport.trimOrNull(entityIDCrit.getEntityId());
- if (entityID == null) {
- return null;
- }
-
- final String digested = digester.apply(entityID);
+ final String digested = digester.apply(criteria.get(EntityIdCriterion.class).getEntityId());
+ return buildKey(digested);
+ }
+
+ /**
+ * Build the key by applying the configured prefix and/or suffix, if present.
+ *
+ * @param keyValue the primary key value data being represented
+ *
+ * @return the key value with prefix and suffix applied
+ */
+ protected String buildKey(@Nonnull final String keyValue) {
if (prefix == null && suffix == null) {
- return digested;
+ return keyValue;
} else {
final StringBuffer buffer = new StringBuffer();
if (prefix != null) {
@@ -114,7 +115,7 @@ public class EntityIDDigestGenerator implements Function<CriteriaSet, String> {
buffer.append(separator);
}
}
- buffer.append(digested);
+ buffer.append(keyValue);
if (suffix != null) {
if (separator != null) {
buffer.append(separator);
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/resolver/impl/FunctionDrivenDynamicHTTPMetadataResolver.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/resolver/impl/FunctionDrivenDynamicHTTPMetadataResolver.java
index c00d1f9..d3f6182 100644
--- a/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/resolver/impl/FunctionDrivenDynamicHTTPMetadataResolver.java
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/resolver/impl/FunctionDrivenDynamicHTTPMetadataResolver.java
@@ -22,18 +22,16 @@ import java.util.Timer;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
-import net.shibboleth.utilities.java.support.component.ComponentSupport;
-import net.shibboleth.utilities.java.support.logic.Constraint;
-import net.shibboleth.utilities.java.support.primitive.StringSupport;
-import net.shibboleth.utilities.java.support.resolver.CriteriaSet;
-
import org.apache.http.client.HttpClient;
-import org.opensaml.core.criterion.EntityIdCriterion;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.base.Function;
+import net.shibboleth.utilities.java.support.component.ComponentSupport;
+import net.shibboleth.utilities.java.support.logic.Constraint;
+import net.shibboleth.utilities.java.support.resolver.CriteriaSet;
+
/**
* Simple implementation of an HTTP-based dynamic metadata resolver which builds the request URL
* to process based on a {@link Function} instance.
@@ -50,7 +48,7 @@ public class FunctionDrivenDynamicHTTPMetadataResolver extends AbstractDynamicHT
private final Logger log = LoggerFactory.getLogger(FunctionDrivenDynamicHTTPMetadataResolver.class);
/** Function for building the request URL. */
- private Function<String, String> requestURLBuilder;
+ private Function<CriteriaSet, String> requestURLBuilder;
/**
* Constructor.
@@ -80,7 +78,7 @@ public class FunctionDrivenDynamicHTTPMetadataResolver extends AbstractDynamicHT
*
* @return the request URL builder function instance
*/
- @Nonnull public Function<String, String> getRequestURLBuilder() {
+ @Nonnull public Function<CriteriaSet, String> getRequestURLBuilder() {
return requestURLBuilder;
}
@@ -90,9 +88,9 @@ public class FunctionDrivenDynamicHTTPMetadataResolver extends AbstractDynamicHT
*
* <p>Defaults to an instance of {@link HTTPEntityIDRequestURLBuilder}.</p>
*
- * @param builder the reqeust URL builder function instance
+ * @param builder the request URL builder function instance
*/
- public void setRequestURLBuilder(@Nonnull final Function<String, String> builder) {
+ public void setRequestURLBuilder(@Nonnull final Function<CriteriaSet, String> builder) {
ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
ComponentSupport.ifDestroyedThrowDestroyedComponentException(this);
requestURLBuilder = Constraint.isNotNull(builder, "Request URL builder function was null");
@@ -101,12 +99,7 @@ public class FunctionDrivenDynamicHTTPMetadataResolver extends AbstractDynamicHT
/** {@inheritDoc} */
@Override
@Nullable protected String buildRequestURL(@Nonnull final CriteriaSet criteria) {
- final String entityID = StringSupport.trimOrNull(criteria.get(EntityIdCriterion.class).getEntityId());
- if (entityID == null) {
- return null;
- }
-
- final String url = getRequestURLBuilder().apply(entityID);
+ final String url = getRequestURLBuilder().apply(criteria);
log.debug("{} URL generated by request builder was: {}", getLogPrefix(), url);
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/resolver/impl/HTTPEntityIDRequestURLBuilder.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/resolver/impl/HTTPEntityIDRequestURLBuilder.java
index 6f0269d..0e19026 100644
--- a/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/resolver/impl/HTTPEntityIDRequestURLBuilder.java
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/resolver/impl/HTTPEntityIDRequestURLBuilder.java
@@ -21,23 +21,32 @@ import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import net.shibboleth.utilities.java.support.logic.Constraint;
+import net.shibboleth.utilities.java.support.resolver.CriteriaSet;
+import org.opensaml.core.criterion.EntityIdCriterion;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.base.Function;
/**
- * Function which examines an entity ID and returns it as a metadata request URL if and only if the entity ID
- * is an HTTP or HTTPS URL.
+ * Function which examines an entity ID from supplied criteria and returns it as a metadata request URL
+ * if and only if the entity ID is an HTTP or HTTPS URL.
*/
-public class HTTPEntityIDRequestURLBuilder implements Function<String, String> {
+public class HTTPEntityIDRequestURLBuilder implements Function<CriteriaSet, String> {
/** Logger. */
private final Logger log = LoggerFactory.getLogger(HTTPEntityIDRequestURLBuilder.class);
/** {@inheritDoc} */
- @Override @Nullable public String apply(@Nonnull final String entityID) {
+ @Override @Nullable public String apply(@Nonnull final CriteriaSet criteria) {
+ Constraint.isNotNull(criteria, "Criteria was null");
+ if (!criteria.contains(EntityIdCriterion.class)) {
+ log.trace("Criteria did not contain entity ID, unable to build request URL");
+ return null;
+ }
+ final String entityID = criteria.get(EntityIdCriterion.class).getEntityId();
+
Constraint.isNotNull(entityID, "Entity ID was null");
if (entityID.toLowerCase().startsWith("http:") || entityID.toLowerCase().startsWith("https:")) {
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/resolver/impl/LocalDynamicMetadataResolver.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/resolver/impl/LocalDynamicMetadataResolver.java
index fca963b..ab7ebe1 100644
--- a/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/resolver/impl/LocalDynamicMetadataResolver.java
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/resolver/impl/LocalDynamicMetadataResolver.java
@@ -54,7 +54,7 @@ public class LocalDynamicMetadataResolver extends AbstractDynamicMetadataResolve
* Constructor.
*
* <p>
- * Source key generator will be an internal instance of {@link EntityIDDigestGenerator},
+ * Source key generator will be an internal instance of {@link DefaultLocalDynamicSourceKeyGenerator},
* with all default parameters.
* </p>
*
@@ -79,7 +79,8 @@ public class LocalDynamicMetadataResolver extends AbstractDynamicMetadataResolve
* Constructor.
*
* <p>
- * If the supplied source key generator is null, an internal instance of {@link EntityIDDigestGenerator}
+ * If the supplied source key generator is null, an internal instance of
+ * {@link DefaultLocalDynamicSourceKeyGenerator}
* will be used, with all default parameters.
* </p>
* @param backgroundTaskTimer timer for management of background tasks
@@ -96,7 +97,7 @@ public class LocalDynamicMetadataResolver extends AbstractDynamicMetadataResolve
sourceKeyGenerator = keyGenerator;
if (sourceKeyGenerator == null) {
- sourceKeyGenerator = new EntityIDDigestGenerator();
+ sourceKeyGenerator = new DefaultLocalDynamicSourceKeyGenerator();
}
}
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/resolver/impl/MetadataQueryProtocolRequestURLBuilder.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/resolver/impl/MetadataQueryProtocolRequestURLBuilder.java
index 30feff4..a68e8a5 100644
--- a/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/resolver/impl/MetadataQueryProtocolRequestURLBuilder.java
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/resolver/impl/MetadataQueryProtocolRequestURLBuilder.java
@@ -17,26 +17,44 @@
package org.opensaml.saml.metadata.resolver.impl;
+import java.util.ArrayList;
+import java.util.List;
+
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
+import org.opensaml.core.criterion.EntityIdCriterion;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.base.Function;
+import com.google.common.base.Predicates;
+import com.google.common.collect.Collections2;
import com.google.common.escape.Escaper;
import com.google.common.net.UrlEscapers;
+import net.shibboleth.utilities.java.support.annotation.ParameterName;
import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
import net.shibboleth.utilities.java.support.logic.Constraint;
import net.shibboleth.utilities.java.support.primitive.StringSupport;
+import net.shibboleth.utilities.java.support.resolver.CriteriaSet;
//TODO reference to protocol spec pending in Javadoc.
/**
- * Function which produces a URL according to the Metadata Query Protocol specification.
+ * Function which produces a URL according to the Metadata Query Protocol (MDQ) specification.
+ *
+ * <p>
+ * Support for building request URLs per the MDQ SAML profile based on an {@link EntityIdCriterion} is built-in.
+ * </p>
+ *
+ * <p>
+ * Support for building request URLs via other criteria may be specified via ordered instances
+ * of {@link MetadataQueryProtocolURLBuilder}. These are evaluated in the supplied order,
+ * and the first non-null result will be returned.
+ * </p>
*/
-public class MetadataQueryProtocolRequestURLBuilder implements Function<String, String> {
+public class MetadataQueryProtocolRequestURLBuilder implements Function<CriteriaSet, String> {
/** Logger. */
private final Logger log = LoggerFactory.getLogger(MetadataQueryProtocolRequestURLBuilder.class);
@@ -50,23 +68,57 @@ public class MetadataQueryProtocolRequestURLBuilder implements Function<String,
/** Path escaper for escaping the input value inserted into the URL path. */
private Escaper pathEscaper = UrlEscapers.urlPathSegmentEscaper();
+ /** List of secondary URL builders. */
+ private List<MetadataQueryProtocolURLBuilder> urlBuilders;
+
/**
* Constructor.
*
* @param baseURL the base URL for the metadata responder
*/
- public MetadataQueryProtocolRequestURLBuilder(@Nonnull @NotEmpty final String baseURL) {
- this(baseURL, null);
+ public MetadataQueryProtocolRequestURLBuilder(
+ @ParameterName(name="baseURL") @Nonnull @NotEmpty final String baseURL) {
+ this(baseURL, null, null);
}
+
/**
* Constructor.
*
* @param baseURL the base URL for the metadata responder
* @param transform function which transforms the entityID prior to URL construction substitution, may be null
*/
- public MetadataQueryProtocolRequestURLBuilder(@Nonnull @NotEmpty final String baseURL,
- @Nullable final Function<String,String> transform) {
+ public MetadataQueryProtocolRequestURLBuilder(
+ @ParameterName(name="baseURL") @Nonnull @NotEmpty final String baseURL,
+ @ParameterName(name="transform") @Nullable final Function<String,String> transform) {
+ this(baseURL, transform, null);
+ }
+ /**
+ * Constructor.
+ *
+ * @param baseURL the base URL for the metadata responder
+ * @param secondaryURLBuilders the list of secondary URL builders, may be null
+ */
+ public MetadataQueryProtocolRequestURLBuilder(
+ @ParameterName(name="baseURL") @Nonnull @NotEmpty final String baseURL,
+ @ParameterName(name="secondaryURLBuilders") @Nullable
+ final List<MetadataQueryProtocolURLBuilder> secondaryURLBuilders) {
+ this(baseURL, null, secondaryURLBuilders);
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param baseURL the base URL for the metadata responder
+ * @param transform function which transforms the entityID prior to URL construction substitution, may be null
+ * @param secondaryURLBuilders the list of secondary URL builders, may be null
+ */
+ public MetadataQueryProtocolRequestURLBuilder(
+ @ParameterName(name="baseURL") @Nonnull @NotEmpty final String baseURL,
+ @ParameterName(name="transform") @Nullable final Function<String,String> transform,
+ @ParameterName(name="secondaryURLBuilders") @Nullable
+ final List<MetadataQueryProtocolURLBuilder> secondaryURLBuilders
+ ) {
base = Constraint.isNotNull(StringSupport.trimOrNull(baseURL), "Base URL was null or empty");
if (!base.endsWith("/")) {
log.debug("Base URL did not end in a trailing '/', one will be added");
@@ -75,14 +127,37 @@ public class MetadataQueryProtocolRequestURLBuilder implements Function<String,
log.debug("Effective base URL value was: {}", base);
transformer = transform;
+
+ if (secondaryURLBuilders != null) {
+ urlBuilders = new ArrayList<>(Collections2.filter(secondaryURLBuilders, Predicates.notNull()));
+ }
}
/** {@inheritDoc} */
- @Override @Nullable public String apply(@Nonnull final String input) {
- String entityID = Constraint.isNotNull(input, "Entity ID was null");
-
+ @Override @Nullable public String apply(@Nonnull final CriteriaSet criteria) {
+ Constraint.isNotNull(criteria, "Criteria was null");
+ if (criteria.contains(EntityIdCriterion.class)) {
+ log.debug("Criteria contained entity ID, building on that basis");
+ return buildFromEntityID(criteria.get(EntityIdCriterion.class).getEntityId());
+ } else if (urlBuilders != null) {
+ log.debug("Criteria did not contain entity ID, attempting to build using secondary URL builders");
+ return buildFromSecondaryLookups(criteria);
+ } else {
+ log.debug("Criteria did not contain entity ID and no secondary URL builders were configured");
+ return null;
+ }
+ }
+
+ /**
+ * Build request URL from entityID.
+ *
+ * @param inputEntityID the entityID
+ * @return the request URL, or null
+ */
+ private String buildFromEntityID(@Nonnull final String inputEntityID) {
+ String entityID = inputEntityID;
if (transformer != null) {
- entityID = transformer.apply(entityID);
+ entityID = transformer.apply(inputEntityID);
log.debug("Transformed entityID is '{}'", entityID);
if (entityID == null) {
log.debug("Transformed entityID was null");
@@ -90,15 +165,48 @@ public class MetadataQueryProtocolRequestURLBuilder implements Function<String,
}
}
- try {
- final String result = base + "entities/" + pathEscaper.escape(entityID);
- log.debug("From entityID '{}' and base URL '{}', built request URL: {}",
- entityID, base, result);
- return result;
- } catch (final Throwable t) {
- log.error("Encountered fatal error attempting to build request URL", t);
- return null;
+ final String result = base + "entities/" + pathEscaper.escape(entityID);
+ log.debug("From entityID '{}' and base URL '{}', built request URL: {}",
+ entityID, base, result);
+ return result;
+ }
+
+ /**
+ * Build request URL from secondary lookup criteria.
+ *
+ * @param criteria the criteria
+ * @return the request URL, or null
+ */
+ private String buildFromSecondaryLookups(@Nonnull final CriteriaSet criteria) {
+ if (urlBuilders != null) {
+ for (final MetadataQueryProtocolURLBuilder builder : urlBuilders) {
+ final String url = builder.buildURL(base, criteria);
+ log.debug("Secondary URL builder '{}' produced URL: {}", builder.getClass().getName(), url);
+ if (url != null) {
+ return url;
+ }
+ }
}
+ log.debug("No configured secondary URL builders produced a non-null request URL");
+ return null;
+ }
+
+ /**
+ * Interface for a component which builds a Metadata Query Protocol request URL from a base URL
+ * and criteria.
+ */
+ public interface MetadataQueryProtocolURLBuilder {
+
+ /**
+ * Build a request URL using the supplied base service URL and criteria.
+ *
+ * @param baseURL the service base URL
+ * @param criteria the criteria
+ * @return a URL based on the supplied inputs, or null if the implementation did not support
+ * or understand any of the supplied criteria
+ */
+ @Nullable public String buildURL(@Nonnull final String baseURL, @Nonnull final CriteriaSet criteria);
+
}
}
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/resolver/impl/MetadataQueryProtocolSHA1Transformer.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/resolver/impl/MetadataQueryProtocolSHA1Transformer.java
deleted file mode 100644
index c9ef1c3..0000000
--- a/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/resolver/impl/MetadataQueryProtocolSHA1Transformer.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Licensed to the University Corporation for Advanced Internet Development,
- * Inc. (UCAID) under one or more contributor license agreements. See the
- * NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The UCAID licenses this file to You under the Apache
- * License, Version 2.0 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.opensaml.saml.metadata.resolver.impl;
-
-import java.security.NoSuchAlgorithmException;
-
-import javax.annotation.Nullable;
-
-import net.shibboleth.utilities.java.support.codec.StringDigester;
-import net.shibboleth.utilities.java.support.codec.StringDigester.OutputFormat;
-import net.shibboleth.utilities.java.support.logic.Constraint;
-import net.shibboleth.utilities.java.support.primitive.StringSupport;
-
-import com.google.common.base.Function;
-
-//TODO reference to protocol spec pending in Javadoc.
-
-/**
- * Function which digests an entity ID using SHA-1 and returns it in the format specified by
- * the Metadata Query Protocol specification.
- */
-public class MetadataQueryProtocolSHA1Transformer implements Function<String, String> {
-
- /** String digester instance. */
- private StringDigester digester;
-
- /** Constructor. */
- public MetadataQueryProtocolSHA1Transformer() {
- try {
- digester = new StringDigester("SHA-1", OutputFormat.HEX_LOWER);
- } catch (final NoSuchAlgorithmException e) {
- // this can't really happen b/c SHA-1 is required to be supported on all JREs.
- }
- }
-
- /** {@inheritDoc} */
- @Override @Nullable public String apply(@Nullable final String input) {
- final String entityID = Constraint.isNotNull(StringSupport.trimOrNull(input), "Entity ID was null or empty");
- final String digested = digester.apply(entityID);
- if (digested == null) {
- return null;
- }
- return "{sha1}" + digested;
- }
-
-}
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/resolver/impl/RegexRequestURLBuilder.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/resolver/impl/RegexRequestURLBuilder.java
index 050fb99..34b4b5b 100644
--- a/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/resolver/impl/RegexRequestURLBuilder.java
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/resolver/impl/RegexRequestURLBuilder.java
@@ -26,15 +26,17 @@ import javax.annotation.Nullable;
import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
import net.shibboleth.utilities.java.support.logic.Constraint;
import net.shibboleth.utilities.java.support.primitive.StringSupport;
+import net.shibboleth.utilities.java.support.resolver.CriteriaSet;
+import org.opensaml.core.criterion.EntityIdCriterion;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.base.Function;
/**
- * Function which produces a URL by evaluating a supplied regular expression against the entity ID, and applying the
- * result to a supplied replacement string.
+ * Function which produces a URL by evaluating a supplied regular expression against the criteria entity ID,
+ * and applying the result to a supplied replacement string.
*
* <p>
* The function uses standard Java regular expression components from the <code>java.util.regex</code> package.
@@ -70,7 +72,7 @@ import com.google.common.base.Function;
* </p>
*
*/
-public class RegexRequestURLBuilder implements Function<String, String> {
+public class RegexRequestURLBuilder implements Function<CriteriaSet, String> {
/** Logger. */
private final Logger log = LoggerFactory.getLogger(RegexRequestURLBuilder.class);
@@ -106,8 +108,13 @@ public class RegexRequestURLBuilder implements Function<String, String> {
/** {@inheritDoc} */
@Override
- @Nullable public String apply(@Nonnull final String entityID) {
- Constraint.isNotNull(entityID, "Entity ID was null");
+ @Nullable public String apply(@Nonnull final CriteriaSet criteria) {
+ Constraint.isNotNull(criteria, "Criteria was null");
+ if (!criteria.contains(EntityIdCriterion.class)) {
+ log.trace("Criteria did not contain entity ID, unable to build request URL");
+ return null;
+ }
+ final String entityID = criteria.get(EntityIdCriterion.class).getEntityId();
try {
final Matcher matcher = pattern.matcher(entityID);
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/resolver/impl/SAMLArtifactURLBuilder.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/resolver/impl/SAMLArtifactURLBuilder.java
new file mode 100644
index 0000000..b11de63
--- /dev/null
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/resolver/impl/SAMLArtifactURLBuilder.java
@@ -0,0 +1,67 @@
+/*
+ * 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 org.opensaml.saml.metadata.resolver.impl;
+
+import javax.annotation.Nonnull;
+
+import org.opensaml.saml.common.binding.artifact.SAMLSourceIDArtifact;
+import org.opensaml.saml.criterion.ArtifactCriterion;
+import org.opensaml.saml.metadata.resolver.impl.MetadataQueryProtocolRequestURLBuilder.MetadataQueryProtocolURLBuilder;
+
+import com.google.common.io.BaseEncoding;
+
+import net.shibboleth.utilities.java.support.resolver.CriteriaSet;
+
+/**
+ * Implementation of {@link MetadataQueryProtocolURLBuilder} which understands {@link ArtifactCriterion}.
+ */
+public class SAMLArtifactURLBuilder implements MetadataQueryProtocolURLBuilder {
+
+ /** Hex encoder. */
+ private static final BaseEncoding HEX = BaseEncoding.base16().lowerCase();
+
+ /** {@inheritDoc} */
+ public String buildURL(@Nonnull final String baseURL, @Nonnull final CriteriaSet criteria) {
+ if (!criteria.contains(ArtifactCriterion.class)) {
+ return null;
+ }
+ final ArtifactCriterion artifactCriterion = criteria.get(ArtifactCriterion.class);
+
+ if (artifactCriterion.getArtifact() instanceof SAMLSourceIDArtifact) {
+ return buildFromSourceID(baseURL, (SAMLSourceIDArtifact)artifactCriterion.getArtifact());
+ }
+
+ return null;
+ }
+
+ /**
+ * Builder URL from SAML artifact source ID.
+ *
+ * @param baseURL the base URL
+ * @param sourceIDArtifact the source ID artifact
+ * @return the request URL
+ *
+ */
+ private String buildFromSourceID(@Nonnull final String baseURL,
+ @Nonnull final SAMLSourceIDArtifact sourceIDArtifact) {
+
+ // We just statically escape "{sha1}" here
+ return baseURL + "entities/" + "%7Bsha1%7D" + HEX.encode(sourceIDArtifact.getSourceID());
+ }
+
+}
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/resolver/impl/TemplateRequestURLBuilder.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/resolver/impl/TemplateRequestURLBuilder.java
index f4514ae..741a974 100644
--- a/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/resolver/impl/TemplateRequestURLBuilder.java
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/resolver/impl/TemplateRequestURLBuilder.java
@@ -25,6 +25,7 @@ import javax.annotation.Nullable;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;
+import org.opensaml.core.criterion.EntityIdCriterion;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -35,11 +36,12 @@ import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
import net.shibboleth.utilities.java.support.logic.Constraint;
import net.shibboleth.utilities.java.support.primitive.DeprecationSupport;
import net.shibboleth.utilities.java.support.primitive.StringSupport;
+import net.shibboleth.utilities.java.support.resolver.CriteriaSet;
import net.shibboleth.utilities.java.support.primitive.DeprecationSupport.ObjectType;
import net.shibboleth.utilities.java.support.velocity.Template;
/**
- * Function which produces a URL by substituting an entity ID value into a Velocity template string.
+ * Function which produces a URL by substituting an entity ID value from criteria into a Velocity template string.
*
* <p>
* The entity ID will be replaced in the template string according to the template variable <code>entityID</code>,
@@ -54,7 +56,7 @@ import net.shibboleth.utilities.java.support.velocity.Template;
* </p>
*
*/
-public class TemplateRequestURLBuilder implements Function<String, String> {
+public class TemplateRequestURLBuilder implements Function<CriteriaSet, String> {
/** EntityID Encoding style. */
public enum EncodingStyle {
@@ -213,8 +215,13 @@ public class TemplateRequestURLBuilder implements Function<String, String> {
/** {@inheritDoc} */
@Override
- @Nullable public String apply(@Nonnull final String input) {
- String entityID = Constraint.isNotNull(input, "Entity ID was null");
+ @Nullable public String apply(@Nonnull final CriteriaSet criteria) {
+ Constraint.isNotNull(criteria, "Criteria was null");
+ if (!criteria.contains(EntityIdCriterion.class)) {
+ log.trace("Criteria did not contain entity ID, unable to build request URL");
+ return null;
+ }
+ String entityID = criteria.get(EntityIdCriterion.class).getEntityId();
log.debug("Saw input entityID '{}'", entityID);
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/resolver/index/impl/LockableMetadataIndexManager.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/resolver/index/impl/LockableMetadataIndexManager.java
new file mode 100644
index 0000000..891ee6e
--- /dev/null
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/resolver/index/impl/LockableMetadataIndexManager.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 org.opensaml.saml.metadata.resolver.index.impl;
+
+import java.util.Set;
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.opensaml.saml.metadata.resolver.index.MetadataIndex;
+import org.opensaml.saml.saml2.metadata.EntityDescriptor;
+
+import com.google.common.base.Function;
+
+import net.shibboleth.utilities.java.support.annotation.constraint.NonnullElements;
+import net.shibboleth.utilities.java.support.annotation.constraint.NotLive;
+import net.shibboleth.utilities.java.support.annotation.constraint.Unmodifiable;
+
+/**
+ * A specialization of {@link MetadataIndexManager} capable of read/write locking.
+ *
+ * @param <T> the type of data being indexed
+ */
+public class LockableMetadataIndexManager<T> extends MetadataIndexManager<T> {
+
+ /** The manager's read write lock. */
+ @Nonnull private final ReadWriteLock readWriteLock;
+
+ /**
+ * Constructor.
+ *
+ * @param initIndexes indexes for which to initialize storage
+ * @param extractionFunction function to extract the indexed data item from an EntityDescriptor
+ */
+ public LockableMetadataIndexManager(
+ @Nullable @NonnullElements @Unmodifiable @NotLive final Set<MetadataIndex> initIndexes,
+ @Nonnull final Function<EntityDescriptor, T> extractionFunction
+ ) {
+ super(initIndexes, extractionFunction);
+ readWriteLock = new ReentrantReadWriteLock(true);
+ }
+
+ /**
+ * Get the manager's instance of the {@link ReadWriteLock}.
+ *
+ * <p>
+ * Callers of the manager are responsible for explicitly locking (and unlocking)
+ * for reading and/or writing, based on application use cases.
+ * </p>
+ *
+ * @return Returns the rwlock.
+ */
+ @Nonnull public ReadWriteLock getReadWriteLock() {
+ return readWriteLock;
+ }
+
+
+}
diff --git a/opensaml-saml-impl/src/test/java/org/opensaml/saml/metadata/resolver/impl/AbstractDynamicHTTPMetadataResolverTest.java b/opensaml-saml-impl/src/test/java/org/opensaml/saml/metadata/resolver/impl/AbstractDynamicHTTPMetadataResolverTest.java
index 7fa79a5..62c0c45 100644
--- a/opensaml-saml-impl/src/test/java/org/opensaml/saml/metadata/resolver/impl/AbstractDynamicHTTPMetadataResolverTest.java
+++ b/opensaml-saml-impl/src/test/java/org/opensaml/saml/metadata/resolver/impl/AbstractDynamicHTTPMetadataResolverTest.java
@@ -85,9 +85,9 @@ public class AbstractDynamicHTTPMetadataResolverTest extends XMLObjectBaseTestCa
// Test uses MDQ protocol
String baseURL = "http://shibboleth.net:9000";
String entityID = "https://foo1.example.org/idp/shibboleth";
- String requestURL = new MetadataQueryProtocolRequestURLBuilder(baseURL).apply(entityID);
+ String requestURL = new MetadataQueryProtocolRequestURLBuilder(baseURL).apply(new CriteriaSet(new EntityIdCriterion(entityID)));
- CriteriaSet criteriaSet = new CriteriaSet(new EntityIdCriterion(entityID), new RequestURLCriterion(requestURL));
+ CriteriaSet criteriaSet = new CriteriaSet(new RequestURLCriterion(requestURL));
EntityDescriptor ed = resolver.resolveSingle(criteriaSet);
Assert.assertNotNull(ed);
diff --git a/opensaml-saml-impl/src/test/java/org/opensaml/saml/metadata/resolver/impl/AbstractDynamicMetadataResolverTest.java b/opensaml-saml-impl/src/test/java/org/opensaml/saml/metadata/resolver/impl/AbstractDynamicMetadataResolverTest.java
index a290657..f310ad8 100644
--- a/opensaml-saml-impl/src/test/java/org/opensaml/saml/metadata/resolver/impl/AbstractDynamicMetadataResolverTest.java
+++ b/opensaml-saml-impl/src/test/java/org/opensaml/saml/metadata/resolver/impl/AbstractDynamicMetadataResolverTest.java
@@ -23,7 +23,9 @@ import java.security.KeyPair;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.Map;
+import java.util.Set;
import java.util.Timer;
import org.opensaml.core.criterion.EntityIdCriterion;
@@ -34,9 +36,19 @@ import org.opensaml.core.xml.io.MarshallingException;
import org.opensaml.core.xml.persist.MapLoadSaveManager;
import org.opensaml.core.xml.persist.XMLObjectLoadSaveManager;
import org.opensaml.core.xml.util.XMLObjectSupport;
+import org.opensaml.saml.criterion.EntityRoleCriterion;
import org.opensaml.saml.metadata.resolver.filter.impl.SignatureValidationFilter;
import org.opensaml.saml.metadata.resolver.impl.AbstractDynamicMetadataResolver.DynamicEntityBackingStore;
+import org.opensaml.saml.metadata.resolver.index.MetadataIndex;
+import org.opensaml.saml.metadata.resolver.index.impl.FunctionDrivenMetadataIndex;
+import org.opensaml.saml.metadata.resolver.index.impl.RoleMetadataIndex;
+import org.opensaml.saml.metadata.resolver.index.impl.SimpleStringCriteriaFunction;
+import org.opensaml.saml.metadata.resolver.index.impl.SimpleStringCriterion;
+import org.opensaml.saml.metadata.resolver.index.impl.UppercaseEntityIdDescriptorFunction;
import org.opensaml.saml.saml2.metadata.EntityDescriptor;
+import org.opensaml.saml.saml2.metadata.IDPSSODescriptor;
+import org.opensaml.saml.saml2.metadata.RoleDescriptor;
+import org.opensaml.saml.saml2.metadata.SPSSODescriptor;
import org.opensaml.security.SecurityException;
import org.opensaml.security.credential.Credential;
import org.opensaml.security.credential.CredentialSupport;
@@ -58,8 +70,11 @@ import org.testng.annotations.Test;
import com.google.common.base.Function;
import com.google.common.base.Objects;
+import com.google.common.base.Optional;
import com.google.common.base.Predicate;
+import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
import net.shibboleth.utilities.java.support.resolver.CriteriaSet;
@@ -109,6 +124,7 @@ public class AbstractDynamicMetadataResolverTest extends XMLObjectBaseTestCase {
id1 = "urn:test:entity:1";
ed1 = buildXMLObject(EntityDescriptor.DEFAULT_ELEMENT_NAME);
ed1.setEntityID(id1);
+ ed1.getRoleDescriptors().add((RoleDescriptor) buildXMLObject(SPSSODescriptor.DEFAULT_ELEMENT_NAME));
SignatureSupport.signObject(ed1, signingParams);
Assert.assertTrue(ed1.isSigned());
baos = new ByteArrayOutputStream();
@@ -120,6 +136,7 @@ public class AbstractDynamicMetadataResolverTest extends XMLObjectBaseTestCase {
id2 = "urn:test:entity:2";
ed2 = buildXMLObject(EntityDescriptor.DEFAULT_ELEMENT_NAME);
ed2.setEntityID(id2);
+ ed2.getRoleDescriptors().add((RoleDescriptor) buildXMLObject(SPSSODescriptor.DEFAULT_ELEMENT_NAME));
SignatureSupport.signObject(ed2, signingParams);
Assert.assertTrue(ed2.isSigned());
baos = new ByteArrayOutputStream();
@@ -131,6 +148,7 @@ public class AbstractDynamicMetadataResolverTest extends XMLObjectBaseTestCase {
id3 = "urn:test:entity:3";
ed3 = buildXMLObject(EntityDescriptor.DEFAULT_ELEMENT_NAME);
ed3.setEntityID(id3);
+ ed3.getRoleDescriptors().add((RoleDescriptor) buildXMLObject(IDPSSODescriptor.DEFAULT_ELEMENT_NAME));
SignatureSupport.signObject(ed3, signingParams);
Assert.assertTrue(ed3.isSigned());
baos = new ByteArrayOutputStream();
@@ -178,9 +196,9 @@ public class AbstractDynamicMetadataResolverTest extends XMLObjectBaseTestCase {
resolver.initialize();
- Assert.assertNotNull(resolver.resolveSingle(new CriteriaSet(new EntityIdCriterion(id1))));
- Assert.assertNotNull(resolver.resolveSingle(new CriteriaSet(new EntityIdCriterion(id2))));
- Assert.assertNotNull(resolver.resolveSingle(new CriteriaSet(new EntityIdCriterion(id3))));
+ Assert.assertSame(resolver.resolveSingle(new CriteriaSet(new EntityIdCriterion(id1))), ed1);
+ Assert.assertSame(resolver.resolveSingle(new CriteriaSet(new EntityIdCriterion(id2))), ed2);
+ Assert.assertSame(resolver.resolveSingle(new CriteriaSet(new EntityIdCriterion(id3))), ed3);
DynamicEntityBackingStore backingStore = resolver.getBackingStore();
@@ -202,9 +220,9 @@ public class AbstractDynamicMetadataResolverTest extends XMLObjectBaseTestCase {
resolver.initialize();
- Assert.assertNotNull(resolver.resolveSingle(new CriteriaSet(new EntityIdCriterion(id1))));
- Assert.assertNotNull(resolver.resolveSingle(new CriteriaSet(new EntityIdCriterion(id2))));
- Assert.assertNotNull(resolver.resolveSingle(new CriteriaSet(new EntityIdCriterion(id3))));
+ Assert.assertSame(resolver.resolveSingle(new CriteriaSet(new EntityIdCriterion(id1))), ed1);
+ Assert.assertSame(resolver.resolveSingle(new CriteriaSet(new EntityIdCriterion(id2))), ed2);
+ Assert.assertSame(resolver.resolveSingle(new CriteriaSet(new EntityIdCriterion(id3))), ed3);
DynamicEntityBackingStore backingStore = resolver.getBackingStore();
@@ -214,9 +232,9 @@ public class AbstractDynamicMetadataResolverTest extends XMLObjectBaseTestCase {
Assert.assertFalse(backingStore.getIndexedDescriptors().containsKey(id2));
Assert.assertFalse(backingStore.getIndexedDescriptors().containsKey(id3));
- Assert.assertNotNull(resolver.resolveSingle(new CriteriaSet(new EntityIdCriterion(id1))));
- Assert.assertNotNull(resolver.resolveSingle(new CriteriaSet(new EntityIdCriterion(id2))));
- Assert.assertNotNull(resolver.resolveSingle(new CriteriaSet(new EntityIdCriterion(id3))));
+ Assert.assertSame(resolver.resolveSingle(new CriteriaSet(new EntityIdCriterion(id1))), ed1);
+ Assert.assertSame(resolver.resolveSingle(new CriteriaSet(new EntityIdCriterion(id2))), ed2);
+ Assert.assertSame(resolver.resolveSingle(new CriteriaSet(new EntityIdCriterion(id3))), ed3);
}
@Test
@@ -227,9 +245,9 @@ public class AbstractDynamicMetadataResolverTest extends XMLObjectBaseTestCase {
resolver.initialize();
- Assert.assertNotNull(resolver.resolveSingle(new CriteriaSet(new EntityIdCriterion(id1))));
- Assert.assertNotNull(resolver.resolveSingle(new CriteriaSet(new EntityIdCriterion(id2))));
- Assert.assertNotNull(resolver.resolveSingle(new CriteriaSet(new EntityIdCriterion(id3))));
+ Assert.assertSame(resolver.resolveSingle(new CriteriaSet(new EntityIdCriterion(id1))), ed1);
+ Assert.assertSame(resolver.resolveSingle(new CriteriaSet(new EntityIdCriterion(id2))), ed2);
+ Assert.assertSame(resolver.resolveSingle(new CriteriaSet(new EntityIdCriterion(id3))), ed3);
DynamicEntityBackingStore backingStore = resolver.getBackingStore();
@@ -240,9 +258,9 @@ public class AbstractDynamicMetadataResolverTest extends XMLObjectBaseTestCase {
Assert.assertFalse(backingStore.getIndexedDescriptors().containsKey(id2));
Assert.assertTrue(backingStore.getIndexedDescriptors().containsKey(id3));
- Assert.assertNotNull(resolver.resolveSingle(new CriteriaSet(new EntityIdCriterion(id1))));
- Assert.assertNotNull(resolver.resolveSingle(new CriteriaSet(new EntityIdCriterion(id2))));
- Assert.assertNotNull(resolver.resolveSingle(new CriteriaSet(new EntityIdCriterion(id3))));
+ Assert.assertSame(resolver.resolveSingle(new CriteriaSet(new EntityIdCriterion(id1))), ed1);
+ Assert.assertSame(resolver.resolveSingle(new CriteriaSet(new EntityIdCriterion(id2))), ed2);
+ Assert.assertSame(resolver.resolveSingle(new CriteriaSet(new EntityIdCriterion(id3))), ed3);
}
@Test
@@ -269,7 +287,7 @@ public class AbstractDynamicMetadataResolverTest extends XMLObjectBaseTestCase {
Assert.assertEquals(persistentCacheMap.size(), 0);
- Assert.assertNotNull(resolver.resolveSingle(new CriteriaSet(new EntityIdCriterion(id1))));
+ Assert.assertSame(resolver.resolveSingle(new CriteriaSet(new EntityIdCriterion(id1))), ed1);
Assert.assertEquals(persistentCacheMap.size(), 1);
@@ -277,8 +295,44 @@ public class AbstractDynamicMetadataResolverTest extends XMLObjectBaseTestCase {
Assert.assertTrue(persistentCacheMap.containsKey(cacheKey));
Assert.assertSame(persistentCacheMap.get(cacheKey), ed1);
- Assert.assertNotNull(resolver.resolveSingle(new CriteriaSet(new EntityIdCriterion(id2))));
- Assert.assertNotNull(resolver.resolveSingle(new CriteriaSet(new EntityIdCriterion(id3))));
+ Assert.assertSame(resolver.resolveSingle(new CriteriaSet(new EntityIdCriterion(id2))), ed2);
+ Assert.assertSame(resolver.resolveSingle(new CriteriaSet(new EntityIdCriterion(id3))), ed2);
+
+ Assert.assertEquals(persistentCacheMap.size(), 3);
+
+ cacheKey = resolver.getPersistentCacheKeyGenerator().apply(ed2);
+ Assert.assertTrue(persistentCacheMap.containsKey(cacheKey));
+ Assert.assertSame(persistentCacheMap.get(cacheKey), ed2);
+
+ cacheKey = resolver.getPersistentCacheKeyGenerator().apply(ed3);
+ Assert.assertTrue(persistentCacheMap.containsKey(cacheKey));
+ Assert.assertSame(persistentCacheMap.get(cacheKey), ed3);
+
+ }
+
+ @Test
+ public void testWithPersistentCache() throws ComponentInitializationException, ResolverException {
+ sourceMap.put(id1, ed1);
+ sourceMap.put(id2, ed2);
+ sourceMap.put(id3, ed3);
+
+ resolver.setPersistentCacheManager(persistentCacheManager);
+ resolver.initialize();
+
+ Assert.assertTrue(resolver.isPersistentCachingEnabled());
+
+ Assert.assertEquals(persistentCacheMap.size(), 0);
+
+ Assert.assertSame(resolver.resolveSingle(new CriteriaSet(new EntityIdCriterion(id1))), ed1);
+
+ Assert.assertEquals(persistentCacheMap.size(), 1);
+
+ String cacheKey = resolver.getPersistentCacheKeyGenerator().apply(ed1);
+ Assert.assertTrue(persistentCacheMap.containsKey(cacheKey));
+ Assert.assertSame(persistentCacheMap.get(cacheKey), ed1);
+
+ Assert.assertSame(resolver.resolveSingle(new CriteriaSet(new EntityIdCriterion(id2))), ed2);
+ Assert.assertSame(resolver.resolveSingle(new CriteriaSet(new EntityIdCriterion(id3))), ed3);
Assert.assertEquals(persistentCacheMap.size(), 3);
@@ -307,6 +361,7 @@ public class AbstractDynamicMetadataResolverTest extends XMLObjectBaseTestCase {
Assert.assertEquals(persistentCacheMap.size(), 0);
Assert.assertNotNull(resolver.resolveSingle(new CriteriaSet(new EntityIdCriterion(id1))));
+ Assert.assertEquals(resolver.resolveSingle(new CriteriaSet(new EntityIdCriterion(id1))).getEntityID(), id1);
Assert.assertEquals(persistentCacheMap.size(), 1);
@@ -315,7 +370,9 @@ public class AbstractDynamicMetadataResolverTest extends XMLObjectBaseTestCase {
Assert.assertSame(persistentCacheMap.get(cacheKey), ed1);
Assert.assertNotNull(resolver.resolveSingle(new CriteriaSet(new EntityIdCriterion(id2))));
+ Assert.assertEquals(resolver.resolveSingle(new CriteriaSet(new EntityIdCriterion(id2))).getEntityID(), id2);
Assert.assertNotNull(resolver.resolveSingle(new CriteriaSet(new EntityIdCriterion(id3))));
+ Assert.assertEquals(resolver.resolveSingle(new CriteriaSet(new EntityIdCriterion(id3))).getEntityID(), id3);
Assert.assertEquals(persistentCacheMap.size(), 3);
@@ -359,6 +416,7 @@ public class AbstractDynamicMetadataResolverTest extends XMLObjectBaseTestCase {
for (String entityID : Lists.newArrayList(id1, id2, id3)) {
EntityDescriptor ed = resolver.resolveSingle(new CriteriaSet(new EntityIdCriterion(entityID)));
Assert.assertNotNull(ed);
+ Assert.assertEquals(ed.getEntityID(), entityID);
Assert.assertNull(ed.getDOM());
}
}
@@ -399,7 +457,7 @@ public class AbstractDynamicMetadataResolverTest extends XMLObjectBaseTestCase {
Assert.assertTrue(sourceMap.isEmpty());
- Assert.assertNotNull(resolver.resolveSingle(new CriteriaSet(new EntityIdCriterion(id1))));
+ Assert.assertSame(resolver.resolveSingle(new CriteriaSet(new EntityIdCriterion(id1))), ed1);
Assert.assertNull(resolver.resolveSingle(new CriteriaSet(new EntityIdCriterion(id2))));
Assert.assertNull(resolver.resolveSingle(new CriteriaSet(new EntityIdCriterion(id3))));
}
@@ -440,9 +498,106 @@ public class AbstractDynamicMetadataResolverTest extends XMLObjectBaseTestCase {
Assert.assertEquals(backingStore.getIndexedDescriptors().get(id3).size(), 1);
Assert.assertTrue(sourceMap.isEmpty());
- Assert.assertNotNull(resolver.resolveSingle(new CriteriaSet(new EntityIdCriterion(id1))));
- Assert.assertNotNull(resolver.resolveSingle(new CriteriaSet(new EntityIdCriterion(id2))));
- Assert.assertNotNull(resolver.resolveSingle(new CriteriaSet(new EntityIdCriterion(id3))));
+ Assert.assertSame(resolver.resolveSingle(new CriteriaSet(new EntityIdCriterion(id1))), ed1);
+ Assert.assertSame(resolver.resolveSingle(new CriteriaSet(new EntityIdCriterion(id2))), ed2);
+ Assert.assertSame(resolver.resolveSingle(new CriteriaSet(new EntityIdCriterion(id3))), ed3);
+ }
+
+ @Test
+ public void testSecondaryIndexAfterEntityIDResolution() throws ComponentInitializationException, ResolverException {
+ sourceMap.put(id1, ed1);
+
+ HashSet<MetadataIndex> indexes = new HashSet<>();
+ indexes.add(new FunctionDrivenMetadataIndex(new UppercaseEntityIdDescriptorFunction(), new SimpleStringCriteriaFunction()));
+ resolver.setIndexes(indexes);
+
+ resolver.initialize();
+
+ DynamicEntityBackingStore backingStore = resolver.getBackingStore();
+ Optional<Set<String>> indexedData = null;
+
+ Assert.assertNull(resolver.resolveSingle(new CriteriaSet(new SimpleStringCriterion(id1.toUpperCase()))));
+
+ Assert.assertSame(resolver.resolveSingle(new CriteriaSet(new EntityIdCriterion(id1))), ed1);
+
+ indexedData = backingStore.getSecondaryIndexManager().lookupIndexedItems(new CriteriaSet(new SimpleStringCriterion(id1.toUpperCase())));
+ Assert.assertTrue(indexedData.isPresent());
+ Assert.assertEquals(indexedData.get(), Sets.newHashSet(id1));
+
+ Assert.assertSame(resolver.resolveSingle(new CriteriaSet(new SimpleStringCriterion(id1.toUpperCase()))), ed1);
+ }
+
+ @Test
+ public void testSecondaryIndexAfterEntityIDResolutionMultipleResults() throws ComponentInitializationException, ResolverException {
+ sourceMap.put(id1, ed1);
+ sourceMap.put(id2, ed2);
+ sourceMap.put(id3, ed3);
+
+ HashSet<MetadataIndex> indexes = new HashSet<>();
+ indexes.add(new RoleMetadataIndex());
+ resolver.setIndexes(indexes);
+
+ resolver.initialize();
+
+ DynamicEntityBackingStore backingStore = resolver.getBackingStore();
+ Optional<Set<String>> indexedData = null;
+
+ Set<EntityDescriptor> results = new HashSet<>();
+
+ results.clear();
+ Iterables.addAll(results, resolver.resolve(new CriteriaSet(new EntityRoleCriterion(SPSSODescriptor.DEFAULT_ELEMENT_NAME))));
+ Assert.assertEquals(results.size(), 0);
+
+ Assert.assertSame(resolver.resolveSingle(new CriteriaSet(new EntityIdCriterion(id1))), ed1);
+
+ indexedData = backingStore.getSecondaryIndexManager().lookupIndexedItems(new CriteriaSet(new EntityRoleCriterion(SPSSODescriptor.DEFAULT_ELEMENT_NAME)));
+ Assert.assertTrue(indexedData.isPresent());
+ Assert.assertEquals(indexedData.get(), Sets.newHashSet(id1));
+
+ results.clear();
+ Iterables.addAll(results, resolver.resolve(new CriteriaSet(new EntityRoleCriterion(SPSSODescriptor.DEFAULT_ELEMENT_NAME))));
+ Assert.assertEquals(results.size(), 1);
+ Assert.assertEquals(results, Sets.newHashSet(ed1));
+
+ Assert.assertSame(resolver.resolveSingle(new CriteriaSet(new EntityIdCriterion(id2))), ed2);
+ Assert.assertSame(resolver.resolveSingle(new CriteriaSet(new EntityIdCriterion(id3))), ed3);
+
+ indexedData = backingStore.getSecondaryIndexManager().lookupIndexedItems(new CriteriaSet(new EntityRoleCriterion(SPSSODescriptor.DEFAULT_ELEMENT_NAME)));
+ Assert.assertTrue(indexedData.isPresent());
+ Assert.assertEquals(indexedData.get(), Sets.newHashSet(id1, id2));
+
+ results.clear();
+ Iterables.addAll(results, resolver.resolve(new CriteriaSet(new EntityRoleCriterion(SPSSODescriptor.DEFAULT_ELEMENT_NAME))));
+ Assert.assertEquals(results.size(), 2);
+ Assert.assertEquals(results, Sets.newHashSet(ed1, ed2));
+ }
+
+ @Test
+ public void testSecondaryLookupThenEntityID() throws ComponentInitializationException, ResolverException {
+ sourceMap.put(id1.toUpperCase(), ed1);
+
+ resolver.setSecondaryLookup(true);
+
+ HashSet<MetadataIndex> indexes = new HashSet<>();
+ indexes.add(new FunctionDrivenMetadataIndex(new UppercaseEntityIdDescriptorFunction(), new SimpleStringCriteriaFunction()));
+ resolver.setIndexes(indexes);
+
+ resolver.initialize();
+
+ DynamicEntityBackingStore backingStore = resolver.getBackingStore();
+ Optional<Set<String>> indexedData = null;
+
+ Assert.assertNull(resolver.resolveSingle(new CriteriaSet(new EntityIdCriterion(id1))));
+
+ Assert.assertSame(resolver.resolveSingle(new CriteriaSet(new SimpleStringCriterion(id1.toUpperCase()))), ed1);
+
+ backingStore.getIndexedDescriptors().containsKey(id1);
+
+ indexedData = backingStore.getSecondaryIndexManager().lookupIndexedItems(new CriteriaSet(new SimpleStringCriterion(id1.toUpperCase())));
+ Assert.assertTrue(indexedData.isPresent());
+ Assert.assertEquals(indexedData.get(), Sets.newHashSet(id1));
+
+ Assert.assertSame(resolver.resolveSingle(new CriteriaSet(new EntityIdCriterion(id1))), ed1);
}
// Helper classes
@@ -450,25 +605,32 @@ public class AbstractDynamicMetadataResolverTest extends XMLObjectBaseTestCase {
private static class MockDynamicResolver extends AbstractDynamicMetadataResolver {
private Map<String,EntityDescriptor> originSourceMap;
+
+ private boolean secondaryLookup;
public MockDynamicResolver(Map<String, EntityDescriptor> map) {
this(map, null);
}
+ public void setSecondaryLookup(boolean flag) {
+ secondaryLookup = flag;
+ }
+
public MockDynamicResolver(Map<String, EntityDescriptor> map, Timer backgroundTaskTimer) {
super(backgroundTaskTimer);
originSourceMap = map;
}
protected XMLObject fetchFromOriginSource(CriteriaSet criteria) throws IOException {
- EntityIdCriterion entityIdCriterion = criteria.get(EntityIdCriterion.class);
- if (entityIdCriterion != null) {
- return originSourceMap.get(entityIdCriterion.getEntityId());
+ if (criteria.contains(EntityIdCriterion.class)) {
+ return originSourceMap.get(criteria.get(EntityIdCriterion.class).getEntityId());
+ } else if (secondaryLookup && criteria.contains(SimpleStringCriterion.class)) {
+ return originSourceMap.get(criteria.get(SimpleStringCriterion.class).getValue());
} else {
return null;
}
}
-
+
}
}
diff --git a/opensaml-saml-impl/src/test/java/org/opensaml/saml/metadata/resolver/impl/DefaultLocalDynamicSourceKeyGeneratorTest.java b/opensaml-saml-impl/src/test/java/org/opensaml/saml/metadata/resolver/impl/DefaultLocalDynamicSourceKeyGeneratorTest.java
new file mode 100644
index 0000000..6b98c42
--- /dev/null
+++ b/opensaml-saml-impl/src/test/java/org/opensaml/saml/metadata/resolver/impl/DefaultLocalDynamicSourceKeyGeneratorTest.java
@@ -0,0 +1,126 @@
+/*
+ * 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 org.opensaml.saml.metadata.resolver.impl;
+
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+
+import org.opensaml.core.criterion.EntityIdCriterion;
+import org.opensaml.saml.common.binding.artifact.SAMLSourceIDArtifact;
+import org.opensaml.saml.common.binding.artifact.SAMLSourceLocationArtifact;
+import org.opensaml.saml.criterion.ArtifactCriterion;
+import org.opensaml.saml.metadata.resolver.index.impl.SimpleStringCriterion;
+import org.opensaml.saml.saml1.binding.artifact.SAML1ArtifactType0002;
+import org.opensaml.saml.saml2.binding.artifact.SAML2ArtifactType0004;
+import org.testng.Assert;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import com.google.common.io.BaseEncoding;
+
+import net.shibboleth.utilities.java.support.resolver.CriteriaSet;
+
+/**
+ *
+ */
+public class DefaultLocalDynamicSourceKeyGeneratorTest {
+
+ private String controlValue;
+
+ private String controlValueSHA1Hex;
+ private byte[] controlValueSHA1Bytes;
+
+ private SAMLSourceIDArtifact sourceIDArtifact;
+ private SAMLSourceLocationArtifact sourceLocationArtifact;
+
+ private CriteriaSet criteria;
+
+ private DefaultLocalDynamicSourceKeyGenerator generator;
+
+ @BeforeMethod
+ public void setUp() throws NoSuchAlgorithmException {
+ controlValue = "urn:test:foobar";
+ controlValueSHA1Hex = "d278c9975472a6b4827b1a8723192b4e99aa969c";
+ controlValueSHA1Bytes = BaseEncoding.base16().lowerCase().decode(controlValueSHA1Hex);
+ criteria = new CriteriaSet();
+
+ SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
+ byte[] messageHandle = new byte[20];
+ secureRandom.nextBytes(messageHandle);
+ sourceIDArtifact = new SAML2ArtifactType0004(new byte[] {0, 0} , controlValueSHA1Bytes, messageHandle);
+ sourceLocationArtifact = new SAML1ArtifactType0002(messageHandle, "https://test.foobar.com/artifactk");
+ }
+
+ @Test
+ public void testEntityIdCriterion() throws NoSuchAlgorithmException {
+ generator = new DefaultLocalDynamicSourceKeyGenerator();
+
+ Assert.assertNull(generator.apply(null));
+
+ criteria.clear();
+ Assert.assertNull(generator.apply(criteria));
+
+ criteria.add(new EntityIdCriterion(controlValue));
+
+ Assert.assertEquals(controlValueSHA1Hex, generator.apply(criteria));
+
+ generator = new DefaultLocalDynamicSourceKeyGenerator("metadata-", ".xml", null);
+
+ Assert.assertEquals("metadata-" + controlValueSHA1Hex + ".xml", generator.apply(criteria));
+
+ generator = new DefaultLocalDynamicSourceKeyGenerator("metadata", "xml", ".");
+
+ Assert.assertEquals("metadata." + controlValueSHA1Hex + ".xml", generator.apply(criteria));
+ }
+
+ @Test
+ public void testArtifactCriterion() throws NoSuchAlgorithmException {
+ generator = new DefaultLocalDynamicSourceKeyGenerator();
+
+ Assert.assertNull(generator.apply(null));
+
+ criteria.clear();
+ Assert.assertNull(generator.apply(criteria));
+
+ criteria.add(new ArtifactCriterion(sourceIDArtifact));
+
+ Assert.assertEquals(controlValueSHA1Hex, generator.apply(criteria));
+
+ generator = new DefaultLocalDynamicSourceKeyGenerator("metadata-", ".xml", null);
+
+ Assert.assertEquals("metadata-" + controlValueSHA1Hex + ".xml", generator.apply(criteria));
+
+ generator = new DefaultLocalDynamicSourceKeyGenerator("metadata", "xml", ".");
+
+ Assert.assertEquals("metadata." + controlValueSHA1Hex + ".xml", generator.apply(criteria));
+
+ // Source location artifact is not supported
+ criteria.clear();
+ criteria.add(new ArtifactCriterion(sourceLocationArtifact));
+ Assert.assertNull(generator.apply(criteria));
+ }
+
+ @Test
+ public void testUnsupportedCriterion() {
+ generator = new DefaultLocalDynamicSourceKeyGenerator();
+
+ criteria.add(new SimpleStringCriterion("foobar"));
+ Assert.assertNull(generator.apply(criteria));
+ }
+
+}
diff --git a/opensaml-saml-impl/src/test/java/org/opensaml/saml/metadata/resolver/impl/FunctionDrivenDynamicHTTPMetadataResolverTest.java b/opensaml-saml-impl/src/test/java/org/opensaml/saml/metadata/resolver/impl/FunctionDrivenDynamicHTTPMetadataResolverTest.java
index db3accb..5660753 100644
--- a/opensaml-saml-impl/src/test/java/org/opensaml/saml/metadata/resolver/impl/FunctionDrivenDynamicHTTPMetadataResolverTest.java
+++ b/opensaml-saml-impl/src/test/java/org/opensaml/saml/metadata/resolver/impl/FunctionDrivenDynamicHTTPMetadataResolverTest.java
@@ -19,6 +19,8 @@ package org.opensaml.saml.metadata.resolver.impl;
import java.io.File;
import java.net.URISyntaxException;
+import java.security.MessageDigest;
+import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Arrays;
@@ -37,8 +39,14 @@ import org.apache.http.conn.socket.LayeredConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.opensaml.core.criterion.EntityIdCriterion;
import org.opensaml.core.xml.XMLObjectBaseTestCase;
+import org.opensaml.saml.common.binding.artifact.SAMLSourceIDArtifact;
+import org.opensaml.saml.criterion.ArtifactCriterion;
+import org.opensaml.saml.metadata.resolver.impl.MetadataQueryProtocolRequestURLBuilder.MetadataQueryProtocolURLBuilder;
+import org.opensaml.saml.metadata.resolver.impl.TemplateRequestURLBuilder.EncodingStyle;
+import org.opensaml.saml.saml2.binding.artifact.SAML2ArtifactType0004;
import org.opensaml.saml.saml2.metadata.EntityDescriptor;
import org.opensaml.security.credential.impl.StaticCredentialResolver;
+import org.opensaml.security.crypto.JCAConstants;
import org.opensaml.security.httpclient.impl.SecurityEnhancedTLSSocketFactory;
import org.opensaml.security.trust.TrustEngine;
import org.opensaml.security.trust.impl.ExplicitKeyTrustEngine;
@@ -56,6 +64,8 @@ import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
+import com.google.common.collect.Lists;
+
public class FunctionDrivenDynamicHTTPMetadataResolverTest extends XMLObjectBaseTestCase {
private static final String DATA_PATH = "/org/opensaml/saml/metadata/resolver/impl/";
@@ -86,7 +96,7 @@ public class FunctionDrivenDynamicHTTPMetadataResolverTest extends XMLObjectBase
TemplateRequestURLBuilder requestURLBuilder = new TemplateRequestURLBuilder(
VelocityEngine.newVelocityEngine(),
template,
- true,
+ EncodingStyle.path,
new StringDigester("SHA-1", OutputFormat.HEX_LOWER));
resolver = new FunctionDrivenDynamicHTTPMetadataResolver(httpClientBuilder.buildClient());
@@ -114,7 +124,7 @@ public class FunctionDrivenDynamicHTTPMetadataResolverTest extends XMLObjectBase
TemplateRequestURLBuilder requestURLBuilder = new TemplateRequestURLBuilder(
VelocityEngine.newVelocityEngine(),
template,
- true,
+ EncodingStyle.path,
new StringDigester("SHA-1", OutputFormat.HEX_LOWER));
resolver = new FunctionDrivenDynamicHTTPMetadataResolver(httpClientBuilder.buildClient());
@@ -143,7 +153,7 @@ public class FunctionDrivenDynamicHTTPMetadataResolverTest extends XMLObjectBase
TemplateRequestURLBuilder requestURLBuilder = new TemplateRequestURLBuilder(
VelocityEngine.newVelocityEngine(),
template,
- true,
+ EncodingStyle.path,
new StringDigester("SHA-1", OutputFormat.HEX_LOWER));
resolver = new FunctionDrivenDynamicHTTPMetadataResolver(httpClientBuilder.buildClient());
@@ -167,7 +177,7 @@ public class FunctionDrivenDynamicHTTPMetadataResolverTest extends XMLObjectBase
TemplateRequestURLBuilder requestURLBuilder = new TemplateRequestURLBuilder(
VelocityEngine.newVelocityEngine(),
template,
- true);
+ EncodingStyle.form);
resolver = new FunctionDrivenDynamicHTTPMetadataResolver(httpClientBuilder.buildClient());
resolver.setId("myDynamicResolver");
@@ -190,7 +200,7 @@ public class FunctionDrivenDynamicHTTPMetadataResolverTest extends XMLObjectBase
TemplateRequestURLBuilder requestURLBuilder = new TemplateRequestURLBuilder(
VelocityEngine.newVelocityEngine(),
template,
- true);
+ EncodingStyle.form);
resolver = new FunctionDrivenDynamicHTTPMetadataResolver(httpClientBuilder.buildClient());
resolver.setId("myDynamicResolver");
@@ -247,6 +257,35 @@ public class FunctionDrivenDynamicHTTPMetadataResolverTest extends XMLObjectBase
}
@Test
+ public void testMDQViaArtifact() throws Exception {
+ String baseURL = "http://shibboleth.net:9000";
+ String entityID = "https://foo1.example.org/idp/shibboleth";
+
+ MetadataQueryProtocolRequestURLBuilder requestURLBuilder = new MetadataQueryProtocolRequestURLBuilder(baseURL,
+ Lists.<MetadataQueryProtocolURLBuilder>newArrayList(new SAMLArtifactURLBuilder()));
+
+ resolver = new FunctionDrivenDynamicHTTPMetadataResolver(httpClientBuilder.buildClient());
+ resolver.setId("myDynamicResolver");
+ resolver.setParserPool(parserPool);
+ resolver.setRequestURLBuilder(requestURLBuilder);
+ resolver.initialize();
+
+ MessageDigest sha1Digester = MessageDigest.getInstance(JCAConstants.DIGEST_SHA1);
+ byte[] entityIDSourceID = sha1Digester.digest(entityID.getBytes("UTF-8"));
+ SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
+ byte[] messageHandle = new byte[20];
+ secureRandom.nextBytes(messageHandle);
+ SAMLSourceIDArtifact sourceIDArtifact = new SAML2ArtifactType0004(new byte[] {0, 0} , entityIDSourceID, messageHandle);
+
+ final CriteriaSet criteriaSet = new CriteriaSet( new ArtifactCriterion(sourceIDArtifact));
+
+ EntityDescriptor ed = resolver.resolveSingle(criteriaSet);
+ Assert.assertNotNull(ed);
+ Assert.assertEquals(ed.getEntityID(), entityID);
+ Assert.assertNull(ed.getDOM());
+ }
+
+ @Test
public void testTrustEngineSocketFactoryNoHTTPSNoTrustEngine() throws Exception {
String template = RepositorySupport.buildHTTPSResourceURL("java-opensaml", "opensaml-saml-impl/src/test/resources/org/opensaml/saml/metadata/resolver/impl/${entityID}.xml");
String entityID = "https://www.example.org/sp";
@@ -255,7 +294,7 @@ public class FunctionDrivenDynamicHTTPMetadataResolverTest extends XMLObjectBase
TemplateRequestURLBuilder requestURLBuilder = new TemplateRequestURLBuilder(
VelocityEngine.newVelocityEngine(),
template,
- true,
+ EncodingStyle.path,
new StringDigester("SHA-1", OutputFormat.HEX_LOWER));
httpClientBuilder.setTLSSocketFactory(buildTrustEngineSocketFactory(false));
@@ -283,7 +322,7 @@ public class FunctionDrivenDynamicHTTPMetadataResolverTest extends XMLObjectBase
TemplateRequestURLBuilder requestURLBuilder = new TemplateRequestURLBuilder(
VelocityEngine.newVelocityEngine(),
template,
- true,
+ EncodingStyle.path,
new StringDigester("SHA-1", OutputFormat.HEX_LOWER));
httpClientBuilder.setTLSSocketFactory(buildTrustEngineSocketFactory());
@@ -312,7 +351,7 @@ public class FunctionDrivenDynamicHTTPMetadataResolverTest extends XMLObjectBase
TemplateRequestURLBuilder requestURLBuilder = new TemplateRequestURLBuilder(
VelocityEngine.newVelocityEngine(),
template,
- true,
+ EncodingStyle.path,
new StringDigester("SHA-1", OutputFormat.HEX_LOWER));
httpClientBuilder.setTLSSocketFactory(buildTrustEngineSocketFactory(false));
@@ -340,7 +379,7 @@ public class FunctionDrivenDynamicHTTPMetadataResolverTest extends XMLObjectBase
TemplateRequestURLBuilder requestURLBuilder = new TemplateRequestURLBuilder(
VelocityEngine.newVelocityEngine(),
template,
- true,
+ EncodingStyle.path,
new StringDigester("SHA-1", OutputFormat.HEX_LOWER));
httpClientBuilder.setTLSSocketFactory(buildTrustEngineSocketFactory());
@@ -369,7 +408,7 @@ public class FunctionDrivenDynamicHTTPMetadataResolverTest extends XMLObjectBase
TemplateRequestURLBuilder requestURLBuilder = new TemplateRequestURLBuilder(
VelocityEngine.newVelocityEngine(),
template,
- true,
+ EncodingStyle.path,
new StringDigester("SHA-1", OutputFormat.HEX_LOWER));
httpClientBuilder.setTLSSocketFactory(buildTrustEngineSocketFactory());
@@ -396,7 +435,7 @@ public class FunctionDrivenDynamicHTTPMetadataResolverTest extends XMLObjectBase
TemplateRequestURLBuilder requestURLBuilder = new TemplateRequestURLBuilder(
VelocityEngine.newVelocityEngine(),
template,
- true,
+ EncodingStyle.path,
new StringDigester("SHA-1", OutputFormat.HEX_LOWER));
httpClientBuilder.setTLSSocketFactory(buildTrustEngineSocketFactory());
@@ -425,7 +464,7 @@ public class FunctionDrivenDynamicHTTPMetadataResolverTest extends XMLObjectBase
TemplateRequestURLBuilder requestURLBuilder = new TemplateRequestURLBuilder(
VelocityEngine.newVelocityEngine(),
template,
- true,
+ EncodingStyle.path,
new StringDigester("SHA-1", OutputFormat.HEX_LOWER));
httpClientBuilder.setTLSSocketFactory(buildTrustEngineSocketFactory());
@@ -454,7 +493,7 @@ public class FunctionDrivenDynamicHTTPMetadataResolverTest extends XMLObjectBase
TemplateRequestURLBuilder requestURLBuilder = new TemplateRequestURLBuilder(
VelocityEngine.newVelocityEngine(),
template,
- true,
+ EncodingStyle.path,
new StringDigester("SHA-1", OutputFormat.HEX_LOWER));
httpClientBuilder.setTLSSocketFactory(buildTrustEngineSocketFactory());
@@ -481,7 +520,7 @@ public class FunctionDrivenDynamicHTTPMetadataResolverTest extends XMLObjectBase
TemplateRequestURLBuilder requestURLBuilder = new TemplateRequestURLBuilder(
VelocityEngine.newVelocityEngine(),
template,
- true,
+ EncodingStyle.path,
new StringDigester("SHA-1", OutputFormat.HEX_LOWER));
httpClientBuilder.setTLSSocketFactory(buildTrustEngineSocketFactory());
@@ -508,7 +547,7 @@ public class FunctionDrivenDynamicHTTPMetadataResolverTest extends XMLObjectBase
TemplateRequestURLBuilder requestURLBuilder = new TemplateRequestURLBuilder(
VelocityEngine.newVelocityEngine(),
template,
- true,
+ EncodingStyle.path,
new StringDigester("SHA-1", OutputFormat.HEX_LOWER));
// Trust engine set, but appropriate socket factory not set
diff --git a/opensaml-saml-impl/src/test/java/org/opensaml/saml/metadata/resolver/impl/HTTPEntityIDRequestURLBuilderTest.java b/opensaml-saml-impl/src/test/java/org/opensaml/saml/metadata/resolver/impl/HTTPEntityIDRequestURLBuilderTest.java
index 3f9eee4..73e2855 100644
--- a/opensaml-saml-impl/src/test/java/org/opensaml/saml/metadata/resolver/impl/HTTPEntityIDRequestURLBuilderTest.java
+++ b/opensaml-saml-impl/src/test/java/org/opensaml/saml/metadata/resolver/impl/HTTPEntityIDRequestURLBuilderTest.java
@@ -18,7 +18,9 @@
package org.opensaml.saml.metadata.resolver.impl;
import net.shibboleth.utilities.java.support.logic.ConstraintViolationException;
+import net.shibboleth.utilities.java.support.resolver.CriteriaSet;
+import org.opensaml.core.criterion.EntityIdCriterion;
import org.testng.Assert;
import org.testng.annotations.Test;
@@ -28,20 +30,20 @@ public class HTTPEntityIDRequestURLBuilderTest {
@Test
public void testHTTP() {
- Assert.assertEquals(function.apply("http://www.example.com/sp"), "http://www.example.com/sp");
- Assert.assertEquals(function.apply("https://www.example.com/sp"), "https://www.example.com/sp");
+ Assert.assertEquals(function.apply(new CriteriaSet(new EntityIdCriterion("http://www.example.com/sp"))), "http://www.example.com/sp");
+ Assert.assertEquals(function.apply(new CriteriaSet(new EntityIdCriterion("https://www.example.com/sp"))), "https://www.example.com/sp");
- Assert.assertEquals(function.apply("HTTP://www.example.com/sp"), "HTTP://www.example.com/sp");
- Assert.assertEquals(function.apply("HTTPS://www.example.com/sp"), "HTTPS://www.example.com/sp");
+ Assert.assertEquals(function.apply(new CriteriaSet(new EntityIdCriterion("HTTP://www.example.com/sp"))), "HTTP://www.example.com/sp");
+ Assert.assertEquals(function.apply(new CriteriaSet(new EntityIdCriterion("HTTPS://www.example.com/sp"))), "HTTPS://www.example.com/sp");
}
@Test
public void testNonHTTP() {
- Assert.assertNull(function.apply("urn:test:sp"));
- Assert.assertNull(function.apply("foo"));
- Assert.assertNull(function.apply("httpblah://not.a.url.com"));
- Assert.assertNull(function.apply(""));
+ Assert.assertNull(function.apply(new CriteriaSet(new EntityIdCriterion("urn:test:sp"))));
+ Assert.assertNull(function.apply(new CriteriaSet(new EntityIdCriterion("foo"))));
+ Assert.assertNull(function.apply(new CriteriaSet(new EntityIdCriterion("httpblah://not.a.url.com"))));
+ Assert.assertNull(function.apply(new CriteriaSet()));
}
@Test(expectedExceptions=ConstraintViolationException.class)
diff --git a/opensaml-saml-impl/src/test/java/org/opensaml/saml/metadata/resolver/impl/MetadataQueryProtocolRequestURLBuilderTest.java b/opensaml-saml-impl/src/test/java/org/opensaml/saml/metadata/resolver/impl/MetadataQueryProtocolRequestURLBuilderTest.java
index f4e0b2a..b099598 100644
--- a/opensaml-saml-impl/src/test/java/org/opensaml/saml/metadata/resolver/impl/MetadataQueryProtocolRequestURLBuilderTest.java
+++ b/opensaml-saml-impl/src/test/java/org/opensaml/saml/metadata/resolver/impl/MetadataQueryProtocolRequestURLBuilderTest.java
@@ -17,11 +17,17 @@
package org.opensaml.saml.metadata.resolver.impl;
-import net.shibboleth.utilities.java.support.logic.ConstraintViolationException;
-
+import org.opensaml.core.criterion.EntityIdCriterion;
+import org.opensaml.saml.metadata.resolver.impl.MetadataQueryProtocolRequestURLBuilder.MetadataQueryProtocolURLBuilder;
+import org.opensaml.saml.metadata.resolver.index.impl.SimpleStringCriterion;
import org.testng.Assert;
import org.testng.annotations.Test;
+import com.google.common.collect.Lists;
+
+import net.shibboleth.utilities.java.support.logic.ConstraintViolationException;
+import net.shibboleth.utilities.java.support.resolver.CriteriaSet;
+
public class MetadataQueryProtocolRequestURLBuilderTest {
private MetadataQueryProtocolRequestURLBuilder function;
@@ -30,29 +36,60 @@ public class MetadataQueryProtocolRequestURLBuilderTest {
public void testWithoutTrailingSlash() {
function = new MetadataQueryProtocolRequestURLBuilder("http://metadata.example.org/service");
- Assert.assertEquals(function.apply("http://example.org/idp"), "http://metadata.example.org/service/entities/http:%2F%2Fexample.org%2Fidp");
+ Assert.assertEquals(function.apply(new CriteriaSet(new EntityIdCriterion("http://example.org/idp"))), "http://metadata.example.org/service/entities/http:%2F%2Fexample.org%2Fidp");
}
@Test
public void testWithTrailingSlash() {
function = new MetadataQueryProtocolRequestURLBuilder("http://metadata.example.org/service/");
- Assert.assertEquals(function.apply("http://example.org/idp"), "http://metadata.example.org/service/entities/http:%2F%2Fexample.org%2Fidp");
- }
-
- @Test
- public void testWithSHA1Transformer() {
- function = new MetadataQueryProtocolRequestURLBuilder("http://metadata.example.org/service/",
- new MetadataQueryProtocolSHA1Transformer());
-
- Assert.assertEquals(function.apply("http://example.org/service"), "http://metadata.example.org/service/entities/%7Bsha1%7D11d72e8cf351eb6c75c721e838f469677ab41bdb");
+ Assert.assertEquals(function.apply(new CriteriaSet(new EntityIdCriterion("http://example.org/idp"))), "http://metadata.example.org/service/entities/http:%2F%2Fexample.org%2Fidp");
}
@Test(expectedExceptions=ConstraintViolationException.class)
- public void testNullEntityID() {
+ public void testNullCriteria() {
function = new MetadataQueryProtocolRequestURLBuilder("http://metadata.example.org/service/");
function.apply(null);
}
+ @Test
+ public void testSecondaryURLBuilders() {
+ MetadataQueryProtocolURLBuilder foo = new MockURLBuilder("tags/foo");
+ MetadataQueryProtocolURLBuilder bar = new MockURLBuilder("tags/bar");
+ MetadataQueryProtocolURLBuilder noValue = new MockURLBuilder(null);
+
+ function = new MetadataQueryProtocolRequestURLBuilder("http://metadata.example.org/service", Lists.newArrayList(foo,bar));
+ Assert.assertEquals(function.apply(new CriteriaSet(new SimpleStringCriterion("will-be-ignored"))), "http://metadata.example.org/service/tags/foo");
+
+ function = new MetadataQueryProtocolRequestURLBuilder("http://metadata.example.org/service", Lists.newArrayList(bar,foo));
+ Assert.assertEquals(function.apply(new CriteriaSet(new SimpleStringCriterion("will-be-ignored"))), "http://metadata.example.org/service/tags/bar");
+
+ function = new MetadataQueryProtocolRequestURLBuilder("http://metadata.example.org/service", Lists.newArrayList(null, null, foo, bar));
+ Assert.assertEquals(function.apply(new CriteriaSet(new SimpleStringCriterion("will-be-ignored"))), "http://metadata.example.org/service/tags/foo");
+
+ function = new MetadataQueryProtocolRequestURLBuilder("http://metadata.example.org/service", Lists.newArrayList(noValue, foo, bar));
+ Assert.assertEquals(function.apply(new CriteriaSet(new SimpleStringCriterion("will-be-ignored"))), "http://metadata.example.org/service/tags/foo");
+ }
+
+ // Test helpers
+
+ public static class MockURLBuilder implements MetadataQueryProtocolURLBuilder {
+
+ private String suffix;
+
+ public MockURLBuilder(String suffix) {
+ this.suffix = suffix;
+ }
+
+ /** {@inheritDoc} */
+ public String buildURL(String baseURL, CriteriaSet criteria) {
+ if (suffix == null) {
+ return null;
+ } else {
+ return baseURL + suffix;
+ }
+ }
+
+ }
}
diff --git a/opensaml-saml-impl/src/test/java/org/opensaml/saml/metadata/resolver/impl/MetadataQueryProtocolSHA1TransformerTest.java b/opensaml-saml-impl/src/test/java/org/opensaml/saml/metadata/resolver/impl/MetadataQueryProtocolSHA1TransformerTest.java
deleted file mode 100644
index e4992f3..0000000
--- a/opensaml-saml-impl/src/test/java/org/opensaml/saml/metadata/resolver/impl/MetadataQueryProtocolSHA1TransformerTest.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Licensed to the University Corporation for Advanced Internet Development,
- * Inc. (UCAID) under one or more contributor license agreements. See the
- * NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The UCAID licenses this file to You under the Apache
- * License, Version 2.0 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.opensaml.saml.metadata.resolver.impl;
-
-import org.testng.Assert;
-import org.testng.annotations.Test;
-
-public class MetadataQueryProtocolSHA1TransformerTest {
-
- @Test
- public void testBasic() {
- MetadataQueryProtocolSHA1Transformer transformer = new MetadataQueryProtocolSHA1Transformer();
- Assert.assertEquals(transformer.apply("foobarbaz"), "{sha1}5f5513f8822fdbe5145af33b64d8d970dcf95c6e");
- }
-
-}
diff --git a/opensaml-saml-impl/src/test/java/org/opensaml/saml/metadata/resolver/impl/RegexRequestURLBuilderTest.java b/opensaml-saml-impl/src/test/java/org/opensaml/saml/metadata/resolver/impl/RegexRequestURLBuilderTest.java
index b26262c..f4e88d8 100644
--- a/opensaml-saml-impl/src/test/java/org/opensaml/saml/metadata/resolver/impl/RegexRequestURLBuilderTest.java
+++ b/opensaml-saml-impl/src/test/java/org/opensaml/saml/metadata/resolver/impl/RegexRequestURLBuilderTest.java
@@ -17,9 +17,12 @@
package org.opensaml.saml.metadata.resolver.impl;
+import org.opensaml.core.criterion.EntityIdCriterion;
import org.testng.Assert;
import org.testng.annotations.Test;
+import net.shibboleth.utilities.java.support.resolver.CriteriaSet;
+
public class RegexRequestURLBuilderTest {
private RegexRequestURLBuilder function;
@@ -29,14 +32,14 @@ public class RegexRequestURLBuilderTest {
// Attempt to pluck out the domain name into match group $1.
function = new RegexRequestURLBuilder("^https?://([a-zA-Z0-9\\.]+).*$", "http://metadata.example.org/query?domain=$1");
- Assert.assertEquals(function.apply("http://example.org"), "http://metadata.example.org/query?domain=example.org");
- Assert.assertEquals(function.apply("http://example.org/"), "http://metadata.example.org/query?domain=example.org");
- Assert.assertEquals(function.apply("http://example.org/idp"), "http://metadata.example.org/query?domain=example.org");
- Assert.assertEquals(function.apply("http://example.org:443/idp"), "http://metadata.example.org/query?domain=example.org");
+ Assert.assertEquals(function.apply(new CriteriaSet(new EntityIdCriterion("http://example.org"))), "http://metadata.example.org/query?domain=example.org");
+ Assert.assertEquals(function.apply(new CriteriaSet(new EntityIdCriterion("http://example.org/"))), "http://metadata.example.org/query?domain=example.org");
+ Assert.assertEquals(function.apply(new CriteriaSet(new EntityIdCriterion("http://example.org/idp"))), "http://metadata.example.org/query?domain=example.org");
+ Assert.assertEquals(function.apply(new CriteriaSet(new EntityIdCriterion("http://example.org:443/idp"))), "http://metadata.example.org/query?domain=example.org");
// These shouldn't match, so should return null.
- Assert.assertNull(function.apply("urn:test:foo"));
- Assert.assertNull(function.apply("ftp://example.org"));
+ Assert.assertNull(function.apply(new CriteriaSet(new EntityIdCriterion("urn:test:foo"))));
+ Assert.assertNull(function.apply(new CriteriaSet(new EntityIdCriterion("ftp://example.org"))));
}
}
diff --git a/opensaml-saml-impl/src/test/java/org/opensaml/saml/metadata/resolver/impl/SAMLArtifactURLBuilderTest.java b/opensaml-saml-impl/src/test/java/org/opensaml/saml/metadata/resolver/impl/SAMLArtifactURLBuilderTest.java
new file mode 100644
index 0000000..3519fa8
--- /dev/null
+++ b/opensaml-saml-impl/src/test/java/org/opensaml/saml/metadata/resolver/impl/SAMLArtifactURLBuilderTest.java
@@ -0,0 +1,85 @@
+/*
+ * 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 org.opensaml.saml.metadata.resolver.impl;
+
+import java.io.UnsupportedEncodingException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+
+import org.opensaml.saml.common.binding.artifact.SAMLSourceIDArtifact;
+import org.opensaml.saml.common.binding.artifact.SAMLSourceLocationArtifact;
+import org.opensaml.saml.criterion.ArtifactCriterion;
+import org.opensaml.saml.metadata.resolver.index.impl.SimpleStringCriterion;
+import org.opensaml.saml.saml1.binding.artifact.SAML1ArtifactType0002;
+import org.opensaml.saml.saml2.binding.artifact.SAML2ArtifactType0004;
+import org.opensaml.security.crypto.JCAConstants;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import com.google.common.io.BaseEncoding;
+
+import net.shibboleth.utilities.java.support.resolver.CriteriaSet;
+
+/**
+ *
+ */
+public class SAMLArtifactURLBuilderTest {
+
+ private SAMLArtifactURLBuilder builder = new SAMLArtifactURLBuilder();
+
+ private String baseURL = "http://metadata.example.org/service/";
+
+ private BaseEncoding HEX = BaseEncoding.base16().lowerCase();
+
+ @Test
+ public void testSourceIDArtifact() throws NoSuchAlgorithmException, UnsupportedEncodingException {
+ String entityID = "https://www.example.com/saml";
+ MessageDigest sha1Digester = MessageDigest.getInstance(JCAConstants.DIGEST_SHA1);
+ byte[] entityIDSourceID = sha1Digester.digest(entityID.getBytes("UTF-8"));
+ SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
+ byte[] messageHandle = new byte[20];
+ secureRandom.nextBytes(messageHandle);
+
+ SAMLSourceIDArtifact sourceIDArtifact = new SAML2ArtifactType0004(new byte[] {0, 0} , entityIDSourceID, messageHandle);
+
+ Assert.assertEquals(builder.buildURL(baseURL, new CriteriaSet(new ArtifactCriterion(sourceIDArtifact))),
+ "http://metadata.example.org/service/entities/%7Bsha1%7D" + HEX.encode(entityIDSourceID));
+
+ }
+
+ @Test
+ public void testSourceLocationArtifact() throws NoSuchAlgorithmException {
+ // Note: Not currently supported by MDQ protocol. Testing for code branch correctness.
+ String sourceLocation = "https://www.example.com/saml/artifactResolve1";
+ SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
+ byte[] messageHandle = new byte[20];
+ secureRandom.nextBytes(messageHandle);
+
+ SAMLSourceLocationArtifact sourceLocationArtifact = new SAML1ArtifactType0002(messageHandle, sourceLocation);
+
+ Assert.assertNull(builder.buildURL(baseURL, new CriteriaSet(new ArtifactCriterion(sourceLocationArtifact))));
+ }
+
+ @Test
+ public void testNonArtifact() {
+ Assert.assertNull(builder.buildURL(baseURL, new CriteriaSet(new SimpleStringCriterion("blah"))));
+ }
+
+
+}
diff --git a/opensaml-saml-impl/src/test/java/org/opensaml/saml/metadata/resolver/impl/TemplateRequestURLBuilderTest.java b/opensaml-saml-impl/src/test/java/org/opensaml/saml/metadata/resolver/impl/TemplateRequestURLBuilderTest.java
index fc6e4aa..ec69730 100644
--- a/opensaml-saml-impl/src/test/java/org/opensaml/saml/metadata/resolver/impl/TemplateRequestURLBuilderTest.java
+++ b/opensaml-saml-impl/src/test/java/org/opensaml/saml/metadata/resolver/impl/TemplateRequestURLBuilderTest.java
@@ -20,8 +20,10 @@ package org.opensaml.saml.metadata.resolver.impl;
import javax.annotation.Nullable;
import net.shibboleth.utilities.java.support.logic.ConstraintViolationException;
+import net.shibboleth.utilities.java.support.resolver.CriteriaSet;
import org.apache.velocity.app.VelocityEngine;
+import org.opensaml.core.criterion.EntityIdCriterion;
import org.opensaml.saml.metadata.resolver.impl.TemplateRequestURLBuilder.EncodingStyle;
import org.testng.Assert;
import org.testng.annotations.BeforeClass;
@@ -46,7 +48,7 @@ public class TemplateRequestURLBuilderTest {
public void testEncodedQueryParamLegacy() {
function = new TemplateRequestURLBuilder(engine, "http://metadata.example.org/?entity=${entityID}", true);
- Assert.assertEquals(function.apply("http://example.org/idp"), "http://metadata.example.org/?entity=http%3A%2F%2Fexample.org%2Fidp");
+ Assert.assertEquals(function.apply(new CriteriaSet(new EntityIdCriterion("http://example.org/idp"))), "http://metadata.example.org/?entity=http%3A%2F%2Fexample.org%2Fidp");
}
@Test
@@ -54,7 +56,7 @@ public class TemplateRequestURLBuilderTest {
public void testMDQStyleLegacy() {
function = new TemplateRequestURLBuilder(engine, "http://metadata.example.org/entities/${entityID}", true);
- Assert.assertEquals(function.apply("http://example.org/idp"), "http://metadata.example.org/entities/http%3A%2F%2Fexample.org%2Fidp");
+ Assert.assertEquals(function.apply(new CriteriaSet(new EntityIdCriterion("http://example.org/idp"))), "http://metadata.example.org/entities/http%3A%2F%2Fexample.org%2Fidp");
}
@Test
@@ -62,35 +64,35 @@ public class TemplateRequestURLBuilderTest {
public void testWellKnownLocationStyleLegacy() {
function = new TemplateRequestURLBuilder(engine, "${entityID}", false);
- Assert.assertEquals(function.apply("http://example.org/idp"), "http://example.org/idp");
+ Assert.assertEquals(function.apply(new CriteriaSet(new EntityIdCriterion("http://example.org/idp"))), "http://example.org/idp");
}
@Test
public void testEncodedQueryParam() {
function = new TemplateRequestURLBuilder(engine, "http://metadata.example.org/?entity=${entityID}", EncodingStyle.form);
- Assert.assertEquals(function.apply("http://example.org/idp"), "http://metadata.example.org/?entity=http%3A%2F%2Fexample.org%2Fidp");
+ Assert.assertEquals(function.apply(new CriteriaSet(new EntityIdCriterion("http://example.org/idp"))), "http://metadata.example.org/?entity=http%3A%2F%2Fexample.org%2Fidp");
}
@Test
public void testEncodedPath() {
function = new TemplateRequestURLBuilder(engine, "http://metadata.example.org/entities/${entityID}", EncodingStyle.path);
- Assert.assertEquals(function.apply("http://example.org/idp"), "http://metadata.example.org/entities/http:%2F%2Fexample.org%2Fidp");
+ Assert.assertEquals(function.apply(new CriteriaSet(new EntityIdCriterion("http://example.org/idp"))), "http://metadata.example.org/entities/http:%2F%2Fexample.org%2Fidp");
}
@Test
public void testEncodedFragment() {
function = new TemplateRequestURLBuilder(engine, "http://metadata.example.org/entities#${entityID}", EncodingStyle.fragment);
- Assert.assertEquals(function.apply("http://example.org/idp"), "http://metadata.example.org/entities#http://example.org/idp");
+ Assert.assertEquals(function.apply(new CriteriaSet(new EntityIdCriterion("http://example.org/idp"))), "http://metadata.example.org/entities#http://example.org/idp");
}
@Test
public void testWellKnownLocationStyle() {
function = new TemplateRequestURLBuilder(engine, "${entityID}", EncodingStyle.none);
- Assert.assertEquals(function.apply("http://example.org/idp"), "http://example.org/idp");
+ Assert.assertEquals(function.apply(new CriteriaSet(new EntityIdCriterion("http://example.org/idp"))), "http://example.org/idp");
}
@Test
@@ -103,7 +105,7 @@ public class TemplateRequestURLBuilderTest {
function = new TemplateRequestURLBuilder(engine, "${entityID}", EncodingStyle.none, transformer);
- Assert.assertEquals(function.apply("http://example.org/idp"), "HTTP://EXAMPLE.ORG/IDP");
+ Assert.assertEquals(function.apply(new CriteriaSet(new EntityIdCriterion("http://example.org/idp"))), "HTTP://EXAMPLE.ORG/IDP");
}
@Test(expectedExceptions=ConstraintViolationException.class)
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list