1

Unfortunately, the workaround given by Oracle and others here (Java applet manifest - Allow all Caller-Allowable-Codebase) for getting around the 7 update 45 problem does NOT work if your app needs to access its loaded signed jar manifests. In my case, our app does this so as to log the relevant manifest info.

With my web start app, everything worked fine and dandy with the "Trusted-Library" attribute that needed to be added for 7u21. With 7u45, removing the "Trusted-Library" attribute and adding in all the additional attributes talked about in other workarounds will NOT work -- I will get the same warning that you would get if you were running 7u21 without the Trusted-Library attribute (stating the application contains both signed and unsigned code):

Java 7 Update 45 warning]![enter image description here

I've tried just about every manifest/JNLP permutation possible -- nothing cuts the mustard.

What I've found is that, basically, when we load one of our applets' jar manifests (not the JRE jars), and call hasMoreElements, additional security checks occur which trigger the warning:

   public List<String> getManifests() {
          ...         

          Enumeration<URL> urls = getClass().getClassLoader().getResources("META-INF/MANIFEST.MF");

          while (urls.hasMoreElements()) {
                 .... a bunch of loop stuff
                 // at the end of the loop...
                 System.out.println("Checkpoint SGMLOOP8.");

                 System.out.println("Breaking....");
                 //break; <<<<<<---- if the next jar is one of our signed jars, the next line will trigger the warning. If instead we choose to break, the app works perfectly with no warning.

                 System.out.println("urls.hasMoreElements(): " + (urls.hasMoreElements() ? "true" : "false"));  <<<<<<-------- will evaluate to false if user clicks Block on the warning, otherwise will evaluate to true when our signed jars are next

                 System.out.println("Checkpoint SGMLOOP9."); 
          }
          ...
      }

This is what prints out in the Java console at maximum tracing:

Checkpoint SGMLOOP8.
Breaking....                  <<<<---- console output pauses here until user answers warning
security: resource name "META-INF/MANIFEST.MF" in http://<path_to_jar> : java.lang.SecurityException: trusted loader attempted to load sandboxed resource from http://<path_to_jar>
(message repeats for all our signed jars)
urls.hasMoreElements(): false <<<<---- false because user clicked blocked, otherwise true when user clicks don't block
Checkpoint SGMLOOP9.

It took me FOREVER to figure out this out, because for some reason when a signed manifest that passes security checks earlier in the startup process, and then later is accessed and is complained about, I don't naturally think it's complaining about the manifest, but rather the resources referenced by the manifest. Go figure!

Looking into the Java source code, I can see why the warning could possibly happen (hasMoreElements leads to more security checks):

// getResources is called in my code above
java.lang.ClassLoader
public Enumeration<URL> getResources(String name) throws IOException {
    Enumeration[] tmp = new Enumeration[2];
    if (parent != null) {
        tmp[0] = parent.getResources(name);
    } else {
        tmp[0] = getBootstrapResources(name);
    }
    tmp[1] = findResources(name); <<<<------ This returns a new Enumeration<URL> object which has its own “hasMoreElments()” method overwritten – see below code

    return new CompoundEnumeration<>(tmp);
}

java.net.URLClassLoader
public Enumeration<URL> findResources(final String name)
    throws IOException
{
    final Enumeration<URL> e = ucp.findResources(name, true);

    return new Enumeration<URL>() {
        private URL url = null;

        private boolean next() {
            if (url != null) {
                return true;
            }
            do {
                URL u = AccessController.doPrivileged(  <<-- Security context could block this
                    new PrivilegedAction<URL>() {
                        public URL run() {
                            if (!e.hasMoreElements())
                                return null;
                            return e.nextElement();
                        }
                    }, acc);
                if (u == null)
                    break;
                url = ucp.checkURL(u);  <<-- Security checks done in here
            } while (url == null);
            return url != null;
        }

        public URL nextElement() {
            if (!next()) {
                throw new NoSuchElementException();
            }
            URL u = url;
            url = null;
            return u;
        }

        public boolean hasMoreElements() {
            return next();
        }
    };
}

Yes, the manifests are properly signed! Yes, the manifests do have the appropriate attributes! In fact, this is proven by the fact that the jars load just fine and execute, as long as we don't try to directly access their manifests! Just to assuage your fears though, here are the relevant manifest attributes (I've tried MANY additions/subtractions of the below attributes):

Manifest-Version: 1.0
Ant-Version: Apache Ant 1.7.0
Created-By: 24.45-b08 (Oracle Corporation)
Application-Name: AppName
Codebase: *
Permissions: all-permissions
Application-Library-Allowable-Codebase: *
Caller-Allowable-Codebase: *
Trusted-Only: false
Class-Path: jar1.jar jar2.jar jar3.jar
Specification-Title: AppName
Specification-Version: 1.0
Specification-Vendor: CompanyName
Implementation-Title: AppName
Implementation-Version: 1.0
Implementation-Vendor: CompanyName

The question is: Should the warning be happening when we try to access the manifests? As it stands, we either have to choose to force users see the warning every time, or we have to remove our logging of our signed jar manifest info. Seems like a bad choice, especially since this manifest info is very useful for debugging issues as it is really the only way to verify an end-user is running the correct version of the app (short of direct physical inspection on-site). This is especially true of our applet since the jars are allowed to be cached on client systems (along with the corresponding JavaScript to access the applet), meaning they could very easily be running the wrong jars after upgrades/downgrades, etc. Not having this info in our logs could lead to large headaches in the future.

Any ideas? This is especially frustrating since Oracle intends to fix the Trusted-Library issue anyway, so putting all this investigative work into this may be doing nothing more than wasting my weekend. Grrr....

EDIT: One observation I had was that first jar that ran into the security exception actually had a dependency on a different jar in my app. I thought, "maybe the dependent jar's manifest should be read in first?" So I forced the load-order so that non-dependent jars would be loaded first. End result? I could see the non-dependent jar now threw the security exception first... and there is still a warning.

4

2 回答 2

1

我遇到了小程序的这个问题,并发现我在我自己的小程序 .jar 文件(不是通过循环返回的前几次的 Java 系统 .jars)上收到有关 hasMoreElements 的警告,并且仅在小程序 .jar 时Java 控制面板中启用了文件缓存。

我不能让我的所有客户都禁用 .jar 文件缓存,但那些这样做的人现在很高兴,因为混合代码警告不会出现在他们身上。这不是答案,充其量只是一种解决方法。

于 2013-11-26T20:54:51.070 回答
0

想要更新这个问题,说从 Ja​​va 7 Update 55 开始,这个问题已经变得没有意义,因为可以再次同时放入“Trusted-Library”和“Caller-Allowable-Codebase”清单属性。在清单中使用这两个属性时,不会触发警告。

于 2014-09-12T20:39:55.450 回答