[java-oidc-common] branch main updated: Add basic strategies for loading and parsing file based metadata
Phil Smart
philip.smart at jisc.ac.uk
Thu Oct 21 10:31:38 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=264cf79ee1e8df3ba28d025d590ae2ff3e8dd7bc
The following commit(s) were added to refs/heads/main by this push:
new 264cf79 Add basic strategies for loading and parsing file based metadata
264cf79 is described below
commit 264cf79ee1e8df3ba28d025d590ae2ff3e8dd7bc
Author: Phil Smart <philip.smart at jisc.ac.uk>
AuthorDate: Thu Oct 21 11:31:35 2021 +0100
Add basic strategies for loading and parsing file based metadata
---
.../metadata/cache/impl/AbstractMetadataCache.java | 16 +++---
.../metadata/cache/impl/BatchMetadataCache.java | 7 ++-
.../cache/impl/DefaultFileLoadingStrategy.java | 64 ++++++++++++++++++++++
...DefaultOIDCProviderMetadataParsingStrategy.java | 38 +++++++++++++
.../impl/OIDCProviderMetadataCacheFactoryBean.java | 29 +++++++++-
5 files changed, 140 insertions(+), 14 deletions(-)
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 ac9a00e..fc6b8cc 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
@@ -31,7 +31,6 @@ import java.util.function.Function;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
-import javax.annotation.concurrent.ThreadSafe;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -67,7 +66,6 @@ import net.shibboleth.utilities.java.support.resolver.CriteriaSet;
* @param <MetadataType> the metadata type
*/
//TODO do not set a maximum cache size? make eviction harder
- at ThreadSafe
public abstract class AbstractMetadataCache<IdentifierType, MetadataType>
extends AbstractIdentifiableInitializableComponent implements MetadataCache<MetadataType> {
@@ -91,7 +89,6 @@ public abstract class AbstractMetadataCache<IdentifierType, MetadataType>
/**
* A hook that is executed just before a cache entry will been removed/invalidated/evicted.
- * The metadata list could be null, the identifier is never null.
*/
@Nullable private BiConsumer<List<MetadataType>, IdentifierType> metadataBeforeRemovalHook;
@@ -481,14 +478,15 @@ public abstract class AbstractMetadataCache<IdentifierType, MetadataType>
protected void invalidate(@Nonnull final IdentifierType identifier) {
final Map<IdentifierType, List<MetadataType>> indexedDescriptors = backingStore.getIndexedValues();
final List<MetadataType> descriptors = indexedDescriptors.get(identifier);
- if (metadataBeforeRemovalHook != null) {
- // descriptors is nullable.
- metadataBeforeRemovalHook.accept(descriptors, identifier);
- }
- if (descriptors != null) {
+
+ if (descriptors != null) {
+ if (metadataBeforeRemovalHook != null) {
+ metadataBeforeRemovalHook.accept(descriptors, identifier);
+ }
backingStore.getOrderedValues().removeAll(descriptors);
+ indexedDescriptors.remove(identifier);
}
- indexedDescriptors.remove(identifier);
+
}
/**
diff --git a/oidc-common-metadata-impl/src/main/java/net/shibboleth/oidc/metadata/cache/impl/BatchMetadataCache.java b/oidc-common-metadata-impl/src/main/java/net/shibboleth/oidc/metadata/cache/impl/BatchMetadataCache.java
index 17d248b..06522c5 100644
--- a/oidc-common-metadata-impl/src/main/java/net/shibboleth/oidc/metadata/cache/impl/BatchMetadataCache.java
+++ b/oidc-common-metadata-impl/src/main/java/net/shibboleth/oidc/metadata/cache/impl/BatchMetadataCache.java
@@ -64,12 +64,11 @@ public class BatchMetadataCache<IdentifierType, MetadataType>
private final Logger log = LoggerFactory.getLogger(BatchMetadataCache.class);
/**
- * Refresh interval used when metadata does not contain any validUntil or cacheDuration information. Default value:
- * 4 hours
+ * Refresh interval used when metadata does not contain any validUntil or cacheDuration information.
*/
@NonnullAfterInit @Positive private Duration maxRefreshDelay;
- /** Floor, in milliseconds, for the refresh interval. Default value: 5 minutes */
+ /** Floor, in milliseconds, for the refresh interval. */
@NonnullAfterInit @Positive private Duration minRefreshDelay;
/** The function to use to load metadata.*/
@@ -237,6 +236,8 @@ public class BatchMetadataCache<IdentifierType, MetadataType>
t.getClass().getName(), t.getMessage()));
}
} finally {
+ // TODO compute refresh time from metadata using a function
+
scheduleNextRefresh(refreshDelay);
getBackingStore().setLastRefresh(now);
}
diff --git a/oidc-common-metadata-impl/src/main/java/net/shibboleth/oidc/metadata/cache/impl/DefaultFileLoadingStrategy.java b/oidc-common-metadata-impl/src/main/java/net/shibboleth/oidc/metadata/cache/impl/DefaultFileLoadingStrategy.java
new file mode 100644
index 0000000..63f7e08
--- /dev/null
+++ b/oidc-common-metadata-impl/src/main/java/net/shibboleth/oidc/metadata/cache/impl/DefaultFileLoadingStrategy.java
@@ -0,0 +1,64 @@
+package net.shibboleth.oidc.metadata.cache.impl;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.time.Instant;
+import java.util.function.Function;
+
+import javax.annotation.Nonnull;
+import javax.annotation.concurrent.ThreadSafe;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.core.io.Resource;
+
+import net.shibboleth.oidc.metadata.cache.CacheLoadingContext;
+import net.shibboleth.oidc.metadata.impl.ResolverHelper;
+import net.shibboleth.utilities.java.support.logic.Constraint;
+import net.shibboleth.utilities.java.support.resolver.ResolverException;
+
+/** Default strategy for loading information from a file.*/
+ at ThreadSafe
+public class DefaultFileLoadingStrategy implements Function<CacheLoadingContext, byte[]> {
+
+ /** Class logger. */
+ @Nonnull private final Logger log = LoggerFactory.getLogger(DefaultFileLoadingStrategy.class);
+
+ /** The metadata file. */
+ @Nonnull private final File metadataFile;
+
+ public DefaultFileLoadingStrategy(@Nonnull final Resource metadata) throws IOException {
+ Constraint.isNotNull(metadata, "The metadata file can not be null");
+ metadataFile = metadata.getFile();
+ }
+
+ /**
+ * Get the time for the last update/modification of the metadata file.
+ * @return The last update time.
+ */
+ private Instant getMetadataUpdateTime() {
+ return Instant.ofEpochMilli(metadataFile.lastModified());
+ }
+
+ @Override
+ public byte[] apply(@Nonnull final CacheLoadingContext context) {
+ try {
+ ResolverHelper.validateMetadataFile(metadataFile);
+ final Instant metadataUpdateTime = getMetadataUpdateTime();
+ if (context.getLastRefresh() == null || context.getLastUpdate() == null ||
+ metadataUpdateTime.isAfter(context.getLastRefresh())) {
+ log.debug("Returning the contents of {} as byte array", metadataFile.toPath());
+ return ResolverHelper.inputstreamToByteArray(new FileInputStream(metadataFile));
+ }
+ return null;
+ } catch (final IOException | ResolverException e) {
+ final String errMsg = "Unable to read metadata file " + metadataFile.getAbsolutePath();
+ log.error(errMsg, e);
+ // FIXME we need an exception really.
+ //throw new MetadataCacheException(errMsg, e);
+ return null;
+ }
+ }
+
+}
diff --git a/oidc-common-metadata-impl/src/main/java/net/shibboleth/oidc/metadata/cache/impl/DefaultOIDCProviderMetadataParsingStrategy.java b/oidc-common-metadata-impl/src/main/java/net/shibboleth/oidc/metadata/cache/impl/DefaultOIDCProviderMetadataParsingStrategy.java
new file mode 100644
index 0000000..6148cf0
--- /dev/null
+++ b/oidc-common-metadata-impl/src/main/java/net/shibboleth/oidc/metadata/cache/impl/DefaultOIDCProviderMetadataParsingStrategy.java
@@ -0,0 +1,38 @@
+package net.shibboleth.oidc.metadata.cache.impl;
+
+import java.nio.charset.StandardCharsets;
+import java.util.Collections;
+import java.util.List;
+import java.util.function.Function;
+
+import javax.annotation.Nonnull;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.nimbusds.oauth2.sdk.ParseException;
+import com.nimbusds.openid.connect.sdk.op.OIDCProviderMetadata;
+
+/** Parse a raw byte array into a *single* OIDCProviderMetadata object.*/
+public class DefaultOIDCProviderMetadataParsingStrategy implements Function<byte[], List<OIDCProviderMetadata>> {
+
+ /** Class logger. */
+ @Nonnull private final Logger log = LoggerFactory.getLogger(DefaultOIDCProviderMetadataParsingStrategy.class);
+
+ @Override
+ @Nonnull public List<OIDCProviderMetadata> apply(@Nonnull final byte[] rawMetdata) {
+
+ try {
+ final OIDCProviderMetadata metadata =
+ OIDCProviderMetadata.parse(new String(rawMetdata,StandardCharsets.UTF_8));
+ if (metadata != null) {
+ return List.of(metadata);
+ }
+ return Collections.emptyList();
+ } catch (ParseException e) {
+ log.error("Error parsing bytes to metadata", e);
+ return Collections.emptyList();
+ }
+ }
+
+}
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
index dda0be5..eeea722 100644
--- 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
@@ -1,5 +1,9 @@
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;
@@ -12,12 +16,33 @@ import net.shibboleth.oidc.metadata.impl.DefaultDynamicBackingStore;
* 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;
}
+
+ /**
+ * {@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();
+ }
@Override
protected MetadataCache<OIDCProviderMetadata> createInstance() throws Exception {
@@ -38,7 +63,7 @@ public class OIDCProviderMetadataCacheFactoryBean extends MetadataCacheBuilder<I
cache.setInitialCleanupTaskDelay(getInitialCleanupTaskDelay());
cache.setMetadataFilterStrategy(getMetadataFilterStrategy());
cache.setMetadataBeforeRemovalHook(getMetadataBeforeRemovalHook());
- cache.setId("OIDCProviderDynamicMetadataCache");
+ cache.setId("OIDCProviderDynamicMetadataCache"+cacheID.getAndIncrement());
cache.initialize();
return cache;
} else if (getCacheOperationMode() == CacheOperationMode.BATCH) {
@@ -56,7 +81,7 @@ public class OIDCProviderMetadataCacheFactoryBean extends MetadataCacheBuilder<I
cache.setCriteriaToIdentifierStrategy(getCriteriaToIdentifierStrategy());
cache.setMetadataFilterStrategy(getMetadataFilterStrategy());
cache.setMetadataBeforeRemovalHook(getMetadataBeforeRemovalHook());
- cache.setId("OIDCProviderBatchMetadataCache");
+ cache.setId("OIDCProviderBatchMetadataCache"+cacheID.getAndIncrement());
cache.initialize();
return cache;
} else {
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list