4

My environment is Jboss AS 7.1.0. I am using JUnit and Arquillian for unit testing. I have SSBs that use getUserPrincipal(), and isCallerInRole() methods in my ejbs. In order to unit test these ejb methods, I have to simulate log-in from the unit test case and then call the ejb.

Here is an example of EJB method that I am trying to test:

@RolesAllowed({"user","admin"})
public User getMyUserDetails() throws BadInputDataException {
    String userName = ctx.getCallerPrincipal().getName();
    return findUser(userName);
}

How do I write a JUnit test case to test this method? I appreciate your help in advance.

Updates on 07/19 (based on Tair's solution below):

My security domain configuration is as under:

<security-domains>
    <security-domain name="other" cache-type="default">
         <authentication>
             <login-module code="Remoting" flag="optional">
                 <module-option name="password-stacking" value="useFirstPass"/>
             </login-module>
             <login-module code="Database" flag="required">
                 <module-option name="dsJndiName" value="java:jboss/datasources/MysqlDS"/>
                 <module-option name="principalsQuery" value="select Password from Principals where PrincipalID=?"/>
                 <module-option name="rolesQuery" value="select Role, RoleGroup from Roles where PrincipalID=?"/>
                 <module-option name="password-stacking" value="useFirstPass"/>
                 <module-option name="hashAlgorithm" value="MD5"/>
                 <module-option name="hashEncoding" value="RFC2617"/>
                 <module-option name="hashUserPassword" value="false"/>
                 <module-option name="hashStorePassword" value="true"/>
                 <module-option name="passwordIsA1Hash" value="true"/>
                 <module-option name="storeDigestCallback" value="org.jboss.security.auth.callback.RFC2617Digest"/>
             </login-module>
         </authentication>
     </security-domain>

I changed the JBossLoginConfigFactory shown in Tair's solution below to use org.jboss.security.auth.spi.DatabaseServerLoginModule.

I have changed the JBossLoginConfigFactory to use the following method for DatabaseServerLoginModule.

private AppConfigurationEntry createDatabaseModuleConfigEntry() {
    Map<String, String> options = new HashMap<String, String>();
    options.put("dsJndiName", "java:jboss/datasources/MysqlDS");
    options.put("hashAlgorithm", "MD5");
    options.put("hashEncoding", "RFC2617");
    options.put("hashUserPassword", "false");
    options.put("hashStorePassword", "true");
    options.put("passwordIsA1Hash", "true");
    options.put("storeDigestCallback", "org.jboss.security.auth.callback.RFC2617Digest");
    options.put("principalsQuery", "select Password from Principals where PrincipalID=?");
    options.put("rolesQuery", "select Role, RoleGroup from Roles where PrincipalID=?");

    return new AppConfigurationEntry("org.jboss.security.auth.spi.DatabaseServerLoginModule",
                AppConfigurationEntry.LoginModuleControlFlag.REQUIRED, options);
}

and I am invoking this method instead of createUsersRolesLoginModuleConfigEntry(). The loginContext.login() in the test case now fails due to:

Caused by: java.io.WriteAbortedException: writing aborted; java.io.NotSerializableException: org.jboss.security.auth.callback.MapCallback

Not sure what I should change now!

Update 07/20/2012: Complete solution to the issue is below. If your solution does not require DatabaseServerLoginModule, just refer the solution in Tair's reply and that is good enough.

In my case I have database as the JaaS authentication and also digest authentication. Hence I had to make the following code changes to the above example.

  1. I have modified the code (JBossLoginContextFactory) to support "org.jboss.security.auth.spi.DatabaseServerLoginModule" as shown below. I am calling this method instead of createUsersRolesLoginModuleConfigEntry() while creating AppConfigurationEntry[].

    private AppConfigurationEntry createDatabaseModuleConfigEntry() { Map options = new HashMap(); options.put("dsJndiName", "java:jboss/datasources/MysqlDS"); options.put("principalsQuery", "select Password from Principals where PrincipalID=?"); options.put("rolesQuery", "select Role, RoleGroup from Roles where PrincipalID=?"); return new AppConfigurationEntry("org.jboss.security.auth.spi.DatabaseServerLoginModule", AppConfigurationEntry.LoginModuleControlFlag.REQUIRED, options); }

  2. As I am using digest authentication, my password is encrypted in the database. So while passing the password from my test case, I am encrypting and passing the password as shown below. LoginContext loginContext = JBossLoginContextFactory.createLoginContext("username", md5Hex("my_username"+":"+PropertyManager.getProp("realm")+":"+"my_password"));

Now the log-in is successful !!

cheb1k4
  • 2,316
  • 7
  • 26
  • 39
Veer Muchandi
  • 267
  • 5
  • 16

1 Answers1

1

Your case is covered in this example. Basically it boils down to:

  1. Use arquillianContext to build a Context with pre-set values for Context.SECURITY_PRINCIPAL and Context.SECURITY_CREDENTIALS
  2. Use that context to obtain reference to you EJB
  3. Test it.

Good luck!

UPDATE: looks like much have changed in Arquillian since then, luckily we have another solution. I tested it and confirm that it works!

Tair
  • 3,779
  • 2
  • 20
  • 33
  • Hello Tair, Thanks for the reply. I tried this before. But I am still stuck because ArquillianContext does not work in the above example. Have you tried this in the past? If so, can you please let me know where to get ArquillianContext from? Please see the thread below: https://community.jboss.org/message/748206#748206. There are other suggestions for the getting the context, but those suggestions are not clear on how to use the context. I appreciate your help. – Veer Muchandi Jul 16 '12 at 11:41
  • Thanks Tair. This looks promising. I am using Database Login Module for JaaS login and this code is expecting UserRolesLoginModule. I am trying to figure out what to change in the JBossLoginContextFactory to get the database login module working. Would you know what I should be changing here? – Veer Muchandi Jul 19 '12 at 03:40
  • Tair, Added more updates. Please see the updates on 7/19 above to understand the issue. I am currently stuck with an exception java.io.NotSerializableException: org.jboss.security.auth.callback.MapCallback Any suggestions will be of great help!! – Veer Muchandi Jul 19 '12 at 05:04
  • You will have to use http://docs.redhat.com/docs/en-US/JBoss_Enterprise_Application_Platform/6/html-single/Javadocs/files/javadoc/index.html?org/jboss/security/auth/spi/DatabaseServerLoginModule.html instead of org.jboss.security.auth.spi.UsersRolesLoginModule – Tair Jul 19 '12 at 05:17
  • Hi Tair, Firstly, thanks a lot for helping me out here. If you see my updates last night, I have changed the code in the JBossLoginConfigFactory to use org.jboss.security.auth.spi.DatabaseServerLoginModule. So I am already using the databaseserver login module. Also for the same reason, I have to pass the datasource name, and other params as options. Also I am using digest authentication - hence the other params. If I don't pass the parameters (for digest) I get incorrect password as error. With digest auth params, I am getting the NotSerializable error shown above. – Veer Muchandi Jul 19 '12 at 12:37
  • Ok, Veer, looks like I answered the original question :) Now the question is 'How to properly use DatabaseServerLoginModule', in which unfortunately, I have no experience. – Tair Jul 19 '12 at 16:00
  • Thanks Tair. The DatabaseServerLoginModule works fine. I think the issue is with the digest authentication settings. If I remove the digest authentication params, it complains about incorrect password. That means the database connection works. If I keep the digest authentication params, it is giving the above exception.Thanks for your help!! – Veer Muchandi Jul 19 '12 at 20:22