You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@syncope.apache.org by il...@apache.org on 2026/05/29 07:53:34 UTC

(syncope) branch 4_1_X updated: Hardening on Groovy sandbox against filesystem and execution bypasses (#1399)

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

ilgrosso pushed a commit to branch 4_1_X
in repository https://gitbox.apache.org/repos/asf/syncope.git


The following commit(s) were added to refs/heads/4_1_X by this push:
     new a9fb47fcd7 Hardening on Groovy sandbox against filesystem and execution bypasses (#1399)
a9fb47fcd7 is described below

commit a9fb47fcd76295a699e682293cd169db73b27ac8
Author: Massimiliano Perrone <ma...@tirasa.net>
AuthorDate: Fri May 29 09:49:36 2026 +0200

    Hardening on Groovy sandbox against filesystem and execution bypasses (#1399)
---
 .../src/main/resources/META-INF/groovy.blacklist   | 140 ++++++++
 .../spring/implementation/GroovySandboxTest.java   | 396 +++++++++++++++++++--
 .../BeansExpressionRuntimeExecMacroActions.groovy  |  35 ++
 .../resources/BeansOverloadsMacroActions.groovy    |  43 +++
 .../BeansStatementSystemExitMacroActions.groovy    |  31 ++
 .../resources/EvalOverloadsMacroActions.groovy     |  34 ++
 .../resources/EvalRuntimeExecMacroActions.groovy   |  31 ++
 .../FileSystemProviderOverloadsMacroActions.groovy |  47 +++
 ...FileSystemProviderReadStringMacroActions.groovy |  32 ++
 .../FileSystemsOverloadsMacroActions.groovy        |  72 ++++
 .../FileSystemsReadStringMacroActions.groovy       |  31 ++
 .../FilesCreateTempDirectoryMacroActions.groovy    |  31 ++
 .../FilesCreateTempFileMacroActions.groovy         |  32 ++
 .../GroovyClassLoaderOverloadsMacroActions.groovy  |  40 +++
 .../GroovyShellOverloadsMacroActions.groovy        |  43 +++
 .../GroovyShellRuntimeExecMacroActions.groovy      |  31 ++
 .../MethodHandlesOverloadsMacroActions.groovy      |  59 +++
 .../MethodHandlesRuntimeExecMacroActions.groovy    |  43 +++
 .../PathOfFilesReadStringMacroActions.groovy       |  31 ++
 .../PathOfFilesWriteStringMacroActions.groovy      |  30 ++
 .../PathOfUriFilesReadStringMacroActions.groovy    |  31 ++
 .../PathsGetFilesReadStringMacroActions.groovy     |  31 ++
 .../PathsGetUriFilesReadStringMacroActions.groovy  |  31 ++
 .../ProcessBuilderStartPipelineMacroActions.groovy |  31 ++
 .../test/resources/RuntimeExecMacroActions.groovy  |  31 ++
 .../RuntimeExecOverloadsMacroActions.groovy        |  42 +++
 .../ScriptEngineOverloadsMacroActions.groovy       |  36 ++
 27 files changed, 1441 insertions(+), 24 deletions(-)

diff --git a/core/spring/src/main/resources/META-INF/groovy.blacklist b/core/spring/src/main/resources/META-INF/groovy.blacklist
index 85292bc608..cfe5dfeccd 100644
--- a/core/spring/src/main/resources/META-INF/groovy.blacklist
+++ b/core/spring/src/main/resources/META-INF/groovy.blacklist
@@ -16,17 +16,90 @@
 # under the License.
 
 # Reflective access to Groovy
+new groovy.lang.GroovyClassLoader
+new groovy.lang.GroovyClassLoader java.lang.ClassLoader
+new groovy.lang.GroovyClassLoader groovy.lang.GroovyClassLoader
+new groovy.lang.GroovyClassLoader java.lang.ClassLoader org.codehaus.groovy.control.CompilerConfiguration
+new groovy.lang.GroovyClassLoader java.lang.ClassLoader org.codehaus.groovy.control.CompilerConfiguration boolean
+new groovy.lang.GroovyShell
+new groovy.lang.GroovyShell groovy.lang.Binding
+new groovy.lang.GroovyShell groovy.lang.Binding org.codehaus.groovy.control.CompilerConfiguration
+new groovy.lang.GroovyShell groovy.lang.GroovyShell
+new groovy.lang.GroovyShell java.lang.ClassLoader
+new groovy.lang.GroovyShell java.lang.ClassLoader groovy.lang.Binding
+new groovy.lang.GroovyShell java.lang.ClassLoader groovy.lang.Binding org.codehaus.groovy.control.CompilerConfiguration
+new groovy.lang.GroovyShell java.lang.ClassLoader org.codehaus.groovy.control.CompilerConfiguration
+new groovy.lang.GroovyShell org.codehaus.groovy.control.CompilerConfiguration
+method groovy.lang.GroovyClassLoader addClasspath java.lang.String
+method groovy.lang.GroovyClassLoader addURL java.net.URL
+method groovy.lang.GroovyClassLoader defineClass java.lang.String byte[]
+method groovy.lang.GroovyClassLoader parseClass groovy.lang.GroovyCodeSource
+method groovy.lang.GroovyClassLoader parseClass groovy.lang.GroovyCodeSource boolean
+method groovy.lang.GroovyClassLoader parseClass java.io.File
+method groovy.lang.GroovyClassLoader parseClass java.io.Reader java.lang.String
+method groovy.lang.GroovyClassLoader parseClass java.lang.String
+method groovy.lang.GroovyClassLoader parseClass java.lang.String java.lang.String
+method groovy.lang.GroovyShell evaluate groovy.lang.GroovyCodeSource
+method groovy.lang.GroovyShell evaluate java.io.File
+method groovy.lang.GroovyShell evaluate java.io.Reader
+method groovy.lang.GroovyShell evaluate java.io.Reader java.lang.String
+method groovy.lang.GroovyShell evaluate java.lang.String
+method groovy.lang.GroovyShell evaluate java.lang.String java.lang.String
+method groovy.lang.GroovyShell evaluate java.lang.String java.lang.String java.lang.String
+method groovy.lang.GroovyShell evaluate java.net.URI
+method groovy.lang.GroovyShell parse groovy.lang.GroovyCodeSource
+method groovy.lang.GroovyShell parse groovy.lang.GroovyCodeSource groovy.lang.Binding
+method groovy.lang.GroovyShell parse java.io.File
+method groovy.lang.GroovyShell parse java.io.Reader
+method groovy.lang.GroovyShell parse java.io.Reader groovy.lang.Binding
+method groovy.lang.GroovyShell parse java.io.Reader java.lang.String
+method groovy.lang.GroovyShell parse java.io.Reader java.lang.String groovy.lang.Binding
+method groovy.lang.GroovyShell parse java.lang.String
+method groovy.lang.GroovyShell parse java.lang.String groovy.lang.Binding
+method groovy.lang.GroovyShell parse java.lang.String java.lang.String
+method groovy.lang.GroovyShell parse java.lang.String java.lang.String groovy.lang.Binding
+method groovy.lang.GroovyShell parse java.net.URI
+method groovy.lang.GroovyShell run groovy.lang.GroovyCodeSource java.lang.String[]
+method groovy.lang.GroovyShell run groovy.lang.GroovyCodeSource java.util.List
+method groovy.lang.GroovyShell run java.io.File java.lang.String[]
+method groovy.lang.GroovyShell run java.io.File java.util.List
+method groovy.lang.GroovyShell run java.io.Reader java.lang.String java.lang.String[]
+method groovy.lang.GroovyShell run java.io.Reader java.lang.String java.util.List
+method groovy.lang.GroovyShell run java.lang.String java.lang.String java.lang.String[]
+method groovy.lang.GroovyShell run java.lang.String java.lang.String java.util.List
+method groovy.lang.GroovyShell run java.net.URI java.lang.String[]
+method groovy.lang.GroovyShell run java.net.URI java.util.List
+staticMethod groovy.lang.GroovyShell withConfig groovy.lang.Closure
+staticMethod groovy.util.Eval me java.lang.String
+staticMethod groovy.util.Eval me java.lang.String java.lang.Object java.lang.String
+staticMethod groovy.util.Eval x java.lang.Object java.lang.String
+staticMethod groovy.util.Eval xy java.lang.Object java.lang.Object java.lang.String
+staticMethod groovy.util.Eval xyz java.lang.Object java.lang.Object java.lang.Object java.lang.String
 method groovy.lang.GroovyObject getMetaClass
 method groovy.lang.GroovyObject getProperty java.lang.String
 method groovy.lang.GroovyObject invokeMethod java.lang.String java.lang.Object
 method groovy.lang.GroovyObject setMetaClass groovy.lang.MetaClass
 method groovy.lang.GroovyObject setProperty java.lang.String java.lang.Object
 
+# Runtime script engines could evaluate code outside the Groovy sandbox transformer.
+new javax.script.ScriptEngineManager
+new javax.script.ScriptEngineManager java.lang.ClassLoader
+method javax.script.ScriptEngine eval java.io.Reader
+method javax.script.ScriptEngine eval java.io.Reader javax.script.Bindings
+method javax.script.ScriptEngine eval java.io.Reader javax.script.ScriptContext
+method javax.script.ScriptEngine eval java.lang.String
+method javax.script.ScriptEngine eval java.lang.String javax.script.Bindings
+method javax.script.ScriptEngine eval java.lang.String javax.script.ScriptContext
+method javax.script.ScriptEngineManager getEngineByExtension java.lang.String
+method javax.script.ScriptEngineManager getEngineByMimeType java.lang.String
+method javax.script.ScriptEngineManager getEngineByName java.lang.String
+
 # Raw file operations
 staticMethod java.io.File createTempFile java.lang.String java.lang.String
 staticMethod java.io.File createTempFile java.lang.String java.lang.String java.io.File
 new java.io.File java.lang.String
 new java.io.File java.lang.String java.lang.String
+new java.io.File java.io.File java.lang.String
 new java.io.File java.net.URI
 staticMethod java.io.File listRoots
 new java.io.FileInputStream java.lang.String
@@ -61,8 +134,19 @@ method java.lang.Class newInstance
 # Same for local process execution.
 new java.lang.ProcessBuilder java.lang.String[]
 new java.lang.ProcessBuilder java.util.List
+staticMethod java.lang.ProcessBuilder startPipeline java.util.List
 method java.lang.Process start
 staticMethod java.lang.Runtime getRuntime
+method java.lang.Runtime exec java.lang.String
+method java.lang.Runtime exec java.lang.String java.lang.String[]
+method java.lang.Runtime exec java.lang.String java.lang.String[] java.io.File
+method java.lang.Runtime exec java.lang.String[]
+method java.lang.Runtime exec java.lang.String[] java.lang.String[]
+method java.lang.Runtime exec java.lang.String[] java.lang.String[] java.io.File
+method java.lang.Runtime exit int
+method java.lang.Runtime halt int
+method java.lang.Runtime load java.lang.String
+method java.lang.Runtime loadLibrary java.lang.String
 staticMethod java.lang.System exit int
 
 # Leak information.
@@ -83,6 +167,62 @@ method java.net.URL openStream
 # NIO file operations must start with a Path:
 staticMethod java.nio.file.Paths get java.lang.String java.lang.String[]
 staticMethod java.nio.file.Paths get java.net.URI
+staticMethod java.nio.file.Path of java.lang.String java.lang.String[]
+staticMethod java.nio.file.Path of java.net.URI
+staticMethod java.nio.file.FileSystems getDefault
+staticMethod java.nio.file.FileSystems getFileSystem java.net.URI
+staticMethod java.nio.file.FileSystems newFileSystem java.net.URI java.util.Map
+staticMethod java.nio.file.FileSystems newFileSystem java.net.URI java.util.Map java.lang.ClassLoader
+staticMethod java.nio.file.FileSystems newFileSystem java.nio.file.Path
+staticMethod java.nio.file.FileSystems newFileSystem java.nio.file.Path java.lang.ClassLoader
+staticMethod java.nio.file.FileSystems newFileSystem java.nio.file.Path java.util.Map
+staticMethod java.nio.file.FileSystems newFileSystem java.nio.file.Path java.util.Map java.lang.ClassLoader
+method java.nio.file.FileSystem getPath java.lang.String java.lang.String[]
+staticMethod java.nio.file.Files createTempDirectory java.lang.String java.nio.file.attribute.FileAttribute[]
+staticMethod java.nio.file.Files createTempFile java.lang.String java.lang.String java.nio.file.attribute.FileAttribute[]
+staticMethod java.nio.file.spi.FileSystemProvider installedProviders
+method java.nio.file.spi.FileSystemProvider getFileSystem java.net.URI
+method java.nio.file.spi.FileSystemProvider getPath java.net.URI
+method java.nio.file.spi.FileSystemProvider newFileSystem java.net.URI java.util.Map
+method java.nio.file.spi.FileSystemProvider newFileSystem java.nio.file.Path java.util.Map
+
+# Indirect method invocation
+staticMethod java.lang.invoke.MethodHandles lookup
+staticMethod java.lang.invoke.MethodHandles privateLookupIn java.lang.Class java.lang.invoke.MethodHandles$Lookup
+staticMethod java.lang.invoke.MethodHandles publicLookup
+staticMethod java.lang.invoke.MethodHandles reflectAs java.lang.Class java.lang.invoke.MethodHandle
+method java.lang.invoke.MethodHandle invoke java.lang.Object[]
+method java.lang.invoke.MethodHandle invokeExact java.lang.Object[]
+method java.lang.invoke.MethodHandle invokeWithArguments java.lang.Object[]
+method java.lang.invoke.MethodHandle invokeWithArguments java.util.List
+method java.lang.invoke.MethodHandles$Lookup bind java.lang.Object java.lang.String java.lang.invoke.MethodType
+method java.lang.invoke.MethodHandles$Lookup defineClass byte[]
+method java.lang.invoke.MethodHandles$Lookup defineHiddenClass byte[] boolean java.lang.invoke.MethodHandles$Lookup$ClassOption[]
+method java.lang.invoke.MethodHandles$Lookup defineHiddenClassWithClassData byte[] java.lang.Object boolean java.lang.invoke.MethodHandles$Lookup$ClassOption[]
+method java.lang.invoke.MethodHandles$Lookup findClass java.lang.String
+method java.lang.invoke.MethodHandles$Lookup findConstructor java.lang.Class java.lang.invoke.MethodType
+method java.lang.invoke.MethodHandles$Lookup findGetter java.lang.Class java.lang.String java.lang.Class
+method java.lang.invoke.MethodHandles$Lookup findSetter java.lang.Class java.lang.String java.lang.Class
+method java.lang.invoke.MethodHandles$Lookup findSpecial java.lang.Class java.lang.String java.lang.invoke.MethodType java.lang.Class
+method java.lang.invoke.MethodHandles$Lookup findStatic java.lang.Class java.lang.String java.lang.invoke.MethodType
+method java.lang.invoke.MethodHandles$Lookup findStaticGetter java.lang.Class java.lang.String java.lang.Class
+method java.lang.invoke.MethodHandles$Lookup findStaticSetter java.lang.Class java.lang.String java.lang.Class
+method java.lang.invoke.MethodHandles$Lookup findStaticVarHandle java.lang.Class java.lang.String java.lang.Class
+method java.lang.invoke.MethodHandles$Lookup findVarHandle java.lang.Class java.lang.String java.lang.Class
+method java.lang.invoke.MethodHandles$Lookup findVirtual java.lang.Class java.lang.String java.lang.invoke.MethodType
+method java.lang.invoke.MethodHandles$Lookup unreflect java.lang.reflect.Method
+method java.lang.invoke.MethodHandles$Lookup unreflectConstructor java.lang.reflect.Constructor
+method java.lang.invoke.MethodHandles$Lookup unreflectGetter java.lang.reflect.Field
+method java.lang.invoke.MethodHandles$Lookup unreflectSetter java.lang.reflect.Field
+method java.lang.invoke.MethodHandles$Lookup unreflectSpecial java.lang.reflect.Method java.lang.Class
+method java.lang.invoke.MethodHandles$Lookup unreflectVarHandle java.lang.reflect.Field
+new java.beans.Expression java.lang.Object java.lang.String java.lang.Object[]
+new java.beans.Expression java.lang.Object java.lang.Object java.lang.String java.lang.Object[]
+new java.beans.Statement java.lang.Object java.lang.String java.lang.Object[]
+method java.beans.Expression execute
+method java.beans.Expression getValue
+method java.beans.Expression setValue java.lang.Object
+method java.beans.Statement execute
 
 # More process execution, Groovy-style:
 staticMethod org.codehaus.groovy.runtime.DefaultGroovyMethods execute java.lang.String
diff --git a/core/spring/src/test/java/org/apache/syncope/core/spring/implementation/GroovySandboxTest.java b/core/spring/src/test/java/org/apache/syncope/core/spring/implementation/GroovySandboxTest.java
index 8293b3c696..fe2e0641bf 100644
--- a/core/spring/src/test/java/org/apache/syncope/core/spring/implementation/GroovySandboxTest.java
+++ b/core/spring/src/test/java/org/apache/syncope/core/spring/implementation/GroovySandboxTest.java
@@ -23,6 +23,11 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
 import org.apache.commons.lang3.exception.ExceptionUtils;
 import org.apache.cxf.helpers.IOUtils;
 import org.apache.syncope.common.lib.types.ImplementationEngine;
@@ -32,53 +37,396 @@ import org.apache.syncope.core.spring.SpringTestConfiguration;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.condition.EnabledOnOs;
 import org.junit.jupiter.api.condition.OS;
+import org.junit.jupiter.api.io.TempDir;
 import org.springframework.beans.factory.BeanCreationException;
 import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
 
 @SpringJUnitConfig(classes = { SpringTestConfiguration.class })
 class GroovySandboxTest {
 
+    @TempDir
+    private Path tempDir;
+
     @Test
     void processBuilder() throws Exception {
-        Implementation impl = mock(Implementation.class);
-        when(impl.getKey()).thenReturn("processBuilder");
-        when(impl.getEngine()).thenReturn(ImplementationEngine.GROOVY);
-        when(impl.getBody()).thenReturn(IOUtils.toString(
-                getClass().getResourceAsStream("/ProcessBuilderMacroActions.groovy")));
+        final MacroActions actions = actions("processBuilder", "/ProcessBuilderMacroActions.groovy");
 
-        MacroActions actions = ImplementationManager.build(impl);
-
-        SecurityException e = assertThrows(
+        final SecurityException e = assertThrows(
                 SecurityException.class, () -> actions.afterAll(null, new StringBuilder()));
         assertTrue(e.getMessage().contains("Insecure call to 'new java.lang.ProcessBuilder java.lang.String[]'"));
     }
 
-    @EnabledOnOs(OS.LINUX)
-    @Test
-    void bash() throws Exception {
-        Implementation impl = mock(Implementation.class);
-        when(impl.getKey()).thenReturn("bash");
+    private MacroActions actions(final String key, final String resource) throws Exception {
+        final Implementation impl = mock(Implementation.class);
+        when(impl.getKey()).thenReturn(key);
         when(impl.getEngine()).thenReturn(ImplementationEngine.GROOVY);
         when(impl.getBody()).thenReturn(IOUtils.toString(
-                getClass().getResourceAsStream("/BashMacroActions.groovy")));
+                Objects.requireNonNull(getClass().getResourceAsStream(resource))));
 
-        MacroActions actions = ImplementationManager.build(impl);
+        return ImplementationManager.build(impl);
+    }
 
-        SecurityException e = assertThrows(
+    @EnabledOnOs(OS.LINUX)
+    @Test
+    void bash() throws Exception {
+        final MacroActions actions = actions("bash", "/BashMacroActions.groovy");
+
+        final SecurityException e = assertThrows(
                 SecurityException.class, () -> actions.afterAll(null, new StringBuilder()));
         assertTrue(e.getMessage().contains("Insecure call to 'new java.io.File java.lang.String'"));
     }
 
     @Test
     void staticMacroActions() throws Exception {
-        Implementation impl = mock(Implementation.class);
-        when(impl.getKey()).thenReturn("staticMacroActions");
-        when(impl.getEngine()).thenReturn(ImplementationEngine.GROOVY);
-        when(impl.getBody()).thenReturn(IOUtils.toString(
-                getClass().getResourceAsStream("/StaticMacroActions.groovy")));
-
-        BeanCreationException e = assertThrows(BeanCreationException.class, () -> ImplementationManager.build(impl));
-        SecurityException sec = (SecurityException) ExceptionUtils.getRootCause(e);
+        final BeanCreationException e =
+                assertThrows(
+                        BeanCreationException.class,
+                        () -> actions("staticMacroActions", "/StaticMacroActions.groovy"));
+        final SecurityException sec = (SecurityException) ExceptionUtils.getRootCause(e);
         assertTrue(sec.getMessage().startsWith("Insecure call to 'new java.lang.ProcessBuilder java.util.List'"));
     }
+
+    @Test
+    void pathOfFilesReadString() throws Exception {
+        final Path testFile = tempDir.resolve("sandbox-read.txt");
+        Files.writeString(testFile, "sandbox-read-ok");
+
+        final MacroActions actions = actions("pathOfFilesReadString", "/PathOfFilesReadStringMacroActions.groovy");
+
+        final SecurityException e = assertThrows(
+                SecurityException.class,
+                () -> actions.afterAll(null, new StringBuilder(testFile.toAbsolutePath().toString())));
+        assertTrue(e.getMessage().contains(
+                "Insecure call to 'staticMethod java.nio.file.Path of java.lang.String java.lang.String[]'"));
+    }
+
+    @Test
+    void pathOfFilesWriteString() throws Exception {
+        final Path testFile = tempDir.resolve("sandbox-write.txt");
+
+        final MacroActions actions = actions("pathOfFilesWriteString", "/PathOfFilesWriteStringMacroActions.groovy");
+
+        final SecurityException e = assertThrows(
+                SecurityException.class,
+                () -> actions.afterAll(null, new StringBuilder(testFile.toAbsolutePath().toString())));
+        assertTrue(e.getMessage().contains(
+                "Insecure call to 'staticMethod java.nio.file.Path of java.lang.String java.lang.String[]'"));
+    }
+
+    @Test
+    void pathOfUriFilesReadString() throws Exception {
+        final Path testFile = tempDir.resolve("sandbox-read-uri.txt");
+        Files.writeString(testFile, "sandbox-read-uri-ok");
+
+        final MacroActions actions =
+                actions("pathOfUriFilesReadString", "/PathOfUriFilesReadStringMacroActions.groovy");
+
+        final SecurityException e = assertThrows(
+                SecurityException.class,
+                () -> actions.afterAll(null, new StringBuilder(testFile.toUri().toString())));
+        assertTrue(e.getMessage().contains(
+                "Insecure call to 'staticMethod java.nio.file.Path of java.net.URI'"));
+    }
+
+    @Test
+    void pathsGetFilesReadString() throws Exception {
+        final Path testFile = tempDir.resolve("sandbox-paths-get-read.txt");
+        Files.writeString(testFile, "sandbox-paths-get-read-ok");
+
+        final MacroActions actions = actions("pathsGetFilesReadString", "/PathsGetFilesReadStringMacroActions.groovy");
+
+        final SecurityException e = assertThrows(
+                SecurityException.class,
+                () -> actions.afterAll(null, new StringBuilder(testFile.toAbsolutePath().toString())));
+        assertTrue(e.getMessage().contains(
+                "Insecure call to 'staticMethod java.nio.file.Paths get java.lang.String java.lang.String[]'"));
+    }
+
+    @Test
+    void pathsGetUriFilesReadString() throws Exception {
+        final Path testFile = tempDir.resolve("sandbox-paths-get-uri-read.txt");
+        Files.writeString(testFile, "sandbox-paths-get-uri-read-ok");
+
+        final MacroActions actions =
+                actions("pathsGetUriFilesReadString", "/PathsGetUriFilesReadStringMacroActions.groovy");
+
+        final SecurityException e = assertThrows(
+                SecurityException.class,
+                () -> actions.afterAll(null, new StringBuilder(testFile.toUri().toString())));
+        assertTrue(e.getMessage().contains(
+                "Insecure call to 'staticMethod java.nio.file.Paths get java.net.URI'"));
+    }
+
+    @Test
+    void fileSystemsReadString() throws Exception {
+        final Path testFile = tempDir.resolve("sandbox-filesystems-read.txt");
+        Files.writeString(testFile, "sandbox-filesystems-read-ok");
+
+        final MacroActions actions = actions("fileSystemsReadString", "/FileSystemsReadStringMacroActions.groovy");
+
+        final SecurityException e = assertThrows(
+                SecurityException.class,
+                () -> actions.afterAll(null, new StringBuilder(testFile.toAbsolutePath().toString())));
+        assertTrue(e.getMessage().contains(
+                "Insecure call to 'staticMethod java.nio.file.FileSystems getDefault'"));
+    }
+
+    @Test
+    void fileSystemProviderReadString() throws Exception {
+        final Path testFile = tempDir.resolve("sandbox-filesystem-provider-read.txt");
+        Files.writeString(testFile, "sandbox-filesystem-provider-read-ok");
+
+        final MacroActions actions =
+                actions("fileSystemProviderReadString", "/FileSystemProviderReadStringMacroActions.groovy");
+
+        final SecurityException e = assertThrows(
+                SecurityException.class,
+                () -> actions.afterAll(null, new StringBuilder(testFile.toUri().toString())));
+        assertTrue(e.getMessage().contains(
+                "Insecure call to 'staticMethod java.nio.file.spi.FileSystemProvider installedProviders'"));
+    }
+
+    @Test
+    void filesCreateTempFile() throws Exception {
+        final MacroActions actions = actions("filesCreateTempFile", "/FilesCreateTempFileMacroActions.groovy");
+
+        final SecurityException e = assertThrows(
+                SecurityException.class,
+                () -> actions.afterAll(null, new StringBuilder()));
+        assertTrue(e.getMessage().contains(
+                "Insecure call to 'staticMethod java.nio.file.Files createTempFile "
+                + "java.lang.String java.lang.String java.nio.file.attribute.FileAttribute[]'"));
+    }
+
+    @Test
+    void filesCreateTempDirectory() throws Exception {
+        final MacroActions actions =
+                actions("filesCreateTempDirectory", "/FilesCreateTempDirectoryMacroActions.groovy");
+
+        final SecurityException e = assertThrows(
+                SecurityException.class,
+                () -> actions.afterAll(null, new StringBuilder()));
+        assertTrue(e.getMessage().contains(
+                "Insecure call to 'staticMethod java.nio.file.Files createTempDirectory "
+                + "java.lang.String java.nio.file.attribute.FileAttribute[]'"));
+    }
+
+    @EnabledOnOs(OS.LINUX)
+    @Test
+    void processBuilderStartPipeline() throws Exception {
+        final MacroActions actions =
+                actions("processBuilderStartPipeline", "/ProcessBuilderStartPipelineMacroActions.groovy");
+
+        @SuppressWarnings("unchecked")
+        final Map<String, java.io.Serializable> ctx =
+                (Map<String, java.io.Serializable>) (Map<?, ?>) Map.of(
+                        "builders",
+                        List.of(new ProcessBuilder("/bin/sh", "-c", "printf sandbox-start-pipeline-ok")));
+
+        final SecurityException e = assertThrows(
+                SecurityException.class,
+                () -> actions.afterAll(ctx, new StringBuilder()));
+        assertTrue(e.getMessage().contains(
+                "Insecure call to 'staticMethod java.lang.ProcessBuilder startPipeline java.util.List'"));
+    }
+
+    @EnabledOnOs(OS.LINUX)
+    @Test
+    void runtimeExec() throws Exception {
+        final MacroActions actions = actions("runtimeExec", "/RuntimeExecMacroActions.groovy");
+
+        @SuppressWarnings("unchecked")
+        final Map<String, java.io.Serializable> ctx =
+                (Map<String, java.io.Serializable>) (Map<?, ?>) Map.of("runtime", Runtime.getRuntime());
+
+        final SecurityException e = assertThrows(
+                SecurityException.class,
+                () -> actions.afterAll(ctx, new StringBuilder()));
+        assertTrue(e.getMessage().contains(
+                "Insecure call to 'method java.lang.Runtime exec java.lang.String[]'"));
+    }
+
+    @EnabledOnOs(OS.LINUX)
+    @Test
+    void beansExpressionRuntimeExec() throws Exception {
+        final MacroActions actions =
+                actions("beansExpressionRuntimeExec", "/BeansExpressionRuntimeExecMacroActions.groovy");
+
+        final SecurityException e = assertThrows(
+                SecurityException.class,
+                () -> actions.afterAll(null, new StringBuilder()));
+        assertTrue(e.getMessage().contains(
+                "Insecure call to 'new java.beans.Expression java.lang.Object java.lang.String java.lang.Object[]'"));
+    }
+
+    @Test
+    void beansStatementSystemExit() throws Exception {
+        final MacroActions actions =
+                actions("beansStatementSystemExit", "/BeansStatementSystemExitMacroActions.groovy");
+
+        final SecurityException e = assertThrows(
+                SecurityException.class,
+                () -> actions.afterAll(null, new StringBuilder()));
+        assertTrue(e.getMessage().contains(
+                "Insecure call to 'new java.beans.Statement java.lang.Object java.lang.String java.lang.Object[]'"));
+    }
+
+    @EnabledOnOs(OS.LINUX)
+    @Test
+    void groovyShellRuntimeExec() throws Exception {
+        final MacroActions actions = actions("groovyShellRuntimeExec", "/GroovyShellRuntimeExecMacroActions.groovy");
+
+        final SecurityException e = assertThrows(
+                SecurityException.class,
+                () -> actions.afterAll(null, new StringBuilder()));
+        assertTrue(e.getMessage().contains("Insecure call to 'new groovy.lang.GroovyShell'"));
+    }
+
+    @EnabledOnOs(OS.LINUX)
+    @Test
+    void evalRuntimeExec() throws Exception {
+        final MacroActions actions = actions("evalRuntimeExec", "/EvalRuntimeExecMacroActions.groovy");
+
+        final SecurityException e = assertThrows(
+                SecurityException.class,
+                () -> actions.afterAll(null, new StringBuilder()));
+        assertTrue(e.getMessage().contains(
+                "Insecure call to 'staticMethod groovy.util.Eval me java.lang.String'"));
+    }
+
+    @EnabledOnOs(OS.LINUX)
+    @Test
+    void methodHandlesRuntimeExec() throws Exception {
+        final MacroActions actions =
+                actions("methodHandlesRuntimeExec", "/MethodHandlesRuntimeExecMacroActions.groovy");
+
+        final SecurityException e = assertThrows(
+                SecurityException.class,
+                () -> actions.afterAll(null, new StringBuilder()));
+        assertTrue(e.getMessage().contains(
+                "Insecure call to 'staticMethod java.lang.invoke.MethodHandles publicLookup'"));
+    }
+
+    @EnabledOnOs(OS.LINUX)
+    @Test
+    void runtimeExecOverloads() throws Exception {
+        final MacroActions actions = actions("runtimeExecOverloads", "/RuntimeExecOverloadsMacroActions.groovy");
+
+        @SuppressWarnings("unchecked")
+        final Map<String, java.io.Serializable> ctx =
+                (Map<String, java.io.Serializable>) (Map<?, ?>) Map.of("runtime", Runtime.getRuntime());
+
+        final SecurityException e = assertThrows(
+                SecurityException.class,
+                () -> actions.afterAll(ctx, new StringBuilder()));
+        assertTrue(e.getMessage().contains(
+                "Insecure call to 'method java.lang.Runtime exec java.lang.String'"));
+    }
+
+    @Test
+    void evalOverloads() throws Exception {
+        final MacroActions actions = actions("evalOverloads", "/EvalOverloadsMacroActions.groovy");
+
+        final SecurityException e = assertThrows(
+                SecurityException.class,
+                () -> actions.afterAll(null, new StringBuilder()));
+        assertTrue(e.getMessage().contains(
+                "Insecure call to 'staticMethod groovy.util.Eval me java.lang.String'"));
+    }
+
+    @Test
+    void groovyShellOverloads() throws Exception {
+        final Path script = tempDir.resolve("sandbox-groovy-shell-overload.groovy");
+        Files.writeString(script, "return 'shell-evaluate-file|'");
+        @SuppressWarnings("unchecked")
+        final Map<String, java.io.Serializable> ctx =
+                (Map<String, java.io.Serializable>) (Map<?, ?>) Map.of("scriptFile", script.toFile());
+
+        final MacroActions actions = actions("groovyShellOverloads", "/GroovyShellOverloadsMacroActions.groovy");
+
+        final SecurityException e = assertThrows(
+                SecurityException.class,
+                () -> actions.afterAll(ctx, new StringBuilder()));
+        assertTrue(e.getMessage().contains("Insecure call to 'new groovy.lang.GroovyShell'"));
+    }
+
+    @Test
+    void groovyClassLoaderOverloads() throws Exception {
+        final MacroActions actions =
+                actions("groovyClassLoaderOverloads", "/GroovyClassLoaderOverloadsMacroActions.groovy");
+
+        final SecurityException e = assertThrows(
+                SecurityException.class,
+                () -> actions.afterAll(null, new StringBuilder()));
+        assertTrue(e.getMessage().contains("Insecure call to 'new groovy.lang.GroovyClassLoader'"));
+    }
+
+    @Test
+    void scriptEngineOverloads() throws Exception {
+        final MacroActions actions = actions("scriptEngineOverloads", "/ScriptEngineOverloadsMacroActions.groovy");
+
+        final SecurityException e = assertThrows(
+                SecurityException.class,
+                () -> actions.afterAll(null, new StringBuilder()));
+        assertTrue(e.getMessage().contains("Insecure call to 'new javax.script.ScriptEngineManager'"));
+    }
+
+    @Test
+    void fileSystemsOverloads() throws Exception {
+        final Path file = tempDir.resolve("sandbox-filesystems-overloads.txt");
+        Files.writeString(file, "sandbox-filesystems-overloads-ok");
+        @SuppressWarnings("unchecked")
+        final Map<String, java.io.Serializable> ctx =
+                (Map<String, java.io.Serializable>) (Map<?, ?>) Map.of("path", file);
+
+        final MacroActions actions = actions("fileSystemsOverloads", "/FileSystemsOverloadsMacroActions.groovy");
+
+        final SecurityException e = assertThrows(
+                SecurityException.class,
+                () -> actions.afterAll(ctx, new StringBuilder()));
+        assertTrue(e.getMessage().contains(
+                "Insecure call to 'staticMethod java.nio.file.FileSystems getFileSystem java.net.URI'"));
+    }
+
+    @Test
+    void fileSystemProviderOverloads() throws Exception {
+        final Path file = tempDir.resolve("sandbox-filesystem-provider-overloads.txt");
+        Files.writeString(file, "sandbox-filesystem-provider-overloads-ok");
+        @SuppressWarnings("unchecked")
+        final Map<String, java.io.Serializable> ctx =
+                (Map<String, java.io.Serializable>) (Map<?, ?>) Map.of(
+                        "path", file,
+                        "provider", file.getFileSystem().provider());
+
+        final MacroActions actions =
+                actions("fileSystemProviderOverloads", "/FileSystemProviderOverloadsMacroActions.groovy");
+
+        final SecurityException e = assertThrows(
+                SecurityException.class,
+                () -> actions.afterAll(ctx, new StringBuilder()));
+        assertTrue(e.getMessage().contains(
+                "Insecure call to 'method java.nio.file.spi.FileSystemProvider getFileSystem java.net.URI'"));
+    }
+
+    @Test
+    void methodHandlesOverloads() throws Exception {
+        final MacroActions actions = actions("methodHandlesOverloads", "/MethodHandlesOverloadsMacroActions.groovy");
+
+        final SecurityException e = assertThrows(
+                SecurityException.class,
+                () -> actions.afterAll(null, new StringBuilder()));
+        assertTrue(e.getMessage().contains(
+                "Insecure call to 'staticMethod java.lang.invoke.MethodHandles lookup'"));
+    }
+
+    @Test
+    void beansOverloads() throws Exception {
+        final MacroActions actions = actions("beansOverloads", "/BeansOverloadsMacroActions.groovy");
+
+        final SecurityException e = assertThrows(
+                SecurityException.class,
+                () -> actions.afterAll(null, new StringBuilder()));
+        assertTrue(e.getMessage().contains(
+                "Insecure call to 'new java.beans.Expression java.lang.Object java.lang.String java.lang.Object[]'"));
+    }
 }
diff --git a/core/spring/src/test/resources/BeansExpressionRuntimeExecMacroActions.groovy b/core/spring/src/test/resources/BeansExpressionRuntimeExecMacroActions.groovy
new file mode 100644
index 0000000000..494f0925fc
--- /dev/null
+++ b/core/spring/src/test/resources/BeansExpressionRuntimeExecMacroActions.groovy
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+import groovy.transform.BaseScript
+import org.apache.syncope.core.provisioning.api.macro.MacroActions
+import java.io.Serializable
+
+abstract class BeansExpressionRuntimeExecMacroActions extends Script implements MacroActions {}
+@BaseScript BeansExpressionRuntimeExecMacroActions _
+
+@Override
+StringBuilder afterAll(Map<String, Serializable> ctx, StringBuilder output) {
+  def runtime = new java.beans.Expression(java.lang.Runtime, 'getRuntime', [] as Object[]).value
+  def process = new java.beans.Expression(
+      runtime,
+      'exec',
+      [['/bin/sh', '-c', 'printf sandbox-beans-expression-ok'] as String[]] as Object[]).value
+  output.append(': ').append(process.inputStream.text)
+  return output
+}
diff --git a/core/spring/src/test/resources/BeansOverloadsMacroActions.groovy b/core/spring/src/test/resources/BeansOverloadsMacroActions.groovy
new file mode 100644
index 0000000000..7c7543a1b8
--- /dev/null
+++ b/core/spring/src/test/resources/BeansOverloadsMacroActions.groovy
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+import groovy.transform.BaseScript
+import org.apache.syncope.core.provisioning.api.macro.MacroActions
+import java.io.Serializable
+
+abstract class BeansOverloadsMacroActions extends Script implements MacroActions {}
+@BaseScript BeansOverloadsMacroActions _
+
+@Override
+StringBuilder afterAll(Map<String, Serializable> ctx, StringBuilder output) {
+  def expression = new java.beans.Expression('beans-', 'concat', ['expression|'] as Object[])
+  output.append(expression.value)
+
+  def preset = new java.beans.Expression(null, 'beans-', 'concat', ['preset|'] as Object[])
+  preset.execute()
+  output.append(preset.value)
+  preset.setValue('beans-set-value|')
+  output.append(preset.value)
+
+  def buffer = new StringBuffer()
+  def statement = new java.beans.Statement(buffer, 'append', ['beans-statement-execute|'] as Object[])
+  statement.execute()
+  output.append(buffer.toString())
+
+  return output
+}
diff --git a/core/spring/src/test/resources/BeansStatementSystemExitMacroActions.groovy b/core/spring/src/test/resources/BeansStatementSystemExitMacroActions.groovy
new file mode 100644
index 0000000000..1d5256d8ec
--- /dev/null
+++ b/core/spring/src/test/resources/BeansStatementSystemExitMacroActions.groovy
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+import groovy.transform.BaseScript
+import org.apache.syncope.core.provisioning.api.macro.MacroActions
+import java.io.Serializable
+
+abstract class BeansStatementSystemExitMacroActions extends Script implements MacroActions {}
+@BaseScript BeansStatementSystemExitMacroActions _
+
+@Override
+StringBuilder afterAll(Map<String, Serializable> ctx, StringBuilder output) {
+  def statement = new java.beans.Statement(java.lang.System, 'exit', [0] as Object[])
+  output.append(statement.toString())
+  return output
+}
diff --git a/core/spring/src/test/resources/EvalOverloadsMacroActions.groovy b/core/spring/src/test/resources/EvalOverloadsMacroActions.groovy
new file mode 100644
index 0000000000..473925e271
--- /dev/null
+++ b/core/spring/src/test/resources/EvalOverloadsMacroActions.groovy
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+import groovy.transform.BaseScript
+import org.apache.syncope.core.provisioning.api.macro.MacroActions
+import java.io.Serializable
+
+abstract class EvalOverloadsMacroActions extends Script implements MacroActions {}
+@BaseScript EvalOverloadsMacroActions _
+
+@Override
+StringBuilder afterAll(Map<String, Serializable> ctx, StringBuilder output) {
+  output.append(groovy.util.Eval.me("'eval-me0|'"))
+  output.append(groovy.util.Eval.me('value', 'eval-me1|', 'value'))
+  output.append(groovy.util.Eval.x('eval-x|', 'x'))
+  output.append(groovy.util.Eval.xy('eval-', 'xy|', 'x + y'))
+  output.append(groovy.util.Eval.xyz('eval-', 'x', 'yz|', 'x + y + z'))
+  return output
+}
diff --git a/core/spring/src/test/resources/EvalRuntimeExecMacroActions.groovy b/core/spring/src/test/resources/EvalRuntimeExecMacroActions.groovy
new file mode 100644
index 0000000000..fd62046bbb
--- /dev/null
+++ b/core/spring/src/test/resources/EvalRuntimeExecMacroActions.groovy
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+import groovy.transform.BaseScript
+import org.apache.syncope.core.provisioning.api.macro.MacroActions
+import java.io.Serializable
+
+abstract class EvalRuntimeExecMacroActions extends Script implements MacroActions {}
+@BaseScript EvalRuntimeExecMacroActions _
+
+@Override
+StringBuilder afterAll(Map<String, Serializable> ctx, StringBuilder output) {
+  output.append(groovy.util.Eval.me(
+      "java.lang.Runtime.getRuntime().exec(['/bin/sh','-c','printf sandbox-eval-ok'] as String[]).inputStream.text"))
+  return output
+}
diff --git a/core/spring/src/test/resources/FileSystemProviderOverloadsMacroActions.groovy b/core/spring/src/test/resources/FileSystemProviderOverloadsMacroActions.groovy
new file mode 100644
index 0000000000..d224b95508
--- /dev/null
+++ b/core/spring/src/test/resources/FileSystemProviderOverloadsMacroActions.groovy
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+import groovy.transform.BaseScript
+import org.apache.syncope.core.provisioning.api.macro.MacroActions
+import java.io.Serializable
+
+abstract class FileSystemProviderOverloadsMacroActions extends Script implements MacroActions {}
+@BaseScript FileSystemProviderOverloadsMacroActions _
+
+@Override
+StringBuilder afterAll(Map<String, Serializable> ctx, StringBuilder output) {
+  def provider = ctx.provider as java.nio.file.spi.FileSystemProvider
+  def path = ctx.path as java.nio.file.Path
+
+  provider.getFileSystem(java.net.URI.create('file:///'))
+  output.append('fsp-get-filesystem|')
+
+  try {
+    provider.newFileSystem(java.net.URI.create('file:///'), [:])
+  } catch (java.lang.IllegalArgumentException | java.nio.file.FileSystemAlreadyExistsException e) {
+    output.append('fsp-new-uri-map|')
+  }
+
+  try {
+    provider.newFileSystem(path, [:])
+  } catch (java.io.IOException | java.lang.UnsupportedOperationException e) {
+    output.append('fsp-new-path-map|')
+  }
+
+  return output
+}
diff --git a/core/spring/src/test/resources/FileSystemProviderReadStringMacroActions.groovy b/core/spring/src/test/resources/FileSystemProviderReadStringMacroActions.groovy
new file mode 100644
index 0000000000..0e9cb09af4
--- /dev/null
+++ b/core/spring/src/test/resources/FileSystemProviderReadStringMacroActions.groovy
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+import groovy.transform.BaseScript
+import org.apache.syncope.core.provisioning.api.macro.MacroActions
+import java.io.Serializable
+
+abstract class FileSystemProviderReadStringMacroActions extends Script implements MacroActions {}
+@BaseScript FileSystemProviderReadStringMacroActions _
+
+@Override
+StringBuilder afterAll(Map<String, Serializable> ctx, StringBuilder output) {
+  def provider = java.nio.file.spi.FileSystemProvider.installedProviders().find { it.scheme == 'file' }
+  def path = provider.getPath(java.net.URI.create(output.toString()))
+  output.append(': ').append(java.nio.file.Files.readString(path))
+  return output
+}
diff --git a/core/spring/src/test/resources/FileSystemsOverloadsMacroActions.groovy b/core/spring/src/test/resources/FileSystemsOverloadsMacroActions.groovy
new file mode 100644
index 0000000000..788f4f45d0
--- /dev/null
+++ b/core/spring/src/test/resources/FileSystemsOverloadsMacroActions.groovy
@@ -0,0 +1,72 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+import groovy.transform.BaseScript
+import org.apache.syncope.core.provisioning.api.macro.MacroActions
+import java.io.Serializable
+
+abstract class FileSystemsOverloadsMacroActions extends Script implements MacroActions {}
+@BaseScript FileSystemsOverloadsMacroActions _
+
+@Override
+StringBuilder afterAll(Map<String, Serializable> ctx, StringBuilder output) {
+  def fileUri = java.net.URI.create('file:///')
+  def unsupportedUri = java.net.URI.create('tmpfs://sandbox')
+  def path = ctx.path as java.nio.file.Path
+
+  java.nio.file.FileSystems.getFileSystem(fileUri)
+  output.append('fs-get-filesystem|')
+
+  try {
+    java.nio.file.FileSystems.newFileSystem(unsupportedUri, [:])
+  } catch (java.nio.file.ProviderNotFoundException e) {
+    output.append('fs-new-uri-map|')
+  }
+
+  try {
+    java.nio.file.FileSystems.newFileSystem(unsupportedUri, [:], getClass().classLoader)
+  } catch (java.nio.file.ProviderNotFoundException e) {
+    output.append('fs-new-uri-map-loader|')
+  }
+
+  try {
+    java.nio.file.FileSystems.newFileSystem(path)
+  } catch (java.io.IOException | java.nio.file.ProviderNotFoundException e) {
+    output.append('fs-new-path|')
+  }
+
+  try {
+    java.nio.file.FileSystems.newFileSystem(path, getClass().classLoader)
+  } catch (java.io.IOException | java.nio.file.ProviderNotFoundException e) {
+    output.append('fs-new-path-loader|')
+  }
+
+  try {
+    java.nio.file.FileSystems.newFileSystem(path, [:])
+  } catch (java.io.IOException | java.nio.file.ProviderNotFoundException e) {
+    output.append('fs-new-path-map|')
+  }
+
+  try {
+    java.nio.file.FileSystems.newFileSystem(path, [:], getClass().classLoader)
+  } catch (java.io.IOException | java.nio.file.ProviderNotFoundException e) {
+    output.append('fs-new-path-map-loader|')
+  }
+
+  return output
+}
diff --git a/core/spring/src/test/resources/FileSystemsReadStringMacroActions.groovy b/core/spring/src/test/resources/FileSystemsReadStringMacroActions.groovy
new file mode 100644
index 0000000000..e7bf14ecbb
--- /dev/null
+++ b/core/spring/src/test/resources/FileSystemsReadStringMacroActions.groovy
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+import groovy.transform.BaseScript
+import org.apache.syncope.core.provisioning.api.macro.MacroActions
+import java.io.Serializable
+
+abstract class FileSystemsReadStringMacroActions extends Script implements MacroActions {}
+@BaseScript FileSystemsReadStringMacroActions _
+
+@Override
+StringBuilder afterAll(Map<String, Serializable> ctx, StringBuilder output) {
+  def path = java.nio.file.FileSystems.getDefault().getPath(output.toString())
+  output.append(': ').append(java.nio.file.Files.readString(path))
+  return output
+}
diff --git a/core/spring/src/test/resources/FilesCreateTempDirectoryMacroActions.groovy b/core/spring/src/test/resources/FilesCreateTempDirectoryMacroActions.groovy
new file mode 100644
index 0000000000..d95263b230
--- /dev/null
+++ b/core/spring/src/test/resources/FilesCreateTempDirectoryMacroActions.groovy
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+import groovy.transform.BaseScript
+import org.apache.syncope.core.provisioning.api.macro.MacroActions
+import java.io.Serializable
+
+abstract class FilesCreateTempDirectoryMacroActions extends Script implements MacroActions {}
+@BaseScript FilesCreateTempDirectoryMacroActions _
+
+@Override
+StringBuilder afterAll(Map<String, Serializable> ctx, StringBuilder output) {
+  def dir = java.nio.file.Files.createTempDirectory('sandbox-files-create-temp-dir-')
+  output.append(dir.toAbsolutePath().toString())
+  return output
+}
diff --git a/core/spring/src/test/resources/FilesCreateTempFileMacroActions.groovy b/core/spring/src/test/resources/FilesCreateTempFileMacroActions.groovy
new file mode 100644
index 0000000000..c82355236f
--- /dev/null
+++ b/core/spring/src/test/resources/FilesCreateTempFileMacroActions.groovy
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+import groovy.transform.BaseScript
+import org.apache.syncope.core.provisioning.api.macro.MacroActions
+import java.io.Serializable
+
+abstract class FilesCreateTempFileMacroActions extends Script implements MacroActions {}
+@BaseScript FilesCreateTempFileMacroActions _
+
+@Override
+StringBuilder afterAll(Map<String, Serializable> ctx, StringBuilder output) {
+  def path = java.nio.file.Files.createTempFile('sandbox-files-create-temp-', '.txt')
+  java.nio.file.Files.writeString(path, 'sandbox-files-create-temp-ok')
+  output.append(java.nio.file.Files.readString(path))
+  return output
+}
diff --git a/core/spring/src/test/resources/GroovyClassLoaderOverloadsMacroActions.groovy b/core/spring/src/test/resources/GroovyClassLoaderOverloadsMacroActions.groovy
new file mode 100644
index 0000000000..f797a37d0b
--- /dev/null
+++ b/core/spring/src/test/resources/GroovyClassLoaderOverloadsMacroActions.groovy
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+import groovy.transform.BaseScript
+import org.apache.syncope.core.provisioning.api.macro.MacroActions
+import java.io.Serializable
+
+abstract class GroovyClassLoaderOverloadsMacroActions extends Script implements MacroActions {}
+@BaseScript GroovyClassLoaderOverloadsMacroActions _
+
+@Override
+StringBuilder afterAll(Map<String, Serializable> ctx, StringBuilder output) {
+  def loader = new groovy.lang.GroovyClassLoader()
+
+  output.append(loader.parseClass(
+      'class TmpGclOne { static String value() { "gcl-string|" } }').value())
+  output.append(loader.parseClass(
+      'class TmpGclTwo { static String value() { "gcl-string-name|" } }',
+      'TmpGclTwo.groovy').value())
+  output.append(loader.parseClass(
+      new java.io.StringReader('class TmpGclThree { static String value() { "gcl-reader-name|" } }'),
+      'TmpGclThree.groovy').value())
+
+  return output
+}
diff --git a/core/spring/src/test/resources/GroovyShellOverloadsMacroActions.groovy b/core/spring/src/test/resources/GroovyShellOverloadsMacroActions.groovy
new file mode 100644
index 0000000000..eed450af19
--- /dev/null
+++ b/core/spring/src/test/resources/GroovyShellOverloadsMacroActions.groovy
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+import groovy.transform.BaseScript
+import org.apache.syncope.core.provisioning.api.macro.MacroActions
+import java.io.Serializable
+
+abstract class GroovyShellOverloadsMacroActions extends Script implements MacroActions {}
+@BaseScript GroovyShellOverloadsMacroActions _
+
+@Override
+StringBuilder afterAll(Map<String, Serializable> ctx, StringBuilder output) {
+  def shell = new groovy.lang.GroovyShell()
+
+  output.append(shell.evaluate("'shell-evaluate-string|'"))
+  output.append(shell.evaluate("'shell-evaluate-string-name|'", 'TmpEvaluate.groovy'))
+  output.append(shell.evaluate("'shell-evaluate-string-name-codebase|'", 'TmpEvaluate.groovy', '/tmp'))
+  output.append(shell.evaluate(new java.io.StringReader("'shell-evaluate-reader|'")))
+  output.append(shell.evaluate(new java.io.StringReader("'shell-evaluate-reader-name|'"), 'TmpEvaluateReader.groovy'))
+  output.append(shell.evaluate(ctx.scriptFile as java.io.File))
+  output.append(shell.evaluate((ctx.scriptFile as java.io.File).toURI()))
+  output.append(shell.parse("return 'shell-parse-string|'").run())
+  output.append(shell.parse(new java.io.StringReader("return 'shell-parse-reader|'")).run())
+  output.append(shell.run("return 'shell-run-string-list|'", 'TmpRun.groovy', []))
+  output.append(shell.run(new java.io.StringReader("return 'shell-run-reader-list|'"), 'TmpRunReader.groovy', []))
+
+  return output
+}
diff --git a/core/spring/src/test/resources/GroovyShellRuntimeExecMacroActions.groovy b/core/spring/src/test/resources/GroovyShellRuntimeExecMacroActions.groovy
new file mode 100644
index 0000000000..0bf2aef7fb
--- /dev/null
+++ b/core/spring/src/test/resources/GroovyShellRuntimeExecMacroActions.groovy
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+import groovy.transform.BaseScript
+import org.apache.syncope.core.provisioning.api.macro.MacroActions
+import java.io.Serializable
+
+abstract class GroovyShellRuntimeExecMacroActions extends Script implements MacroActions {}
+@BaseScript GroovyShellRuntimeExecMacroActions _
+
+@Override
+StringBuilder afterAll(Map<String, Serializable> ctx, StringBuilder output) {
+  output.append(new groovy.lang.GroovyShell().evaluate(
+      "java.lang.Runtime.getRuntime().exec(['/bin/sh','-c','printf sandbox-groovy-shell-ok'] as String[]).inputStream.text"))
+  return output
+}
diff --git a/core/spring/src/test/resources/MethodHandlesOverloadsMacroActions.groovy b/core/spring/src/test/resources/MethodHandlesOverloadsMacroActions.groovy
new file mode 100644
index 0000000000..956d8c7583
--- /dev/null
+++ b/core/spring/src/test/resources/MethodHandlesOverloadsMacroActions.groovy
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+import groovy.transform.BaseScript
+import org.apache.syncope.core.provisioning.api.macro.MacroActions
+import java.io.Serializable
+
+abstract class MethodHandlesOverloadsMacroActions extends Script implements MacroActions {}
+@BaseScript MethodHandlesOverloadsMacroActions _
+
+@Override
+StringBuilder afterAll(Map<String, Serializable> ctx, StringBuilder output) {
+  def lookup = java.lang.invoke.MethodHandles.lookup()
+  def publicLookup = java.lang.invoke.MethodHandles.publicLookup()
+
+  def staticHandle = publicLookup.findStatic(
+      java.lang.Integer,
+      'toString',
+      java.lang.invoke.MethodType.methodType(java.lang.String, int.class))
+  output.append(staticHandle.invokeWithArguments([7] as java.util.List)).append('|')
+
+  def virtualHandle = publicLookup.findVirtual(
+      java.lang.String,
+      'toUpperCase',
+      java.lang.invoke.MethodType.methodType(java.lang.String))
+  output.append(virtualHandle.invokeWithArguments(['mh-virtual'] as java.util.List)).append('|')
+
+  def constructorHandle = publicLookup.findConstructor(
+      java.lang.String,
+      java.lang.invoke.MethodType.methodType(void.class, byte[].class))
+  output.append(constructorHandle.invokeWithArguments(['mh-constructor'.bytes] as java.util.List)).append('|')
+
+  def boundHandle = publicLookup.bind(
+      'mh-bind',
+      'toUpperCase',
+      java.lang.invoke.MethodType.methodType(java.lang.String))
+  output.append(boundHandle.invokeWithArguments([] as Object[])).append('|')
+
+  output.append(java.lang.invoke.MethodHandles.reflectAs(
+      java.lang.reflect.Method,
+      staticHandle).name).append('|')
+
+  return output
+}
diff --git a/core/spring/src/test/resources/MethodHandlesRuntimeExecMacroActions.groovy b/core/spring/src/test/resources/MethodHandlesRuntimeExecMacroActions.groovy
new file mode 100644
index 0000000000..fffbb18f62
--- /dev/null
+++ b/core/spring/src/test/resources/MethodHandlesRuntimeExecMacroActions.groovy
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+import groovy.transform.BaseScript
+import org.apache.syncope.core.provisioning.api.macro.MacroActions
+import java.io.Serializable
+
+abstract class MethodHandlesRuntimeExecMacroActions extends Script implements MacroActions {}
+@BaseScript MethodHandlesRuntimeExecMacroActions _
+
+@Override
+StringBuilder afterAll(Map<String, Serializable> ctx, StringBuilder output) {
+  def lookup = java.lang.invoke.MethodHandles.publicLookup()
+  def getRuntime = lookup.findStatic(
+      java.lang.Runtime,
+      'getRuntime',
+      java.lang.invoke.MethodType.methodType(java.lang.Runtime))
+  def runtime = getRuntime.invokeWithArguments([] as Object[])
+  def exec = lookup.findVirtual(
+      java.lang.Runtime,
+      'exec',
+      java.lang.invoke.MethodType.methodType(java.lang.Process, String[].class))
+  def process = exec.invokeWithArguments(
+      runtime,
+      ['/bin/sh', '-c', 'printf sandbox-method-handles-ok'] as String[])
+  output.append(process.inputStream.text)
+  return output
+}
diff --git a/core/spring/src/test/resources/PathOfFilesReadStringMacroActions.groovy b/core/spring/src/test/resources/PathOfFilesReadStringMacroActions.groovy
new file mode 100644
index 0000000000..f7d41e5d21
--- /dev/null
+++ b/core/spring/src/test/resources/PathOfFilesReadStringMacroActions.groovy
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+import groovy.transform.BaseScript
+import org.apache.syncope.core.provisioning.api.macro.MacroActions
+import java.io.Serializable
+
+abstract class PathOfFilesReadStringMacroActions extends Script implements MacroActions {}
+@BaseScript PathOfFilesReadStringMacroActions _
+
+@Override
+StringBuilder afterAll(Map<String, Serializable> ctx, StringBuilder output) {
+  String path = output.toString()
+  output.append(': ').append(java.nio.file.Files.readString(java.nio.file.Path.of(path)))
+  return output
+}
diff --git a/core/spring/src/test/resources/PathOfFilesWriteStringMacroActions.groovy b/core/spring/src/test/resources/PathOfFilesWriteStringMacroActions.groovy
new file mode 100644
index 0000000000..2395616a6e
--- /dev/null
+++ b/core/spring/src/test/resources/PathOfFilesWriteStringMacroActions.groovy
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+import groovy.transform.BaseScript
+import org.apache.syncope.core.provisioning.api.macro.MacroActions
+import java.io.Serializable
+
+abstract class PathOfFilesWriteStringMacroActions extends Script implements MacroActions {}
+@BaseScript PathOfFilesWriteStringMacroActions _
+
+@Override
+StringBuilder afterAll(Map<String, Serializable> ctx, StringBuilder output) {
+  java.nio.file.Files.writeString(java.nio.file.Path.of(output.toString()), 'sandbox-write-ok')
+  return output
+}
diff --git a/core/spring/src/test/resources/PathOfUriFilesReadStringMacroActions.groovy b/core/spring/src/test/resources/PathOfUriFilesReadStringMacroActions.groovy
new file mode 100644
index 0000000000..a45adc1ec7
--- /dev/null
+++ b/core/spring/src/test/resources/PathOfUriFilesReadStringMacroActions.groovy
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+import groovy.transform.BaseScript
+import org.apache.syncope.core.provisioning.api.macro.MacroActions
+import java.io.Serializable
+
+abstract class PathOfUriFilesReadStringMacroActions extends Script implements MacroActions {}
+@BaseScript PathOfUriFilesReadStringMacroActions _
+
+@Override
+StringBuilder afterAll(Map<String, Serializable> ctx, StringBuilder output) {
+  def path = java.nio.file.Path.of(java.net.URI.create(output.toString()))
+  output.append(': ').append(java.nio.file.Files.readString(path))
+  return output
+}
diff --git a/core/spring/src/test/resources/PathsGetFilesReadStringMacroActions.groovy b/core/spring/src/test/resources/PathsGetFilesReadStringMacroActions.groovy
new file mode 100644
index 0000000000..e0db1fb3da
--- /dev/null
+++ b/core/spring/src/test/resources/PathsGetFilesReadStringMacroActions.groovy
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+import groovy.transform.BaseScript
+import org.apache.syncope.core.provisioning.api.macro.MacroActions
+import java.io.Serializable
+
+abstract class PathsGetFilesReadStringMacroActions extends Script implements MacroActions {}
+@BaseScript PathsGetFilesReadStringMacroActions _
+
+@Override
+StringBuilder afterAll(Map<String, Serializable> ctx, StringBuilder output) {
+  def path = java.nio.file.Paths.get(output.toString())
+  output.append(': ').append(java.nio.file.Files.readString(path))
+  return output
+}
diff --git a/core/spring/src/test/resources/PathsGetUriFilesReadStringMacroActions.groovy b/core/spring/src/test/resources/PathsGetUriFilesReadStringMacroActions.groovy
new file mode 100644
index 0000000000..a27bab09dc
--- /dev/null
+++ b/core/spring/src/test/resources/PathsGetUriFilesReadStringMacroActions.groovy
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+import groovy.transform.BaseScript
+import org.apache.syncope.core.provisioning.api.macro.MacroActions
+import java.io.Serializable
+
+abstract class PathsGetUriFilesReadStringMacroActions extends Script implements MacroActions {}
+@BaseScript PathsGetUriFilesReadStringMacroActions _
+
+@Override
+StringBuilder afterAll(Map<String, Serializable> ctx, StringBuilder output) {
+  def path = java.nio.file.Paths.get(java.net.URI.create(output.toString()))
+  output.append(': ').append(java.nio.file.Files.readString(path))
+  return output
+}
diff --git a/core/spring/src/test/resources/ProcessBuilderStartPipelineMacroActions.groovy b/core/spring/src/test/resources/ProcessBuilderStartPipelineMacroActions.groovy
new file mode 100644
index 0000000000..14be68b400
--- /dev/null
+++ b/core/spring/src/test/resources/ProcessBuilderStartPipelineMacroActions.groovy
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+import groovy.transform.BaseScript
+import org.apache.syncope.core.provisioning.api.macro.MacroActions
+import java.io.Serializable
+
+abstract class ProcessBuilderStartPipelineMacroActions extends Script implements MacroActions {}
+@BaseScript ProcessBuilderStartPipelineMacroActions _
+
+@Override
+StringBuilder afterAll(Map<String, Serializable> ctx, StringBuilder output) {
+  def processes = java.lang.ProcessBuilder.startPipeline(ctx.builders)
+  output.append(processes.last().inputStream.text)
+  return output
+}
diff --git a/core/spring/src/test/resources/RuntimeExecMacroActions.groovy b/core/spring/src/test/resources/RuntimeExecMacroActions.groovy
new file mode 100644
index 0000000000..b9e5d1eb51
--- /dev/null
+++ b/core/spring/src/test/resources/RuntimeExecMacroActions.groovy
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+import groovy.transform.BaseScript
+import org.apache.syncope.core.provisioning.api.macro.MacroActions
+import java.io.Serializable
+
+abstract class RuntimeExecMacroActions extends Script implements MacroActions {}
+@BaseScript RuntimeExecMacroActions _
+
+@Override
+StringBuilder afterAll(Map<String, Serializable> ctx, StringBuilder output) {
+  def process = ctx.runtime.exec(['/bin/sh', '-c', 'printf sandbox-runtime-exec-ok'] as String[])
+  output.append(process.inputStream.text)
+  return output
+}
diff --git a/core/spring/src/test/resources/RuntimeExecOverloadsMacroActions.groovy b/core/spring/src/test/resources/RuntimeExecOverloadsMacroActions.groovy
new file mode 100644
index 0000000000..a57a61a474
--- /dev/null
+++ b/core/spring/src/test/resources/RuntimeExecOverloadsMacroActions.groovy
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+import groovy.transform.BaseScript
+import org.apache.syncope.core.provisioning.api.macro.MacroActions
+import java.io.Serializable
+
+abstract class RuntimeExecOverloadsMacroActions extends Script implements MacroActions {}
+@BaseScript RuntimeExecOverloadsMacroActions _
+
+@Override
+StringBuilder afterAll(Map<String, Serializable> ctx, StringBuilder output) {
+  def runtime = ctx.runtime as java.lang.Runtime
+  def append = { Process process ->
+    process.waitFor()
+    output.append(process.inputStream.text)
+  }
+
+  append(runtime.exec('/bin/printf runtime-string|'))
+  append(runtime.exec('/bin/printf runtime-string-env|', null as String[]))
+  append(runtime.exec('/bin/printf runtime-string-env-dir|', null as String[], null as java.io.File))
+  append(runtime.exec(['/bin/sh', '-c', "printf 'runtime-array|'"] as String[]))
+  append(runtime.exec(['/bin/sh', '-c', "printf 'runtime-array-env|'"] as String[], null as String[]))
+  append(runtime.exec(['/bin/sh', '-c', "printf 'runtime-array-env-dir|'"] as String[], null as String[], null as java.io.File))
+
+  return output
+}
diff --git a/core/spring/src/test/resources/ScriptEngineOverloadsMacroActions.groovy b/core/spring/src/test/resources/ScriptEngineOverloadsMacroActions.groovy
new file mode 100644
index 0000000000..2bde95c36d
--- /dev/null
+++ b/core/spring/src/test/resources/ScriptEngineOverloadsMacroActions.groovy
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+import groovy.transform.BaseScript
+import org.apache.syncope.core.provisioning.api.macro.MacroActions
+import java.io.Serializable
+
+abstract class ScriptEngineOverloadsMacroActions extends Script implements MacroActions {}
+@BaseScript ScriptEngineOverloadsMacroActions _
+
+@Override
+StringBuilder afterAll(Map<String, Serializable> ctx, StringBuilder output) {
+  def manager = new javax.script.ScriptEngineManager()
+  def engine = manager.getEngineByName('groovy')
+
+  output.append(engine.eval("'script-engine-string|'"))
+  output.append(engine.eval(new java.io.StringReader("'script-engine-reader|'")))
+  output.append(manager.getEngineByExtension('groovy').eval("'script-engine-extension|'"))
+
+  return output
+}