JDK-4809366 : all-permissions does not grant permission for getClassLoader()
  • Type: Bug
  • Component: deploy
  • Sub-Component: webstart
  • Affected Version: 1.2.0
  • Priority: P3
  • Status: Closed
  • Resolution: Not an Issue
  • OS: windows_xp
  • CPU: x86
  • Submitted: 2003-01-28
  • Updated: 2003-05-05
  • Resolved: 2003-05-05
Description

Name: nt126004			Date: 01/28/2003


FULL PRODUCT VERSION :
Command-line version info:

java version "1.3.1_04"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.3.1_04-b02)
Java HotSpot(TM) Client VM (build 1.3.1_04-b02, mixed mode)

Java WebStart version info:

Java Web Start 1.2 Console, started Thu Dec 26 12:48:11 CST 2002

Java 2 Runtime Environment: Version 1.3.1_04 by Sun Microsystems Inc.


FULL OPERATING SYSTEM VERSION :

Microsoft Windows XP [Version 5.1.2600]

EXTRA RELEVANT SYSTEM CONFIGURATION :
Java Webstart 1.2 (also seen in 1.0.1)

A DESCRIPTION OF THE PROBLEM :
Our application gets a java.security.AccessControlException
when running from Java WebStart.  It successfully runs when
started from the command line (with null SecurityManager).

The jar files are signed and the jnlp file requests
all-permissions.  Java WebStart starts executing the
application, but it quickly stops with the exception.

This a command-line JMS client application using the BEA
WebLogic 7.0SP1 jar files to talk to BEA's JMS
implementation.  This is just a simple utility that
demonstrates a general problem using BEA's WLS 7.0SP1
libraries with java webstart.

We see this bug with Java WebStart 1.0.1_01 also.

(Please see comments)

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. build app
2. jar it up
3. sign app jar and weblogic WLS 7.0SP1 jar file
4. install on web server with .jnlp file shown
5. launch w/ web browser (using java webstart) and see exception

EXPECTED VERSUS ACTUAL BEHAVIOR :
Application should successfully initialize.


ERROR MESSAGES/STACK TRACES THAT OCCUR :
java.security.AccessControlException: access denied (java.lang.RuntimePermission
getClassLoader)

	at java.security.AccessControlContext.checkPermission(Unknown Source)
	at java.security.AccessController.checkPermission(Unknown Source)
	at java.lang.SecurityManager.checkPermission(Unknown Source)
	at java.lang.ClassLoader.getParent(Unknown Source)
	at
weblogic.rmi.internal.ClientRuntimeDescriptor.computeInterfaces(ClientRuntimeDescriptor.java:253)
	at
weblogic.rmi.internal.ClientRuntimeDescriptor.intern(ClientRuntimeDescriptor.java:123)
	at weblogic.rmi.internal.StubInfo.readObject(StubInfo.java:100)
	at java.lang.reflect.Method.invoke(Native Method)
	at java.io.ObjectInputStream.invokeObjectReader(Unknown Source)
	at java.io.ObjectInputStream.inputObject(Unknown Source)
	at java.io.ObjectInputStream.readObject(Unknown Source)
	at java.io.ObjectInputStream.readObject(Unknown Source)
	at
weblogic.common.internal.ChunkedObjectInputStream.readObject(ChunkedObjectInputStream.java:140)
	at
weblogic.jms.client.JMSConnectionFactory.readExternal(JMSConnectionFactory.java:173)
	at
weblogic.common.internal.ChunkedObjectInputStream.readObject(ChunkedObjectInputStream.java:131)
	at weblogic.rjvm.MsgAbbrevInputStream.readObject(MsgAbbrevInputStream.java:91)
	at weblogic.rmi.internal.ObjectIO.readObject(ObjectIO.java:56)
	at weblogic.rjvm.ResponseImpl.unmarshalReturn(ResponseImpl.java:161)
	at
weblogic.rmi.cluster.ReplicaAwareRemoteRef.invoke(ReplicaAwareRemoteRef.java:263)
	at
weblogic.rmi.cluster.ReplicaAwareRemoteRef.invoke(ReplicaAwareRemoteRef.java:229)
	at weblogic.jndi.internal.ServerNamingNode_WLStub.lookup(Unknown Source)
	at weblogic.jndi.internal.WLContextImpl.lookup(WLContextImpl.java:337)
	at weblogic.jndi.internal.WLContextImpl.lookup(WLContextImpl.java:332)
	at javax.naming.InitialContext.lookup(Unknown Source)
	at com.ti.mtc.facops.util.TopicDump.init(TopicDump.java:113)
	at com.ti.mtc.facops.util.TopicDump.<init>(TopicDump.java:107)
	at com.ti.mtc.facops.util.TopicDump.main(TopicDump.java:91)
	at java.lang.reflect.Method.invoke(Native Method)
	at com.sun.javaws.Launcher.executeApplication(Unknown Source)
	at com.sun.javaws.Launcher.executeMainClass(Unknown Source)
	at com.sun.javaws.Launcher.continueLaunch(Unknown Source)
	at com.sun.javaws.Launcher.handleApplicationDesc(Unknown Source)
	at com.sun.javaws.Launcher.handleLaunchFile(Unknown Source)
	at com.sun.javaws.Launcher.run(Unknown Source)
	at java.lang.Thread.run(Unknown Source)


REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
// see comments section

/** This class will create connections to a JMS topic and dump the messages
being distributed.

*/

package com.ti.mtc.facops.util;

import java.util.*;
import javax.naming.*;
import javax.jms.*;

public class TopicDump
    implements MessageListener, ExceptionListener
{
    private static final java.text.DateFormat DATE_FORMAT =
 new java.text.SimpleDateFormat("yyyy/MM/dd kk:mm:ss.SSS");
    static final String JMS_FACTORY="javax.jms.TopicConnectionFactory";

    private TopicConnectionFactory conFactory;
    private TopicConnection con;
    private TopicSession session;
    private TopicSubscriber consumer;
    private Topic destination;

    /** Run the program
     * @param args 0: JNDI name of destination
     */
    public static void main(String args[]) throws Exception {
 // Command-line processing.  Ick, isn't there a class to do this?
 int argIndex;    // This will point to first arg after optoins

 /** optional message selector */
 String selector = null;
 /** required JNDI name for Destination we'll read from */
 String jndiName = null;

 final String USAGE_STRING = "TopicDump [-selector selector] jndiName";

 try {
     for (argIndex = 0; argIndex < args.length; argIndex++) {
  String arg = args[argIndex];
  String argParm = (argIndex + 1 < args.length) ?
      args[argIndex + 1] : null;
    
  // We're outta here if not an option
  if (!arg.startsWith("-")) {
      break;
  }
   
  // Consume a -- end-of-args marker and exit
  if (arg.equals("--")) {
      argIndex++;
      break;
  }
    
  // Series of if/else if/else if... for the args we understand
  // Manually advance argIndex if an argParm is consumed
  if (arg.equals("-selector") && argParm != null) {
      // optional message selector
      selector = argParm;
      argIndex++;
  }
  // Other "else if" checks above here, end with this error "else"
  else {
      throw new Exception("Error parsing option \""
     + args[argIndex] + "\"");
  }
     }

     /* Set up for pre-increments next.
      * That's useful so argIndex points to bad arg if we get exception.
      */
     argIndex--;
     try {
  jndiName = args[++argIndex];
     } catch (Exception e) {
  throw new Exception("Exception " + e.getClass()
        + " parsing required parameter \""
        + ((argIndex < args.length) ? args[argIndex] : "(empty)")
        + "\"\n" + e);
     }
     // At the end, make sure there are no extra parameters
     if (argIndex + 1 < args.length) {
  throw new Exception("Ignoring extra parameters, \"" +
        args[argIndex + 1] + "\" and after");
     }
 } catch (Exception e) {
     throw new Exception(USAGE_STRING + "\n" + e.getMessage());
 }


 TopicDump d = new TopicDump(jndiName, selector);
 if (true) {
     d.dumpAsynchronously();
     // Wait forever
     synchronized (d) {
  d.wait();
     }
 }
 else {
     d.dumpMessages();
 }
 d.close();
    }

    public TopicDump(String jndiName, String selector) throws Exception {
 InitialContext ic = new InitialContext();
 init(ic, jndiName, selector);
    }

    /** Initialize JMS topic connection */
    private void init(Context ctx, String name, String selector)
 throws NamingException, JMSException {
 conFactory = (TopicConnectionFactory)ctx.lookup(JMS_FACTORY);
 con = conFactory.createTopicConnection();
 session = con.createTopicSession(false, Session.AUTO_ACKNOWLEDGE);
 destination = (Topic)ctx.lookup(name);

 con.setExceptionListener(this);

 // Create a consumer with the selector (if specified)
 // "noLocal" option isn't interesting as we don't publish, set false
 consumer = (selector == null) ?
     session.createSubscriber(destination) :
     session.createSubscriber(destination, selector, false);
 con.start();
    }

    /** Register us for async callback on message availability */
    void dumpAsynchronously() throws JMSException {
 consumer.setMessageListener(this);
    }

    /** Dump out messages.  Exit when empty */
    void dumpMessages() throws Exception {
 while (true) {
     Message m;

     // If no messages available, break out
     m = consumer.receiveNoWait();
     if (m == null) {
  break;
     }

     // Process the message
     onMessage(m);
 }
    }

    /**
     * Closes JMS objects
     */
    public void close() {
 // silently ignore all exceptions
 try {consumer.close();} catch (Exception e) {};
 try {session.close();} catch (Exception e) {};
 try {con.close();} catch (Exception e) {};
    }


    /**  Called automatically (or by us) on receipt of a message.
    */
    public void onMessage(javax.jms.Message msg) {
 try {
     String msgText;
     if (msg instanceof TextMessage) {
  msgText = ((TextMessage)msg).getText();
     } else if (msg instanceof ObjectMessage) {
  msgText = ((ObjectMessage)msg).getObject().toString();
     } else {
  msgText = msg.toString();
     }

     StringBuffer sb = new StringBuffer(8192);
     sb.append("Message: id=").append(msg.getJMSMessageID());
     sb.append(" corr=").append(msg.getJMSCorrelationID());
     sb.append(" dest=").append(msg.getJMSDestination());
     sb.append(" reply=").append(msg.getJMSReplyTo());
     sb.append(" ts=").append(DATE_FORMAT.format(new Date(msg.getJMSTimestamp())));
     System.out.println(sb.toString());

     sb = new StringBuffer(8192);
     sb.append("Properties:");
     for (Enumeration e = msg.getPropertyNames();
   e.hasMoreElements(); ) {
  String propName = (String)e.nextElement();
  sb.append(' ').append(propName).append('=');
  sb.append(msg.getObjectProperty(propName));
     }
     System.out.println(sb.toString());
     System.out.println(msgText);
     System.out.println("");
 } catch (Exception e) {
     e.printStackTrace(System.err);
 }
    }

    public void onException(JMSException e) {
 e.printStackTrace(System.err);
 close();

 // Wake us from the wait
 synchronized (this) {
     this.notifyAll();
 }
    }
}


Here's the .jnlp file

<?xml version="1.0" encoding="UTF-8"?>

<jnlp spec="1.0+"
codebase="http://www.mtc.ti.com/applications/facops/whiteboard/javaws/test"
href="TopicDump-neptune7001.jnlp">
       <information>
         <title>TopicDump</title>
         <vendor>Texas Instruments</vendor>
         <homepage href="http://www.mtc.ti.com/~jmaline/"/>
         <description>help me understand Java WebStart security</description>
         <description kind="short">security check</description>
         <offline-allowed/>
       </information>
       <resources>
         <j2se version="1.3"/>
         <jar href="facops.jar"/>
  <jar href="../wli70sp1/weblogic.jar"/>
         <property name="java.naming.factory.initial"
value="weblogic.jndi.WLInitialContextFactory"/>
         <property name="java.naming.provider.url"
value="t3://neptune.mtc.ti.com:7001"/>
       </resources>
        <security>
                <all-permissions/>
        </security>
       <application-desc main-class="com.ti.mtc.facops.util.TopicDump">
  <argument>com.bea.wlpi.AuditTopic</argument>
       </application-desc>
     </jnlp>

---------- END SOURCE ----------

CUSTOMER WORKAROUND :
Edit jre\lib\security\java.policy files on client to grant
the following:
 permission java.lang.RuntimePermission "getClassLoader";

This is unsatisfying since it requires touching all the
client computers.  Plus I'm not sure if security
implications of granting this.

This is BEA's recommended workaround.
(Review ID: 179436) 
======================================================================

Comments
EVALUATION At first description this dosn't seem to be a java web start problem, but I will assign it to myself to help expidite resolving it. key factors are: 1.) seemed to work with WLS 6.1SP1 but not WLS 7.0SP1 2.) works when client application is run from commandline w/o security manager 2.a) - can you run from command line with security manager? 2.b) - can you run from java web start w/o security manager ? (call System.setSecurityManager(null) early on in initialization. The: <security> <all-permissions> </security> tag in conjunction with signed jar files only sets the permissions for code loaded by the JNLPClassLoader from the jars specified in the jnlp file. The code that is leading to the java.security.AccessControlException seems to have been loaded by some form of RMIClassLoader (notice the stacktrace lines: at weblogic.rmi.internal.StubInfo.readObject(StubInfo.java:100) at java.lang.reflect.Method.invoke(Native Method) ) It is the responsibility of whatever classloader loaded this code to assign permission collections to it, it looks like this code is assuming a security manager is not installed. ###@###.### 2003-01-28
28-01-2003