1.7.0\u 40上的Java WebStart签名JAR出错
我们知道jar softlinker的问题 并且使用了下面的类(在web上找到并进行了修改以处理Java7)1.7.0\u 40上的Java WebStart签名JAR出错,java,classloader,java-web-start,jnlp,jarsigner,Java,Classloader,Java Web Start,Jnlp,Jarsigner,我们知道jar softlinker的问题 并且使用了下面的类(在web上找到并进行了修改以处理Java7) 此异常重复52次(对于所有JAR) 我们已经确保所有52个jar/文件(除了JNLP本身)都已正确签名,并且在启动应用程序之前清除了java缓存 在windows机器上使用的JAVA版本是JDK 7u40 尝试的方案有: 删除jdk.certpath.disabledAlgorithms=MD2,RSA密钥大小问题(JRE版本){ callNoArgMethod(“getSignin
此异常重复52次(对于所有JAR) 我们已经确保所有52个jar/文件(除了JNLP本身)都已正确签名,并且在启动应用程序之前清除了java缓存 在windows机器上使用的JAVA版本是JDK 7u40 尝试的方案有:
非常感谢您的帮助 @jorge\u B:我们使用ant任务在罐子上签名。但是由于Java6U19中的一个问题(软引用的JAR有时会被垃圾收集),我们决定在遇到JAVA版本6u19或更高版本时立即硬链接JAR。这个问题与jar签名无关。问题是当我们努力参考罐子时。我们的JAR没有得到硬引用,相反,我们在日志中得到了nosuchmethod和nosuchfield异常。
import java.io.IOException;
import java.io.IOException;
import java.lang.ref.SoftReference;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.JarURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.util.*;
import java.util.jar.JarFile;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* A utility class for working around the java webstart jar signing/security bug
* <p/>
* see http://bugs.sun.com/view_bug.do?bug_id=6967414 and http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6805618
*
* @author Scott Chan
*/
public class JarSignersHardLinker {
private static final String JRE_VERSION_START = "1.";
private static final int PROBLEM_JRE_VERSION = 6;
private static final String DOT_ZERO = ".0_";
/**
* the 1.6.0 update where this problem first occurred
*/
private static final int PROBLEM_JRE_UPDATE = 19;
private static String majorVersionStr = null;
public static final List sm_hardRefs = new ArrayList();
protected static void makeHardSignersRef(JarFile jar) throws java.io.IOException {
Logger.info("Making hard refs for: " + (jar != null ? jar.getName() : null) + " with Java Version: "+majorVersionStr);
if (jar != null && jar.getClass().getName().equals("com.sun.deploy.cache.CachedJarFile")) {
//lets attempt to get at the each of the soft links.
//first neet to call the relevant no-arg method to ensure that the soft ref is populated
//then we access the private member, resolve the softlink and throw it in a static list.
if (majorVersionStr != null && Integer.parseInt(majorVersionStr) > PROBLEM_JRE_VERSION) {
callNoArgMethod("getSigningData", jar);
makeHardLink("signingDataRef", jar);
} else {
callNoArgMethod("getSigners", jar);
makeHardLink("signersRef", jar);
callNoArgMethod("getSignerMap", jar);
makeHardLink("signerMapRef", jar);
// callNoArgMethod("getCodeSources", jar);
// makeHardLink("codeSourcesRef", jar);
callNoArgMethod("getCodeSourceCache", jar);
makeHardLink("codeSourceCacheRef", jar);
}
}
}
/**
* if the specified field for the given instance is a Softreference
* That soft reference is resolved and the returned ref is stored in a static list,
* making it a hard link that should never be garbage collected
*
* @param fieldName
* @param instance
*/
private static void makeHardLink(String fieldName, Object instance) {
Logger.info("attempting hard ref to " + instance.getClass().getName() + "." + fieldName);
try {
Field signersRef = instance.getClass().getDeclaredField(fieldName);
signersRef.setAccessible(true);
Object o = signersRef.get(instance);
if (o instanceof SoftReference) {
SoftReference r = (SoftReference) o;
Object o2 = r.get();
sm_hardRefs.add(o2);
} else {
Logger.warn(fieldName + ": is not an instance of soft reference");
}
} catch (NoSuchFieldException e) {
e.printStackTrace();
return;
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
/**
* Call the given no-arg method on the given instance
*
* @param methodName
* @param instance
*/
private static void callNoArgMethod(String methodName, Object instance) {
Logger.info("calling noarg method hard ref to " + instance.getClass().getName() + "." + methodName + "()");
try {
Method m = instance.getClass().getDeclaredMethod(methodName);
m.setAccessible(true);
m.invoke(instance);
} catch (SecurityException e1) {
e1.printStackTrace();
} catch (NoSuchMethodException e1) {
e1.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
/**
* is the preloader enabled. ie: will the preloader run in the current environment
*
* @return
*/
public static boolean isHardLinkerEnabled() {
boolean isHardLinkerDisabled = false; //change this to use whatever mechanism you use to enable or disable the preloader
return !isHardLinkerDisabled && isRunningOnJre1_6_0_19OrHigher() && isRunningOnWebstart();
}
/**
* is the application currently running on webstart
* <p/>
* detect the presence of a JNLPclassloader
*
* @return
*/
public static boolean isRunningOnWebstart() {
ClassLoader cl = Thread.currentThread().getContextClassLoader();
while (cl != null) {
if (cl.getClass().getName().equals("com.sun.jnlp.JNLPClassLoader")) {
return true;
}
cl = cl.getParent();
}
return false;
}
/**
* Is the JRE 1.6.0_19 or higher?
*
* @return
*/
public static boolean isRunningOnJre1_6_0_19OrHigher() {
String javaVersion = System.getProperty("java.version");
// Sometimes java releases version 1.X.0_YY-rev for specific issue and specific user,
// to resolve this we use patter instead of string split.
//ERP-6460: Checking whether JRE is 6 update 19 or higher
String updateStr = null;
majorVersionStr = null;
boolean isHardReferenceRequired = false;
Pattern pattern = Pattern.compile(JRE_VERSION_START + "([6-9]+)" + DOT_ZERO + "([0-9]+)(.*)");
Matcher matcher = pattern.matcher(javaVersion);
while (matcher.find()) {
majorVersionStr = matcher.group(1);
updateStr = matcher.group(2);
break;
}
try {
if (majorVersionStr != null) {
int java_version = Integer.parseInt(majorVersionStr);
if (java_version > PROBLEM_JRE_VERSION) {
isHardReferenceRequired = true;
} else if (java_version == PROBLEM_JRE_VERSION && Integer.parseInt(updateStr) >= PROBLEM_JRE_UPDATE) {
isHardReferenceRequired = true;
}
}
return isHardReferenceRequired;
} catch (NumberFormatException e) {
e.printStackTrace();
return isHardReferenceRequired;
}
}
/**
* get all the JarFile objects for all of the jars in the classpath
*
* @return
*/
public static Set<JarFile> getAllJarsFilesInClassPath() {
Set<JarFile> jars = new LinkedHashSet<JarFile>();
for (URL url : getAllJarUrls()) {
try {
jars.add(getJarFile(url));
} catch (IOException e) {
Logger.error("unable to retrieve jar at URL: " + url);
}
}
return jars;
}
/**
* Returns set of URLS for the jars in the classpath.
* URLS will have the protocol of jar eg: jar:http://HOST/PATH/JARNAME.jar!/META-INF/MANIFEST.MF
*/
static Set<URL> getAllJarUrls() {
try {
Set<URL> urls = new LinkedHashSet<URL>();
Enumeration<URL> mfUrls = Thread.currentThread().getContextClassLoader().getResources("META-INF/MANIFEST.MF");
while (mfUrls.hasMoreElements()) {
URL jarUrl = mfUrls.nextElement();
// System.out.println(jarUrl);
if (!jarUrl.getProtocol().equals("jar")) {
continue;
}
urls.add(jarUrl);
}
return urls;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
/**
* get the jarFile object for the given url
*
* @param jarUrl
* @return
* @throws IOException
*/
public static JarFile getJarFile(URL jarUrl) throws IOException {
URLConnection urlConnnection = jarUrl.openConnection();
if (urlConnnection instanceof JarURLConnection) {
// Using a JarURLConnection will load the JAR from the cache when using Webstart 1.6
// In Webstart 1.5, the URL will point to the cached JAR on the local filesystem
JarURLConnection jcon = (JarURLConnection) urlConnnection;
return jcon.getJarFile();
} else {
throw new AssertionError("Expected JarURLConnection");
}
}
/**
* Spawn a new thread to run through each jar in the classpath and create a hardlink
* to the jars softly referenced signers infomation.
*/
public static void go() {
if (!isHardLinkerEnabled()) {
return;
}
Logger.info("Starting Resource Preloader Hardlinker");
Thread t = new Thread(new Runnable() {
public void run() {
try {
Set<JarFile> jars = getAllJarsFilesInClassPath();
for (JarFile jar : jars) {
makeHardSignersRef(jar);
}
} catch (Exception e) {
Logger.error("Problem preloading resources", e);
} catch (Error e) {
Logger.error("Error preloading resources", e);
}
}
});
t.start();
}
}
导入java.lang.ref.SoftReference;
导入java.lang.reflect.Field;
导入java.lang.reflect.InvocationTargetException;
导入java.lang.reflect.Method;
导入java.net.JarURLConnection;
导入java.net.URL;
导入java.net.URLConnection;
导入java.util.*;
导入java.util.jar.jar文件;
导入java.util.regex.Matcher;
导入java.util.regex.Pattern;
/**
*用于解决JavaWebStart jar签名/安全缺陷的实用程序类
*
*看http://bugs.sun.com/view_bug.do?bug_id=6967414 和http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6805618
*
*@作者陈兆恺
*/
公共类JarSignerSharedLinker{
私有静态最终字符串JRE\u VERSION\u START=“1。”;
私有静态最终整数问题_JRE_VERSION=6;
私有静态最终字符串DOT_ZERO=“.0_”;
/**
*首次出现此问题的1.6.0更新
*/
私有静态最终整数问题_JRE_UPDATE=19;
私有静态字符串majorVersionStr=null;
public static final List sm_hardRefs=new ArrayList();
受保护的静态void makeHardSignersRef(JarFile jar)抛出java.io.IOException{
Logger.info(“在Java版本为“+majorVersionStr”的情况下对“+(jar!=null?jar.getName():null)+”进行硬引用);
if(jar!=null&&jar.getClass().getName().equals(“com.sun.deploy.cache.CachedJarFile”)){
//让我们尝试访问每个软链接。
//首先neet调用相关的no arg方法,以确保填充了soft ref
//然后我们访问私有成员,解析软链接并将其放入静态列表中。
如果(majorVersionStr!=null&&Integer.parseInt(majorVersionStr)>问题(JRE版本){
callNoArgMethod(“getSigningData”,jar);
makeHardLink(“signingDataRef”,jar);
}否则{
callNoArgMethod(“getSigners”,jar);
makeHardLink(“signersRef”,jar);
callNoArgMethod(“getSignerMap”,jar);
makeHardLink(“signerMapRef”,jar);
//callNoArgMethod(“getCodeSources”,jar);
//makeHardLink(“codeSourcesRef”,jar);
callNoArgMethod(“getCodeSourceCache”,jar);
makeHardLink(“codeSourceCacheRef”,jar);
}
}
}
/**
*如果给定实例的指定字段是Softreference
*软引用被解析,返回的ref存储在静态列表中,
*使其成为一个不应被垃圾收集的硬链接
*
*@param fieldName
*@param实例
*/
私有静态void makeHardLink(字符串字段名,对象实例){
Logger.info(“正在尝试硬引用”+实例.getClass().getName()+”+字段名);
试一试{
Field signersRef=instance.getClass().getDeclaredField(fieldName);
signersRef.setAccessible(true);
对象o=signersRef.get(实例);
if(o实例of SoftReference){
软参考r=(软参考)o;
对象o2=r.get();
sm_硬参考添加(o2);
}否则{
Logger.warn(fieldName+“:不是软引用的实例”);
}
}捕获(无此字段例外){
e、 printStackTrace();
回来
}捕获(非法访问例外e){
e、 printStackTrace();
}
}
/**
*对给定实例调用给定的no-arg方法
*
*@param methodName
*@param实例
*/
私有静态void callNoArgMethod(字符串方法名,对象实例){
info(“调用noarg方法硬引用到“+instance.getClass().getName()+”“+methodName+”()”;
试一试{
方法m=instance.getClass().getDeclaredMethod(methodName);
m、 setAccessible(true);
m、 调用(实例);
}捕获(安全异常e1){
e1.printStackTrace();
}捕获(NoSuchMethodException e1){
e1.printStackTrace();
}捕获(IllegalArgumentException e){
e、 printStackTrace();
}捕获(非法访问例外e){
e、 printStackTrace();
}捕获(调用TargetException e){
e、 printStackTrace();
}
}
/**
*是否启用预加载。即:预加载
java.lang.NoSuchMethodException: com.sun.deploy.cache.CachedJarFile.getSigners()
at java.lang.Class.getDeclaredMethod(Unknown Source)
at com.XXXXXX.ui.main.JarSignersHardLinker.callNoArgMethod(JarSignersHardLinker.java:96)
at com.XXXXXX.ui.main.JarSignersHardLinker.makeHardSignersRef(JarSignersHardLinker.java:45)
at com.XXXXXX.ui.main.JarSignersHardLinker$1.run(JarSignersHardLinker.java:262)
at java.lang.Thread.run(Unknown Source)
java.lang.NoSuchFieldException: signersRef
at java.lang.Class.getDeclaredField(Unknown Source)
at com.XXXXXX.ui.main.JarSignersHardLinker.makeHardLink(JarSignersHardLinker.java:69)
at com.XXXXXX.ui.main.JarSignersHardLinker.makeHardSignersRef(JarSignersHardLinker.java:46)
at com.XXXXXX.ui.main.JarSignersHardLinker$1.run(JarSignersHardLinker.java:262)
at java.lang.Thread.run(Unknown Source)
import java.io.IOException;
import java.lang.ref.SoftReference;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.JarURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.util.*;
import java.util.jar.JarFile;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* A utility class for working around the java webstart jar signing/security bug
* <p/>
* see http://bugs.sun.com/view_bug.do?bug_id=6967414 and http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6805618
*
* @author Scott Chan
*/
public class JarSignersHardLinker {
private static final String JRE_VERSION_START = "1.";
private static final int PROBLEM_JRE_VERSION = 6;
private static final String DOT_ZERO = ".0_";
/**
* the 1.6.0 update where this problem first occurred
*/
private static final int PROBLEM_JRE_UPDATE = 19;
private static String majorVersionStr = null;
public static final List sm_hardRefs = new ArrayList();
protected static void makeHardSignersRef(JarFile jar) throws java.io.IOException {
Logger.info("Making hard refs for: " + (jar != null ? jar.getName() : null) + " with Java Version: "+majorVersionStr);
if (jar != null && jar.getClass().getName().equals("com.sun.deploy.cache.CachedJarFile")) {
//lets attempt to get at the each of the soft links.
//first neet to call the relevant no-arg method to ensure that the soft ref is populated
//then we access the private member, resolve the softlink and throw it in a static list.
if (majorVersionStr != null && Integer.parseInt(majorVersionStr) > PROBLEM_JRE_VERSION) {
callNoArgMethod("getSigningData", jar);
makeHardLink("signingDataRef", jar);
} else {
callNoArgMethod("getSigners", jar);
makeHardLink("signersRef", jar);
callNoArgMethod("getSignerMap", jar);
makeHardLink("signerMapRef", jar);
// callNoArgMethod("getCodeSources", jar);
// makeHardLink("codeSourcesRef", jar);
callNoArgMethod("getCodeSourceCache", jar);
makeHardLink("codeSourceCacheRef", jar);
}
}
}
/**
* if the specified field for the given instance is a Softreference
* That soft reference is resolved and the returned ref is stored in a static list,
* making it a hard link that should never be garbage collected
*
* @param fieldName
* @param instance
*/
private static void makeHardLink(String fieldName, Object instance) {
Logger.info("attempting hard ref to " + instance.getClass().getName() + "." + fieldName);
try {
Field signersRef = instance.getClass().getDeclaredField(fieldName);
signersRef.setAccessible(true);
Object o = signersRef.get(instance);
if (o instanceof SoftReference) {
SoftReference r = (SoftReference) o;
Object o2 = r.get();
sm_hardRefs.add(o2);
} else {
Logger.warn(fieldName + ": is not an instance of soft reference");
}
} catch (NoSuchFieldException e) {
e.printStackTrace();
return;
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
/**
* Call the given no-arg method on the given instance
*
* @param methodName
* @param instance
*/
private static void callNoArgMethod(String methodName, Object instance) {
Logger.info("calling noarg method hard ref to " + instance.getClass().getName() + "." + methodName + "()");
try {
Method m = instance.getClass().getDeclaredMethod(methodName);
m.setAccessible(true);
m.invoke(instance);
} catch (SecurityException e1) {
e1.printStackTrace();
} catch (NoSuchMethodException e1) {
e1.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
/**
* is the preloader enabled. ie: will the preloader run in the current environment
*
* @return
*/
public static boolean isHardLinkerEnabled() {
boolean isHardLinkerDisabled = false; //change this to use whatever mechanism you use to enable or disable the preloader
return !isHardLinkerDisabled && isRunningOnJre1_6_0_19OrHigher() && isRunningOnWebstart();
}
/**
* is the application currently running on webstart
* <p/>
* detect the presence of a JNLPclassloader
*
* @return
*/
public static boolean isRunningOnWebstart() {
ClassLoader cl = Thread.currentThread().getContextClassLoader();
while (cl != null) {
if (cl.getClass().getName().equals("com.sun.jnlp.JNLPClassLoader")) {
return true;
}
cl = cl.getParent();
}
return false;
}
/**
* Is the JRE 1.6.0_19 or higher?
*
* @return
*/
public static boolean isRunningOnJre1_6_0_19OrHigher() {
String javaVersion = System.getProperty("java.version");
// Sometimes java releases version 1.X.0_YY-rev for specific issue and specific user,
// to resolve this we use patter instead of string split.
//ERP-6460: Checking whether JRE is 6 update 19 or higher
String updateStr = null;
majorVersionStr = null;
boolean isHardReferenceRequired = false;
Pattern pattern = Pattern.compile(JRE_VERSION_START + "([6-9]+)" + DOT_ZERO + "([0-9]+)(.*)");
Matcher matcher = pattern.matcher(javaVersion);
while (matcher.find()) {
majorVersionStr = matcher.group(1);
updateStr = matcher.group(2);
break;
}
try {
if (majorVersionStr != null) {
int java_version = Integer.parseInt(majorVersionStr);
if (java_version > PROBLEM_JRE_VERSION) {
isHardReferenceRequired = true;
} else if (java_version == PROBLEM_JRE_VERSION && Integer.parseInt(updateStr) >= PROBLEM_JRE_UPDATE) {
isHardReferenceRequired = true;
}
}
return isHardReferenceRequired;
} catch (NumberFormatException e) {
e.printStackTrace();
return isHardReferenceRequired;
}
}
/**
* get all the JarFile objects for all of the jars in the classpath
*
* @return
*/
public static Set<JarFile> getAllJarsFilesInClassPath() {
Set<JarFile> jars = new LinkedHashSet<JarFile>();
for (URL url : getAllJarUrls()) {
try {
jars.add(getJarFile(url));
} catch (IOException e) {
Logger.error("unable to retrieve jar at URL: " + url);
}
}
return jars;
}
/**
* Returns set of URLS for the jars in the classpath.
* URLS will have the protocol of jar eg: jar:http://HOST/PATH/JARNAME.jar!/META-INF/MANIFEST.MF
*/
static Set<URL> getAllJarUrls() {
try {
Set<URL> urls = new LinkedHashSet<URL>();
Enumeration<URL> mfUrls = Thread.currentThread().getContextClassLoader().getResources("META-INF/MANIFEST.MF");
while (mfUrls.hasMoreElements()) {
URL jarUrl = mfUrls.nextElement();
// System.out.println(jarUrl);
if (!jarUrl.getProtocol().equals("jar")) {
continue;
}
urls.add(jarUrl);
}
return urls;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
/**
* get the jarFile object for the given url
*
* @param jarUrl
* @return
* @throws IOException
*/
public static JarFile getJarFile(URL jarUrl) throws IOException {
URLConnection urlConnnection = jarUrl.openConnection();
if (urlConnnection instanceof JarURLConnection) {
// Using a JarURLConnection will load the JAR from the cache when using Webstart 1.6
// In Webstart 1.5, the URL will point to the cached JAR on the local filesystem
JarURLConnection jcon = (JarURLConnection) urlConnnection;
return jcon.getJarFile();
} else {
throw new AssertionError("Expected JarURLConnection");
}
}
/**
* Spawn a new thread to run through each jar in the classpath and create a hardlink
* to the jars softly referenced signers infomation.
*/
public static void go() {
if (!isHardLinkerEnabled()) {
return;
}
Logger.info("Starting Resource Preloader Hardlinker");
Thread t = new Thread(new Runnable() {
public void run() {
try {
Set<JarFile> jars = getAllJarsFilesInClassPath();
for (JarFile jar : jars) {
makeHardSignersRef(jar);
}
} catch (Exception e) {
Logger.error("Problem preloading resources", e);
} catch (Error e) {
Logger.error("Error preloading resources", e);
}
}
});
t.start();
}
}