[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