jar签名后,Spring启动不会读取组件

问题描述 投票:8回答:2

我正在开发一个提供REST HTTP(S)请求的Spring Boot应用程序。 (很常见)。

它按预期工作,但在最终(和工作)jar签名后(通过有效证书),所有URL映射都停止工作,只返回404到任何请求。 (请注意,嵌入式Tomcat服务器启动没有问题,我没有收到任何异常)

经过一些调试后,我发现Java的默认ClassLoader(Laucher $ AppClassLoader)在jar签名时不会返回我配置的包(@ComponentScan)中的类。

//org.springframework.core.io.support.PathMatchingResourcePatternResolver
//Param 'path' has my valid, existing and desired package with @Controller or @Component inside
protected Set<Resource> doFindAllClassPathResources(String path) throws IOException {
            Set<Resource> result = new LinkedHashSet<Resource>(16);
            ClassLoader cl = getClassLoader(); //sun.misc.Laucher$AppClassLoader
            Enumeration<URL> resourceUrls = (cl != null ? cl.getResources(path) : ClassLoader.getSystemResources(path));
            //Empty enumeration when jar is signed
            ...
}

我尝试使用自定义类加载器但没有成功;同样的问题。

由于它在我使用自签名证书对jar进行签名时起作用,我认为签名过程可能存在由另一个人完成的问题。但我找不到任何证据。

看来,一旦签名,我就无法列出包裹内容......

如果我认为有用,我会尝试更多的测试并添加到这里...

UPDATE

在自定义类加载器的帮助下调试后,我发现:

((java.net.JarURLConnection)new java.net.URL("jar:file:/home/user/my-app-with-dependencies_signed.jar!/META-INF/MANIFEST.MF").openConnection()).getJarEntry(); 

好。作品。

((java.net.JarURLConnection)new java.net.URL("jar:file:/home/user/my-app-with-dependencies_signed.jar!/META-INF/").openConnection()).getJarEntry();

不行! >。<它抛出

Exception occurred in target VM: JAR entry META-INF/ not found in /home/user/my-app-with-dependencies_signed.jar 
java.io.FileNotFoundException: JAR entry META-INF/ not found in /home/user/my-app-with-dependencies_signed.jar
    at sun.net.www.protocol.jar.JarURLConnection.connect(JarURLConnection.java:142)
    at sun.net.www.protocol.jar.JarURLConnection.getJarEntry(JarURLConnection.java:94)
...

当尝试访问未签名或自签名的jar时,同样的第二个示例也适用。

当从@ComponentScan中的给定包读取@Controller和@Component时,Spring执行打开jar的操作。

同样,Java的类加载器不读取目录内容,只读取指定的文件。

this.getClass().getClassLoader(); //sun.misc.Launcher$AppClassLoader@18b4aac2
this.getClass().getClassLoader().getResources("META-INF/MANIFEST.MF").hasMoreElements(); //always true
this.getClass().getClassLoader().getResources("META-INF/").hasMoreElements(); //false when signed

更新2

我得到了有关签名的信息。负责签名和证书的人实际上使用的Windows应用程序使用来自Windows-MY密钥库的证书和来自USB令牌的私钥来标记jar。

并不是说这肯定是原因,但我认为重要的是要注意不使用jarsigner

更新3

我创建了一个带有简单测试用例的github存储库:https://github.com/jesjobom/signed-jar-class-loader-test

java spring spring-boot classloader jarsigner
2个回答
1
投票

我已经达成了解决方案,但问题仍然存在。

当加载我通过@ComponentScan指向的类时,Spring向ClassLoader(Laucher$AppClassLoader)询问我告知的每个包的java.net.URL。由于某些未知原因,我无法加载包/文件夹,因此我创建了一个自定义ClassLoader,如果包是我的,它总是返回预期的URL。

public class CustomClassLoader extends ClassLoader {

...

@Override
public Enumeration<URL> getResources(String name) throws IOException {
    if(name.startsWith("com/my/package/")) {
        readBasePath(); //obtains path to jar (e.g. "jar:file:/home/app.jar!/")
        List<URL> resources = new ArrayList<>();
        resources.add(new URL(basePath + name));
        return Collections.enumeration(resources);
    }
    return fallback.getResources(name); //default classloader
}
...
}

即便如此,稍后,Spring会尝试从包中加载“.class”并因同样的原因而失败...所以,我创建了一个PathMatchingResourcePatternResolver的自定义实现,它将列出jar的所有内容(我可以这样做! )并仅选择给定包中的那些。

public class CustomPathMatchingResourceLoader extends PathMatchingResourcePatternResolver {

@Override
protected Set<Resource> doFindPathMatchingJarResources(final Resource rootDirResource, URL rootDirURL, String subPattern) throws IOException {

    try {

        String searchBase = ...; //package within jar
        String pathBase = ...; //path to jar

        URLConnection conn = new URL(pathBase).openConnection();

        Set<Resource> resources = new HashSet();
        JarFile file = ((JarURLConnection) conn).getJarFile();

        Enumeration<JarEntry> entries = file.entries();
        while (entries.hasMoreElements()) {
            JarEntry entry = entries.nextElement();
            if (entry.getName().startsWith(searchBase) && !entry.getName().endsWith("/")) {
                resources.add(new UrlResource(pathBase + entry.getName()));
            }
        }

        return resources;

    } catch (Exception e) {
        e.printStackTrace();
    }

    return super.doFindPathMatchingJarResources(rootDirResource, rootDirURL, subPattern);
}
...
}

所以它在签署过程中没有任何干扰就行了......我非常有信心与jarsigner签约可以解决问题,但我认为这很难......

无论如何,虽然它有效,但它不是一个解决方案。因此,我不会接受这个答案作为正确的答案......


0
投票

问题是签名的jar没有明确包含条目META-INFcom/jesjobom

使用7zip,您可以列出zip条目:例如7za l signed-jar-class-loader-test_signed.jar

  • 你签名的罐子: Date Time Attr Size Compressed Name ------------------- ----- ------------ ------------ ------------------------ 2018-02-27 15:27:08 ..... 1907 999 com\jesjobom\Main.class 2018-02-27 15:27:08 ..... 2978 944 META-INF\maven\com.jesjobom\signed-jar-class-loader-test\pom.xml 2018-02-27 15:27:08 ..... 113 111 META-INF\maven\com.jesjobom\signed-jar-class-loader-test\pom.properties 2018-02-27 15:27:08 ..... 595 361 META-INF\MANIFEST.MF 2018-02-27 15:27:08 ..... 609 386 META-INF\BANCO_DO_BRASIL_SA.SF 2018-02-27 15:27:08 ..... 4520 3251 META-INF\BANCO_DO_BRASIL_SA.RSA ------------------- ----- ------------ ------------ ------------------------ 2018-02-27 15:27:08 10722 6052 6 files
  • 在编译之后,有一些D(目录)条目,在签名版本中缺失。 Date Time Attr Size Compressed Name ------------------- ----- ------------ ------------ ------------------------ 2018-02-27 15:27:08 D.... 0 0 META-INF 2018-02-27 15:27:08 D.... 0 0 com 2018-02-27 15:27:08 D.... 0 0 com\jesjobom 2018-02-27 15:27:08 D.... 0 0 META-INF\maven 2018-02-27 15:27:08 D.... 0 0 META-INF\maven\com.jesjobom 2018-02-27 15:27:08 D.... 0 0 META-INF\maven\com.jesjobom\signed-jar-class-loader-test 2018-02-27 15:27:08 ..... 1907 999 com\jesjobom\Main.class 2018-03-09 14:15:16 ..... 3082 949 META-INF\maven\com.jesjobom\signed-jar-class-loader-test\pom.xml 2018-02-27 15:27:08 ..... 117 114 META-INF\maven\com.jesjobom\signed-jar-class-loader-test\pom.properties ------------------- ----- ------------ ------------ ------------------------ 2018-02-27 15:27:08 5324 2221 4 files, 6 folders

我不知道为什么缺少文件夹条目。我怀疑因为他们在\META-INF\MANIFEST.MF中没有SHA签名,所以他们会从签名的JAR中删除。

© www.soinside.com 2019 - 2024. All rights reserved.