我实际上遇到了角色传播问题,我需要帮助。
我正在使用Glassfish 4.0,我正在部署一个包含JAX-RS
资源的战争和一个带有远程和本地视图的EJB
用于测试目的。
我在我的web.xml
和glassfish-web.xml
部署描述符中声明了角色,链接到Glassfish中的文件域。
JAX-RS
资源正确使用了这些角色,但EJB
似乎没有看到它们。
我将向您展示我正在使用的文件,然后是我到目前为止测试的不同呼叫输出的结果。
TL / DR:很抱歉这篇文章太长了。请转到第II部分/测试2
glassfish-web.xml
部署描述符<!DOCTYPE glassfish-web-app PUBLIC "-//GlassFish.org//DTD GlassFish Application Server 3.1 Servlet 3.0//EN" "http://glassfish.org/dtds/glassfish-web-app_3_0-1.dtd">
<glassfish-web-app>
<context-root>/war-test-4</context-root>
<security-role-mapping>
<role-name>test</role-name>
<group-name>test</group-name>
</security-role-mapping>
<security-role-mapping>
<role-name>test2</role-name>
<group-name>test2</group-name>
</security-role-mapping>
<security-role-mapping>
<role-name>authenticated</role-name>
<group-name>authenticated</group-name>
</security-role-mapping>
</glassfish-web-app>
web.xml
部署描述符<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
id="WebApp_ID" version="3.1">
<display-name>war-test-4</display-name>
<servlet>
<description>JAX-RS Tools Generated - Do not modify</description>
<servlet-name>javax.ws.rs.core.Application</servlet-name>
<load-on-startup>1</load-on-startup>
<security-role-ref>
<description>Test</description>
<role-name>test</role-name>
<role-link>test</role-link>
</security-role-ref>
<security-role-ref>
<description>Auth users</description>
<role-name>authenticated</role-name>
<role-link>authenticated</role-link>
</security-role-ref>
<security-role-ref>
<description>Test2</description>
<role-name>test2</role-name>
<role-link>test2</role-link>
</security-role-ref>
</servlet>
<servlet-mapping>
<servlet-name>javax.ws.rs.core.Application</servlet-name>
<url-pattern>/jaxrs/*</url-pattern>
</servlet-mapping>
<security-constraint>
<web-resource-collection>
<web-resource-name>Admin Resources</web-resource-name>
<description>Administration resources</description>
<url-pattern>/jaxrs/*</url-pattern>
<http-method>GET</http-method>
</web-resource-collection>
<auth-constraint>
<description>TEST</description>
<role-name>test</role-name>
<role-name>test2</role-name>
<role-name>authenticated</role-name>
</auth-constraint>
</security-constraint>
<login-config>
<auth-method>BASIC</auth-method>
<realm-name>test-realm</realm-name>
</login-config>
<security-role>
<description>Test</description>
<role-name>test</role-name>
</security-role>
<security-role>
<description>Auth users</description>
<role-name>authenticated</role-name>
</security-role>
<security-role>
<description>Test2</description>
<role-name>test2</role-name>
</security-role>
</web-app>
SessionBeanTest.java
/**
* Session Bean implementation class SessionBeanTest
*/
@Stateless(mappedName = "SessionBeanTest")
//@RolesAllowed({"authenticated"})
//@DeclareRoles({"authenticated","test","test2"})
public class SessionBeanTest implements SessionBeanRemote, SessionBeanLocal {
@Resource
private SessionContext sessionContext;
@Override
public String get() {
return MessageFormat
.format("EJB Call by :{0} authenticated? : {1} / test2 ? : {2} / test ? : {3}",
sessionContext.getCallerPrincipal().getName(),
sessionContext.isCallerInRole("authenticated"),
sessionContext.isCallerInRole("test2"), sessionContext.isCallerInRole("test"));
}
}
AccessTest.java
@Path("access")
//@DeclareRoles({/*"authenticated","test",*/"test2"})
@Stateless
public class AccessTest {
@Inject
private SessionBeanLocal testBean;
@GET
@Path("1")
public Response test(@Context HttpServletRequest req){
return Response.ok(MessageFormat
.format("JAX-RS Call by :{0} authenticated? : {1} / test2 ? : {2} / test ? : {3}",
req.getUserPrincipal().getName(),
req.isUserInRole("authenticated"),
req.isUserInRole("test2"),
req.isUserInRole("test"))).build();
}
@GET
@Path("2")
public Response test2(){
return Response.ok(testBean.get()).build();
}
}
正如您可能已经注意到的那样,我在EJB和JAX-RS资源中都注释了@DeclareRoles
和@RolesAllowed
注释。我的注册表中也有2个URI JAX-RS服务。一个是直接向用户提供信息和角色,另一个使用EJB来检索相同的信息。 如果用户已登录,则两者都应返回完全相同的输出。
现在,使用网络服务测试人员(Paw on Mac,基于Curl,非常有用!),我正在访问这两个URI:
URI /jaxrs/access/1
的输出,没有用户
HTTP/1.1 401 Unauthorized
X-Powered-By: Servlet/3.1 JSP/2.3 (GlassFish Server Open Source Edition 4.0 Java/Oracle Corporation/1.7)
URI /jaxrs/access/2
的输出,没有用户
HTTP/1.1 401 Unauthorized
X-Powered-By: Servlet/3.1 JSP/2.3 (GlassFish Server Open Source Edition 4.0 Java/Oracle Corporation/1.7)
到目前为止,它似乎按计划工作,需要经过身份验证的用户才能访问该资源。 但看看第二次测试...
用户具有所有角色
的URI/jaxrs/access/1
的输出
HTTP/1.1 200 OK
X-Powered-By: Servlet/3.1 JSP/2.3 (GlassFish Server Open Source Edition 4.0 Java/Oracle Corporation/1.7)
JAX-RS Call by :testadmin authenticated? : true / test2 ? : true / test ? : true
用户具有所有角色
的URI/jaxrs/access/2
的输出
HTTP/1.1 200 OK
X-Powered-By: Servlet/3.1 JSP/2.3 (GlassFish Server Open Source Edition 4.0 Java/Oracle Corporation/1.7)
EJB Call by :testadmin authenticated? : **false** / test2 ? : **false** / test ? : **false**
这是我不明白的部分。在web.xml
和glassfish-web.xml
中声明的角色不会传播到EJB,它位于同一个WAR项目中。
@DeclareRoles
注释我是否取消注释EJB或JAX-RS服务中的@DeclareRoles({"authenticated"})
,我得到以下输出:
URI /jaxrs/access/1
的输出,用户拥有所有角色,@DeclareRoles
取消注释
HTTP/1.1 200 OK
X-Powered-By: Servlet/3.1 JSP/2.3 (GlassFish Server Open Source Edition 4.0 Java/Oracle Corporation/1.7)
JAX-RS Call by :testadmin authenticated? : true / test2 ? : true / test ? : true
URI /jaxrs/access/2
的输出,用户拥有所有角色,@DeclareRoles
取消注释
HTTP/1.1 200 OK
X-Powered-By: Servlet/3.1 JSP/2.3 (GlassFish Server Open Source Edition 4.0 Java/Oracle Corporation/1.7)
EJB Call by :testadmin authenticated? : **true** / test2 ? : **false** / test ? : **false**
EJB只能看到我声明的角色,但JAX-RS服务会看到它们
我还有一个纯Java客户端用于测试目的。这是:
public class Main {
public static void main(String[] args) throws Exception {
getRemoteService();
}
public static void getRemoteService() throws Exception {
String host = "127.0.0.1";
String port = "3700";
Properties props = new Properties();
props.setProperty("java.naming.factory.initial", "com.sun.enterprise.naming.SerialInitContextFactory");
props.setProperty("java.naming.factory.url.pkgs", "com.sun.enterprise.naming");
props.setProperty("java.naming.factory.state", "com.sun.cobra.ee.impl.presentation.rmi.JNDIStateFactoryImpl");
props.setProperty("org.omg.CORBA.ORBInitialHost", host);
props.setProperty("org.omg.CORBA.ORBInitialPort", port);
Context amInitial = null;
amInitial = new InitialContext(props);
ProgrammaticLogin programmaticLogin = new ProgrammaticLogin();
programmaticLogin.login("testuser2", "password");
SessionBeanRemote service = (SessionBeanRemote) amInitial.lookup("SessionBeanTest");
System.out.println(service.get());
programmaticLogin.logout();
programmaticLogin.login("testadmin", "password");
System.out.println(service.get());
}
}
此客户端使用ProgrammaticLogin
接口登录并将EJB与CORBA一起使用。除了测试之外,我不打算使用它。
首先,客户端将使用受限用户登录,然后使用具有所有角色的用户登录。 以下是使用此客户端的测试结果:
@DeclareRoles
注释EJB Call by :ANONYMOUS authenticated? : false / test2 ? : false / test ? : false
EJB Call by :ANONYMOUS authenticated? : false / test2 ? : false / test ? : false
@DeclareRoles({"authenticated","test","test2"})
未注释的EJB Call by :ANONYMOUS authenticated? : false / test2 ? : false / test ? : false
EJB Call by :ANONYMOUS authenticated? : false / test2 ? : false / test ? : false
此处,用户也未经过身份验证。但是当我向EJB添加@RolesAllowed
注释时,我得到了这个:
@DeclareRoles
和@RolesAllowed({"authenticated"})
添加EJB Call by :testuser2 authenticated? : true / test2 ? : true / test ? : false
EJB Call by :testadmin authenticated? : true / test2 ? : true / test ? : true
到目前为止,这是我测试的全部内容。我不明白为什么部署描述符中声明的角色被JAX-RS服务正确使用,而不是无状态EJB。我需要你的帮助,我并不是真的在每个EJB上使用样板Roles注释。
答案 0 :(得分:1)
我不知道EJB 3.2和Java EE 7规范要求或至少建议兼容实现的容器来支持其他人的安全角色声明。相反,我认为这些文件的含义是,这些声明受到约束 - 至少从“用户空间”代码的角度来看 - 在它们被定义的操作环境中。
关于你的观察:
web.xml
和ejb-jar.xml
元素或等效注释声明的角色将被“翻译”为{{ 3}} s和WebRoleRefPermission
分别由默认的JACC提供程序提供;因此他们是完全不同的。这些以及一些其他Java EE特定的Permission
- 至少在理论上 - 可以从“用户空间”代码访问,例如,正如所展示EJBRoleRefPermission
(这种方法在GlassFish 4.1上实际上对我有用)。SecurityContext.isUserInRole(String)
在此方案中等效的原因。但是,对于不同的假设Servlet独立实现,情况并非如此,并且需要再次定义安全角色两次。总之,我不认为这种行为违反了规范。这可能是违反直觉的 - 但这是一个不同的故事。
顺便说一句,我完全同意平台安全设施(特别是JACC和JASPIC)的资源严重缺乏令人沮丧;我至少期望在官方教程中包含关于每个的专门章节。如果不是HttpServletRequest.isUserInRole(String)
Arjan Tijms's extensive collection of - in depth这个问题,我们很多人仍然会留在黑暗中。人们只能希望新的articles能够帮助改变它 - 更多 - 没有(希望!)重新发明轮子和/或在Servlet Filter
上面层层叠来。
答案 1 :(得分:1)
提示让您的web.xml缩短一点。 Servlet不需要以下内容:
<security-role-ref>
<description>Test2</description>
<role-name>test2</role-name>
<role-link>test2</role-link>
</security-role-ref>
如果您的二进制Servlet使用的角色与您的应用程序使用的角色不同,则只应使用此方法。 role-refs已经默认为应用程序角色。
您的测试看起来非常像这个:https://github.com/javaee-samples/javaee7-samples/tree/master/jaspic/ejb-propagation
在GlassFish 4.1(比您使用的版本高一个版本)上,如果我的记忆正确地为我提供了测试,那么该测试就会通过。