Problems with Java web start when upgrading to j7u45

As you can guess from the title, the post will be dedicated to the security update released by Java, which will probably break / break the launch of the web start application. All are not indifferent - I ask for a cat.

Our company has adopted the practice of updating Java on all servers as soon as new versions are released. Actually, this is what we did this time. But something went wrong, the web start client stopped running and the application, without declaring war, just started to close.
Rolling up her sleeves, I had to figure out what caused this behavior.

By launching the client locally, previously unknown warnings appeared that the manifest files were missing properties: Permissions, Application-Name, Codebase. After reading a little about them, as a test, it was decided to add them to the fool in all manifests, approximately in the following form:

  Permissions: all-permissions
  Application-Name: AppName
  Codebase: *


Not too beautiful, it got rid of warnings, but did not solve the problem.
Further, during long debugs (thank you Eclipse RCP for a happy childhood), it was noticed that the system parameters were somehow transferred incorrectly, which led to the next post on stackoverflow: stackoverflow.com/questions/19400725/with-java-update- 7-45-the-system-properties-no-more-set-from-jnlp-tag-property .
Summarizing it, we can say that now you can’t just take it and transfer it to the JNLP file.

3 solutions were found:
1) Sign the JNLP file - docs.oracle.com/javase/7/docs/technotes/guides/jweb/signedJNLP.html#signedJnlp - in short - just put jnlp in the signed dzharik in the JNLP-INF folder with named APPLICATION.JNLP and there will be happiness.
The main problem with this method was that we have different JNLPs for each client and, generally speaking, are generated on the fly.

2) Create a signed JNLP file template - blogs.oracle.com/thejavatutorials/entry/signing_jar_files_with_a
Initially, I settled on this method, nothing complicated: the same as in the previous paragraph, only the file name APPLICATION_TEMPLATE.JNLP and those places that can change replace with '*'.
But everything turned out not so rosy, nothing worked. I had to shamanize a bit and get into the inside of the web start to see how the template and the jnlp file are compared. As a result, the following code was discovered in com.sun.javaws.jnl.XMLFormat:

  public static boolean isBlacklisted(XMLNode paramXMLNode)
  {
    if (paramXMLNode == null) {
      return false;
    }
    if (paramXMLNode.getName() != null)
    {
      XMLAttribute localXMLAttribute;
      String str;
      if ((paramXMLNode.getName().equals("java")) || (paramXMLNode.getName().equals("j2se"))) {
        for (localXMLAttribute = paramXMLNode.getAttributes(); localXMLAttribute != null; localXMLAttribute = localXMLAttribute.getNext()) {
          if (localXMLAttribute.getName().equals("java-vm-args"))
          {
            str = localXMLAttribute.getValue();
            if ((str != null) && (str.indexOf("*") >= 0))
            {
              Trace.println("Blacklisted - a = " + localXMLAttribute, TraceLevel.SECURITY);
              return true;
            }
          }
        }
      } else if (paramXMLNode.getName().equals("property")) {
        for (localXMLAttribute = paramXMLNode.getAttributes(); localXMLAttribute != null; localXMLAttribute = localXMLAttribute.getNext())
        {
          str = localXMLAttribute.getValue();
          if ((str != null) && (str.indexOf("*") >= 0))
          {
            Trace.println("Blacklisted - a = " + localXMLAttribute, TraceLevel.SECURITY);
            return true;
          }
        }
      }
    }
    if (isBlacklisted(paramXMLNode.getNested())) {
      return true;
    }
    return isBlacklisted(paramXMLNode.getNext());
  }


It checks something like this: when comparing a template with a file, it looks to see if the current tag is in the black list, if so, it does not skip such a jnlp file. In the current implementation, you cannot add templates to the java-vm-args property of java or j2se tags, and you cannot pass parameters containing a template to the value.

And again a failure, many properties for each client are unique and are transmitted just through the parameters in the form:


And we can’t just write in the template:


Only the last option (at that time) remains:

3) According to bugs.openjdk.java.net/browse/JDK-8023821 , properties can be transferred by adding the prefix 'jnlp' to them, they will be successfully transferred to system properties and further in our code it will be possible to shift them to their place. Since no other alternative was found, the code found here was added at the very beginning of the application launch :

  private static void initializeSystemProperiesFromJnlp() {
    //Hack for not signing JNLP file
    Properties properties = System.getProperties();
    // copy properties to avoid ConcurrentModificationException
    Properties copiedProperties = new Properties();
    copiedProperties.putAll(properties);
    Set keys = copiedProperties.keySet();
    for (Object key : keys) {
      if (key instanceof String) {
        String keyString = (String) key;
        if (keyString.startsWith("jnlp.")) { //$NON-NLS-1$
          // re set all properties starting with the jnlp-prefix 
          // and set them without the prefix
          String property = System.getProperty(keyString);
          String replacedKeyString = keyString.replaceFirst("jnlp.", ""); //$NON-NLS-1$ //$NON-NLS-2$
          System.setProperty(replacedKeyString, property);
        }
      }
    }
  }


После данной манипуляции все заработало.
Прошу обратить внимание, что код, приведенный выше, не является правилом хорошего тона, и как минимум, стоит проверить значения, которые лежат в пропертях, вдруг нас похакали и подменили их.

Кроме того, есть еще один, более тернистый, но правильный способ, о котором я узнал позже. Он описан вот здесь.

Надеюсь данный пост будет кому-нибудь полезен.

Also popular now: