我有一个简单的请求范围bean,它包含一个注入的Principal,以便我可以确定当前用户的ID。然后将该bean注入Servlet,Servlet使用该bean来显示用户的ID。例如:
界面:
public interface UserManager {
public String getCurrentUserName();
}
实施:
@RequestScoped
public class CdiUserManager implements UserManager {
@Inject
private Principal principal;
public CdiUserManager() {
}
@Override
public String getCurrentUserName() {
String name = null;
if(principal != null && principal.getName() != null){
name = principal.getName();
}
return name;
}
}
servlet:
@WebServlet({"/public/user", "/authenticated/user"})
public class UserServlet extends HttpServlet {
@Inject
private UserManager manager;
public UserServlet() {
super();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.getWriter().write("UserName: " + manager.getCurrentUserName());
}
}
servlet被映射为经过身份验证和未经身份验证的访问。我为web.xml配置了适当的安全性约束,因此仅对经过身份验证的URL进行基本身份验证。
我还有一个EAR文件。 EAR中的application.xml包括带有servlet和托管bean的Web模块以及web.xml中定义的安全角色。另外,我有一个ibm-application-bnd.xml文件,它将web.xml和application.xml中的安全角色映射到特殊主题ALL_AUTHENTICATED_USERS。
我在WAR的WEB-INF目录中有一个空的beans.xml文件。
我目前有两个问题似乎无法解决。
1)当我作为未经身份验证的用户访问公共URL时,我希望inject Principal或对principal.getName()的调用将为null或其他一些可识别的值...即“UNAUTHENTICATED”。目前我得到一个NPE,下面是堆栈跟踪。如果我访问经过身份验证的URL并通过基本身份验证登录,则servlet会按预期返回我的用户名。我不确定在这种情况下应该返回标准说什么,但我认为这是一个错误?
java.lang.NullPointerException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:95)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:56)
at java.lang.reflect.Method.invoke(Method.java:620)
at org.apache.webbeans.component.BuildInOwbBean$BuildInBeanMethodHandler.invoke(BuildInOwbBean.java:273)
at [internal classes]
at org.javassist.tmp.java.lang.Object_$$_javassist_1.getName(Object_$$_javassist_1.java)
at com.testing.cdi.CdiUserManager.getCurrentUserName(CdiUserManager.java:23)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:95)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:56)
at java.lang.reflect.Method.invoke(Method.java:620)
at org.apache.webbeans.intercept.InterceptorHandler.invoke(InterceptorHandler.java:327)
at [internal classes]
at com.testing.cdi.CdiUserManager_$$_javassist_0.getCurrentUserName(CdiUserManager_$$_javassist_0.java)
at com.testing.cdi.UserServlet.doGet(UserServlet.java:31)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:575)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:668)
at com.ibm.ws.webcontainer.servlet.ServletWrapper.service(ServletWrapper.java:1285)
at [internal classes]
2)我遇到的第二个问题是如何使用注入的Principal进行集成测试?我目前正在使用Arquillian,我已经构建了一个如下所示的部署方法:
@Deployment
public static EnterpriseArchive createDeployment() {
EnterpriseArchive ear = ShrinkWrap.create(EnterpriseArchive.class, CONTEXT_ROOT + ".ear");
WebArchive war = ShrinkWrap.create(WebArchive.class, CONTEXT_ROOT + ".war");
war.addPackages(true, UserManager.class.getPackage());
war.addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml");
war.setWebXML(new File("src/main/webapp/WEB-INF/web.xml"));
ear.setApplicationXML(new File("../testing-ear/src/main/application/META-INF/application.xml"));
ear.addAsManifestResource(new File("../testing-ear/src/main/application/META-INF/ibm-application-bnd.xml"));
ear.addAsModule(war);
return ear;
}
我在每个测试用例之前验证我的测试用户:
@Before
public void setup() throws LoginException, WSSecurityException {
// WLP provided classes to authenticate a user.
CallbackHandler wscbh = new WSCallbackHandlerImpl("user", "password");
LoginContext ctx = new LoginContext("WSLogin", wscbh);
ctx.login();
// Set the user as the current user on the thread.
Subject mySubject = ctx.getSubject();
WSSubject.setRunAsSubject(mySubject);
}
然后在测试用例中,我正在检查用户名是否为null,如下所示:
@Test
public void testAuthenticatedPrincipal() throws LoginException, WSSecurityException {
assertNull("User name should not be null.", manager.getCurrentUserName());
}
执行此测试用例总是会产生带有堆栈跟踪的NPE:
java.lang.NullPointerException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:95)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:56)
at java.lang.reflect.Method.invoke(Method.java:620)
at org.apache.webbeans.component.BuildInOwbBean$BuildInBeanMethodHandler.invoke(BuildInOwbBean.java:273)
at org.apache.webbeans.component.BuildInOwbBean$BuildInBeanMethodHandler.invoke(BuildInOwbBean.java:267)
at org.javassist.tmp.java.lang.Object_$$_javassist_2.getName(Object_$$_javassist_2.java)
at com.testing.cdi.CdiUserManager.getCurrentUserName(CdiUserManager.java:23)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:95)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:56)
at java.lang.reflect.Method.invoke(Method.java:620)
at org.apache.webbeans.intercept.InterceptorHandler.invoke(InterceptorHandler.java:327)
at org.apache.webbeans.intercept.NormalScopedBeanInterceptorHandler.invoke(NormalScopedBeanInterceptorHandler.java:117)
at org.apache.webbeans.intercept.NormalScopedBeanInterceptorHandler.invoke(NormalScopedBeanInterceptorHandler.java:108)
at com.testing.cdi.CdiUserManager_$$_javassist_1.getCurrentUserName(CdiUserManager_$$_javassist_1.java)
at com.testing.cdi.test.UserManagerTest.testAuthenticatedPrincipal(UserManagerTest.java:85)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:95)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:56)
at java.lang.reflect.Method.invoke(Method.java:620)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
at org.jboss.arquillian.junit.Arquillian$6$1.invoke(Arquillian.java:325)
at org.jboss.arquillian.container.test.impl.execution.LocalTestExecuter.execute(LocalTestExecuter.java:60)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:95)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:56)
at java.lang.reflect.Method.invoke(Method.java:620)
at org.jboss.arquillian.core.impl.ObserverImpl.invoke(ObserverImpl.java:94)
at org.jboss.arquillian.core.impl.EventContextImpl.invokeObservers(EventContextImpl.java:99)
at org.jboss.arquillian.core.impl.EventContextImpl.proceed(EventContextImpl.java:81)
at org.jboss.arquillian.core.impl.ManagerImpl.fire(ManagerImpl.java:145)
at org.jboss.arquillian.core.impl.ManagerImpl.fire(ManagerImpl.java:116)
at org.jboss.arquillian.core.impl.EventImpl.fire(EventImpl.java:67)
at org.jboss.arquillian.container.test.impl.execution.ContainerTestExecuter.execute(ContainerTestExecuter.java:38)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:95)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:56)
at java.lang.reflect.Method.invoke(Method.java:620)
at org.jboss.arquillian.core.impl.ObserverImpl.invoke(ObserverImpl.java:94)
at org.jboss.arquillian.core.impl.EventContextImpl.invokeObservers(EventContextImpl.java:99)
at org.jboss.arquillian.core.impl.EventContextImpl.proceed(EventContextImpl.java:81)
at org.jboss.arquillian.test.impl.TestContextHandler.createTestContext(TestContextHandler.java:102)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:95)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:56)
at java.lang.reflect.Method.invoke(Method.java:620)
at org.jboss.arquillian.core.impl.ObserverImpl.invoke(ObserverImpl.java:94)
at org.jboss.arquillian.core.impl.EventContextImpl.proceed(EventContextImpl.java:88)
at org.jboss.arquillian.test.impl.TestContextHandler.createClassContext(TestContextHandler.java:84)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:95)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:56)
at java.lang.reflect.Method.invoke(Method.java:620)
at org.jboss.arquillian.core.impl.ObserverImpl.invoke(ObserverImpl.java:94)
at org.jboss.arquillian.core.impl.EventContextImpl.proceed(EventContextImpl.java:88)
at org.jboss.arquillian.test.impl.TestContextHandler.createSuiteContext(TestContextHandler.java:65)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:95)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:56)
at java.lang.reflect.Method.invoke(Method.java:620)
at org.jboss.arquillian.core.impl.ObserverImpl.invoke(ObserverImpl.java:94)
at org.jboss.arquillian.core.impl.EventContextImpl.proceed(EventContextImpl.java:88)
at org.jboss.arquillian.core.impl.ManagerImpl.fire(ManagerImpl.java:145)
at org.jboss.arquillian.test.impl.EventTestRunnerAdaptor.test(EventTestRunnerAdaptor.java:135)
at org.jboss.arquillian.junit.Arquillian$6.evaluate(Arquillian.java:318)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.jboss.arquillian.junit.Arquillian$5.evaluate(Arquillian.java:277)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
at org.jboss.arquillian.junit.Arquillian$2.evaluate(Arquillian.java:202)
at org.jboss.arquillian.junit.Arquillian.multiExecute(Arquillian.java:377)
at org.jboss.arquillian.junit.Arquillian.access$200(Arquillian.java:52)
at org.jboss.arquillian.junit.Arquillian$3.evaluate(Arquillian.java:216)
at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
at org.jboss.arquillian.junit.Arquillian.run(Arquillian.java:164)
at org.junit.runner.JUnitCore.run(JUnitCore.java:160)
at org.junit.runner.JUnitCore.run(JUnitCore.java:138)
at org.jboss.arquillian.junit.container.JUnitTestRunner.execute(JUnitTestRunner.java:66)
at org.jboss.arquillian.protocol.servlet.runner.ServletTestRunner.executeTest(ServletTestRunner.java:159)
at org.jboss.arquillian.protocol.servlet.runner.ServletTestRunner.execute(ServletTestRunner.java:125)
at org.jboss.arquillian.protocol.servlet.runner.ServletTestRunner.doGet(ServletTestRunner.java:89)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:575)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:668)
at com.ibm.ws.webcontainer.servlet.ServletWrapper.service(ServletWrapper.java:1285)
at com.ibm.ws.webcontainer.servlet.ServletWrapper.handleRequest(ServletWrapper.java:776)
at com.ibm.ws.webcontainer.servlet.ServletWrapper.handleRequest(ServletWrapper.java:473)
at com.ibm.ws.webcontainer.filter.WebAppFilterManager.invokeFilters(WebAppFilterManager.java:1104)
at com.ibm.ws.webcontainer.webapp.WebApp.handleRequest(WebApp.java:4845)
at com.ibm.ws.webcontainer.osgi.DynamicVirtualHost$2.handleRequest(DynamicVirtualHost.java:297)
at com.ibm.ws.webcontainer.WebContainer.handleRequest(WebContainer.java:981)
at com.ibm.ws.webcontainer.osgi.DynamicVirtualHost$2.run(DynamicVirtualHost.java:262)
at com.ibm.ws.http.dispatcher.internal.channel.HttpDispatcherLink$TaskWrapper.run(HttpDispatcherLink.java:955)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1157)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:627)
at java.lang.Thread.run(Thread.java:863)
过去我已经构建了EJB项目,并使用此方法对它们进行集成测试。注入SessionContext将替换该场景中的Principal。有没有人对如何运行这个测试用例有任何建议或经验?
P.S。我正在将IBM JDK v1.7.1与WebSphere Liberty Developer Edition v8.5.5.5一起使用。
答案 0 :(得分:0)
通常,空值用于未登录的用户的主体,例如如果用户尚未通过身份验证,则HttpServletRequest.getUserPrincipal()将返回null。
因此,我认为注入的校长无效是不合理的。但是,Principal也是一个代理的CDI bean。由于你有一个注入的代理对象,你不能测试它是否为null,但是当你调用getName()时,CDI会尝试为登录用户找到真实的Principal并在其上调用getName(),从而导致NullPointerException
我意识到这并不是很有帮助,因为你无法真正使用Principal bean来检查用户是否经过身份验证,但我认为它不对。
对于Arquillian测试,您可以将测试作为客户端而不是服务器运行,以便您可以手动调用servlet URL并提供身份验证凭据。您必须让servlet打印出用户名并检查客户端上的响应是否正确。
有关于在客户端模式下运行测试的一些信息:https://docs.jboss.org/author/display/ARQ/Test+run+modes