【问题标题】:tomcat8.0 and tomcat8.5.6 WebappClassLoaderBasetomcat8.0 和 tomcat8.5.6 WebappClassLoaderBase
【发布时间】:2017-05-27 02:46:41
【问题描述】:

我们最近将tomcat从8.0.32更新到8.5.6,在尝试加载/opt/apache-tomcat-8.5.6_1/webapps/example/WEB-INF/classes/com/sun/xml/internal/ws/runtime/config/jaxb.properties时遇到AccessControlException,我调试tomcat 8.5.6和8.0.32之间的源代码,它在org.apache.catalina.loader.WebappClassLoaderBase.findResource

Tomcat8.0

public URL findResource(final String name) {

    if (log.isDebugEnabled())
        log.debug("    findResource(" + name + ")");

    checkStateForResourceLoading(name);

    URL url = null;

    String path = nameToPath(name);

    ResourceEntry entry = resourceEntries.get(path);
    if (entry == null) {
        if (securityManager != null) {
            PrivilegedAction<ResourceEntry> dp =
                new PrivilegedFindResourceByName(name, path);
            entry = AccessController.doPrivileged(dp);
        } else {
            entry = findResourceInternal(name, path);
        }
    }
    if (entry != null) {
        url = entry.source;
        entry.webResource = null;
    }

    if ((url == null) && hasExternalRepositories) {
        url = super.findResource(name);
    }

    if (log.isDebugEnabled()) {
        if (url != null)
            log.debug("    --> Returning '" + url.toString() + "'");
        else
            log.debug("    --> Resource not found, returning null");
    }
    return url;
}

Tomcat8.5.6

public URL findResource(final String name) {

    if (log.isDebugEnabled())
        log.debug("    findResource(" + name + ")");

    checkStateForResourceLoading(name);

    URL url = null;

    String path = nameToPath(name);

    WebResource resource = resources.getClassLoaderResource(path);
    if (resource.exists()) {
        url = resource.getURL();
        trackLastModified(path, resource);
    }

    if ((url == null) && hasExternalRepositories) {
        url = super.findResource(name);
    }

    if (log.isDebugEnabled()) {
        if (url != null)
            log.debug("    --> Returning '" + url.toString() + "'");
        else
            log.debug("    --> Resource not found, returning null");
    }
    return url;
}

如您所见,tomcat8.0 通过 AccessController.doPrivileged 加载资源,但在 tomcat8.5.6 中,它直接加载资源,我想这就是我得到异常的原因

java.security.AccessControlException: access denied 
("java.io.FilePermission" 
"/opt/apache-tomcat-8.5.6_1/webapps/example/WEB-INF/classes/com/sun/xml/internal/ws/runtime/config/jaxb.properties" 
"read")

java.lang.IllegalStateException: MASM0003: Default [ jaxws-tubes-default.xml ] configuration file was not loaded
        at com.sun.xml.internal.ws.assembler.MetroConfigLoader.init(MetroConfigLoader.java:133)
        at com.sun.xml.internal.ws.assembler.MetroConfigLoader.<init>(MetroConfigLoader.java:104)

这个文件是由MetroConfigLoader加载的,

private static JAXBContext createJAXBContext() throws Exception {
        return isJDKInternal()?(JAXBContext)AccessController.doPrivileged(new PrivilegedExceptionAction<JAXBContext>() {
            public JAXBContext run() throws Exception {
                return JAXBContext.newInstance(MetroConfig.class.getPackage().getName());
            }
        }, createSecurityContext()):JAXBContext.newInstance(MetroConfig.class.getPackage().getName());
    }

    private static AccessControlContext createSecurityContext() {
        PermissionCollection perms = new Permissions();
        perms.add(new RuntimePermission("accessClassInPackage.com.sun.xml.internal.ws.runtime.config"));
        perms.add(new ReflectPermission("suppressAccessChecks"));
        return new AccessControlContext(new ProtectionDomain[]{new ProtectionDomain((CodeSource)null, perms)});
    }

有人遇到同样的问题吗?或者还有其他一些问题。谢谢。

【问题讨论】:

    标签: java tomcat java-8 jax-ws


    【解决方案1】:

    经过三天的研究,现在我使用 jaxws-rt 代替 JDK 中的默认实现,您可以从 JDK 中的代码中阅读:

    private static JAXBContext createJAXBContext() throws Exception {
            return isJDKInternal()?(JAXBContext)AccessController.doPrivileged(new PrivilegedExceptionAction<JAXBContext>() {
                public JAXBContext run() throws Exception {
                    return JAXBContext.newInstance(MetroConfig.class.getPackage().getName());
                }
            }, createSecurityContext()):JAXBContext.newInstance(MetroConfig.class.getPackage().getName());
    }
    

    如果是JDK内部的,会创建具有特定权限的实例,tomcat在tomcat8.0中通过doPrivileged获取资源,而在tomcat8.5中则不同,所以没有权限是无法获取资源的

    java.security.AccessControlException: access denied ("java.io.FilePermission" 
    "/opt/apache-tomcat-8.5.6_1/webapps/example/WEB-INF/classes/com/sun/xml/internal/ws/runtime/config/jaxb.properties" 
    "read")
    

    所以我改成外部jaxws-rt,它会直接创建实例。我只是在 pom 中添加jaxws-rt

     <dependency>
            <groupId>com.sun.xml.ws</groupId>
            <artifactId>jaxws-rt</artifactId>
            <version>2.2.10</version>
     </dependency>
    

    【讨论】:

      【解决方案2】:

      我想在上面的 chaoluo 的answer 上添加一个通知。如果您基于每个请求使用 ssl 证书或请求超时或连接超时,您应该在从默认 JDK 实现切换到外部 jaxws-rt 后仔细检查此功能。外部实现使用与 JDK 实现不同的属性名称。如果您使用字符串常量提供它们,您可能会忘记更新它们。在这种情况下,ssl 证书和超时将被完全忽略。

      JDK实现示例代码:

      javax.xml.ws.BindingProvider proxy = someCustomCodeWhichCreatesProxy()
      proxy.getRequestContext().put("com.sun.xml.internal.ws.transport.https.client.SSLSocketFactory", customCodeWhichCreateSSLFactory());
      proxy.getRequestContext().put("com.sun.xml.internal.ws.request.timeout", customCodeWhichDefinesRequestTimeout());
      proxy.getRequestContext().put("com.sun.xml.internal.ws.connect.timeout", customCodeWhichDefinesConnectionTimeout());
      // ... some code, which uses the proxy for calling external webservice
      

      外部 jaxws-rt 的示例代码:

      javax.xml.ws.BindingProvider proxy = someCustomCodeWhichCreatesProxy()
      proxy.getRequestContext().put("com.sun.xml.ws.transport.https.client.SSLSocketFactory", customCodeWhichCreateSSLFactory());
      proxy.getRequestContext().put("com.sun.xml.ws.request.timeout", customCodeWhichDefinesRequestTimeout());
      proxy.getRequestContext().put("com.sun.xml.ws.connect.timeout", customCodeWhichDefinesConnectionTimeout());
      // ... some code, which uses the proxy for calling external webservice
      

      或者,可以使用 jaxws-rt 的 com.sun.xml.ws.developer.JAXWSProperties 中定义的常量,而不是硬编码的字符串

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-04-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-08-25
        • 2011-02-17
        相关资源
        最近更新 更多