12

我正在从事一个具有严格安全限制的项目。一个要求是密封我们的罐子。

由于我们密封了 jars,我们的很多 junit-tests 都失败了,并出现以下错误:

java.lang.SecurityException: sealing violation: package [a.dependency.package] is sealed
    at java.net.URLClassLoader.defineClass(URLClassLoader.java:234)
    at java.net.URLClassLoader.access$000(URLClassLoader.java:58)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:197)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
    at java.lang.Class.getDeclaredMethods0(Native Method)
    at java.lang.Class.privateGetDeclaredMethods(Class.java:2427)
    at java.lang.Class.getDeclaredMethods(Class.java:1791)
    at org.mockito.cglib.core.ReflectUtils.addAllMethods(ReflectUtils.java:349)
    at org.mockito.cglib.proxy.Enhancer.getMethods(Enhancer.java:422)
    at org.mockito.cglib.proxy.Enhancer.generateClass(Enhancer.java:457)
    at org.mockito.cglib.core.DefaultGeneratorStrategy.generate(DefaultGeneratorStrategy.java:25)
    at org.mockito.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:217)
    at org.mockito.cglib.proxy.Enhancer.createHelper(Enhancer.java:378)
    at org.mockito.cglib.proxy.Enhancer.createClass(Enhancer.java:318)
    at org.mockito.internal.creation.jmock.ClassImposterizer.createProxyClass(ClassImposterizer.java:93)
    at org.mockito.internal.creation.jmock.ClassImposterizer.imposterise(ClassImposterizer.java:50)
    at org.mockito.internal.util.MockUtil.createMock(MockUtil.java:54)
    at org.mockito.internal.MockitoCore.mock(MockitoCore.java:45)
    at org.mockito.Mockito.spy(Mockito.java:991)
    at [...]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:27)
    at org.junit.runners.BlockJUnit4ClassRunner.runNotIgnored(BlockJUnit4ClassRunner.java:79)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:71)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:49)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)

看起来问题是由 Mockito 引起的:

我们“mock”和“spy”来自一些外部密封 jar 的类,而 Mockito 生成的“mock classes”与“mocked classes”具有相同的包。

因为依赖 jar 中的包是密封的,所以被测试的 jar 无法在同一个包中创建类(URLClassLoader 会检查不同密封 jar 中没有使用同一个包)。

I tried to add a specific SecurityManager .policy file for junit testing, but I didn't found a property allowing to have classes inside a package already sealed by a dependency.

Moreover, it seems that the URLClassLoader has no option to remove sealing violation check.

The version of Mockito we use is 1.8.5. I tried to use the latest version (1.9.5) but it didn't fix the error.

If someone has an idea...

4

3 回答 3

3

You can work around this by putting traits in a different package and when testing mock that trait instead of the classes in your sealed jar. That could be construed as a security concern but you can argue against that quite easily.

You could seal a jar that imports all your unsealed code and not add any behavior there. That would give your customer the security he needs, but avoid you having to deal with the restrictions in tests or other implementations where you don't have this requirement.

I'm sure you're using dependencies that are unsealed, so you just make your own testable code a dependency of the sealed jar too.

于 2013-03-05T20:46:46.660 回答
1

You could consider ways to run these tests against code that's not in sealed jars. Either build unsealed jars as well, and use them to test, or unpack the jars before testing.

于 2013-03-09T11:16:28.270 回答
0

I had to deal with Mockito.spy and signed jars recently.

Actually one solution would be to force the test task to unsign all the problematic jars (i.e. those signed).


With Apache Ant you can define a macro

<macrodef name="unsignjar">
    <attribute name="jarFile" />
    <sequential>
        <jar update="yes"
             jarfile="@{jarFile}.tmp">
            <zipfileset src="@{jarFile}">
                <include name="**"/>
                <exclude name="META-INF/*.SF"/>
                <exclude name="META-INF/*.DSA"/>
                <exclude name="META-INF/*.RSA"/>
            </zipfileset>
        </jar>
        <move file="@{jarFile}.tmp"
              tofile="@{jarFile}"
              overwrite="true" />
    </sequential>
</macrodef>

and then call it like in the following:

<target name="unsign-problematic-jars">
    <unsignjar jarFile="my-signed.jar" />
</target>

With Apache Maven, you can do as suggested in this answer, so you resort to the maven-jarsigner-plugin plugin.

于 2016-12-20T10:25:11.433 回答