Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/security/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何在Groovy脚本中通过@Grab禁止依赖关系_Java_Security_Groovy_Scripting - Fatal编程技术网

Java 如何在Groovy脚本中通过@Grab禁止依赖关系

Java 如何在Groovy脚本中通过@Grab禁止依赖关系,java,security,groovy,scripting,Java,Security,Groovy,Scripting,我想允许用户在我的Java服务器应用程序中运行Groovy脚本,但我也不允许他们使用@Grab添加任何随机依赖项 是的,通过在源代码中搜索和替换,我可以简单地切断所有@Grab注释,但最好以更优雅的方式完成,例如,只允许批准的依赖项 是的,我知道这个问题的最佳解决方案是JVM的SecurityManager 有各种方法,例如,可能比您将要看到的效果更好 import groovy.grape.Grape Grape.metaClass.static.grab = {String endorse

我想允许用户在我的Java服务器应用程序中运行Groovy脚本,但我也不允许他们使用
@Grab
添加任何随机依赖项

是的,通过在源代码中搜索和替换,我可以简单地切断所有
@Grab
注释,但最好以更优雅的方式完成,例如,只允许批准的依赖项


是的,我知道这个问题的最佳解决方案是JVM的
SecurityManager

有各种方法,例如,可能比您将要看到的效果更好

import groovy.grape.Grape

Grape.metaClass.static.grab = {String endorsed ->
    throw new SecurityException("Oh no you didn't! Grabbing is forbidden.")
}

Grape.metaClass.static.grab = {Map dependency ->
    throw new SecurityException("Oh no you didn't! Grabbing is forbidden.")
}

Grape.metaClass.static.grab = {Map args, Map dependency ->
    throw new SecurityException("Oh no you didn't! Grabbing is forbidden.")
}

def source1 = '''
println('This is a nice safe Groovy script.')
'''

def source2 = '''
@Grab('commons-validator:commons-validator:1.4.1')

import org.apache.commons.validator.routines.EmailValidator

def emailValidator = EmailValidator.getInstance();

assert emailValidator.isValid('what.a.shame@us.elections.gov')
assert !emailValidator.isValid('an_invalid_emai_address')

println 'You should not see this message!'
'''

def script
def shell = new GroovyShell()

try {
    script = shell.parse(source1)
    script.run()
} catch (Exception e) { 
    assert false, "Oh, oh. That wasn't supposed to happen :("
}    

try {
    script = shell.parse(source2)
    assert false, "Oh, oh. That wasn't supposed to happen :("
} catch (ExceptionInInitializerError e) { 
    println 'Naughty script was blocked when parsed.'
}  
上面的示例演示了如何阻止@Grab。它不是通过阻止注释来实现的,而是通过重写注释添加的方法调用:groovy.grape.grape.grab()

下面是Groovy控制台AST查看器剖析的顽皮脚本:

@groovy.lang.Grab(module = 'commons-validator', group = 'commons-validator', version = '1.4.1')
import org.apache.commons.validator.routines.EmailValidator as EmailValidator

public class script1440223706571 extends groovy.lang.Script { 

    private static org.codehaus.groovy.reflection.ClassInfo $staticClassInfo 
    public static transient boolean __$stMC 

    public script1440223706571() {
    }

    public script1440223706571(groovy.lang.Binding context) {
        super(context)
    }

    public static void main(java.lang.String[] args) {
        org.codehaus.groovy.runtime.InvokerHelper.runScript(script1440223706571, args)
    }

    public java.lang.Object run() {
        java.lang.Object emailValidator = org.apache.commons.validator.routines.EmailValidator.getInstance()
        assert emailValidator.isValid('what.a.shame@us.elections.gov') : null
        assert !(emailValidator.isValid('an_invalid_emai_address')) : null
        return null
    }

    static { 
        groovy.grape.Grape.grab([:], ['group': 'commons-validator', 'module': 'commons-validator', 'version': '1.4.1'])
    }

    protected groovy.lang.MetaClass $getStaticMetaClass() {
    }

}
在这里,您可以看到静态初始值设定项中对Grape.grab()的调用。要添加对依赖项的细粒度筛选,可以内省依赖项和已认可的参数

附属国 ['group':'commons validator','module':'commons validator','version':'1.4.1']

认可 commons验证程序:commons验证程序:1.4.1

订正执行情况 这个新的实现使用拦截器来阻止/允许葡萄抓取

import groovy.grape.GrapeIvy

def source1 = '''
println('This is a nice safe Groovy script.')
'''

def source2 = '''
@Grab('commons-validator:commons-validator:1.4.1')

import org.apache.commons.validator.routines.EmailValidator

def emailValidator = EmailValidator.getInstance();

assert emailValidator.isValid('what.a.shame@us.elections.gov')
assert !emailValidator.isValid('an_invalid_emai_address')

println 'You should not see this message!'
'''

def script
def shell = new GroovyShell()
def proxy = ProxyMetaClass.getInstance(GrapeIvy)

proxy.interceptor = new GrapeInterceptor({group, module, version ->
    if(group == 'commons-validator' && module == 'commons-validator') false
    else true
})

proxy.use {
    shell.parse(source1).run()

    try {
        shell.parse(source2).run()
    } catch (org.codehaus.groovy.control.MultipleCompilationErrorsException e) {
        assert e.message.contains('unable to resolve class')
    }
}

@groovy.transform.TupleConstructor
class GrapeInterceptor implements Interceptor {
    private boolean invokeMethod = true
    Closure authorizer

    def afterInvoke(Object object, String methodName, Object[] arguments, Object result) {
        invokeMethod = true

        return result
    }

    def beforeInvoke(Object object, String methodName, Object[] arguments) {
        if(methodName == 'createGrabRecord') {
            def dependencies = arguments[0]
            invokeMethod = authorizer(dependencies.group, dependencies.module, dependencies.version)
        } else {
            invokeMethod = true
        }

        return null
    }

    boolean doInvoke() { invokeMethod }
}
GrapeInterceptor构造函数将闭包作为其唯一参数。使用此闭包,您可以轻松决定是否允许抓取:

例如,如果抓取看起来像这样:@Grab('commons-validator:commons-validator:1.4.1')

闭包的参数分配如下:

  • 组:commons验证程序
  • 模块:公共验证程序
  • 版本:1.4.1

要允许抓取,闭包必须返回true。返回false以阻止它。

很好,太多的工作应该手动完成,但仍然可以实现。谢谢,不客气。我更新了答案以包含更好的解决方案。这将允许您有选择地允许/阻止抓取。更好,谢谢!对此解决方案的唯一抱怨是,我必须了解太多有关
GrapeIvy
实现的细节,即
createGrabRecord
方法,但肯定更好,而且可以使用。
ProxyMetaClass
的魔力是什么!不客气。ProxyMetaClass确实很棒。我不知道你说的要知道太多细节是什么意思。(自定义)GrapeInterceptor处理细节。您只需创建它的实例,然后将其与代理一起使用。您甚至可以创建一个工厂类或方法来返回一个可供使用的代理。
import groovy.grape.GrapeIvy

def source1 = '''
println('This is a nice safe Groovy script.')
'''

def source2 = '''
@Grab('commons-validator:commons-validator:1.4.1')

import org.apache.commons.validator.routines.EmailValidator

def emailValidator = EmailValidator.getInstance();

assert emailValidator.isValid('what.a.shame@us.elections.gov')
assert !emailValidator.isValid('an_invalid_emai_address')

println 'You should not see this message!'
'''

def script
def shell = new GroovyShell()
def proxy = ProxyMetaClass.getInstance(GrapeIvy)

proxy.interceptor = new GrapeInterceptor({group, module, version ->
    if(group == 'commons-validator' && module == 'commons-validator') false
    else true
})

proxy.use {
    shell.parse(source1).run()

    try {
        shell.parse(source2).run()
    } catch (org.codehaus.groovy.control.MultipleCompilationErrorsException e) {
        assert e.message.contains('unable to resolve class')
    }
}

@groovy.transform.TupleConstructor
class GrapeInterceptor implements Interceptor {
    private boolean invokeMethod = true
    Closure authorizer

    def afterInvoke(Object object, String methodName, Object[] arguments, Object result) {
        invokeMethod = true

        return result
    }

    def beforeInvoke(Object object, String methodName, Object[] arguments) {
        if(methodName == 'createGrabRecord') {
            def dependencies = arguments[0]
            invokeMethod = authorizer(dependencies.group, dependencies.module, dependencies.version)
        } else {
            invokeMethod = true
        }

        return null
    }

    boolean doInvoke() { invokeMethod }
}