This is an automated email from the ASF dual-hosted git repository.

ctubbsii pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/accumulo-classloaders.git


The following commit(s) were added to refs/heads/main by this push:
     new 2040075  Add allowed URLs security property (#55)
2040075 is described below

commit 204007565085030ad1b4fc6c6a72378f115d28aa
Author: Christopher Tubbs <[email protected]>
AuthorDate: Fri Jan 30 19:15:46 2026 -0500

    Add allowed URLs security property (#55)
    
    To mitigate the risks of file disclosure vulnerabilities, a property is
    added to ensure the library cannot copy data from unapproved sources,
    into the local cache directory.
---
 modules/local-caching-classloader/README.md        | 28 +++++++-
 .../lcc/LocalCachingContextClassLoaderFactory.java | 37 ++++++++++-
 .../accumulo/classloader/lcc/util/LocalStore.java  | 11 +++-
 .../LocalCachingContextClassLoaderFactoryTest.java | 75 ++++++++++++++++------
 .../MiniAccumuloClusterClassLoaderFactoryTest.java |  2 +
 .../classloader/lcc/util/LocalStoreTest.java       | 25 +++++---
 6 files changed, 142 insertions(+), 36 deletions(-)

diff --git a/modules/local-caching-classloader/README.md 
b/modules/local-caching-classloader/README.md
index a624386..988e947 100644
--- a/modules/local-caching-classloader/README.md
+++ b/modules/local-caching-classloader/README.md
@@ -111,8 +111,8 @@ exist in the de-duplicating cache).
 ## Local Storage Cache
 
 The local storage cache location is configured by the user by setting the
-Accumulo property named `general.custom.classloader.lcc.cache.dir` to a
-directory on the local filesystem. This location may be specified as an
+required Accumulo property named `general.custom.classloader.lcc.cache.dir` to
+a directory on the local filesystem. This location may be specified as an
 absolute path or as a URL representing an absolute path with the `file` scheme.
 
 The selected location should be a persistent location with plenty of space to
@@ -131,6 +131,29 @@ unexpected behavior to classloaders still using the file.
 * The local storage cache location **MUST** use a filesystem that supports
   atomic moves.
 
+## Security
+
+The Accumulo property `general.custom.classloader.lcc.allowed.urls.pattern` is
+another required parameter. It is used to limit the allowed URLs that can be
+fetched when downloading context definitions or context resources. Since the
+process using this factory will be using its own permissions to fetch
+resources, and placing a copy of those resources in a local directory where
+others may access them, that presents presents a potential file disclosure
+security risk. This property allows a system administrator to mitigate that
+risk by restricting access to only approved URLs. (e.g. to exclude non-approved
+locations like `file:/path/to/accumulo.properties` or
+`hdfs://host/path/to/accumulo/rfile.rf`).
+
+An example value for this property might look like:
+`https://example.com/path/to/contexts/.*` or
+`(file:/etc|hdfs://example[.]com:9000)/path/to/contexts/.*`
+
+Note: this property affects all URLs fetched by this factory, including context
+definition URLs and any resource URLs defined inside any fetched context
+definition. It should be updated by a system maintainer if any new context
+definitions have need to use new locations. It may be updated on a running
+system, and will take effect after approximately a minute.
+
 ## Creating a ContextDefinition file
 
 Users may take advantage of the `ContextDefinition.create(int,String,URL[])`
@@ -224,6 +247,7 @@ To use this with Accumulo:
 1. Set the following Accumulo properties:
    * 
`general.context.class.loader.factory=org.apache.accumulo.classloader.lcc.LocalCachingContextClassLoaderFactory`
    * `general.custom.classloader.lcc.cache.dir=file://path/to/some/directory`
+   * 
`general.custom.classloader.lcc.allowed.urls.pattern=someRegexPatternForAllowedUrls`
 2. Set the following table property to link to a context definition file. For 
example:
    * 
`table.class.loader.context=(file|hdfs|http|https)://path/to/context/definition.json`
 
diff --git 
a/modules/local-caching-classloader/src/main/java/org/apache/accumulo/classloader/lcc/LocalCachingContextClassLoaderFactory.java
 
b/modules/local-caching-classloader/src/main/java/org/apache/accumulo/classloader/lcc/LocalCachingContextClassLoaderFactory.java
index dd232c1..f0d54b0 100644
--- 
a/modules/local-caching-classloader/src/main/java/org/apache/accumulo/classloader/lcc/LocalCachingContextClassLoaderFactory.java
+++ 
b/modules/local-caching-classloader/src/main/java/org/apache/accumulo/classloader/lcc/LocalCachingContextClassLoaderFactory.java
@@ -37,7 +37,9 @@ import java.util.concurrent.Executors;
 import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicReference;
+import java.util.function.BiConsumer;
 import java.util.function.Supplier;
+import java.util.regex.Pattern;
 
 import javax.management.InstanceAlreadyExistsException;
 import javax.management.MBeanRegistrationException;
@@ -59,6 +61,7 @@ import org.slf4j.LoggerFactory;
 
 import com.google.common.base.Preconditions;
 import com.google.common.base.Stopwatch;
+import com.google.common.base.Suppliers;
 
 /**
  * A ContextClassLoaderFactory implementation that creates and maintains a 
ClassLoader for a context
@@ -77,7 +80,8 @@ import com.google.common.base.Stopwatch;
  * resource URL and caches it in a directory on the local filesystem. This 
class uses the value of
  * the property {@link #CACHE_DIR_PROPERTY} passed via {@link 
#init(ContextClassLoaderEnvironment)}
  * as the root directory and creates a sub-directory for context definition 
files, and another for
- * resource files. All cached files have a name that includes their checksum.
+ * resource files. All cached files have a name that includes their checksum. 
The required property,
+ * {@link #ALLOWED_URLS_PATTERN}, is used to specify a pattern for allowed 
URLs to be fetched.
  * <p>
  * An in-progress signal file is used for each resource file while it is being 
downloaded, to allow
  * multiple processes or threads to try to avoid redundant downloads. Atomic 
filesystem moves are
@@ -94,6 +98,9 @@ public class LocalCachingContextClassLoaderFactory implements 
ContextClassLoader
   public static final String UPDATE_FAILURE_GRACE_PERIOD_MINS =
       "general.custom.classloader.lcc.update.grace.minutes";
 
+  public static final String ALLOWED_URLS_PATTERN =
+      "general.custom.classloader.lcc.allowed.urls.pattern";
+
   private static final Logger LOG =
       LoggerFactory.getLogger(LocalCachingContextClassLoaderFactory.class);
 
@@ -114,6 +121,9 @@ public class LocalCachingContextClassLoaderFactory 
implements ContextClassLoader
   private final Map<String,Stopwatch> classloaderFailures = new HashMap<>();
   private volatile Duration updateFailureGracePeriodMins;
 
+  // this is a BiConsumer so we can pass a type in the String
+  private volatile BiConsumer<String,URL> allowedUrlChecker;
+
   /**
    * Schedule a task to execute at {@code interval} seconds to update the 
LocalCachingContext if the
    * ContextDefinition has changed. The task schedules a follow-on task at the 
update interval value
@@ -144,6 +154,26 @@ public class LocalCachingContextClassLoaderFactory 
implements ContextClassLoader
     String graceProp = 
env.getConfiguration().get(UPDATE_FAILURE_GRACE_PERIOD_MINS);
     long graceMins = graceProp == null ? 0 : Long.parseLong(graceProp);
     updateFailureGracePeriodMins = Duration.ofMinutes(graceMins);
+    // limit the frequency at which we check the config and re-compile the 
pattern
+    Supplier<Pattern> allowedUrlsPattern = Suppliers.memoizeWithExpiration(
+        () -> 
Pattern.compile(requireNonNull(env.getConfiguration().get(ALLOWED_URLS_PATTERN),
+            "Property " + ALLOWED_URLS_PATTERN + " not set, no URLs are 
allowed")),
+        Duration.ofMinutes(1));
+    allowedUrlChecker = (locationType, url) -> {
+      var p = allowedUrlsPattern.get();
+      Preconditions.checkArgument(p.matcher(url.toExternalForm()).matches(),
+          "%s location (%s) not allowed by pattern (%s)", locationType, 
url.toExternalForm(),
+          p.pattern());
+    };
+    try {
+      // check the allowed URLs pattern, getting it ready for first use, and 
warning if it is bad
+      allowedUrlsPattern.get();
+    } catch (RuntimeException npe) {
+      LOG.warn(
+          "Property {} is not set or contains an invalid pattern ()."
+              + " No ClassLoader instances will be created until it is set.",
+          ALLOWED_URLS_PATTERN, 
env.getConfiguration().get(ALLOWED_URLS_PATTERN), npe);
+    }
     final Path baseCacheDir;
     if (value.startsWith("file:")) {
       try {
@@ -159,7 +189,7 @@ public class LocalCachingContextClassLoaderFactory 
implements ContextClassLoader
           "Base directory is neither a file URL nor an absolute file path: " + 
value);
     }
     try {
-      localStore.set(new LocalStore(baseCacheDir));
+      localStore.set(new LocalStore(baseCacheDir, allowedUrlChecker));
     } catch (IOException e) {
       throw new UncheckedIOException("Unable to create the local storage area 
at " + baseCacheDir,
           e);
@@ -225,9 +255,10 @@ public class LocalCachingContextClassLoaderFactory 
implements ContextClassLoader
     return computedDefinition;
   }
 
-  private static ContextDefinition getDefinition(String contextLocation) 
throws IOException {
+  private ContextDefinition getDefinition(String contextLocation) throws 
IOException {
     LOG.trace("Retrieving context definition file from {}", contextLocation);
     URL url = new URL(contextLocation);
+    allowedUrlChecker.accept("Context definition", url);
     return ContextDefinition.fromRemoteURL(url);
   }
 
diff --git 
a/modules/local-caching-classloader/src/main/java/org/apache/accumulo/classloader/lcc/util/LocalStore.java
 
b/modules/local-caching-classloader/src/main/java/org/apache/accumulo/classloader/lcc/util/LocalStore.java
index 81cedad..40a143a 100644
--- 
a/modules/local-caching-classloader/src/main/java/org/apache/accumulo/classloader/lcc/util/LocalStore.java
+++ 
b/modules/local-caching-classloader/src/main/java/org/apache/accumulo/classloader/lcc/util/LocalStore.java
@@ -46,6 +46,7 @@ import java.util.concurrent.ExecutionException;
 import java.util.concurrent.FutureTask;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
+import java.util.function.BiConsumer;
 import java.util.regex.Pattern;
 
 import org.apache.accumulo.classloader.lcc.definition.ContextDefinition;
@@ -91,10 +92,13 @@ public final class LocalStore {
 
   private final Path contextsDir;
   private final Path resourcesDir;
+  private final BiConsumer<String,URL> allowedUrlChecker;
 
-  public LocalStore(final Path baseDir) throws IOException {
+  public LocalStore(final Path baseDir, final BiConsumer<String,URL> 
allowedUrlChecker)
+      throws IOException {
     this.contextsDir = 
requireNonNull(baseDir).toAbsolutePath().resolve("contexts");
     this.resourcesDir = baseDir.resolve("resources");
+    this.allowedUrlChecker = requireNonNull(allowedUrlChecker);
     Files.createDirectories(contextsDir);
     Files.createDirectories(resourcesDir);
   }
@@ -301,10 +305,13 @@ public final class LocalStore {
   @SuppressFBWarnings(value = "URLCONNECTION_SSRF_FD",
       justification = "user-supplied URL is the intended functionality")
   private void downloadFile(Path tempPath, Resource resource) {
+    URL url = resource.getLocation();
+    allowedUrlChecker.accept("Resource", url);
+
     // CREATE_NEW ensures the temporary file name is unique for this attempt
     // SYNC ensures file integrity on each write, in case of system failure. 
Buffering minimizes
     // system calls te read/write data which minimizes the number of syncs.
-    try (var in = new BufferedInputStream(resource.getLocation().openStream(), 
DL_BUFF_SIZE);
+    try (var in = new BufferedInputStream(url.openStream(), DL_BUFF_SIZE);
         var out = new BufferedOutputStream(Files.newOutputStream(tempPath, 
CREATE_NEW, WRITE, SYNC),
             DL_BUFF_SIZE)) {
       in.transferTo(out);
diff --git 
a/modules/local-caching-classloader/src/test/java/org/apache/accumulo/classloader/lcc/LocalCachingContextClassLoaderFactoryTest.java
 
b/modules/local-caching-classloader/src/test/java/org/apache/accumulo/classloader/lcc/LocalCachingContextClassLoaderFactoryTest.java
index 72d8824..8354376 100644
--- 
a/modules/local-caching-classloader/src/test/java/org/apache/accumulo/classloader/lcc/LocalCachingContextClassLoaderFactoryTest.java
+++ 
b/modules/local-caching-classloader/src/test/java/org/apache/accumulo/classloader/lcc/LocalCachingContextClassLoaderFactoryTest.java
@@ -18,6 +18,7 @@
  */
 package org.apache.accumulo.classloader.lcc;
 
+import static 
org.apache.accumulo.classloader.lcc.LocalCachingContextClassLoaderFactory.ALLOWED_URLS_PATTERN;
 import static 
org.apache.accumulo.classloader.lcc.LocalCachingContextClassLoaderFactory.CACHE_DIR_PROPERTY;
 import static 
org.apache.accumulo.classloader.lcc.LocalCachingContextClassLoaderFactory.UPDATE_FAILURE_GRACE_PERIOD_MINS;
 import static 
org.apache.accumulo.classloader.lcc.TestUtils.createContextDefinitionFile;
@@ -168,11 +169,53 @@ public class LocalCachingContextClassLoaderFactoryTest {
   public void beforeEach() throws Exception {
     baseCacheDir = tempDir.resolve("base");
     ConfigurationCopy acuConf = new ConfigurationCopy(
-        Map.of(CACHE_DIR_PROPERTY, 
baseCacheDir.toAbsolutePath().toUri().toURL().toExternalForm()));
+        Map.of(CACHE_DIR_PROPERTY, 
baseCacheDir.toAbsolutePath().toUri().toURL().toExternalForm(),
+            UPDATE_FAILURE_GRACE_PERIOD_MINS, "1", ALLOWED_URLS_PATTERN, 
".*"));
     FACTORY = new LocalCachingContextClassLoaderFactory();
     FACTORY.init(() -> new ConfigurationImpl(acuConf));
   }
 
+  @Test
+  public void testAllowedUrls() throws Exception {
+    // use a different factory than other tests; only allow file: URLs
+    ConfigurationCopy acuConf = new ConfigurationCopy(
+        Map.of(CACHE_DIR_PROPERTY, 
baseCacheDir.toAbsolutePath().toUri().toURL().toExternalForm(),
+            ALLOWED_URLS_PATTERN, "file:.*"));
+    var factory = new LocalCachingContextClassLoaderFactory();
+    factory.init(() -> new ConfigurationImpl(acuConf));
+
+    // case 1: all URLs pass (normal case, covered by other tests)
+
+    // case 2: context definition URL fails to match the pattern
+    var ex = assertThrows(ContextClassLoaderException.class,
+        () -> factory.getClassLoader(hdfsAllContext.toExternalForm()));
+    assertTrue(ex.getCause() instanceof IllegalArgumentException);
+    assertTrue(ex.getCause().getMessage().contains("Context definition 
location (hdfs:"));
+
+    // case 3a: context definition URL matches, but resource URL should fail 
to match the pattern,
+    // but it works anyway, because the resources were downloaded already by a 
different instance
+    // (in this case, by a less restrictive FACTORY instance) and no new 
connection is made
+    FACTORY.getClassLoader(hdfsAllContext.toExternalForm());
+    factory.getClassLoader(localAllContext.toExternalForm()); // same resources
+
+    // case 3b: context definition URL matches, but resource URL fails to 
match the pattern
+    // in this case, we use a new context definition, with a resource that 
doesn't exist locally
+    var newResources = new LinkedHashSet<Resource>();
+    var badUrl = "http://localhost/some/path";;
+    newResources.add(new Resource(new URL(badUrl), "MD5", BAD_MD5));
+    var context2 = new ContextDefinition(MONITOR_INTERVAL_SECS, newResources);
+    var disallowedContext = 
tempDir.resolve("context-with-disallowed-resource-url.json");
+    Files.writeString(disallowedContext, context2.toJson(), 
StandardOpenOption.CREATE,
+        StandardOpenOption.TRUNCATE_EXISTING);
+    ex = assertThrows(ContextClassLoaderException.class,
+        () -> 
factory.getClassLoader(disallowedContext.toUri().toURL().toExternalForm()));
+    assertTrue(ex.getCause() instanceof IllegalStateException);
+    assertTrue(ex.getCause().getCause() instanceof ExecutionException);
+    assertTrue(ex.getCause().getCause().getCause() instanceof 
IllegalArgumentException);
+    assertTrue(ex.getCause().getCause().getCause().getMessage().contains(
+        "Resource location (" + badUrl + ")"), 
ex.getCause().getCause().getCause()::getMessage);
+  }
+
   @Test
   public void testCreateFromLocal() throws Exception {
     final ClassLoader cl = FACTORY.getClassLoader(localAllContext.toString());
@@ -336,7 +379,7 @@ public class LocalCachingContextClassLoaderFactoryTest {
         ex.getCause().getCause().getCause()::getMessage);
     assertTrue(
         ex.getCause().getCause().getCause().getMessage()
-            .endsWith("TestA.jar does not match checksum in context definition 
1234"),
+            .endsWith("TestA.jar does not match checksum in context definition 
" + BAD_MD5),
         ex.getCause().getCause().getCause()::getMessage);
   }
 
@@ -609,17 +652,17 @@ public class LocalCachingContextClassLoaderFactoryTest {
     testClassLoads(cl, classC);
     testClassLoads(cl, classD);
 
-    final List<URL> masterList = new ArrayList<>();
-    masterList.add(jarAOrigLocation);
-    masterList.add(jarBOrigLocation);
-    masterList.add(jarCOrigLocation);
-    masterList.add(jarDOrigLocation);
+    final List<URL> allList = new ArrayList<>();
+    allList.add(jarAOrigLocation);
+    allList.add(jarBOrigLocation);
+    allList.add(jarCOrigLocation);
+    allList.add(jarDOrigLocation);
 
-    List<URL> priorList = masterList;
+    List<URL> priorList = allList;
     ClassLoader priorCL = cl;
 
     for (int i = 0; i < 20; i++) {
-      final List<URL> updatedList = new ArrayList<>(masterList);
+      final List<URL> updatedList = new ArrayList<>(allList);
       Collections.shuffle(updatedList);
       final URL removed = updatedList.remove(0);
 
@@ -669,20 +712,12 @@ public class LocalCachingContextClassLoaderFactoryTest {
 
   @Test
   public void testGracePeriod() throws Exception {
-    final LocalCachingContextClassLoaderFactory localFactory =
-        new LocalCachingContextClassLoaderFactory();
-
-    String baseCacheDir = tempDir.resolve("base").toUri().toString();
-    ConfigurationCopy acuConf = new ConfigurationCopy(
-        Map.of(CACHE_DIR_PROPERTY, baseCacheDir, 
UPDATE_FAILURE_GRACE_PERIOD_MINS, "1"));
-    localFactory.init(() -> new ConfigurationImpl(acuConf));
-
     final var def = ContextDefinition.create(MONITOR_INTERVAL_SECS, "SHA-512", 
jarAOrigLocation);
     final var defFilePath =
         createContextDefinitionFile(fs, "UpdateNonExistentResource.json", 
def.toJson());
     final URL updateDefUrl = new URL(fs.getUri().toString() + 
defFilePath.toUri().toString());
 
-    final ClassLoader cl = 
localFactory.getClassLoader(updateDefUrl.toString());
+    final ClassLoader cl = FACTORY.getClassLoader(updateDefUrl.toString());
 
     testClassLoads(cl, classA);
     testClassFailsToLoad(cl, classB);
@@ -708,7 +743,7 @@ public class LocalCachingContextClassLoaderFactoryTest {
     // wait 2x the monitor interval
     Thread.sleep(MONITOR_INTERVAL_SECS * 2 * 1000);
 
-    final ClassLoader cl2 = 
localFactory.getClassLoader(updateDefUrl.toString());
+    final ClassLoader cl2 = FACTORY.getClassLoader(updateDefUrl.toString());
 
     // validate that the classloader has not updated
     assertEquals(cl, cl2);
@@ -721,7 +756,7 @@ public class LocalCachingContextClassLoaderFactoryTest {
     Thread.sleep(120_000);
 
     var ex = assertThrows(ContextClassLoaderException.class,
-        () -> localFactory.getClassLoader(updateDefUrl.toString()));
+        () -> FACTORY.getClassLoader(updateDefUrl.toString()));
     boolean foundExpectedException = false;
     var cause = ex.getCause();
     do {
diff --git 
a/modules/local-caching-classloader/src/test/java/org/apache/accumulo/classloader/lcc/MiniAccumuloClusterClassLoaderFactoryTest.java
 
b/modules/local-caching-classloader/src/test/java/org/apache/accumulo/classloader/lcc/MiniAccumuloClusterClassLoaderFactoryTest.java
index 8ebad35..75b4d95 100644
--- 
a/modules/local-caching-classloader/src/test/java/org/apache/accumulo/classloader/lcc/MiniAccumuloClusterClassLoaderFactoryTest.java
+++ 
b/modules/local-caching-classloader/src/test/java/org/apache/accumulo/classloader/lcc/MiniAccumuloClusterClassLoaderFactoryTest.java
@@ -22,6 +22,7 @@ import static java.nio.charset.StandardCharsets.UTF_8;
 import static java.nio.file.attribute.PosixFilePermission.OWNER_EXECUTE;
 import static java.nio.file.attribute.PosixFilePermission.OWNER_READ;
 import static java.nio.file.attribute.PosixFilePermission.OWNER_WRITE;
+import static 
org.apache.accumulo.classloader.lcc.LocalCachingContextClassLoaderFactory.ALLOWED_URLS_PATTERN;
 import static 
org.apache.accumulo.classloader.lcc.LocalCachingContextClassLoaderFactory.CACHE_DIR_PROPERTY;
 import static 
org.apache.accumulo.classloader.lcc.LocalCachingContextClassLoaderFactory.UPDATE_FAILURE_GRACE_PERIOD_MINS;
 import static org.junit.jupiter.api.Assertions.assertEquals;
@@ -112,6 +113,7 @@ public class MiniAccumuloClusterClassLoaderFactoryTest 
extends SharedMiniCluster
       cfg.setProperty(Property.GENERAL_CONTEXT_CLASSLOADER_FACTORY.getKey(),
           LocalCachingContextClassLoaderFactory.class.getName());
       cfg.setProperty(CACHE_DIR_PROPERTY, 
tempDir.resolve("base").toUri().toString());
+      cfg.setProperty(ALLOWED_URLS_PATTERN, ".*");
       cfg.setProperty(UPDATE_FAILURE_GRACE_PERIOD_MINS, "1");
     }
   }
diff --git 
a/modules/local-caching-classloader/src/test/java/org/apache/accumulo/classloader/lcc/util/LocalStoreTest.java
 
b/modules/local-caching-classloader/src/test/java/org/apache/accumulo/classloader/lcc/util/LocalStoreTest.java
index 3d637ab..74408fb 100644
--- 
a/modules/local-caching-classloader/src/test/java/org/apache/accumulo/classloader/lcc/util/LocalStoreTest.java
+++ 
b/modules/local-caching-classloader/src/test/java/org/apache/accumulo/classloader/lcc/util/LocalStoreTest.java
@@ -34,6 +34,7 @@ import java.nio.file.Files;
 import java.nio.file.Path;
 import java.util.Comparator;
 import java.util.LinkedHashSet;
+import java.util.function.BiConsumer;
 import java.util.stream.Collectors;
 
 import org.apache.accumulo.classloader.lcc.TestUtils;
@@ -54,6 +55,9 @@ public class LocalStoreTest {
   @TempDir
   private static Path tempDir;
 
+  // a mock URL checker that allows all for test
+  private static final BiConsumer<String,URL> ALLOW_ALL_URLS = (type, url) -> 
{};
+
   private static final int MONITOR_INTERVAL_SECS = 5;
   private static MiniDFSCluster hdfs;
   private static Server jetty;
@@ -128,13 +132,16 @@ public class LocalStoreTest {
 
   @Test
   public void testPropertyNotSet() {
-    assertThrows(NullPointerException.class, () -> new LocalStore(null));
+    // test baseDir not set
+    assertThrows(NullPointerException.class, () -> new LocalStore(null, 
ALLOW_ALL_URLS));
+    // test URL checker not set
+    assertThrows(NullPointerException.class, () -> new 
LocalStore(baseCacheDir, null));
   }
 
   @Test
   public void testCreateBaseDirs() throws Exception {
     assertFalse(Files.exists(baseCacheDir));
-    var localStore = new LocalStore(baseCacheDir);
+    var localStore = new LocalStore(baseCacheDir, ALLOW_ALL_URLS);
     assertTrue(Files.exists(baseCacheDir));
     assertTrue(Files.exists(baseCacheDir.resolve("contexts")));
     assertTrue(Files.exists(baseCacheDir.resolve("resources")));
@@ -145,10 +152,10 @@ public class LocalStoreTest {
   @Test
   public void testCreateBaseDirsMultipleTimes() throws Exception {
     assertFalse(Files.exists(baseCacheDir));
-    assertNotNull(new LocalStore(baseCacheDir));
-    assertNotNull(new LocalStore(baseCacheDir));
-    assertNotNull(new LocalStore(baseCacheDir));
-    assertNotNull(new LocalStore(baseCacheDir));
+    assertNotNull(new LocalStore(baseCacheDir, ALLOW_ALL_URLS));
+    assertNotNull(new LocalStore(baseCacheDir, ALLOW_ALL_URLS));
+    assertNotNull(new LocalStore(baseCacheDir, ALLOW_ALL_URLS));
+    assertNotNull(new LocalStore(baseCacheDir, ALLOW_ALL_URLS));
     assertTrue(Files.exists(baseCacheDir));
   }
 
@@ -213,7 +220,7 @@ public class LocalStoreTest {
 
   @Test
   public void testStoreContextResources() throws Exception {
-    var localStore = new LocalStore(baseCacheDir);
+    var localStore = new LocalStore(baseCacheDir, ALLOW_ALL_URLS);
     localStore.storeContextResources(def);
 
     // Confirm the 3 jars are cached locally
@@ -227,7 +234,7 @@ public class LocalStoreTest {
 
   @Test
   public void testClassLoader() throws Exception {
-    var urls = new LocalStore(baseCacheDir).storeContextResources(def);
+    var urls = new LocalStore(baseCacheDir, 
ALLOW_ALL_URLS).storeContextResources(def);
     var contextClassLoader = LccUtils.createClassLoader("url", urls);
 
     testClassLoads(contextClassLoader, classA);
@@ -237,7 +244,7 @@ public class LocalStoreTest {
 
   @Test
   public void testClassLoaderUpdate() throws Exception {
-    var localStore = new LocalStore(baseCacheDir);
+    var localStore = new LocalStore(baseCacheDir, ALLOW_ALL_URLS);
     var urls = localStore.storeContextResources(def);
     final var contextClassLoader = LccUtils.createClassLoader("url", urls);
 

Reply via email to