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.
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); }
- 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 !!