[java-oidc-common] branch main updated: JCOMOIDC-102 - Implement metadata cache loading strategy for generic resources

Henri Mikkonen henri.mikkonen at iki.fi
Fri Mar 1 14:01:44 UTC 2024


This is an automated email from the git hooks/post-receive script.

hjmikkon 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=6bcb04c53ed49f5b287e6c305bd656dc34e84f03

The following commit(s) were added to refs/heads/main by this push:
     new 6bcb04c  JCOMOIDC-102 - Implement metadata cache loading strategy for generic resources
6bcb04c is described below

commit 6bcb04c53ed49f5b287e6c305bd656dc34e84f03
Author: Henri Mikkonen <henri.mikkonen at iki.fi>
AuthorDate: Fri Mar 1 16:01:17 2024 +0200

    JCOMOIDC-102 - Implement metadata cache loading strategy for generic resources
    
    https://shibboleth.atlassian.net/browse/JCOMOIDC-102
    
    New DefaultResourceLoadingStrategy can be used with non-File resources.
    Added new buildResourceLoadingMetadataPolicyResolver method to MetadataPolicyLookupStrategyFactory.
---
 .../cache/impl/DefaultResourceLoadingStrategy.java | 99 ++++++++++++++++++++++
 .../impl/MetadataPolicyLookupStrategyFactory.java  | 67 +++++++++++++--
 .../MetadataPolicyLookupStrategyFactoryTest.java   | 10 ++-
 3 files changed, 168 insertions(+), 8 deletions(-)

diff --git a/oidc-common-metadata-impl/src/main/java/net/shibboleth/oidc/metadata/cache/impl/DefaultResourceLoadingStrategy.java b/oidc-common-metadata-impl/src/main/java/net/shibboleth/oidc/metadata/cache/impl/DefaultResourceLoadingStrategy.java
new file mode 100644
index 0000000..231cfde
--- /dev/null
+++ b/oidc-common-metadata-impl/src/main/java/net/shibboleth/oidc/metadata/cache/impl/DefaultResourceLoadingStrategy.java
@@ -0,0 +1,99 @@
+/*
+ * Licensed 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.io.IOException;
+import java.time.Instant;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import javax.annotation.concurrent.ThreadSafe;
+
+import org.slf4j.Logger;
+import org.springframework.core.io.Resource;
+
+import net.shibboleth.oidc.metadata.cache.CacheLoadingContext;
+import net.shibboleth.oidc.metadata.cache.CacheLoadingException;
+import net.shibboleth.oidc.metadata.cache.LoadingStrategy;
+import net.shibboleth.shared.annotation.constraint.NotEmpty;
+import net.shibboleth.shared.primitive.LoggerFactory;
+
+/** Default strategy for loading information from a resource.*/
+ at ThreadSafe
+public class DefaultResourceLoadingStrategy implements LoadingStrategy {
+    
+    /** Class logger. */
+    @Nonnull private final Logger log = LoggerFactory.getLogger(DefaultResourceLoadingStrategy.class);
+    
+    /** The metadata resource. */
+    @Nullable private final Resource metadataResource;
+    
+    /** The metadata resource name to use in logs. */
+    @Nonnull @NotEmpty private final String metadataResourceFriendlyName;
+    
+    /**
+     * 
+     * Constructor.
+     *
+     * @param metadata the metadata resource. Can be {@literal null}.
+     */
+    public DefaultResourceLoadingStrategy(@Nullable final Resource metadata) {
+       if (metadata == null) {
+           log.warn("Resource is null, no bytes will be returned");
+           metadataResource = null;
+           metadataResourceFriendlyName = "No resource specified";
+       } else {
+           metadataResource = metadata;
+           metadataResourceFriendlyName = metadata.getDescription();
+       }
+    }
+    
+    /**
+     * Get the time for the last update/modification of the metadata resource.
+     * @return The last update time.
+     * @throws IOException if the time cannot be fetched.
+     */
+    @Nullable private Instant getMetadataUpdateTime() throws IOException {
+        return metadataResource != null ? Instant.ofEpochMilli(metadataResource.lastModified()) : null;
+    }
+
+    /** {@inheritDoc} */
+    @Nullable public byte[] load(@Nonnull final CacheLoadingContext context) throws CacheLoadingException {
+        
+        if (metadataResource == null) {
+            return null;
+        }
+        
+        try {
+            final Instant metadataUpdateTime = getMetadataUpdateTime();
+            if (context.getLastRefresh() == null || context.getLastUpdate() == null || metadataUpdateTime == null ||
+                    metadataUpdateTime.isAfter(context.getLastRefresh())) {
+                assert metadataResource != null;
+                return metadataResource.getContentAsByteArray();
+            }
+            return null;
+        } catch (final Exception e) {
+            final String errMsg = "Unable to read metadata resource " + metadataResource;
+            log.error(errMsg, e.getMessage());
+            throw new CacheLoadingException(errMsg, e);
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Nonnull public String getSourceIdentifier() {
+       return metadataResourceFriendlyName;
+    }
+
+}
\ No newline at end of file
diff --git a/oidc-common-metadata-impl/src/main/java/net/shibboleth/oidc/metadata/cache/impl/MetadataPolicyLookupStrategyFactory.java b/oidc-common-metadata-impl/src/main/java/net/shibboleth/oidc/metadata/cache/impl/MetadataPolicyLookupStrategyFactory.java
index 49a7909..667caed 100644
--- a/oidc-common-metadata-impl/src/main/java/net/shibboleth/oidc/metadata/cache/impl/MetadataPolicyLookupStrategyFactory.java
+++ b/oidc-common-metadata-impl/src/main/java/net/shibboleth/oidc/metadata/cache/impl/MetadataPolicyLookupStrategyFactory.java
@@ -26,6 +26,7 @@ import org.opensaml.profile.context.ProfileRequestContext;
 import org.springframework.core.io.Resource;
 import org.springframework.core.io.ResourceLoader;
 
+import net.shibboleth.oidc.metadata.cache.LoadingStrategy;
 import net.shibboleth.oidc.metadata.cache.MetadataCache;
 import net.shibboleth.oidc.metadata.policy.MetadataPolicy;
 import net.shibboleth.oidc.metadata.policy.MetadataPolicyResolver;
@@ -69,17 +70,69 @@ public class MetadataPolicyLookupStrategyFactory {
             final Function<ProfileRequestContext, CriteriaSet> criteriaSetLookupStrategy,
             @ParameterName(name="id") @Nonnull final String id) throws ComponentInitializationException, IOException{
         
-        final MetadataCacheBuilder.Builder<String, Map<String, MetadataPolicy>> builder = 
-                new MetadataCacheBuilder.Builder<>();
-        
         Resource fileResource = null;
         if (resource != null && !resource.isEmpty()) {
             final ResourceLoader resourceLoader = new PreferFileSystemResourceLoader();
             fileResource = resourceLoader.getResource(resource);
         }
+        @Nonnull final DefaultFileLoadingStrategy fileStrategy = new DefaultFileLoadingStrategy(fileResource);
+        return buildMetadataPolicyResolver(fileStrategy, cacheSpec, criteriaSetLookupStrategy, id);
+        
+    }
+
+    /**
+     * Build a Function that maps a profile request context to a map of metadata policies. The map is resolved
+     * from a newly instantiated {@link MetadataPolicyResolver}. The Resolver calls a new {@link BatchMetadataCache}
+     * which is hard-wired to use a default file loading strategy with the file resource supplied.
+     * 
+     * @param resource the resource to inject into the loading strategy. Can be null or empty.
+     * @param cacheSpec the metadata cache specification
+     * @param criteriaSetLookupStrategy the lookup strategy for the criteria set used for the metadata policy resolver.
+     * @param id the identifier/name for the back-end cache created
+     * 
+     * @return the function
+     * 
+     * @throws ComponentInitializationException on error.
+     * @throws IOException on error.
+     */
+    @Nonnull
+    public Function<ProfileRequestContext,Map<String,MetadataPolicy>> buildResourceLoadingMetadataPolicyResolver(
+            @ParameterName(name="resource") @Nullable final Resource resource,
+            @ParameterName(name="cacheSpec") @Nonnull 
+            final BatchMetadataCacheBuilderSpec<String, Map<String, MetadataPolicy>> cacheSpec,
+            @ParameterName(name="criteriaSetLookupStrategy") @Nullable 
+            final Function<ProfileRequestContext, CriteriaSet> criteriaSetLookupStrategy,
+            @ParameterName(name="id") @Nonnull final String id) throws ComponentInitializationException, IOException{
         
-        final DefaultFileLoadingStrategy fileStrategy = new DefaultFileLoadingStrategy(fileResource);
-        cacheSpec.setLoadingStrategy(fileStrategy);
+        @Nonnull final DefaultResourceLoadingStrategy resourceStrategy = new DefaultResourceLoadingStrategy(resource);
+        return buildMetadataPolicyResolver(resourceStrategy, cacheSpec, criteriaSetLookupStrategy, id);
+    }
+
+    /**
+     * Build a Function that maps a profile request context to a map of metadata policies. The map is resolved
+     * from a newly instantiated {@link MetadataPolicyResolver}. The Resolver calls a new {@link BatchMetadataCache}
+     * which is hard-wired to use a default file loading strategy with the file resource supplied.
+     * 
+     * @param loadingStrategy the loading strategy containing the metadata resource.
+     * @param cacheSpec the metadata cache specification
+     * @param criteriaSetLookupStrategy the lookup strategy for the criteria set used for the metadata policy resolver.
+     * @param id the identifier/name for the back-end cache created
+     * 
+     * @return the function
+     * 
+     * @throws ComponentInitializationException on error.
+     * @throws IOException on error.
+     */
+    @Nonnull protected Function<ProfileRequestContext,Map<String,MetadataPolicy>> buildMetadataPolicyResolver(
+            @Nonnull final LoadingStrategy loadingStrategy,
+            @Nonnull final BatchMetadataCacheBuilderSpec<String, Map<String, MetadataPolicy>> cacheSpec,
+            @Nullable  final Function<ProfileRequestContext, CriteriaSet> criteriaSetLookupStrategy,
+            @Nonnull final String id) throws ComponentInitializationException, IOException {
+
+        final MetadataCacheBuilder.Builder<String, Map<String, MetadataPolicy>> builder = 
+                new MetadataCacheBuilder.Builder<>();
+
+        cacheSpec.setLoadingStrategy(loadingStrategy);
         cacheSpec.setCacheId(id + "-cache");
 
         final MetadataCache<Map<String, MetadataPolicy>> cache = builder.build(cacheSpec);
@@ -94,7 +147,7 @@ public class MetadataPolicyLookupStrategyFactory {
         function.setCriteriaSetLookupStrategy(criteriaSetLookupStrategy);
 
         return function;
-        
+
     }
-    
+        
 }
\ No newline at end of file
diff --git a/oidc-common-metadata-impl/src/test/java/net/shibboleth/oidc/metadata/cache/impl/MetadataPolicyLookupStrategyFactoryTest.java b/oidc-common-metadata-impl/src/test/java/net/shibboleth/oidc/metadata/cache/impl/MetadataPolicyLookupStrategyFactoryTest.java
index 4ffa079..67af301 100644
--- a/oidc-common-metadata-impl/src/test/java/net/shibboleth/oidc/metadata/cache/impl/MetadataPolicyLookupStrategyFactoryTest.java
+++ b/oidc-common-metadata-impl/src/test/java/net/shibboleth/oidc/metadata/cache/impl/MetadataPolicyLookupStrategyFactoryTest.java
@@ -76,7 +76,15 @@ public class MetadataPolicyLookupStrategyFactoryTest {
                 factory.buildFileLoadingMetadataPolicyResolver(null,spec, null, "Mock");
         assertNotNull(createdFunction);
     }
-    
+
+    /* Test the factory creates the function correctly. Not throwing an exception is likely enough to test this.*/
+    @Test
+    public void testFactoryBuild_ResourceBased_Success() throws ComponentInitializationException, IOException {
+        final var createdFunction = 
+                factory.buildResourceLoadingMetadataPolicyResolver(null,spec, null, "Mock");
+        assertNotNull(createdFunction);
+    }
+
     @Test
     public void testXMLDefinitionLoads() {
         final GenericXmlApplicationContext context = new GenericXmlApplicationContext();

-- 
To stop receiving notification emails like this one, please contact
the administrator of this repository.


More information about the commits mailing list