[java-oidc-common] branch main updated: Improve cache builders/factories
Phil Smart
philip.smart at jisc.ac.uk
Fri Oct 29 13:04:50 UTC 2021
This is an automated email from the git hooks/post-receive script.
philsmart pushed a commit to branch main
in repository java-oidc-common.
View the commit online:
http://git.shibboleth.net/view/?p=java-oidc-common.git;a=commit;h=99885d8024524c9274f994d970f765b79132a662
The following commit(s) were added to refs/heads/main by this push:
new 99885d8 Improve cache builders/factories
99885d8 is described below
commit 99885d8024524c9274f994d970f765b79132a662
Author: Phil Smart <philip.smart at jisc.ac.uk>
AuthorDate: Fri Oct 29 14:04:47 2021 +0100
Improve cache builders/factories
- Improves XML configuration. Although runtime injection is obviously
not going to be type safe.
- Remove redundant factories
- Add JSON map resolvers
---
.../oidc/metadata/JSONMetadataResolver.java | 38 ++
.../metadata/cache/impl/AbstractMetadataCache.java | 3 +-
.../cache/impl/BatchMetadataCacheBuilder.java | 82 +++
.../cache/impl/BatchMetadataCacheBuilderSpec.java | 117 +++++
.../cache/impl/DefaultJSONMapParsingStrategy.java | 6 +-
.../cache/impl/DynamicMetadataCacheBuilder.java | 61 +++
.../impl/DynamicMetadataCacheBuilderSpec.java | 147 ++++++
.../impl/MapBasedMetadataCacheFactoryBean.java | 79 ---
.../metadata/cache/impl/MetadataCacheBuilder.java | 553 ---------------------
.../cache/impl/MetadataCacheBuilderSpec.java | 256 ++++++++++
.../impl/OIDCProviderMetadataCacheFactoryBean.java | 83 ----
...aResolver.java => JSONMapMetadataResolver.java} | 15 +-
.../impl/OIDCProviderMetadataResolver.java | 2 +-
.../cache/impl/BatchMetadataCacheBuilderTest.java | 75 +++
.../impl/DynamicMetadataCacheBuilderTest.java | 76 +++
15 files changed, 867 insertions(+), 726 deletions(-)
diff --git a/oidc-common-metadata-api/src/main/java/net/shibboleth/oidc/metadata/JSONMetadataResolver.java b/oidc-common-metadata-api/src/main/java/net/shibboleth/oidc/metadata/JSONMetadataResolver.java
new file mode 100644
index 0000000..b7329a0
--- /dev/null
+++ b/oidc-common-metadata-api/src/main/java/net/shibboleth/oidc/metadata/JSONMetadataResolver.java
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements. See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID licenses this file to You under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.shibboleth.oidc.metadata;
+
+import java.util.Map;
+
+import net.shibboleth.oidc.metadata.criterion.IssuerIDCriterion;
+import net.shibboleth.utilities.java.support.component.IdentifiedComponent;
+import net.shibboleth.utilities.java.support.resolver.CriteriaSet;
+import net.shibboleth.utilities.java.support.resolver.Resolver;
+
+/**
+ * A resolver that is capable of resolving {@link Map} instances which meet certain supplied criteria.
+ * <p>
+ * At a minimum, a {@link JSONMetadataResolver} implementation MUST support the following criteria:</p>
+ * <ul>
+ * <li>{@link IssuerIDCriterion}</li>
+ * </ul>
+ */
+//TODO do we need this interface if we already have a concrete type?
+public interface JSONMetadataResolver extends Resolver<Map<String, Object>, CriteriaSet>, IdentifiedComponent {
+
+}
diff --git a/oidc-common-metadata-impl/src/main/java/net/shibboleth/oidc/metadata/cache/impl/AbstractMetadataCache.java b/oidc-common-metadata-impl/src/main/java/net/shibboleth/oidc/metadata/cache/impl/AbstractMetadataCache.java
index fc6b8cc..3329283 100644
--- a/oidc-common-metadata-impl/src/main/java/net/shibboleth/oidc/metadata/cache/impl/AbstractMetadataCache.java
+++ b/oidc-common-metadata-impl/src/main/java/net/shibboleth/oidc/metadata/cache/impl/AbstractMetadataCache.java
@@ -50,6 +50,7 @@ import net.shibboleth.utilities.java.support.component.AbstractIdentifiableIniti
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.logic.ConstraintViolationException;
import net.shibboleth.utilities.java.support.primitive.TimerSupport;
import net.shibboleth.utilities.java.support.resolver.CriteriaSet;
@@ -354,7 +355,7 @@ public abstract class AbstractMetadataCache<IdentifierType, MetadataType>
ComponentSupport.ifDestroyedThrowDestroyedComponentException(this);
if (factor <= 0 || factor >= 1) {
- throw new IllegalArgumentException("Refresh delay factor must be a number between 0.0 and 1.0, exclusive");
+ throw new ConstraintViolationException("Refresh delay factor must be a number between 0.0 and 1.0, exclusive");
}
refreshDelayFactor = factor;
diff --git a/oidc-common-metadata-impl/src/main/java/net/shibboleth/oidc/metadata/cache/impl/BatchMetadataCacheBuilder.java b/oidc-common-metadata-impl/src/main/java/net/shibboleth/oidc/metadata/cache/impl/BatchMetadataCacheBuilder.java
new file mode 100644
index 0000000..61e444f
--- /dev/null
+++ b/oidc-common-metadata-impl/src/main/java/net/shibboleth/oidc/metadata/cache/impl/BatchMetadataCacheBuilder.java
@@ -0,0 +1,82 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements. See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID licenses this file to You under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.shibboleth.oidc.metadata.cache.impl;
+
+import javax.annotation.Nonnull;
+
+import net.shibboleth.oidc.metadata.impl.DefaultBatchBackingStore;
+import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
+
+
+/**
+ * Build a fully initialized and safely published batch metadata cache for use. Each cache is built from its own
+ * specification.
+ *
+ * <p>Spring's XML injection can not enforce type safety here, so an incorrect specification will
+ * not be picked up until it is used.</p>
+ *
+ */
+public final class BatchMetadataCacheBuilder {
+
+ /** Private constructor.*/
+ private BatchMetadataCacheBuilder() {
+
+ }
+
+ /**
+ * A static builder for generating a batch metadata cache from a given specification.
+ *
+ * @param <IdentifierType> The identifier type
+ * @param <MetadataType> The metadata type>
+ */
+ public static class Builder<IdentifierType, MetadataType> {
+
+
+ /**
+ * Build the metadata cache from the given specification.
+ *
+ * @param spec the metadata cache specification.
+ *
+ * @return the batch metadata cache.
+ *
+ * @throws ComponentInitializationException on error.
+ */
+ public BatchMetadataCache<IdentifierType, MetadataType> build(
+ @Nonnull final BatchMetadataCacheBuilderSpec<IdentifierType, MetadataType> spec)
+ throws ComponentInitializationException {
+
+ final BatchMetadataCache<IdentifierType, MetadataType> cache =
+ new BatchMetadataCache<>(
+ new DefaultBatchBackingStore<>(), spec.getLoadingStrategy(), spec.getParsingStrategy());
+ cache.setMinCacheDuration(spec.getMinCacheDuration());
+ // cache.setMaxCacheDuration(getMaxCacheDuration());
+ cache.setMinRefreshDelay(spec.getMinRefreshDelay());
+ cache.setMaxRefreshDelay(spec.getMaxRefreshDelay());
+ cache.setRefreshDelayFactor(spec.getRefreshDelayFactor());
+ cache.setMetadataExpirationTimeStrategy(spec.getMetadataExpirationTimeStrategy());
+ cache.setIdentifierExtractionStrategy(spec.getIdentifierExtractionStrategy());
+ cache.setCriteriaToIdentifierStrategy(spec.getCriteriaToIdentifierStrategy());
+ cache.setMetadataFilterStrategy(spec.getMetadataFilterStrategy());
+ cache.setMetadataBeforeRemovalHook(spec.getMetadataBeforeRemovalHook());
+ cache.setId("BatchMetadataCache");
+ cache.initialize();
+ return cache;
+ }
+ }
+
+}
diff --git a/oidc-common-metadata-impl/src/main/java/net/shibboleth/oidc/metadata/cache/impl/BatchMetadataCacheBuilderSpec.java b/oidc-common-metadata-impl/src/main/java/net/shibboleth/oidc/metadata/cache/impl/BatchMetadataCacheBuilderSpec.java
new file mode 100644
index 0000000..0bf97c2
--- /dev/null
+++ b/oidc-common-metadata-impl/src/main/java/net/shibboleth/oidc/metadata/cache/impl/BatchMetadataCacheBuilderSpec.java
@@ -0,0 +1,117 @@
+package net.shibboleth.oidc.metadata.cache.impl;
+
+import java.time.Duration;
+import java.util.List;
+import java.util.function.Function;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import net.shibboleth.oidc.metadata.cache.CacheLoadingContext;
+import net.shibboleth.utilities.java.support.annotation.constraint.Positive;
+import net.shibboleth.utilities.java.support.logic.Constraint;
+
+public class BatchMetadataCacheBuilderSpec<IdentifierType, MetadataType>
+ extends MetadataCacheBuilderSpec<IdentifierType, MetadataType> {
+
+ /**
+ * How to parse the loaded metadata from the loadingStrategy into a usable metadatatype.
+ * Applicable for {@link BatchMetadataCache} types.
+ */
+ @Nullable private Function<byte[], List<MetadataType>> parsingStrategy;
+
+ /** The function to use to load metadata. Applicable for {@link BatchMetadataCache} types.*/
+ @Nullable private Function<CacheLoadingContext, byte[]> loadingStrategy;
+
+ /**
+ * Refresh interval used when metadata does not contain any validUntil or cacheDuration information.
+ * Default value: 4 hours
+ */
+ @Nonnull @Positive private Duration maxRefreshDelay;
+
+ /** Floor, in milliseconds, for the refresh interval. Default value: 5 minutes */
+ @Nonnull @Positive private Duration minRefreshDelay;
+
+ /** Constructor.*/
+ public BatchMetadataCacheBuilderSpec() {
+ maxRefreshDelay = Duration.ofHours(4);
+ minRefreshDelay = Duration.ofMinutes(5);
+ }
+
+ /**
+ * Get the min delay to wait before refreshing metadata.
+ *
+ * @return the min delay.
+ */
+ @Nonnull protected Duration getMinRefreshDelay() {
+ return minRefreshDelay;
+ }
+
+ /**
+ * Get the max delay to wait before refreshing metadata.
+ *
+ * @return the max delay.
+ */
+ @Nonnull protected Duration getMaxRefreshDelay() {
+ return maxRefreshDelay;
+ }
+
+
+
+ /**
+ * Sets the minimum amount of time between refreshes.
+ *
+ * @param delay minimum amount of time between refreshes
+ */
+ public void setMinRefreshDelay(@Positive @Nonnull final Duration delay) {
+ Constraint.isFalse(delay == null || delay.isNegative(), "Minimum refresh delay must be greater than 0");
+ minRefreshDelay = delay;
+ }
+
+ /**
+ * Sets the maximum amount of time between refresh intervals.
+ *
+ * @param delay maximum amount of time, in milliseconds, between refresh intervals
+ */
+ public void setMaxRefreshDelay(@Positive @Nonnull final Duration delay) {
+ Constraint.isFalse(delay == null || delay.isNegative(), "Maximum refresh delay must be greater than 0");
+ maxRefreshDelay = delay;
+ }
+
+ /**
+ * Set he raw batch metadata to metadata type parsing strategy.
+ *
+ * @param strategy the parsing strategy.
+ */
+ public void setParsingStrategy(@Nonnull final Function<byte[], List<MetadataType>> strategy) {
+ parsingStrategy = Constraint.isNotNull(strategy, "Parsing strategy can not be null");
+ }
+
+ /**
+ * Get the raw batch metadata to metadata type parsing strategy.
+ *
+ * @return the parsing strategy.
+ */
+ @Nullable protected Function<byte[], List<MetadataType>> getParsingStrategy() {
+ return parsingStrategy;
+ }
+
+ /**
+ * Set the batch metadata loading strategy, applies to the {@link BatchMetadataCache} type.
+ *
+ * @param strategy the strategy to set.
+ */
+ public void setLoadingStrategy(@Nonnull final Function<CacheLoadingContext, byte[]> strategy) {
+ loadingStrategy = Constraint.isNotNull(strategy,"Batch metadata loading strategy can not be null");
+ }
+
+ /**
+ * Get the batch metadata loading strategy.
+ *
+ * @return the strategy.
+ */
+ @Nullable protected Function<CacheLoadingContext, byte[]> getLoadingStrategy() {
+ return loadingStrategy;
+ }
+
+}
diff --git a/oidc-common-metadata-impl/src/main/java/net/shibboleth/oidc/metadata/cache/impl/DefaultJSONMapParsingStrategy.java b/oidc-common-metadata-impl/src/main/java/net/shibboleth/oidc/metadata/cache/impl/DefaultJSONMapParsingStrategy.java
index 0b96004..dffef6a 100644
--- a/oidc-common-metadata-impl/src/main/java/net/shibboleth/oidc/metadata/cache/impl/DefaultJSONMapParsingStrategy.java
+++ b/oidc-common-metadata-impl/src/main/java/net/shibboleth/oidc/metadata/cache/impl/DefaultJSONMapParsingStrategy.java
@@ -52,6 +52,10 @@ public class DefaultJSONMapParsingStrategy implements Function<byte[], List<Map<
public DefaultJSONMapParsingStrategy(@Nonnull final ObjectMapper mapper) {
objectMapper = Constraint.isNotNull(mapper, "Object mapper can not be null");
}
+
+ public DefaultJSONMapParsingStrategy() {
+ this(new ObjectMapper());
+ }
@Override
public List<Map<String, Object>> apply(byte[] rawMetadata) {
@@ -64,7 +68,7 @@ public class DefaultJSONMapParsingStrategy implements Function<byte[], List<Map<
}
return Collections.emptyList();
} catch (final JsonProcessingException e) {
- log.error("Could not parse input raw metadata to a map");
+ log.error("Could not parse input raw metadata to a map", e);
return Collections.emptyList();
}
}
diff --git a/oidc-common-metadata-impl/src/main/java/net/shibboleth/oidc/metadata/cache/impl/DynamicMetadataCacheBuilder.java b/oidc-common-metadata-impl/src/main/java/net/shibboleth/oidc/metadata/cache/impl/DynamicMetadataCacheBuilder.java
new file mode 100644
index 0000000..075bb98
--- /dev/null
+++ b/oidc-common-metadata-impl/src/main/java/net/shibboleth/oidc/metadata/cache/impl/DynamicMetadataCacheBuilder.java
@@ -0,0 +1,61 @@
+
+package net.shibboleth.oidc.metadata.cache.impl;
+
+import javax.annotation.Nonnull;
+
+import net.shibboleth.oidc.metadata.impl.DefaultDynamicBackingStore;
+import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
+
+/**
+ * Build a fully initialized and safely published dynamic metadata cache for use. Each cache is built from its own
+ * specification.
+ *
+ * <p>Spring's XML injection can not enforce type safety here, so an incorrect specification will
+ * not be picked up until it is used.</p>
+ *
+ * @param <IdentifierType> The identifier type
+ * @param <MetadataType> The metadata type
+ */
+public final class DynamicMetadataCacheBuilder {
+
+ /** Private constructor.*/
+ private DynamicMetadataCacheBuilder() {
+
+ }
+
+ /**
+ * A static builder for generating a dynamic metadata cache from a given specification.
+ *
+ * @param <IdentifierType> The identifier type
+ * @param <MetadataType> The metadata type>
+ */
+ public static class Builder<IdentifierType, MetadataType> {
+
+ public DynamicMetadataCache<IdentifierType, MetadataType>
+ build(@Nonnull final DynamicMetadataCacheBuilderSpec<IdentifierType, MetadataType> spec)
+ throws ComponentInitializationException {
+
+ final DynamicMetadataCache<IdentifierType, MetadataType> cache = new DynamicMetadataCache<>(
+ new DefaultDynamicBackingStore<>(spec.getMaxCacheDuration()), spec.getFetchStrategy());
+ cache.setMinCacheDuration(spec.getMinCacheDuration());
+ // FIXME what did we do with this.
+ // cache.setMaxCacheDuration(getMaxCacheDuration());
+ cache.setRefreshDelayFactor(spec.getRefreshDelayFactor());
+ cache.setMaxIdleEntityData(spec.getMaxIdleEntityData());
+ cache.setMetadataExpirationTimeStrategy(spec.getMetadataExpirationTimeStrategy());
+ cache.setIdentifierExtractionStrategy(spec.getIdentifierExtractionStrategy());
+ cache.setCriteriaToIdentifierStrategy(spec.getCriteriaToIdentifierStrategy());
+ cache.setCleanupTaskInterval(spec.getCleanupTaskInterval());
+ cache.setRemoveIdleEntityData(spec.isRemoveIdleEntityData());
+ cache.setInitialCleanupTaskDelay(spec.getInitialCleanupTaskDelay());
+ cache.setMetadataFilterStrategy(spec.getMetadataFilterStrategy());
+ cache.setMetadataBeforeRemovalHook(spec.getMetadataBeforeRemovalHook());
+ cache.setId("DynamicMetadataCache");
+ cache.initialize();
+ return cache;
+ }
+
+ }
+
+
+}
diff --git a/oidc-common-metadata-impl/src/main/java/net/shibboleth/oidc/metadata/cache/impl/DynamicMetadataCacheBuilderSpec.java b/oidc-common-metadata-impl/src/main/java/net/shibboleth/oidc/metadata/cache/impl/DynamicMetadataCacheBuilderSpec.java
new file mode 100644
index 0000000..186643b
--- /dev/null
+++ b/oidc-common-metadata-impl/src/main/java/net/shibboleth/oidc/metadata/cache/impl/DynamicMetadataCacheBuilderSpec.java
@@ -0,0 +1,147 @@
+package net.shibboleth.oidc.metadata.cache.impl;
+
+import java.time.Duration;
+import java.util.function.Function;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import net.shibboleth.utilities.java.support.logic.Constraint;
+import net.shibboleth.utilities.java.support.resolver.CriteriaSet;
+
+public class DynamicMetadataCacheBuilderSpec <IdentifierType, MetadataType>
+ extends MetadataCacheBuilderSpec<IdentifierType, MetadataType> {
+
+
+ /** The function to use to fetch metadata if either none exists, or the existing is stale.*/
+ @Nullable private Function<CriteriaSet, MetadataType> fetchStrategy;
+
+ /** The maximum idle time for which the cache will keep data for before it is removed. */
+ @Nullable private Duration maxIdleEntityData;
+
+ /** The interval at which the cleanup task should run. */
+ @Nonnull private Duration cleanupTaskInterval;
+
+ /** Flag indicating whether idle entity data should be removed. */
+ private boolean removeIdleEntityData;
+
+ /** The initial cleanup task delay.*/
+ @Nonnull private Duration initialCleanupTaskDelay;
+
+ /** Constructor. */
+ protected DynamicMetadataCacheBuilderSpec() {
+ maxIdleEntityData = Duration.ofHours(8);
+ cleanupTaskInterval = Duration.ofMinutes(30);
+ initialCleanupTaskDelay = Duration.ofMinutes(1);
+ removeIdleEntityData = true;
+ }
+
+ /**
+ * Set the flag indicating whether idle entity data should be removed.
+ *
+ * @param flag true if idle entity data should be removed, false otherwise
+ */
+ public void setRemoveIdleEntityData(final boolean flag) {
+ removeIdleEntityData = flag;
+ }
+
+ /**
+ * Should idle metadata be removed?
+ *
+ * @return if idle metadata should be resolved.
+ */
+ protected boolean isRemoveIdleEntityData() {
+ return removeIdleEntityData;
+ }
+
+ /**
+ * Get the interval at which the cleanup task should run.
+ *
+ * <p>Defaults to: 30 minutes.</p>
+ *
+ * @return return the interval
+ */
+ @Nonnull protected Duration getCleanupTaskInterval() {
+ return cleanupTaskInterval;
+ }
+
+ /**
+ * Set the interval at which the cleanup task should run.
+ *
+ * <p>Defaults to: 30 minutes.</p>
+ *
+ * @param interval the interval to set
+ */
+ public void setCleanupTaskInterval(@Nonnull final Duration interval) {
+ Constraint.isNotNull(interval, "Cleanup task interval may not be null");
+ Constraint.isFalse(interval.isNegative() || interval.isZero(), "Cleanup task interval must be positive");
+
+ cleanupTaskInterval = interval;
+ }
+
+ /**
+ * Set the metadata fetching strategy.
+ *
+ * @param strategy the strategy to use.
+ */
+ public void setFetchStrategy(@Nonnull final Function<CriteriaSet, MetadataType> strategy) {
+ fetchStrategy = Constraint.isNotNull(strategy, "Metadata fetch strategy can not be null");
+ }
+
+ /**
+ * Get the metadata fetching strategy.
+ *
+ * @return the fetching strategy.
+ */
+ @Nullable protected Function<CriteriaSet, MetadataType> getFetchStrategy() {
+ return fetchStrategy;
+ }
+
+ /**
+ * Get the maximum idle time for which the resolver will keep data for before it is removed.
+ *
+ * <p>Defaults to: 8 hours.</p>
+ *
+ * @return return the maximum idle time
+ */
+ @Nonnull protected Duration getMaxIdleEntityData() {
+ return maxIdleEntityData;
+ }
+
+ /**
+ * Set the maximum idle time for which the resolver will keep data for before it is removed.
+ *
+ * <p>Defaults to: 8 hours.</p>
+ *
+ * @param max the maximum entity data idle time
+ */
+ public void setMaxIdleEntityData(@Nonnull final Duration max) {
+ Constraint.isNotNull(max, "Max idle time cannot be null");
+ Constraint.isFalse(max.isNegative(), "Max idle time cannot be negative");
+
+ maxIdleEntityData = max;
+ }
+
+
+ /**
+ * Get the initial cleanup task delay.
+ *
+ * @return Returns the initialCleanupTaskDelay.
+ */
+ @Nonnull protected Duration getInitialCleanupTaskDelay() {
+ return initialCleanupTaskDelay;
+ }
+
+ /**
+ * Set the initial cleanup task delay.
+ *
+ * @param delay The initialCleanupTaskDelay to set.
+ */
+ public void setInitialCleanupTaskDelay(@Nonnull final Duration delay) {
+ Constraint.isNotNull(delay, "Cleanup task delay can not be null");
+ Constraint.isFalse(delay.isNegative() || delay.isZero(), "Cleanup task delay must be positive");
+ initialCleanupTaskDelay = delay;
+
+ }
+
+}
diff --git a/oidc-common-metadata-impl/src/main/java/net/shibboleth/oidc/metadata/cache/impl/MapBasedMetadataCacheFactoryBean.java b/oidc-common-metadata-impl/src/main/java/net/shibboleth/oidc/metadata/cache/impl/MapBasedMetadataCacheFactoryBean.java
deleted file mode 100644
index 111d3bd..0000000
--- a/oidc-common-metadata-impl/src/main/java/net/shibboleth/oidc/metadata/cache/impl/MapBasedMetadataCacheFactoryBean.java
+++ /dev/null
@@ -1,79 +0,0 @@
-package net.shibboleth.oidc.metadata.cache.impl;
-
-import java.util.Map;
-import java.util.concurrent.atomic.AtomicInteger;
-
-import net.shibboleth.oidc.metadata.cache.MetadataCache;
-import net.shibboleth.oidc.metadata.impl.DefaultBatchBackingStore;
-import net.shibboleth.oidc.metadata.impl.DefaultDynamicBackingStore;
-
-/**
- * Factory bean to create a map based metadata cache. Either a {@link DynamicMetadataCache}
- * or {@link BatchMetadataCache} is created depending on the cache properties configured.
- */
-public class MapBasedMetadataCacheFactoryBean extends MetadataCacheBuilder<String, Map<String, Object>> {
-
-
- private final AtomicInteger cacheID;
-
- /** Constructor.*/
- public MapBasedMetadataCacheFactoryBean() {
- cacheID = new AtomicInteger(1);
- }
-
- @SuppressWarnings("rawtypes")
- @Override
- public Class<MetadataCache> getObjectType() {
- return MetadataCache.class;
- }
-
- @Override
- protected MetadataCache<Map<String, Object>> createInstance() throws Exception {
-
- if (getCacheOperationMode() == CacheOperationMode.DYNAMIC) {
- final DynamicMetadataCache<String, Map<String, Object>> cache = new DynamicMetadataCache<>(
- new DefaultDynamicBackingStore<>(getMaxCacheDuration()), getFetchStrategy());
- cache.setMinCacheDuration(getMinCacheDuration());
- //FIXME what did we do with this.
- // cache.setMaxCacheDuration(getMaxCacheDuration());
- cache.setRefreshDelayFactor(getRefreshDelayFactor());
- cache.setMaxIdleEntityData(getMaxIdleEntityData());
- cache.setMetadataExpirationTimeStrategy(getMetadataExpirationTimeStrategy());
- cache.setIdentifierExtractionStrategy(getIdentifierExtractionStrategy());
- cache.setCriteriaToIdentifierStrategy(getCriteriaToIdentifierStrategy());
- cache.setCleanupTaskInterval(getCleanupTaskInterval());
- cache.setRemoveIdleEntityData(isRemoveIdleEntityData());
- cache.setInitialCleanupTaskDelay(getInitialCleanupTaskDelay());
- cache.setMetadataFilterStrategy(getMetadataFilterStrategy());
- cache.setMetadataBeforeRemovalHook(getMetadataBeforeRemovalHook());
- cache.setId("MapBasedDynamicMetadataCache"+cacheID.getAndIncrement());
- cache.initialize();
- return cache;
- } else if (getCacheOperationMode() == CacheOperationMode.BATCH) {
- //TODO why have the backing stores as interfaces if you are setting the concrete type here? inject somehow?
- final BatchMetadataCache<String, Map<String, Object>> cache =
- new BatchMetadataCache<>(
- new DefaultBatchBackingStore<>(), getLoadingStrategy(), getParsingStrategy());
- cache.setMinCacheDuration(getMinCacheDuration());
- // cache.setMaxCacheDuration(getMaxCacheDuration());
- cache.setMinRefreshDelay(getMinRefreshDelay());
- cache.setMaxRefreshDelay(getMaxRefreshDelay());
- cache.setRefreshDelayFactor(getRefreshDelayFactor());
- cache.setMetadataExpirationTimeStrategy(getMetadataExpirationTimeStrategy());
- cache.setIdentifierExtractionStrategy(getIdentifierExtractionStrategy());
- cache.setCriteriaToIdentifierStrategy(getCriteriaToIdentifierStrategy());
- cache.setMetadataFilterStrategy(getMetadataFilterStrategy());
- cache.setMetadataBeforeRemovalHook(getMetadataBeforeRemovalHook());
- cache.setId("MapBasedBatchMetadataCache"+cacheID.getAndIncrement());
- cache.initialize();
- return cache;
- } else {
- //should never get here.
- throw new Exception("Cache mode of operation not supported");
- }
-
- }
-
-
-
-}
diff --git a/oidc-common-metadata-impl/src/main/java/net/shibboleth/oidc/metadata/cache/impl/MetadataCacheBuilder.java b/oidc-common-metadata-impl/src/main/java/net/shibboleth/oidc/metadata/cache/impl/MetadataCacheBuilder.java
deleted file mode 100644
index f0d44d7..0000000
--- a/oidc-common-metadata-impl/src/main/java/net/shibboleth/oidc/metadata/cache/impl/MetadataCacheBuilder.java
+++ /dev/null
@@ -1,553 +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 net.shibboleth.oidc.metadata.cache.impl;
-
-import java.time.Duration;
-import java.time.Instant;
-import java.util.List;
-import java.util.function.BiConsumer;
-import java.util.function.BiFunction;
-import java.util.function.Function;
-
-import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
-
-import org.springframework.beans.factory.FactoryBeanNotInitializedException;
-import org.springframework.beans.factory.config.AbstractFactoryBean;
-
-import net.shibboleth.oidc.metadata.cache.CacheLoadingContext;
-import net.shibboleth.oidc.metadata.cache.MetadataCache;
-import net.shibboleth.oidc.metadata.filter.MetadataFilterContext;
-import net.shibboleth.utilities.java.support.annotation.constraint.Positive;
-import net.shibboleth.utilities.java.support.component.DestructableComponent;
-import net.shibboleth.utilities.java.support.logic.Constraint;
-import net.shibboleth.utilities.java.support.resolver.CriteriaSet;
-
-/**
- * Base metadata cache builder instance. Holds values common to all metadata cache implementations.
- *
- * @param <T> the metadata identifier/key
- * @param <U> the metadata type.
- */
-public abstract class MetadataCacheBuilder<T,U> extends AbstractFactoryBean<MetadataCache<U>> {
-
-
- /** Which mode of operation to support.*/
- public enum CacheOperationMode {
-
- /**
- * A batch mode of operation where caches are completely reloaded
- * on refresh using refresh-ahead semantics.
- * Satisfied by constructing a {@link BatchMetadataCache}.
- */
- BATCH,
-
- /**
- * A dynamic mode of operation where individual entries are updated
- * when stale or not found using a read-through semantic.
- * Satisfied by constructing a {@link DynamicMetadataCache}.
- */
- DYNAMIC,
- }
-
- /** Maximum cache duration. */
- @Nonnull private Duration maxCacheDuration;
-
- /** Minimum cache duration. */
- @Nonnull private Duration minCacheDuration;
-
- /**
- * Refresh interval used when metadata does not contain any validUntil or cacheDuration information. Default value:
- * 4 hours
- */
- @Nonnull @Positive private Duration maxRefreshDelay;
-
- /** Floor, in milliseconds, for the refresh interval. Default value: 5 minutes */
- @Nonnull @Positive private Duration minRefreshDelay;
-
- /** Factor used to compute when the next refresh interval will occur. Default value: 0.75 */
- @Positive private Float refreshDelayFactor;
-
- /** The maximum idle time for which the resolver will keep data for a given entityID,
- * before it is removed. */
- @Nullable private Duration maxIdleEntityData;
-
- /** The interval at which the cleanup task should run. */
- @Nonnull private Duration cleanupTaskInterval;
-
- /** The initial cleanup task delay.*/
- @Nonnull private Duration initialCleanupTaskDelay;
-
- /** Strategy used to extract an identifier from the given metadata.*/
- @Nullable private Function<U, T> identifierExtractionStrategy;
-
- /** Strategy used to compute an expiration time. */
- @Nullable private BiFunction<U, Instant, Instant> metadataExpirationTimeStrategy;
-
- /** Map criteria to identifiers to use as keys to the backing store.*/
- @Nullable private Function<CriteriaSet, T> criteriaToIdentifierStrategy;
-
- /** A strategy to filter metadata. */
- @Nonnull private BiFunction<U, MetadataFilterContext , U> metadataFilterStrategy;
-
- /**
- * A hook that is executed just before a cache entry will been removed/invalidated/evicted.
- * The metadata list could be {@literal null}, the identifier is never {@literal null}.
- */
- @Nullable private BiConsumer<List<U>, T> metadataBeforeRemovalHook;
-
- /** Flag indicating whether idle entity data should be removed. */
- private boolean removeIdleEntityData;
-
- /** The function to use to fetch metadata if either none exists, or the existing is stale.*/
- @Nullable private Function<CriteriaSet, U> fetchStrategy;
-
- /**
- * How to parse the loaded metadata from the loadingStrategy into a usable metadatatype.
- * Applicable for {@link BatchMetadataCache} types.
- */
- @Nullable private Function<byte[], List<U>> parsingStrategy;
-
- /** The function to use to load metadata. Applicable for {@link BatchMetadataCache} types.*/
- @Nullable private Function<CacheLoadingContext, byte[]> loadingStrategy;
-
- /** Which cache mode of operation to use.*/
- @Nonnull private CacheOperationMode cacheOperationMode;
-
-
-
- /** Constructor.*/
- protected MetadataCacheBuilder() {
- // defaults
- maxCacheDuration = Duration.ofHours(8);
- minCacheDuration = Duration.ofMinutes(10);
- maxIdleEntityData = Duration.ofHours(8);
- refreshDelayFactor = 0.75f;
- cleanupTaskInterval = Duration.ofMinutes(30);
- initialCleanupTaskDelay = Duration.ofMinutes(1);
- maxRefreshDelay = Duration.ofHours(4);
- minRefreshDelay = Duration.ofMinutes(5);
- removeIdleEntityData = true;
- // create a default direct in/out filter
- metadataFilterStrategy = (metadata, context) -> metadata;
- // create batch mode by default
- cacheOperationMode = CacheOperationMode.BATCH;
- }
-
- /**
- * {@inheritDoc}
- * <p>Only supports prototype metadata instances, each resolver must have its own cache.</p>
- */
- @Override
- public void afterPropertiesSet() throws Exception {
- if (isSingleton()) {
- throw new
- FactoryBeanNotInitializedException("Only prototype metadata cache instances are supported");
- }
- super.afterPropertiesSet();
- }
-
- /**
- * Set the cache operation mode.
- *
- * @param mode the cache operation mode.
- */
- public void setCacheOperationMode(@Nonnull final CacheOperationMode mode) {
- cacheOperationMode = Constraint.isNotNull(mode, "Cache operation mode can not be null");
- }
-
- /**
- * Get the cache operation mode.
- *
- * @return the cache operation mode.
- */
- @Nonnull protected CacheOperationMode getCacheOperationMode() {
- return cacheOperationMode;
- }
-
- /**
- * Get the min delay to wait before refreshing metadata.
- *
- * @return the min delay.
- */
- @Nonnull protected Duration getMinRefreshDelay() {
- return minRefreshDelay;
- }
-
- /**
- * Get the max delay to wait before refreshing metadata.
- *
- * @return the max delay.
- */
- @Nonnull protected Duration getMaxRefreshDelay() {
- return maxRefreshDelay;
- }
-
- /**
- * Set he raw batch metadata to metadata type parsing strategy.
- *
- * @param strategy the parsing strategy.
- */
- public void setParsingStrategy(@Nonnull final Function<byte[], List<U>> strategy) {
- parsingStrategy = Constraint.isNotNull(strategy, "Parsing strategy can not be null");
- }
-
- /**
- * Get the raw batch metadata to metadata type parsing strategy.
- *
- * @return the parsing strategy.
- */
- @Nullable protected Function<byte[], List<U>> getParsingStrategy() {
- return parsingStrategy;
- }
-
- /**
- * Set the batch metadata loading strategy, applies to the {@link BatchMetadataCache} type.
- *
- * @param strategy the strategy to set.
- */
- public void setLoadingStrategy(@Nonnull final Function<CacheLoadingContext, byte[]> strategy) {
- loadingStrategy = Constraint.isNotNull(strategy,"Batch metadata loading strategy can not be null");
- }
-
- /**
- * Get the batch metadata loading strategy.
- *
- * @return the strategy.
- */
- @Nullable protected Function<CacheLoadingContext, byte[]> getLoadingStrategy() {
- return loadingStrategy;
- }
-
- /**
- * Sets the minimum amount of time between refreshes.
- *
- * @param delay minimum amount of time between refreshes
- */
- public void setMinRefreshDelay(@Positive @Nonnull final Duration delay) {
- Constraint.isFalse(delay == null || delay.isNegative(), "Minimum refresh delay must be greater than 0");
- minRefreshDelay = delay;
- }
-
- /**
- * Sets the maximum amount of time between refresh intervals.
- *
- * @param delay maximum amount of time, in milliseconds, between refresh intervals
- */
- public void setMaxRefreshDelay(@Positive @Nonnull final Duration delay) {
- Constraint.isFalse(delay == null || delay.isNegative(), "Maximum refresh delay must be greater than 0");
- maxRefreshDelay = delay;
- }
-
- /**
- * Set the metadata fetching strategy.
- *
- * @param strategy the strategy to use.
- */
- public void setFetchStrategy(@Nonnull final Function<CriteriaSet, U> strategy) {
- fetchStrategy = Constraint.isNotNull(strategy, "Metadata fetch strategy can not be null");
- }
-
- /**
- * Get the metadata fetching strategy.
- *
- * @return the fetching strategy.
- */
- @Nullable protected Function<CriteriaSet, U> getFetchStrategy() {
- return fetchStrategy;
- }
-
- /**
- * {@inheritDoc}
- *
- * Call destroy if the cache implementation supports it.
- */
- @Override protected void destroyInstance(
- final @Nullable MetadataCache<U> instance) throws Exception {
- if (instance instanceof DestructableComponent) {
- ((DestructableComponent)instance).destroy();
- }
- }
-
- /**
- * Set a hook to run before a metadata cache entry is removed from the cache.
- * <p>The hook is required to gracefully handle null metadata lists.</p>
- *
- * @param hook the hook to run.
- */
- public void setMetadataBeforeRemovalHook(@Nullable final BiConsumer<List<U>, T> hook) {
- metadataBeforeRemovalHook = hook;
- }
-
- /**
- * Get the metadata before removal hook. Could be {@literal null}.
- *
- * @return the hook.
- */
- @Nullable public BiConsumer<List<U>, T> getMetadataBeforeRemovalHook() {
- return metadataBeforeRemovalHook;
- }
-
- /**
- * Set the metadata filtering strategy.
- *
- * <p>Defaults to a no-op strategy.</p>
- *
- * @param strategy the metadata filtering strategy.
- */
- public void setMetadataFilterStrategy(@Nonnull final BiFunction<U, MetadataFilterContext, U> strategy) {
- metadataFilterStrategy = Constraint.isNotNull(strategy,"Metadata filtering strategy can not be null");
- }
-
- /**
- * Get the metadata filter strategy.
- *
- * @return the metadata filtering strategy
- */
- @Nonnull public BiFunction<U, MetadataFilterContext, U> getMetadataFilterStrategy() {
- return metadataFilterStrategy;
- }
-
- /**
- * Get the initial cleanup task delay.
- *
- * @return Returns the initialCleanupTaskDelay.
- */
- @Nonnull protected Duration getInitialCleanupTaskDelay() {
- return initialCleanupTaskDelay;
- }
-
- /**
- * Set the initial cleanup task delay.
- *
- * @param delay The initialCleanupTaskDelay to set.
- */
- public void setInitialCleanupTaskDelay(@Nonnull final Duration delay) {
- Constraint.isNotNull(delay, "Cleanup task delay can not be null");
- Constraint.isFalse(delay.isNegative() || delay.isZero(), "Cleanup task delay must be positive");
- initialCleanupTaskDelay = delay;
-
- }
-
- /**
- * Set the flag indicating whether idle entity data should be removed.
- *
- * @param flag true if idle entity data should be removed, false otherwise
- */
- public void setRemoveIdleEntityData(final boolean flag) {
- removeIdleEntityData = flag;
- }
-
- /**
- * Should idle metadata be removed?
- *
- * @return if idle metadata should be resolved.
- */
- protected boolean isRemoveIdleEntityData() {
- return removeIdleEntityData;
- }
-
- /**
- * Set the identifier extraction strategy.
- *
- * @param strategy the strategy to set.
- */
- public void setIdentifierExtractionStrategy(@Nonnull final Function<U, T> strategy) {
- identifierExtractionStrategy = Constraint.isNotNull(strategy, "Strategy can not be null");
- }
-
-
- /**
- * Get the identifier extraction strategy.
- *
- * @return strategy the strategy.
- */
- @Nullable protected Function<U, T> getIdentifierExtractionStrategy() {
- return identifierExtractionStrategy;
- }
-
- /**
- * Set the metadata expiration time strategy.
- *
- * @param strategy the strategy.
- */
- public void setMetadataExpirationTimeStrategy(
- @Nonnull final BiFunction<U, Instant, Instant> strategy) {
- metadataExpirationTimeStrategy = Constraint.isNotNull(strategy, "Strategy can not be null");
- }
-
- /**
- * Get the metadata expiration time strategy.
- *
- * @return the strategy.
- */
- @Nullable protected BiFunction<U, Instant, Instant> getMetadataExpirationTimeStrategy() {
- return metadataExpirationTimeStrategy;
- }
-
- /**
- * Set the criteria set to identifier lookup strategy.
- *
- * @param strategy the strategy to set.
- */
- public void setCriteriaToIdentifierStrategy(@Nonnull final Function<CriteriaSet, T> strategy) {
- criteriaToIdentifierStrategy =
- Constraint.isNotNull(strategy,"Criteria to identifier strategy can not be null");
- }
-
- /**
- * Get the criteria set to identifier lookup strategy.
- *
- * @return strategy the strategy.
- */
- @Nullable protected Function<CriteriaSet, T> getCriteriaToIdentifierStrategy() {
- return criteriaToIdentifierStrategy;
- }
-
- /**
- * Get the interval at which the cleanup task should run.
- *
- * <p>Defaults to: 30 minutes.</p>
- *
- * @return return the interval
- */
- @Nonnull protected Duration getCleanupTaskInterval() {
- return cleanupTaskInterval;
- }
-
- /**
- * Set the interval at which the cleanup task should run.
- *
- * <p>Defaults to: 30 minutes.</p>
- *
- * @param interval the interval to set
- */
- public void setCleanupTaskInterval(@Nonnull final Duration interval) {
- Constraint.isNotNull(interval, "Cleanup task interval may not be null");
- Constraint.isFalse(interval.isNegative() || interval.isZero(), "Cleanup task interval must be positive");
-
- cleanupTaskInterval = interval;
- }
-
- /**
- * Get the maximum idle time for which the resolver will keep data for a given entityID,
- * before it is removed.
- *
- * <p>Defaults to: 8 hours.</p>
- *
- * @return return the maximum idle time
- */
- @Nonnull protected Duration getMaxIdleEntityData() {
- return maxIdleEntityData;
- }
-
- /**
- * Set the maximum idle time for which the resolver will keep data for a given entityID,
- * before it is removed.
- *
- * <p>Defaults to: 8 hours.</p>
- *
- * @param max the maximum entity data idle time
- */
- public void setMaxIdleEntityData(@Nonnull final Duration max) {
- Constraint.isNotNull(max, "Max idle time cannot be null");
- Constraint.isFalse(max.isNegative(), "Max idle time cannot be negative");
-
- maxIdleEntityData = max;
- }
-
- /**
- * Get the maximum cache duration for metadata.
- *
- * <p>Defaults to: 8 hours.</p>
- *
- * @return the maximum cache duration
- */
- @Nonnull protected Duration getMaxCacheDuration() {
- return maxCacheDuration;
- }
-
- /**
- * Set the maximum cache duration for metadata.
- *
- * <p>Defaults to: 8 hours.</p>
- *
- * @param duration the maximum cache duration
- */
- public void setMaxCacheDuration(@Nonnull final Duration duration) {
- Constraint.isNotNull(duration, "Duration cannot be null");
- Constraint.isFalse(duration.isNegative(), "Duration cannot be negative");
-
- maxCacheDuration = duration;
- }
-
- /**
- * Get the minimum cache duration for metadata.
- *
- * <p>Defaults to: 10 minutes.</p>
- *
- * @return the minimum cache duration
- */
- @Nonnull protected Duration getMinCacheDuration() {
- return minCacheDuration;
- }
-
-
- /**
- * Set the minimum cache duration for metadata.
- *
- * <p>Defaults to: 10 minutes.</p>
- *
- * @param duration the minimum cache duration
- */
- public void setMinCacheDuration(@Nonnull final Duration duration) {
- Constraint.isNotNull(duration, "Duration cannot be null");
- Constraint.isFalse(duration.isNegative(), "Duration cannot be negative");
-
- minCacheDuration = duration;
- }
-
- /**
- * Gets the delay factor used to compute the next refresh time.
- *
- * <p>Defaults to: 0.75.</p>
- *
- * @return delay factor used to compute the next refresh time
- */
- @Nonnull protected Float getRefreshDelayFactor() {
- return refreshDelayFactor;
- }
-
-
- /**
- * Sets the delay factor used to compute the next refresh time. The delay must be between 0.0 and 1.0, exclusive.
- *
- * <p>Defaults to: 0.75.</p>
- *
- * @param factor delay factor used to compute the next refresh time
- */
- public void setRefreshDelayFactor(@Nonnull final Float factor) {
-
- if (factor <= 0 || factor >= 1) {
- throw new IllegalArgumentException("Refresh delay factor must be a number between 0.0 and 1.0, exclusive");
- }
-
- refreshDelayFactor = factor;
- }
-
-}
diff --git a/oidc-common-metadata-impl/src/main/java/net/shibboleth/oidc/metadata/cache/impl/MetadataCacheBuilderSpec.java b/oidc-common-metadata-impl/src/main/java/net/shibboleth/oidc/metadata/cache/impl/MetadataCacheBuilderSpec.java
new file mode 100644
index 0000000..93df6b2
--- /dev/null
+++ b/oidc-common-metadata-impl/src/main/java/net/shibboleth/oidc/metadata/cache/impl/MetadataCacheBuilderSpec.java
@@ -0,0 +1,256 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements. See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID licenses this file to You under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package net.shibboleth.oidc.metadata.cache.impl;
+
+import java.time.Duration;
+import java.time.Instant;
+import java.util.List;
+import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
+import java.util.function.Function;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import net.shibboleth.oidc.metadata.filter.MetadataFilterContext;
+import net.shibboleth.utilities.java.support.annotation.constraint.Positive;
+import net.shibboleth.utilities.java.support.logic.Constraint;
+import net.shibboleth.utilities.java.support.logic.ConstraintViolationException;
+import net.shibboleth.utilities.java.support.resolver.CriteriaSet;
+
+public class MetadataCacheBuilderSpec<IdentifierType, MetadataType> {
+
+ /** Maximum cache duration. */
+ @Nonnull private Duration maxCacheDuration;
+
+ /** Minimum cache duration. */
+ @Nonnull private Duration minCacheDuration;
+
+ /** Factor used to compute when the next refresh interval will occur. Default value: 0.75 */
+ @Positive private Float refreshDelayFactor;
+
+ /** Strategy used to extract an identifier from the given metadata.*/
+ @Nullable private Function<MetadataType, IdentifierType> identifierExtractionStrategy;
+
+ /** Strategy used to compute an expiration time. */
+ @Nullable private BiFunction<MetadataType, Instant, Instant> metadataExpirationTimeStrategy;
+
+ /** Map criteria to identifiers to use as keys to the backing store.*/
+ @Nullable private Function<CriteriaSet, IdentifierType> criteriaToIdentifierStrategy;
+
+ /** A strategy to filter metadata. */
+ @Nonnull private BiFunction<MetadataType, MetadataFilterContext , MetadataType> metadataFilterStrategy;
+
+ /**
+ * A hook that is executed just before a cache entry will been removed/invalidated/evicted.
+ * The metadata list could be {@literal null}, the identifier is never {@literal null}.
+ */
+ @Nullable private BiConsumer<List<MetadataType>, IdentifierType> metadataBeforeRemovalHook;
+
+
+ /** Constructor.*/
+ protected MetadataCacheBuilderSpec() {
+ // defaults
+ maxCacheDuration = Duration.ofHours(8);
+ minCacheDuration = Duration.ofMinutes(10);
+ refreshDelayFactor = 0.75f;
+ // create a default direct in/out filter
+ metadataFilterStrategy = (metadata, context) -> metadata;
+
+ }
+
+
+ /**
+ * Set a hook to run before a metadata cache entry is removed from the cache.
+ * <p>The hook is required to gracefully handle null metadata lists.</p>
+ *
+ * @param hook the hook to run.
+ */
+ public void setMetadataBeforeRemovalHook(@Nullable final BiConsumer<List<MetadataType>, IdentifierType> hook) {
+ metadataBeforeRemovalHook = hook;
+ }
+
+ /**
+ * Get the metadata before removal hook. Could be {@literal null}.
+ *
+ * @return the hook.
+ */
+ @Nullable public BiConsumer<List<MetadataType>, IdentifierType> getMetadataBeforeRemovalHook() {
+ return metadataBeforeRemovalHook;
+ }
+
+ /**
+ * Set the metadata filtering strategy.
+ *
+ * <p>Defaults to a no-op strategy.</p>
+ *
+ * @param strategy the metadata filtering strategy.
+ */
+ public void setMetadataFilterStrategy(@Nonnull final BiFunction<MetadataType, MetadataFilterContext, MetadataType> strategy) {
+ metadataFilterStrategy = Constraint.isNotNull(strategy,"Metadata filtering strategy can not be null");
+ }
+
+ /**
+ * Get the metadata filter strategy.
+ *
+ * @return the metadata filtering strategy
+ */
+ @Nonnull public BiFunction<MetadataType, MetadataFilterContext, MetadataType> getMetadataFilterStrategy() {
+ return metadataFilterStrategy;
+ }
+
+
+ /**
+ * Set the identifier extraction strategy.
+ *
+ * @param strategy the strategy to set.
+ */
+ public void setIdentifierExtractionStrategy(@Nonnull final Function<MetadataType, IdentifierType> strategy) {
+ identifierExtractionStrategy = Constraint.isNotNull(strategy, "Strategy can not be null");
+ }
+
+
+ /**
+ * Get the identifier extraction strategy.
+ *
+ * @return strategy the strategy.
+ */
+ @Nullable protected Function<MetadataType, IdentifierType> getIdentifierExtractionStrategy() {
+ return identifierExtractionStrategy;
+ }
+
+ /**
+ * Set the metadata expiration time strategy.
+ *
+ * @param strategy the strategy.
+ */
+ public void setMetadataExpirationTimeStrategy(
+ @Nonnull final BiFunction<MetadataType, Instant, Instant> strategy) {
+ metadataExpirationTimeStrategy = Constraint.isNotNull(strategy, "Strategy can not be null");
+ }
+
+ /**
+ * Get the metadata expiration time strategy.
+ *
+ * @return the strategy.
+ */
+ @Nullable protected BiFunction<MetadataType, Instant, Instant> getMetadataExpirationTimeStrategy() {
+ return metadataExpirationTimeStrategy;
+ }
+
+ /**
+ * Set the criteria set to identifier lookup strategy.
+ *
+ * @param strategy the strategy to set.
+ */
+ public void setCriteriaToIdentifierStrategy(@Nonnull final Function<CriteriaSet, IdentifierType> strategy) {
+ criteriaToIdentifierStrategy =
+ Constraint.isNotNull(strategy,"Criteria to identifier strategy can not be null");
+ }
+
+ /**
+ * Get the criteria set to identifier lookup strategy.
+ *
+ * @return strategy the strategy.
+ */
+ @Nullable protected Function<CriteriaSet, IdentifierType> getCriteriaToIdentifierStrategy() {
+ return criteriaToIdentifierStrategy;
+ }
+
+
+ /**
+ * Get the maximum cache duration for metadata.
+ *
+ * <p>Defaults to: 8 hours.</p>
+ *
+ * @return the maximum cache duration
+ */
+ @Nonnull protected Duration getMaxCacheDuration() {
+ return maxCacheDuration;
+ }
+
+ /**
+ * Set the maximum cache duration for metadata.
+ *
+ * <p>Defaults to: 8 hours.</p>
+ *
+ * @param duration the maximum cache duration
+ */
+ public void setMaxCacheDuration(@Nonnull final Duration duration) {
+ Constraint.isNotNull(duration, "Duration cannot be null");
+ Constraint.isFalse(duration.isNegative(), "Duration cannot be negative");
+
+ maxCacheDuration = duration;
+ }
+
+ /**
+ * Get the minimum cache duration for metadata.
+ *
+ * <p>Defaults to: 10 minutes.</p>
+ *
+ * @return the minimum cache duration
+ */
+ @Nonnull protected Duration getMinCacheDuration() {
+ return minCacheDuration;
+ }
+
+
+ /**
+ * Set the minimum cache duration for metadata.
+ *
+ * <p>Defaults to: 10 minutes.</p>
+ *
+ * @param duration the minimum cache duration
+ */
+ public void setMinCacheDuration(@Nonnull final Duration duration) {
+ Constraint.isNotNull(duration, "Duration cannot be null");
+ Constraint.isFalse(duration.isNegative(), "Duration cannot be negative");
+
+ minCacheDuration = duration;
+ }
+
+ /**
+ * Gets the delay factor used to compute the next refresh time.
+ *
+ * <p>Defaults to: 0.75.</p>
+ *
+ * @return delay factor used to compute the next refresh time
+ */
+ @Nonnull protected Float getRefreshDelayFactor() {
+ return refreshDelayFactor;
+ }
+
+
+ /**
+ * Sets the delay factor used to compute the next refresh time. The delay must be between 0.0 and 1.0, exclusive.
+ *
+ * <p>Defaults to: 0.75.</p>
+ *
+ * @param factor delay factor used to compute the next refresh time
+ */
+ public void setRefreshDelayFactor(@Nonnull final Float factor) {
+
+ if (factor <= 0 || factor >= 1) {
+ throw new ConstraintViolationException("Refresh delay factor must be a number between 0.0 and 1.0, exclusive");
+ }
+
+ refreshDelayFactor = factor;
+ }
+
+}
diff --git a/oidc-common-metadata-impl/src/main/java/net/shibboleth/oidc/metadata/cache/impl/OIDCProviderMetadataCacheFactoryBean.java b/oidc-common-metadata-impl/src/main/java/net/shibboleth/oidc/metadata/cache/impl/OIDCProviderMetadataCacheFactoryBean.java
deleted file mode 100644
index dedfdc6..0000000
--- a/oidc-common-metadata-impl/src/main/java/net/shibboleth/oidc/metadata/cache/impl/OIDCProviderMetadataCacheFactoryBean.java
+++ /dev/null
@@ -1,83 +0,0 @@
-package net.shibboleth.oidc.metadata.cache.impl;
-
-import java.util.concurrent.atomic.AtomicInteger;
-
-import org.springframework.beans.factory.FactoryBeanNotInitializedException;
-
-import com.nimbusds.oauth2.sdk.id.Issuer;
-import com.nimbusds.openid.connect.sdk.op.OIDCProviderMetadata;
-
-import net.shibboleth.oidc.metadata.cache.MetadataCache;
-import net.shibboleth.oidc.metadata.impl.DefaultBatchBackingStore;
-import net.shibboleth.oidc.metadata.impl.DefaultDynamicBackingStore;
-
-/**
- * Factory bean to create an OIDC specific metadata cache. Either a {@link DynamicMetadataCache}
- * or {@link BatchMetadataCache} is created depending on the cache properties configured.
- */
-public class OIDCProviderMetadataCacheFactoryBean extends MetadataCacheBuilder<Issuer, OIDCProviderMetadata> {
-
-
- private final AtomicInteger cacheID;
-
- /** Constructor.*/
- public OIDCProviderMetadataCacheFactoryBean() {
- cacheID = new AtomicInteger(1);
- }
-
- @SuppressWarnings("rawtypes")
- @Override
- public Class<MetadataCache> getObjectType() {
- return MetadataCache.class;
- }
-
- @Override
- protected MetadataCache<OIDCProviderMetadata> createInstance() throws Exception {
-
- if (getCacheOperationMode() == CacheOperationMode.DYNAMIC) {
- final DynamicMetadataCache<Issuer, OIDCProviderMetadata> cache = new DynamicMetadataCache<>(
- new DefaultDynamicBackingStore<>(getMaxCacheDuration()), getFetchStrategy());
- cache.setMinCacheDuration(getMinCacheDuration());
- //FIXME what did we do with this.
- // cache.setMaxCacheDuration(getMaxCacheDuration());
- cache.setRefreshDelayFactor(getRefreshDelayFactor());
- cache.setMaxIdleEntityData(getMaxIdleEntityData());
- cache.setMetadataExpirationTimeStrategy(getMetadataExpirationTimeStrategy());
- cache.setIdentifierExtractionStrategy(getIdentifierExtractionStrategy());
- cache.setCriteriaToIdentifierStrategy(getCriteriaToIdentifierStrategy());
- cache.setCleanupTaskInterval(getCleanupTaskInterval());
- cache.setRemoveIdleEntityData(isRemoveIdleEntityData());
- cache.setInitialCleanupTaskDelay(getInitialCleanupTaskDelay());
- cache.setMetadataFilterStrategy(getMetadataFilterStrategy());
- cache.setMetadataBeforeRemovalHook(getMetadataBeforeRemovalHook());
- cache.setId("OIDCProviderDynamicMetadataCache"+cacheID.getAndIncrement());
- cache.initialize();
- return cache;
- } else if (getCacheOperationMode() == CacheOperationMode.BATCH) {
- //TODO why have the backing stores as interfaces if you are setting the concrete type here? inject somehow?
- final BatchMetadataCache<Issuer, OIDCProviderMetadata> cache =
- new BatchMetadataCache<>(
- new DefaultBatchBackingStore<>(), getLoadingStrategy(), getParsingStrategy());
- cache.setMinCacheDuration(getMinCacheDuration());
- // cache.setMaxCacheDuration(getMaxCacheDuration());
- cache.setMinRefreshDelay(getMinRefreshDelay());
- cache.setMaxRefreshDelay(getMaxRefreshDelay());
- cache.setRefreshDelayFactor(getRefreshDelayFactor());
- cache.setMetadataExpirationTimeStrategy(getMetadataExpirationTimeStrategy());
- cache.setIdentifierExtractionStrategy(getIdentifierExtractionStrategy());
- cache.setCriteriaToIdentifierStrategy(getCriteriaToIdentifierStrategy());
- cache.setMetadataFilterStrategy(getMetadataFilterStrategy());
- cache.setMetadataBeforeRemovalHook(getMetadataBeforeRemovalHook());
- cache.setId("OIDCProviderBatchMetadataCache"+cacheID.getAndIncrement());
- cache.initialize();
- return cache;
- } else {
- //should never get here.
- throw new Exception("Cache mode of operation not supported");
- }
-
- }
-
-
-
-}
diff --git a/oidc-common-metadata-impl/src/main/java/net/shibboleth/oidc/metadata/impl/OIDCProviderMetadataResolver.java b/oidc-common-metadata-impl/src/main/java/net/shibboleth/oidc/metadata/impl/JSONMapMetadataResolver.java
similarity index 76%
copy from oidc-common-metadata-impl/src/main/java/net/shibboleth/oidc/metadata/impl/OIDCProviderMetadataResolver.java
copy to oidc-common-metadata-impl/src/main/java/net/shibboleth/oidc/metadata/impl/JSONMapMetadataResolver.java
index 0c44970..fe5aaf9 100644
--- a/oidc-common-metadata-impl/src/main/java/net/shibboleth/oidc/metadata/impl/OIDCProviderMetadataResolver.java
+++ b/oidc-common-metadata-impl/src/main/java/net/shibboleth/oidc/metadata/impl/JSONMapMetadataResolver.java
@@ -17,26 +17,25 @@
package net.shibboleth.oidc.metadata.impl;
-import javax.annotation.Nonnull;
+import java.util.Map;
-import com.nimbusds.oauth2.sdk.id.Issuer;
-import com.nimbusds.openid.connect.sdk.op.OIDCProviderMetadata;
+import javax.annotation.Nonnull;
-import net.shibboleth.oidc.metadata.ProviderMetadataResolver;
+import net.shibboleth.oidc.metadata.JSONMetadataResolver;
import net.shibboleth.oidc.metadata.cache.MetadataCache;
import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
/** Concrete metadata resolver for OIDC Provider configuration metadata resolution.*/
-public class OIDCProviderMetadataResolver extends AbstractOIDCMetadataResolver<Issuer, OIDCProviderMetadata>
- implements ProviderMetadataResolver {
+public class JSONMapMetadataResolver
+ extends AbstractOIDCMetadataResolver<String, Map<String, Object>> implements JSONMetadataResolver {
/**
* Constructor.
*
* @param metadataCache the cache to hold metadata.
*/
- protected OIDCProviderMetadataResolver(
- @Nonnull final MetadataCache<OIDCProviderMetadata> metadataCache) {
+ public JSONMapMetadataResolver(
+ @Nonnull final MetadataCache<Map<String, Object>> metadataCache) {
super(metadataCache);
}
diff --git a/oidc-common-metadata-impl/src/main/java/net/shibboleth/oidc/metadata/impl/OIDCProviderMetadataResolver.java b/oidc-common-metadata-impl/src/main/java/net/shibboleth/oidc/metadata/impl/OIDCProviderMetadataResolver.java
index 0c44970..e119200 100644
--- a/oidc-common-metadata-impl/src/main/java/net/shibboleth/oidc/metadata/impl/OIDCProviderMetadataResolver.java
+++ b/oidc-common-metadata-impl/src/main/java/net/shibboleth/oidc/metadata/impl/OIDCProviderMetadataResolver.java
@@ -35,7 +35,7 @@ public class OIDCProviderMetadataResolver extends AbstractOIDCMetadataResolver<I
*
* @param metadataCache the cache to hold metadata.
*/
- protected OIDCProviderMetadataResolver(
+ public OIDCProviderMetadataResolver(
@Nonnull final MetadataCache<OIDCProviderMetadata> metadataCache) {
super(metadataCache);
diff --git a/oidc-common-metadata-impl/src/test/java/net/shibboleth/oidc/metadata/cache/impl/BatchMetadataCacheBuilderTest.java b/oidc-common-metadata-impl/src/test/java/net/shibboleth/oidc/metadata/cache/impl/BatchMetadataCacheBuilderTest.java
new file mode 100644
index 0000000..34629b3
--- /dev/null
+++ b/oidc-common-metadata-impl/src/test/java/net/shibboleth/oidc/metadata/cache/impl/BatchMetadataCacheBuilderTest.java
@@ -0,0 +1,75 @@
+package net.shibboleth.oidc.metadata.cache.impl;
+/*
+ * 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.
+ */
+
+import static org.testng.Assert.assertNotNull;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.time.Duration;
+import java.util.Collections;
+import java.util.List;
+
+import org.testng.annotations.Test;
+
+import com.nimbusds.oauth2.sdk.id.Issuer;
+import com.nimbusds.openid.connect.sdk.SubjectType;
+import com.nimbusds.openid.connect.sdk.op.OIDCProviderMetadata;
+
+import net.shibboleth.oidc.metadata.criterion.IssuerIDCriterion;
+import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
+
+public class BatchMetadataCacheBuilderTest {
+
+
+ @Test
+ public void testBatchCacheBuilder_Success() throws ComponentInitializationException {
+ var builder = new BatchMetadataCacheBuilder.Builder<Issuer, OIDCProviderMetadata>();
+
+ BatchMetadataCacheBuilderSpec<Issuer, OIDCProviderMetadata> spec = new BatchMetadataCacheBuilderSpec<>();
+ spec.setIdentifierExtractionStrategy(m -> m.getIssuer());
+ spec.setMinRefreshDelay(Duration.ofMinutes(5));
+ spec.setMaxRefreshDelay(Duration.ofMinutes(10));
+ spec.setMetadataExpirationTimeStrategy((m, time) -> time.plus(Duration.ofMinutes(5)));
+ spec.setCriteriaToIdentifierStrategy(crit -> {
+ final IssuerIDCriterion issuerId = crit.get(IssuerIDCriterion.class);
+ if (issuerId != null) {
+ return issuerId.getIssuerID();
+ }
+ return null;
+ });
+
+ spec.setRefreshDelayFactor(0.75f);
+ spec.setMinCacheDuration(Duration.ofMinutes(10));
+ // cache.setMaxCacheDuration(Duration.ofMinutes(20));
+ spec.setMetadataFilterStrategy((metadata, context) -> metadata);
+ spec.setLoadingStrategy(context -> "test".getBytes());
+ spec.setParsingStrategy(bytesIn -> {
+ try {
+ return List.of(new OIDCProviderMetadata(new Issuer("http://www.example.org"),
+ List.of(SubjectType.PUBLIC),
+ new URI("http://example.oidc.op.org")));
+ } catch (URISyntaxException e) {
+ return Collections.emptyList();
+ }
+ });
+ final BatchMetadataCache<Issuer, OIDCProviderMetadata> cache = builder.build(spec);
+ assertNotNull(cache);
+
+ }
+
+}
diff --git a/oidc-common-metadata-impl/src/test/java/net/shibboleth/oidc/metadata/cache/impl/DynamicMetadataCacheBuilderTest.java b/oidc-common-metadata-impl/src/test/java/net/shibboleth/oidc/metadata/cache/impl/DynamicMetadataCacheBuilderTest.java
new file mode 100644
index 0000000..3436572
--- /dev/null
+++ b/oidc-common-metadata-impl/src/test/java/net/shibboleth/oidc/metadata/cache/impl/DynamicMetadataCacheBuilderTest.java
@@ -0,0 +1,76 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements. See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID licenses this file to You under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.shibboleth.oidc.metadata.cache.impl;
+
+import static org.testng.Assert.assertNotNull;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.time.Duration;
+import java.util.List;
+
+import org.testng.annotations.Test;
+
+import com.nimbusds.oauth2.sdk.id.Issuer;
+import com.nimbusds.openid.connect.sdk.SubjectType;
+import com.nimbusds.openid.connect.sdk.op.OIDCProviderMetadata;
+
+import net.shibboleth.oidc.metadata.criterion.IssuerIDCriterion;
+import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
+
+public class DynamicMetadataCacheBuilderTest {
+
+
+ @Test
+ public void testDynamicCacheBuilder_Success() throws ComponentInitializationException {
+ var builder = new DynamicMetadataCacheBuilder.Builder<Issuer, OIDCProviderMetadata>();
+
+ DynamicMetadataCacheBuilderSpec<Issuer, OIDCProviderMetadata> spec = new DynamicMetadataCacheBuilderSpec<>();
+ spec.setIdentifierExtractionStrategy(m -> m.getIssuer());
+
+ spec.setMetadataExpirationTimeStrategy((m, time) -> time.plus(Duration.ofMinutes(5)));
+ spec.setCriteriaToIdentifierStrategy(crit -> {
+ final IssuerIDCriterion issuerId = crit.get(IssuerIDCriterion.class);
+ if (issuerId != null) {
+ return issuerId.getIssuerID();
+ }
+ return null;
+ });
+ spec.setCleanupTaskInterval(Duration.ofSeconds(100));
+ spec.setInitialCleanupTaskDelay(Duration.ofSeconds(1));
+ spec.setMaxIdleEntityData(Duration.ofMinutes(10));
+ spec.setRefreshDelayFactor(0.75f);
+ spec.setMinCacheDuration(Duration.ofMinutes(10));
+ // cache.setMaxCacheDuration(Duration.ofMinutes(20));
+ spec.setMetadataFilterStrategy((metadata, context) -> metadata);
+ spec.setFetchStrategy(crit -> {
+ try {
+ final Issuer iss = crit.get(IssuerIDCriterion.class).getIssuerID();
+ return new OIDCProviderMetadata(iss, List.of(SubjectType.PUBLIC),
+ new URI("http://example.oidc.op.org"));
+ } catch (URISyntaxException e) {
+ return null;
+ }
+ });
+
+ final DynamicMetadataCache<Issuer, OIDCProviderMetadata> cache = builder.build(spec);
+ assertNotNull(cache);
+
+ }
+
+}
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list