Embedded Glassfish, security and Arquillian questi

2019-02-02 00:17发布

问题:

I want to test my EJBs on an embedded Glassfish using Arquillian.

The important thing is that I have to have security up because my bean logic does some programmatic security checking (sessionContext.isCallerInRole(role)).

Is it possible to simulate a login with Arquillian on an Embedded Glassfish?

How do I setup the Embedded Glassfish to use user and role property files?

[EDIT]

I found a post who's directions I decided to follow (http://community.jboss.org/message/580290) but I still got issues.

1 my arquillian.xml isn't picked up
2 I get warnings concerning @Resource SessionContext
3 I can't get the running server's instance

src/test/resources/arquillian.xml:

<arquillian xmlns="http://jboss.com/arquillian" 
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns:glassfish="urn:arq:org.jboss.arquillian.container.glassfish.embedded_3">

    <glassfish:container>
        <glassfish:bindHttpPort>9090</glassfish:bindHttpPort>
        <glassfish:instanceRoot>src/test/glassfish</glassfish:instanceRoot>
        <glassfish:autoDelete>true</glassfish:autoDelete>
    </glassfish:container>

</arquillian>

my test:

@RunWith(Arquillian.class)
public class ArquillianTestCase {

    @Deployment
    public static JavaArchive createDeployment() {
        final JavaArchive jar = ShrinkWrap.create(JavaArchive.class, "test.jar")
                .addClasses(FileBrowser.class, FileBrowserBean.class).addAsResource("META-INF/ejb-jar.xml")
                .addAsResource("META-INF/glassfish-ejb-jar.xml");
        return jar;
    }

    @EJB
    private FileBrowser fileBrowser;

    @Test
    public void setupSecurity() throws Exception {
        GlassfishTestHelper.createFileUser("user1", "xxx", "role1");
    }

    @Test
    public void testLoadConfiguration() throws Exception {
        final boolean loggedIn = GlassfishTestHelper.loginFileUser("user1", "xxx");
        Assert.assertEquals(true, loggedIn);
        this.fileBrowser.loadConfiguration();
    }

my login helper class:

public final class GlassfishTestHelper {

    private GlassfishTestHelper() {
    }

    public static void createFileUser(final String username, final String password, final String groups) throws Exception {
        final Server server = Server.getServer(Server.getServerNames().get(0)); // NPE
        final String command = "create-file-user";
        final ParameterMap params = new ParameterMap();
        params.add("userpassword", password);
        params.add("groups", groups);
        params.add("username", username);
        final CommandRunner runner = server.getHabitat().getComponent(CommandRunner.class);
        final ActionReport report = server.getHabitat().getComponent(ActionReport.class);
        runner.getCommandInvocation(command, report).parameters(params).execute();

        if (report.getMessage() != null) {
            throw new Exception(String.format("Failed to create user : %s - message %s", username, report.getMessage()),
                report.getFailureCause());
        }
    }

    public static boolean loginFileUser(final String username, final String password) throws Exception {
        final ProgrammaticLogin login = new ProgrammaticLogin();
        return login.login(username, password.toCharArray(), "fileRealm", true);
    }
}

my EJB:

@Stateless
@Local(FileBrowser.class)
public class FileBrowserBean implements FileBrowser {

    @Resource
    private SessionContext sessionContext;

    @Override
    public Set<Application> loadConfiguration() throws FileBrowserException {
        // ...
    }
}

If I run the test, this is the output:

Running com.jnj.gtsc.services.filebrowser.ArquillianTestCase
18-Apr-2011 16:14:30 org.jboss.arquillian.impl.client.container.ContainerRegistryCreator getActivatedConfiguration
INFO: Could not read active container configuration: null
18-Apr-2011 16:14:31 com.sun.enterprise.v3.server.CommonClassLoaderServiceImpl findDerbyClient
INFO: Cannot find javadb client jar file, derby jdbc driver will not be available by default.
18-Apr-2011 16:14:31 org.hibernate.validator.util.Version <clinit>
INFO: Hibernate Validator null
18-Apr-2011 16:14:31 org.hibernate.validator.engine.resolver.DefaultTraversableResolver detectJPA
INFO: Instantiated an instance of org.hibernate.validator.engine.resolver.JPATraversableResolver.
18-Apr-2011 16:14:32 com.sun.enterprise.v3.services.impl.GrizzlyService createNetworkProxy
INFO: Network listener https-listener on port 0 disabled per domain.xml
18-Apr-2011 16:14:32 com.sun.enterprise.v3.server.AppServerStartup run
INFO: GlassFish Server Open Source Edition 3.1 (java_re-private) startup time : Embedded (655ms), startup services(395ms), total(1,050ms)
18-Apr-2011 16:14:32 com.sun.enterprise.v3.services.impl.GrizzlyProxy$2$1 onReady
INFO: Grizzly Framework 1.9.31 started in: 121ms - bound to [0.0.0.0:8181]
18-Apr-2011 16:14:32 org.glassfish.admin.mbeanserver.JMXStartupService$JMXConnectorsStarterThread run
INFO: JMXStartupService: JMXConnector system is disabled, skipping.
18-Apr-2011 16:14:33 com.sun.enterprise.security.SecurityLifecycle <init>
INFO: SEC1002: Security Manager is OFF.
18-Apr-2011 16:14:33 com.sun.enterprise.security.SecurityLifecycle onInitialization
INFO: SEC1010: Entering Security Startup Service
18-Apr-2011 16:14:33 com.sun.enterprise.security.PolicyLoader loadPolicy
INFO: SEC1143: Loading policy provider com.sun.enterprise.security.jacc.provider.SimplePolicyProvider.
18-Apr-2011 16:14:34 com.sun.enterprise.security.auth.realm.Realm doInstantiate
INFO: SEC1115: Realm [admin-realm] of classtype [com.sun.enterprise.security.auth.realm.file.FileRealm] successfully created.
18-Apr-2011 16:14:34 com.sun.enterprise.security.auth.realm.Realm doInstantiate
INFO: SEC1115: Realm [file] of classtype [com.sun.enterprise.security.auth.realm.file.FileRealm] successfully created.
18-Apr-2011 16:14:34 com.sun.enterprise.security.auth.realm.Realm doInstantiate
INFO: SEC1115: Realm [certificate] of classtype [com.sun.enterprise.security.auth.realm.certificate.CertificateRealm] successfully created.
18-Apr-2011 16:14:34 com.sun.enterprise.security.SecurityLifecycle onInitialization
INFO: SEC1011: Security Service(s) Started Successfully
18-Apr-2011 16:14:34 com.sun.enterprise.web.WebContainer createHttpListener
INFO: WEB0169: Created HTTP listener [http-listener] on host/port [0.0.0.0:8181]
18-Apr-2011 16:14:34 com.sun.enterprise.web.WebContainer createHosts
INFO: WEB0171: Created virtual server [server]
18-Apr-2011 16:14:34 com.sun.enterprise.web.WebContainer loadSystemDefaultWebModules
INFO: WEB0172: Virtual server [server] loaded default web module []
18-Apr-2011 16:14:35 org.glassfish.apf.impl.DefaultErrorHandler warning
WARNING: Incorrect @Resource annotation class definition - missing lookup attribute
 symbol: FIELD
 location: private javax.ejb.SessionContext com.jnj.gtsc.services.filebrowser.ejb.FileBrowserBean.sessionContext

18-Apr-2011 16:14:35 org.glassfish.apf.impl.DefaultErrorHandler warning
WARNING: Incorrect @Resource annotation class definition - missing lookup attribute
 symbol: FIELD
 location: private javax.ejb.SessionContext com.jnj.gtsc.services.filebrowser.ejb.FileBrowserBean.sessionContext

classLoader = WebappClassLoader (delegate=true; repositories=WEB-INF/classes/)
SharedSecrets.getJavaNetAccess()=java.net.URLClassLoader$7@720f6c
18-Apr-2011 16:14:35 com.sun.ejb.containers.BaseContainer initializeHome
INFO: Portable JNDI names for EJB FileBrowserBean : [java:global/test/FileBrowserBean!com.jnj.gtsc.services.filebrowser.ejb.FileBrowser, java:global/test/FileBrowserBean]
18-Apr-2011 16:14:36 com.sun.enterprise.web.WebApplication start
INFO: WEB0671: Loading application [test] at [/test]
18-Apr-2011 16:14:36 org.glassfish.deployment.admin.DeployCommand execute
PlainTextActionReporterSUCCESSDescription: deploy AdminCommandApplication deployed with name test.
INFO: test was successfully deployed in 2,845 milliseconds.
[name=test
18-Apr-2011 16:14:36 org.jboss.arquillian.testenricher.cdi.CDIInjectionEnricher injectClass
INFO: BeanManager cannot be located at java:comp/BeanManager. Either you are using an archive with no beans.xml, or the BeanManager has not been bound to that location in JNDI.
18-Apr-2011 16:14:36 org.jboss.arquillian.testenricher.cdi.CDIInjectionEnricher injectClass
INFO: BeanManager cannot be located at java:comp/BeanManager. Either you are using an archive with no beans.xml, or the BeanManager has not been bound to that location in JNDI.
18-Apr-2011 16:14:36 com.sun.appserv.security.ProgrammaticLogin login
SEVERE: SEC9050: Programmatic login failed
com.sun.enterprise.security.auth.login.common.LoginException: Login failed: Unable to locate a login configuration
    at com.sun.enterprise.security.auth.login.LoginContextDriver.doPasswordLogin(LoginContextDriver.java:394)
    at com.sun.enterprise.security.auth.login.LoginContextDriver.login(LoginContextDriver.java:240)
    at com.sun.enterprise.security.auth.login.LoginContextDriver.login(LoginContextDriver.java:153)
    at com.sun.appserv.security.ProgrammaticLogin$1.run(ProgrammaticLogin.java:174)
    at java.security.AccessController.doPrivileged(Native Method)
    at com.sun.appserv.security.ProgrammaticLogin.login(ProgrammaticLogin.java:168)
    at com.jnj.gtsc.services.filebrowser.util.GlassfishTestHelper.loginFileUser(GlassfishTestHelper.java:67)
    at com.jnj.gtsc.services.filebrowser.ArquillianTestCase.testLoadConfiguration(ArquillianTestCase.java:71)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
    at org.jboss.arquillian.junit.Arquillian$6$1.invoke(Arquillian.java:259)
    at org.jboss.arquillian.impl.execution.LocalTestExecuter.execute(LocalTestExecuter.java:63)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.jboss.arquillian.impl.core.ObserverImpl.invoke(ObserverImpl.java:90)
    at org.jboss.arquillian.impl.core.EventContextImpl.invokeObservers(EventContextImpl.java:98)
    at org.jboss.arquillian.impl.core.EventContextImpl.proceed(EventContextImpl.java:80)
    at org.jboss.arquillian.impl.core.ManagerImpl.fire(ManagerImpl.java:126)
    at org.jboss.arquillian.impl.core.ManagerImpl.fire(ManagerImpl.java:106)
    at org.jboss.arquillian.impl.core.EventImpl.fire(EventImpl.java:67)
    at org.jboss.arquillian.impl.execution.ContainerTestExecuter.execute(ContainerTestExecuter.java:38)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.jboss.arquillian.impl.core.ObserverImpl.invoke(ObserverImpl.java:90)
    at org.jboss.arquillian.impl.core.EventContextImpl.invokeObservers(EventContextImpl.java:98)
    at org.jboss.arquillian.impl.core.EventContextImpl.proceed(EventContextImpl.java:80)
    at org.jboss.arquillian.impl.TestContextHandler.createTestContext(TestContextHandler.java:82)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.jboss.arquillian.impl.core.ObserverImpl.invoke(ObserverImpl.java:90)
    at org.jboss.arquillian.impl.core.EventContextImpl.proceed(EventContextImpl.java:87)
    at org.jboss.arquillian.impl.TestContextHandler.createClassContext(TestContextHandler.java:68)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.jboss.arquillian.impl.core.ObserverImpl.invoke(ObserverImpl.java:90)
    at org.jboss.arquillian.impl.core.EventContextImpl.proceed(EventContextImpl.java:87)
    at org.jboss.arquillian.impl.TestContextHandler.createSuiteContext(TestContextHandler.java:54)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.jboss.arquillian.impl.core.ObserverImpl.invoke(ObserverImpl.java:90)
    at org.jboss.arquillian.impl.core.EventContextImpl.proceed(EventContextImpl.java:87)
    at org.jboss.arquillian.impl.core.ManagerImpl.fire(ManagerImpl.java:126)
    at org.jboss.arquillian.impl.EventTestRunnerAdaptor.test(EventTestRunnerAdaptor.java:101)
    at org.jboss.arquillian.junit.Arquillian$6.evaluate(Arquillian.java:251)
    at org.jboss.arquillian.junit.Arquillian$4.evaluate(Arquillian.java:214)
    at org.jboss.arquillian.junit.Arquillian.multiExecute(Arquillian.java:303)
    at org.jboss.arquillian.junit.Arquillian.access$300(Arquillian.java:45)
    at org.jboss.arquillian.junit.Arquillian$5.evaluate(Arquillian.java:228)
    at org.junit.runners.BlockJUnit4ClassRunner.runNotIgnored(BlockJUnit4ClassRunner.java:79)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:71)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:49)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
    at org.jboss.arquillian.junit.Arquillian$2.evaluate(Arquillian.java:173)
    at org.jboss.arquillian.junit.Arquillian.multiExecute(Arquillian.java:303)
    at org.jboss.arquillian.junit.Arquillian.access$300(Arquillian.java:45)
    at org.jboss.arquillian.junit.Arquillian$3.evaluate(Arquillian.java:187)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
    at org.jboss.arquillian.junit.Arquillian.run(Arquillian.java:127)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:157)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:136)
    at org.jboss.arquillian.junit.JUnitTestRunner.execute(JUnitTestRunner.java:69)
    at org.jboss.arquillian.protocol.servlet.runner.ServletTestRunner.doGet(ServletTestRunner.java:84)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:735)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:848)
    at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1534)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:281)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
    at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:655)
    at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:595)
    at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:98)
    at com.sun.enterprise.web.PESessionLockingStandardPipeline.invoke(PESessionLockingStandardPipeline.java:91)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:162)
    at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:326)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:227)
    at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:170)
    at com.sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.java:822)
    at com.sun.grizzly.http.ProcessorTask.doProcess(ProcessorTask.java:719)
    at com.sun.grizzly.http.ProcessorTask.process(ProcessorTask.java:1013)
    at com.sun.grizzly.http.DefaultProtocolFilter.execute(DefaultProtocolFilter.java:225)
    at com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:137)
    at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:104)
    at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:90)
    at com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:79)
    at com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:54)
    at com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:59)
    at com.sun.grizzly.ContextTask.run(ContextTask.java:71)
    at com.sun.grizzly.util.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:532)
    at com.sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractThreadPool.java:513)
    at java.lang.Thread.run(Thread.java:662)
Caused by: java.lang.SecurityException: Unable to locate a login configuration
    at com.sun.security.auth.login.ConfigFile.<init>(ConfigFile.java:93)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
    at java.lang.Class.newInstance0(Class.java:355)
    at java.lang.Class.newInstance(Class.java:308)
    at javax.security.auth.login.Configuration$3.run(Configuration.java:247)
    at java.security.AccessController.doPrivileged(Native Method)
    at javax.security.auth.login.Configuration.getConfiguration(Configuration.java:242)
    at javax.security.auth.login.LoginContext$1.run(LoginContext.java:237)
    at java.security.AccessController.doPrivileged(Native Method)
    at javax.security.auth.login.LoginContext.init(LoginContext.java:234)
    at javax.security.auth.login.LoginContext.<init>(LoginContext.java:367)
    at javax.security.auth.login.LoginContext.<init>(LoginContext.java:444)
    at com.sun.enterprise.security.auth.login.LoginContextDriver.doPasswordLogin(LoginContextDriver.java:381)
    ... 107 more
Caused by: java.io.IOException: Unable to locate a login configuration
    at com.sun.security.auth.login.ConfigFile.init(ConfigFile.java:250)
    at com.sun.security.auth.login.ConfigFile.<init>(ConfigFile.java:91)
    ... 122 more
classLoader = WebappClassLoader (delegate=true; repositories=WEB-INF/classes/)
SharedSecrets.getJavaNetAccess()=java.net.URLClassLoader$7@720f6c
PlainTextActionReporterSUCCESSNo monitoring data to report.

回答1:

Glassfish standalone instance configuration may be used with Arquillian GlassFish Embedded containter adapter. You need to check security in your tests, so you must prepare your GlassFish instance configuration first. This can be achieved also by programmatic configuration (see https://stackoverflow.com/a/20411981/2169124), but for me configuration in test resources looks more natural. To configure users in file realm (used by default) you need to:

  1. Install standalone Glassfish server;
  2. Start Glassfish instance with asadmin command:

    $GLASSFISH_HOME/bin/asadmin start-domain
    
  3. Add users to file realm with asadmin command (stored in file named keyfile):

    $GLASSFISH_HOME/bin/asadmin create-file-user --user username
    
  4. Copy folders

    $GLASSFISH_HOME/glassfish/domains/domain1/config
    $GLASSFISH_HOME/glassfish/domains/domain1/docroot
    

    to test resources (for example src/test/resources/domain, assuming that you are using maven)

  5. In arquillian.xml define path to glassfish configuration (it will be copied to target/test-classes/domain by maven):

    <?xml version="1.0" encoding="UTF-8"?>
    <arquillian xmlns="http://jboss.org/schema/arquillian"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:schemaLocation="
        http://jboss.org/schema/arquillian
        http://jboss.org/schema/arquillian/arquillian_1_0.xsd">
    <container qualifier="glassfish-embedded" default="true">
        <configuration>
            <property name="instanceRoot">target/test-classes/domain</property>
        </configuration>
    </container>
    

  6. Map users to roles in glassfish-application.xml:

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE glassfish-application PUBLIC "-//GlassFish.org//DTD GlassFish Application Server 3.1 Java EE Application 6.0//EN" "http://glassfish.org/dtds/glassfish-application_6_0-1.dtd">
    <glassfish-application>
        <security-role-mapping>
            <role-name>admin</role-name>
            <principal-name>username</principal-name>
        </security-role-mapping>
    </glassfish-application>
    
  7. Add glassfish-application.xml to test artifact:

    ShrinkWrap.create(EnterpriseArchive.class)
            .addAsModule(ejbJar)
            .addAsManifestResource(new File("src/test/resources/glassfish-application.xml"))
    
  8. In test method use ProgrammaticLogin to handle authentication:

    ProgrammaticLogin programmaticLogin = new ProgrammaticLogin();
    programmaticLogin.login("username", "password");