From 83db1555233d219fe0d8642a16ef64fc127ada54 Mon Sep 17 00:00:00 2001
From: Valery Kharseko <vharseko@3a-systems.ru>
Date: Mon, 27 Jul 2026 13:22:06 +0000
Subject: [PATCH] Fix java/local-temp-file-or-directory-information-disclosure CodeQL alerts by using NIO temp file APIs (#763)

---
 opendj-embedded/src/main/java/org/openidentityplatform/opendj/embedded/EmbeddedOpenDJ.java |   37 ++++++++++++++++++++++++++++++-------
 1 files changed, 30 insertions(+), 7 deletions(-)

diff --git a/opendj-embedded/src/main/java/org/openidentityplatform/opendj/embedded/EmbeddedOpenDJ.java b/opendj-embedded/src/main/java/org/openidentityplatform/opendj/embedded/EmbeddedOpenDJ.java
index fc88890..d2ef004 100644
--- a/opendj-embedded/src/main/java/org/openidentityplatform/opendj/embedded/EmbeddedOpenDJ.java
+++ b/opendj-embedded/src/main/java/org/openidentityplatform/opendj/embedded/EmbeddedOpenDJ.java
@@ -11,7 +11,7 @@
  * Header, with the fields enclosed by brackets [] replaced by your own identifying
  * information: "Portions Copyright [year] [name of copyright owner]".
  *
- * Copyright 2024 3A Systems LLC.
+ * Copyright 2024-2026 3A Systems LLC.
  */
 
 package org.openidentityplatform.opendj.embedded;
@@ -60,6 +60,9 @@
 
     final Config config;
 
+    private final File instanceDirectory;
+    private final File rootDirectory;
+
     public EmbeddedOpenDJ() {
         this(new Config());
     }
@@ -69,13 +72,18 @@
         logger.info("Create embedded OpenDJ instance: {}", config);
 
         this.config = config;
-        File tempDirectory = new File(System.getProperty("java.io.tmpdir"));
-        File rootDirectory = new File(tempDirectory, "opendj");
+        File instanceDirectory = null;
         try {
-            if(rootDirectory.exists()) {
-                FileUtils.deleteDirectory(rootDirectory);
-            }
+            // Create a fresh per-instance parent directory, only accessible by the
+            // current user, instead of the fixed shared {java.io.tmpdir}/opendj
+            // directory. The server root inside it must be named "opendj" because
+            // setup from an archive requires the server root directory to match the
+            // root directory contained in the archive. The whole directory is
+            // deleted on close().
+            instanceDirectory = Files.createTempDirectory("opendj").toFile();
+            File rootDirectory = new File(instanceDirectory, "opendj");
             rootDirectory.mkdir();
+            logger.info("OpenDJ server root: {}", rootDirectory);
 
             File configDirectory = new File(rootDirectory, "config");
             File schemaDirectory = new File(configDirectory, "schema");
@@ -109,13 +117,25 @@
 
             copyFilesFromJar(schemaFiles, JAR_SCHEMA_DIRECTORY, schemaDirectory);
 
+            this.instanceDirectory = instanceDirectory;
+            this.rootDirectory = rootDirectory;
         }catch (Exception e) {
             logger.error("Error initializing OpenDJ");
+            FileUtils.deleteQuietly(instanceDirectory);
             throw new RuntimeException(e);
         }
         Runtime.getRuntime().addShutdownHook(new Thread(this::close));
     }
 
+    /**
+     * Returns the server root directory of this embedded instance.
+     *
+     * @return the server root directory
+     */
+    public File getServerRootDirectory() {
+        return rootDirectory;
+    }
+
     @Override
     public void run() {
         try {
@@ -145,13 +165,16 @@
 
     @Override
     public void close()  {
-        if (server.isRunning())
+        if (server.isRunning()) {
             try {
                 logger.info("Shutting down OpenDJ ...");
                 server.stop(this.getClass().getName(), LocalizableMessage.raw("Stopped after receiving Control-C"));
             }catch (Throwable e) {
                 logger.error("Error stopping OpenDJ", e);
             }
+        }
+        // close() is also registered as a shutdown hook, so deletion must stay idempotent
+        FileUtils.deleteQuietly(instanceDirectory);
     }
 
     private void copyFilesFromJar(List<String> jarFiles, String jarDirectory, File outputDirectory) throws IOException{

--
Gitblit v1.10.0