0

Problem: I am trying to provide restriction (blacklisting ) all and allow only what I provided when we execute groovy using GroovyClassLoader

I am able to execute custom policy using with limited permission for GroovyClassLoader only.

Now I am trying to provide package restriction going to use as part of groovy execution. Let say If I allowed com.x.y this package if any package other then this used in groovy should throw SecurityException

I have tried to achieve the same with custom security manager and overriding the checkPackageAccess but didn't get success.

    public TestSecurityManager extends SecurityManager{

    List<String> whiteListedPkgList;

     public void checkPackageAccess(String pkg){
         if(!pkg.startWith(any of given white list pkg)){
           throw new SecurityException("Access Denied");
           }
        //If package not belong to whilelisted package list throw security exception
       }
    }

When I tried using above approach we need to provide all packages for execution like com, java etc instead of java.nio.file. in whitelist list

UPDATE

If we try to allow package like com.x.y using white list comparison using start with check access pkg, it will allow that package but later on it will throw security exception for com package.

Could any one help for the same how we can achieve it ?

Thanks in advance

Ranjitsinh
  • 1,323
  • 1
  • 11
  • 28

1 Answers1

1

If you're able to, instead of using Java's SecurityManager, using the Groovy DSL features you can more easily achieve this.

See https://www.groovy-lang.org/dsls.html#_secure_ast_customizer

Example:

import groovy.transform.CompileStatic
import org.codehaus.groovy.control.CompilerConfiguration
import org.codehaus.groovy.control.customizers.CompilationCustomizer
import org.codehaus.groovy.control.customizers.SecureASTCustomizer

@CompileStatic
class Main {
    static final CompilationCustomizer scz = new SecureASTCustomizer().with {
        closuresAllowed = false // user will not be able to write closures
        methodDefinitionAllowed = false // user will not be able to define methods
        importsWhitelist = [] // empty whitelist means imports are disallowed
        staticImportsWhitelist = [] // same for static imports
        staticStarImportsWhitelist = ['java.lang.Math'] // only java.lang.Math is allowed
        constantTypesClassesWhiteList = [
                Integer,
                Float,
                Long,
                Double,
                BigDecimal,
                Integer.TYPE,
                Long.TYPE,
                Float.TYPE,
                Double.TYPE,
                Object,
                String,
        ].asImmutable() as List<Class>
        // method calls are only allowed if the receiver is of one of those types
        // be careful, it's not a runtime type!
        receiversClassesWhiteList = [
                Math,
                Integer,
                Float,
                Double,
                Long,
                BigDecimal,
                PrintStream,
                Object,
        ].asImmutable() as List<Class>

        it
    }

    static void main(args) {
        def configuration = new CompilerConfiguration()
        configuration.addCompilationCustomizers(scz)

        // evaluate sandboxed code
        new GroovyShell(configuration).evaluate(
                """ println 'hello world' """)
    }

}

If all you need is to whitelist certain classes, you can also try writing your own class loader and using that to evalute the sandboxed script:

class MyClassLoader extends ClassLoader {

    Set<String> whiteListPackages = [
            'java.lang.', 'java.util.', 'groovy.', 'org.codehaus.groovy.', 'Script'
    ]

    MyClassLoader(ClassLoader parent) {
        super(parent)
    }

    @Override
    protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
        if (!whiteListPackages.any { okPkg -> name.startsWith(okPkg) }) {
            throw new ClassNotFoundException('Access is forbidden')
        }
        return super.loadClass(name, resolve)
    }
}

def shell = new GroovyShell(new MyClassLoader(GroovySystem.classLoader))

// evaluate the script with our own classloader
shell.evaluate('''
println 'hello'
println([1,2,3])

// This line throws an error because the `java.net` package is not whitelisted
println(new URL('https://groovy-lang.org'))
''')
Renato
  • 12,940
  • 3
  • 54
  • 85
  • Thank you for the answer ! I have tried the same but found below problems. 1.) It doesn't allow sub packages. Like if you add package x.y in white-list, it won't allow x.y.z sub-package. 2.) it won't able to identify packages if we use external jar using class loader in groovy. – Ranjitsinh Jan 29 '20 at 08:51
  • if you only care about packages of the classes being used, you just need to implement and use your own classloader... pretty easy to do. Will post another answer showing how. – Renato Jan 29 '20 at 18:18
  • I need restriction not only for packages used but also for other component. like If I will allow access to read only file for any location but not write and delete and more. – Ranjitsinh Jan 30 '20 at 07:33
  • Would be great if you could provide a way to restrict specific method of any class using DSL – Ranjitsinh Jan 30 '20 at 09:32
  • to restrict methods like that, just expose your own types to the script which implement whatever restriction you want. – Renato Jan 30 '20 at 19:37
  • Could you provide a example you suggested for own class-loader ? – Ranjitsinh Feb 17 '20 at 12:53
  • Added example in the answer. – Renato Feb 18 '20 at 09:28
  • Thanks you ! I have checked added example but it won't help in case if we use external jar reference >> class in groovy. Do have any idea how we can block the used class in external jar file ? – Ranjitsinh Feb 24 '20 at 09:01
  • This example can already do that... what exactly do you mean you cannot block?? – Renato Feb 24 '20 at 12:36
  • It won't work for me. The reason is I am generating my groovy class dynamically using parse class method of GroovyClassLoader instead of loadClass method. I wanted to restrict the class used in groovy which is coming from external jar file references. – Ranjitsinh Feb 24 '20 at 12:52
  • I am able to restrict packages but now wanted to block/prevent access of specific class for given package access for groovy execution. Groovy DSL works only for compile time not for external jar reference – Ranjitsinh Feb 24 '20 at 12:55
  • 1
    You should ask this in a new question, with an example sample code showing what exactly doesn't work. – Renato Feb 24 '20 at 19:11