From ac219948d35f943ba5048e9d97b74b0ab7ccc635 Mon Sep 17 00:00:00 2001 From: Francois Prunayre Date: Tue, 27 Jul 2021 18:54:40 +0200 Subject: [PATCH] Harvester / Local folder / Allow known scripts. Fix for https://github.com/geonetwork/core-geonetwork/pull/5651. --- .../LocalFilesystemHarvester.java | 68 +++++++++++++++---- 1 file changed, 54 insertions(+), 14 deletions(-) diff --git a/harvesters/src/main/java/org/fao/geonet/kernel/harvest/harvester/localfilesystem/LocalFilesystemHarvester.java b/harvesters/src/main/java/org/fao/geonet/kernel/harvest/harvester/localfilesystem/LocalFilesystemHarvester.java index e4338d7de99..0a4a5960cea 100644 --- a/harvesters/src/main/java/org/fao/geonet/kernel/harvest/harvester/localfilesystem/LocalFilesystemHarvester.java +++ b/harvesters/src/main/java/org/fao/geonet/kernel/harvest/harvester/localfilesystem/LocalFilesystemHarvester.java @@ -32,11 +32,13 @@ import java.util.Set; import org.apache.commons.lang.StringUtils; +import org.fao.geonet.ApplicationContextHolder; import org.fao.geonet.Logger; import org.fao.geonet.domain.AbstractMetadata; import org.fao.geonet.domain.ISODate; import org.fao.geonet.domain.Metadata; import org.fao.geonet.domain.MetadataType; +import org.fao.geonet.kernel.GeonetworkDataDirectory; import org.fao.geonet.kernel.UpdateDatestamp; import org.fao.geonet.kernel.harvest.BaseAligner; import org.fao.geonet.kernel.harvest.harvester.AbstractHarvester; @@ -54,6 +56,7 @@ import com.google.common.collect.Sets; import java.util.*; +import java.util.stream.Collectors; /** * Harvester for local filesystem. @@ -235,19 +238,56 @@ private void runBeforeScript() throws IOException, InterruptedException { return; } - throw new InterruptedException("Script option is currently disabled."); - // TODO: Script MUST be limited to well known ones added by a - // catalog admin in the data directory. To be improved - // log.info("Running the before script: " + params.beforeScript); - // List args = new ArrayList(Arrays.asList(params.beforeScript.split(" "))); - // Process process = new ProcessBuilder(args). - // redirectError(ProcessBuilder.Redirect.INHERIT). - // redirectOutput(ProcessBuilder.Redirect.INHERIT). - // start(); - // int result = process.waitFor(); - // if ( result != 0 ) { - // log.warning("The beforeScript failed with exit value=" + Integer.toString(result)); - // throw new RuntimeException("The beforeScript returned an error: " + Integer.toString(result)); - // } + // Script MUST be limited to well known ones added by a + // catalog admin in the data directory. + log.info("Checking script: " + params.beforeScript); + List args = new ArrayList(Arrays.asList(params.beforeScript.split(" "))); + if (isScriptAllowed(args)) { + log.info("Running script: " + params.beforeScript); + Process process = new ProcessBuilder(args). + redirectError(ProcessBuilder.Redirect.INHERIT). + redirectOutput(ProcessBuilder.Redirect.INHERIT). + start(); + int result = process.waitFor(); + if (result != 0) { + log.warning("The beforeScript failed with exit value=" + Integer.toString(result)); + throw new RuntimeException("The beforeScript returned an error: " + Integer.toString(result)); + } + } else { + throw new RuntimeException(String.format( + "Script %s is not allowed. Only script in the data directory can be triggered.", + params.beforeScript)); + } } + + private boolean isScriptAllowed(List args) { + String scriptFile = args.get(0); + if(scriptFile == null) { + log.warning("The beforeScript can't be null."); + return false; + } + if(scriptFile.contains("..")) { + log.warning("The beforeScript can't contains '..'."); + return false; + } + + GeonetworkDataDirectory dataDirectory = ApplicationContextHolder.get().getBean(GeonetworkDataDirectory.class); + Path scriptPath = dataDirectory.getConfigDir().resolve(scriptFile); + if(!Files.exists(scriptPath)) { + log.warning("The beforeScript MUST exists."); + return false; + } else { + args.set(0, scriptPath.toString()); + } + + List argsWithSemiColon = args + .stream() + .filter(a -> a.contains(";")) + .collect(Collectors.toList()); + if (argsWithSemiColon.size() > 0) { + log.warning("The beforeScript can't contains ';'. Only one script can be triggered."); + return false; + } + return true; + } }