我们将Spring Boot(1.1.6)应用程序部署为.war文件到Tomcat 7.0.52 / OpenJDK 7服务器。我们需要在SecurityManager下运行此服务器。
即使我们使用允许AllPermission到所有代码的策略来运行服务器(基本上与在SecurityManager下运行的不相同),我们也会因反射活动而抛出异常。这是一个例外的完整堆栈跟踪。
java.lang.IllegalAccessException: Class org.apache.catalina.security.SecurityUtil$1 can not access a member of class org.springframework.boot.context.web.ErrorPageFilter with modifiers "public"
at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:109) ~[na:1.7.0_65]
at java.lang.reflect.AccessibleObject.slowCheckMemberAccess(AccessibleObject.java:261) ~[na:1.7.0_65]
at java.lang.reflect.AccessibleObject.checkAccess(AccessibleObject.java:253) ~[na:1.7.0_65]
at java.lang.reflect.Method.invoke(Method.java:599) ~[na:1.7.0_65]
at org.apache.catalina.security.SecurityUtil$1.run(SecurityUtil.java:277) ~[catalina.jar:7.0.52]
at org.apache.catalina.security.SecurityUtil$1.run(SecurityUtil.java:274) ~[catalina.jar:7.0.52]
at java.security.AccessController.doPrivileged(Native Method) ~[na:1.7.0_65]
at javax.security.auth.Subject.doAsPrivileged(Subject.java:536) ~[na:1.7.0_65]
at org.apache.catalina.security.SecurityUtil.execute(SecurityUtil.java:309) ~[catalina.jar:7.0.52]
at org.apache.catalina.security.SecurityUtil.doAsPrivilege(SecurityUtil.java:249) ~[catalina.jar:7.0.52]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:237) ~[catalina.jar:7.0.52]
at org.apache.catalina.core.ApplicationFilterChain.access$000(ApplicationFilterChain.java:55) ~[catalina.jar:7.0.52]
at org.apache.catalina.core.ApplicationFilterChain$1.run(ApplicationFilterChain.java:191) ~[catalina.jar:7.0.52]
at org.apache.catalina.core.ApplicationFilterChain$1.run(ApplicationFilterChain.java:187) ~[catalina.jar:7.0.52]
at java.security.AccessController.doPrivileged(Native Method) ~[na:1.7.0_65]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:186) ~[catalina.jar:7.0.52]
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:220) ~[catalina.jar:7.0.52]
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122) [catalina.jar:7.0.52]
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:501) [catalina.jar:7.0.52]
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:170) [catalina.jar:7.0.52]
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:98) [catalina.jar:7.0.52]
at org.apache.catalina.valves.RemoteIpValve.invoke(RemoteIpValve.java:683) [catalina.jar:7.0.52]
at ch.qos.logback.access.tomcat.LogbackValve.invoke(LogbackValve.java:178) [logback-access-1.0.13.jar:na]
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116) [catalina.jar:7.0.52]
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408) [catalina.jar:7.0.52]
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1040) [tomcat-coyote.jar:7.0.52]
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:607) [tomcat-coyote.jar:7.0.52]
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:313) [tomcat-coyote.jar:7.0.52]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) [na:1.7.0_65]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) [na:1.7.0_65]
at java.lang.Thread.run(Thread.java:745) [na:1.7.0_65]
应用于服务器的策略文件如下所示:
grant {
permission java.security.AllPermission;
permission java.lang.reflect.ReflectPermission "suppressAccessChecks";
};
..我们添加了明确的ReflectPermission
,以防AllPermission
没有包含它,但我们尝试了两种方式。
有关为什么只有在我们使用上述策略在SecurityManager下运行时抛出异常的指针?
答案 0 :(得分:3)
错误不是由Java安全性引起的,而是由Java语言访问规则引起的。
ErrorPageFilter类是包可见的[1]。 Tomcat尝试通过反射调用该类的公共方法,但不能,因为通过Java语言规则,类本身不可访问。
(我链接到master分支,但你实际上使用的是1.1.6版本,因此上述链接的内容可能会随着时间的推移而改变)
非公开过滤器不常见。在以前在web.xml中声明所有过滤器的情况下,无法使用此类非公共过滤器。我不知道Spring Boot内部,但我想这个过滤器是使用Servlet 3.0 API以编程方式添加到Web应用程序的。
可能的进行方式:
a)让Spring Boot开发人员将该课程公开
b)更改Apache Tomcat,以便不是查找特定类声明的方法,而是查找特定接口声明的方法。可以在实现该接口的类上调用由接口声明的java.lang.reflect.Method。我希望这个解决方案能在sun.reflect.Reflection.ensureMemberAccess()中传递这些检查,但是需要进行实际测试。
这需要更改内部Tomcat API以传递接口类(在本例中为javax.servlet.Filter)作为这些方法的附加参数。
从技术上讲,这需要:
更新:我将此归档到Bugzilla, https://issues.apache.org/bugzilla/show_bug.cgi?id=57281