JarUtil assumes that the URL of a JOGL class file will start with "jar:" if it's being run from a JAR file. However, this is not always the case. In an Eclipse RCP app, each plugin is given a custom classloader, which returns URLs beginning with "bundleresource:", even though JOGL really is being run from a JAR. These URLs cause JarUtil.getJarURL() to throw a IllegalArgumentException, which prevents JOGL from finding the native library JARs. I have a solution to this that I've tested in Eclipse RCP apps (both launched from within Eclipse and from a binary installation). I'm currently writing a unit test for this fix, then I'll submit a pull request for review.
I submitted a pull request that fixes this bug: https://github.com/WadeWalker/gluegen/commit/f3894c9fa1904572ee21b5c3aa2ca9e26a5d5d1e A unit test is included, and I verified that the unit test (plus my own tests) run on Windows 7 64-bit, Mac OS X 10.7.5, and Ubuntu 12 64-bit. With this fix, it will be possible to create an Eclipse RCP app that uses the new native library JARs! This should remove the last necessity for anyone to use the "raw" native libraries.
Who shall be allowed to invoke JarUtil.setResolver(..) ? Security concerns of hijacking the whole show ?
To address security, you could do something like this in JarUtil.getJarURL(): // only call resolver if URL contains an unknown protocol if(resolver != null) { try { new URL(url.toExternalForm()); } catch(MalformedURLException e) { url = resolver.resolve(url); } } That way, the resolver is only called if JOGL/GlueGen is being classloaded by an unknown protocol (like OSGi's "bundleresource" protocol). Or you could just check that the URL doesn't start with some known protocol: if(resolver != null && !url.toString().startsWith("jar:") && !url.toString().startsWith("file:") && !url.toString().startsWith("http:") && !url.toString().startsWith("https:")) { url = resolver.resolve(url); } Note that since URL.setURLStreamHandlerFactory() exists, nothing that uses URLs will ever be safe from code within the same JVM :)
(In reply to comment #3) > Note that since URL.setURLStreamHandlerFactory() exists, nothing that uses > URLs will ever be safe from code within the same JVM :) Good point .. but pro security: http://docs.oracle.com/javase/1.5.0/docs/api/java/net/URL.html#setURLStreamHandlerFactory%28java.net.URLStreamHandlerFactory%29 "Throws: SecurityException - if a security manager exists and its checkSetFactory method doesn't allow the operation." So we could restrict the caller to be signed w/ same certificate as gluegen .. or a certificate at all, if gluegen is signed ? If gluegen is not signed - we could allow it always. Almost similar mechanism is impl. in JARUtil.validateCertificate().
Well, I could enhance JarUtil.setResolver() a bit, so that it can't be set twice, and so the setter requires the same permissions as for URL.setURLStreamHandlerFactory(), like this: public static void setResolver(Resolver r) { if(resolver != null) { throw new Error("Resolver already set!"); } SecurityManager security = System.getSecurityManager(); if(security != null) { security.checkSetFactory(); } resolver = r; } As far as the certificates, I think we should be OK, since even if evil use of JarUtil.setResolver() may point us to an evil JAR, its certificate will still be checked and rejected when the TempJarCache tries to load it. Please let me know which of these changes you'd like me to put in the pull request -- I'll need to re-test the code and unit test on all three platforms before I re-submit it to you :)
(In reply to comment #5) > Well, I could enhance JarUtil.setResolver() a bit, so that it can't be set > twice, and so the setter requires the same permissions as for > URL.setURLStreamHandlerFactory(), like this: > > public static void setResolver(Resolver r) { > if(resolver != null) { > throw new Error("Resolver already set!"); > } > SecurityManager security = System.getSecurityManager(); > if(security != null) { > security.checkSetFactory(); > } > resolver = r; > } > > As far as the certificates, I think we should be OK, since even if evil use > of JarUtil.setResolver() may point us to an evil JAR, its certificate will > still be checked and rejected when the TempJarCache tries to load it. > > Please let me know which of these changes you'd like me to put in the pull > request -- I'll need to re-test the code and unit test on all three > platforms before I re-submit it to you :) The above code looks perfect and gives equal security as URL.setURLStreamHandlerFactory(). Great! I will merge such pull request .. gogo :)
.. maybe add a null check .. to the argument 'r', but .. doesn't matter that much.
I updated the pull request on GitHub. The branch is https://github.com/WadeWalker/gluegen/tree/bug_687_jar_resolver There are two commits in the branch. The first one is my initial version, and the second one (commit 45a84db7739aba2ab4526d7ef87850b9eb824740) adds the changes you requested. I've tested the latest commit on Windows, Linux, and Mac OS X, and it works properly on all of them.
(In reply to comment #8) > I updated the pull request on GitHub. The branch is > > https://github.com/WadeWalker/gluegen/tree/bug_687_jar_resolver > > There are two commits in the branch. The first one is my initial version, > and the second one (commit 45a84db7739aba2ab4526d7ef87850b9eb824740) adds > the changes you requested. > > I've tested the latest commit on Windows, Linux, and Mac OS X, and it works > properly on all of them. Has your fix been integrated?
Thank you Wade. Added minor edit with last commit 27424d9f36659a09195eaae77cf774f7ba3c0eec, it should not break functionality.
Looks good! I'll pull the latest daily build and confirm that it works with my RCP projects. Thanks for merging this!
Tested with the latest autobuild, and the fix is present and working.