Я разрабатываю приложение Spring Boot, которое обслуживает запросы REST HTTP (S). (довольно часто).
Он работает так, как предполагается, но после того, как окончательный (и рабочий) jar будет подписан (действующим сертификатом), все сопоставления URL-адресов перестают работать, возвращая только 404 на любой запрос. (Обратите внимание, что встроенный сервер Tomcat запускается без проблем, и я не получаю никаких исключений)
После некоторой отладки я обнаружил, что загрузчик классов Java по умолчанию (Laucher$AppClassLoader) просто не возвращает классы в пакетах, которые я настроил (@ComponentScan), когда jar подписан.
//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
...
}
Я безуспешно пытался использовать собственный загрузчик классов; та же проблема.
Поскольку это работает, когда я подписываю банку самоподписанным сертификатом, я думаю, что может быть проблема с процессом подписания, который был выполнен другим человеком. Но я не могу найти никаких доказательств этого.
Похоже, что после подписания я не могу перечислить содержимое пакета...
Я попробую еще несколько тестов и добавлю сюда, если сочту нужным...
ОБНОВЛЕНИЕ
После отладки с помощью пользовательского загрузчика классов я обнаружил, что:
((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 выполняется Spring при чтении @Controller и @Component из заданных пакетов в @ComponentScan.
Точно так же загрузчик классов 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-токена.
Не то чтобы это было причиной, но я думаю, что важно отметить, что jarsigner
не используется.
ОБНОВЛЕНИЕ 3
Я создал репозиторий github с простым тестовым примером: https://github.com/jesjobom/signed-jar-class-loader-test
jarsigner -verify
. Так что все должно быть в порядке, включая MANIFEST.MF. Но я проверил некоторые записи в этом файле. Подпись сделана не мной, поэтому я не знаю процесса (но я посмотрю). Я знаю, что эта подпись действительна. И в своих тестах я запускаю банку, используяjava -jar
. - person Jairton Junior   schedule 20.02.2018unzip -l my-app-self_signed.jar "*/"
. Но если сделать то же самое с подписанной версией, ничего не будет перечислено. Это не имеет смысла, так как папки существуют, внутри них есть файлы, но они не перечислены... Я имею в виду, что папка org/springframework/util/ существует, потому что в ней есть файл FileCopyUtils.class внутри, но только папка не будет указан в подписанном банке, пока он указан в самоподписанном. - person Jairton Junior   schedule 26.02.2018