What am I doing wrong? Please help.
minmay Nov 15, 2004 12:12 PMHere is the scenario. I have a custom jaas login module that my web app and EJBs use. A user performs a login. The webpage calls an EJB to do something. It seems as though the web application authenticates and authorisizes properly, however, the EJB seems to fail in the same process. Am I doing something wrong with security?
Here is my error message and login module:
2004-11-12 12:28:36,613 ERROR [org.jboss.ejb.plugins.SecurityInterceptor] Authentication exception, principal=villalobosm
2004-11-12 12:28:36,613 ERROR [org.jboss.ejb.plugins.LogInterceptor] EJBException in method: public abstract kineteque.myapp.ejb.session.scriptaudit.ScriptAuditSystem kineteque.myapp.ejb.session.scriptaudit.ScriptAuditSystemHome.create() throws java.rmi.RemoteException,javax.ejb.CreateException, causedBy:
java.lang.SecurityException: Authentication exception, principal=villalobosm
at org.jboss.ejb.plugins.SecurityInterceptor.checkSecurityAssociation(SecurityInterceptor.java:173)
package kineteque.myapp.jaas;
import org.jboss.security.SimpleGroup;
import org.jboss.security.auth.spi.AbstractServerLoginModule;
import javax.security.auth.Subject;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.NameCallback;
import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.UnsupportedCallbackException;
import javax.security.auth.login.FailedLoginException;
import javax.security.auth.login.LoginException;
import java.io.IOException;
import java.security.Principal;
import java.security.acl.Group;
import java.util.Map;
import kineteque.myapp.JNDINames;
/**
* When subclassing the AbstractServerLoginModule implement the following:
*
* void initialize(Subject, CallbackHandler, Map, Map) if you have custom options to parse.
* boolean login() to perform the authentication activity.
* Principal getIdentity() to return the Principal object for the user authenticated by the log() step.
* Group[] getRoleSets() to return at least a Group named Roles that contains the roles assigned to the Principal authenticated during login(). A second common group is CallerPrincipal; it provides, if necessary, the user's application identity rather than the security domain identity.
*
*/
public class MyAppLoginModule extends AbstractServerLoginModule
{
/** The roles that the principal belongs too. */
private Group roles = null;
/** The principal that was authenticated. */
private Principal identity = null;
/** Standard fail message */
private static final String STANDARD_FAIL_AUTH_MESSAGE = "Not Authorized.";
/**
* Initialize the login module. This stores the subject, callbackHandler
* and sharedState, and options for the login session. Subclasses should override
* if they need to process their own options. A call to super.initialize(...)
* must be made in the case of an override.
* @param subject the Subject to update after a successful login.
* @param callbackHandler the CallbackHandler that will be used to obtain the
* the user identity and credentials.
* @param sharedState a Map shared between all configured login module instances
* @param options option password-stacking: if true, the login identity will be taken from the
* javax.security.auth.login.name value of the sharedState map, and
* the proof of identity from the javax.security.auth.login.password
* value of the sharedState map.
*/
public void initialize(Subject subject,
CallbackHandler callbackHandler, Map sharedState, Map options)
{
//jboss documentation states that this should be
//the first line of this method.
super.initialize(subject,callbackHandler,sharedState,options);
}
/**
* Looks for javax.security.auth.login.name and javax.security.auth.login.password
* values in the sharedState map if the useFirstPass option was true and returns
* true if they exist. If they do not or are null, this method returns false.
* Subclasses should override to perform the required credential validation steps.
* @return
* @throws LoginException
*/
public boolean login() throws LoginException
{
if (callbackHandler==null)
throw new LoginException("No Callback handler available.");
//initialize a callback for the username and password
NameCallback ncb = new NameCallback("Username: ");
PasswordCallback pcb = new PasswordCallback("Password: ",false);
Callback[] cb = {ncb,pcb};
try
{
//get the username and password
callbackHandler.handle(cb);
//get the username
String name = ncb.getName();
identity = createIdentity(name);
try
{
//validate the username and password pair
AuthenticateCmd authenticate = new AuthenticateCmd();
if (!authenticate.execute(identity.getName(),pcb.getPassword()))
throw new FailedLoginException(STANDARD_FAIL_AUTH_MESSAGE);
}
finally
{
pcb.clearPassword();
}
}
catch (IOException e)
{
throw new LoginException("Failed to handle callback.");
}
catch (UnsupportedCallbackException e)
{
throw new LoginException("Failed to handle callback.");
}
catch (Exception e)
{
throw new FailedLoginException(STANDARD_FAIL_AUTH_MESSAGE);
}
loginOk = true;
return true;
}
/**
* Retrieve the users primary identity.
* @return The users primary identiy.
*/
protected Principal getIdentity()
{
return identity;
}
/**
* Overridden by subclasses to return the Groups that correspond
* to the role sets assigned to the user. Subclasses should create at
* least a Group named "Roles" that contains the roles assigned to the user.
* A second common group is "CallerPrincipal," which provides the application
* identity of the user rather than the security domain identity.
* @return Group[] containing the sets of roles
*/
protected Group[] getRoleSets() throws LoginException
{
Group[] value = null;
try
{
if (roles==null)
{
roles = new SimpleGroup("Roles");
AuthorizeCmd authorize = null;
try
{
String datasource = JNDINames.DATASOURCE;
authorize = new AuthorizeCmd();
}
catch(Error e)
{
e.printStackTrace();
}
catch(RuntimeException e)
{
e.printStackTrace();
}
authorize.setUsername(identity.getName());
authorize.execute();
RoleDTO roleDTO = null;
Principal p = null;
while(authorize.hasNext())
{
roleDTO = (RoleDTO)authorize.next();
p = createIdentity(roleDTO.getRole());
roles.addMember(p);
}
value = new Group[]{roles};
}
}
catch (Exception e)
{
throw new LoginException("Cannot create roles.");
}
return value;
}
}
Here are my configuration files:
login-config.xml:
<application-policy name="kineteque-security" >
<login-module code="kineteque.myapp.jaas.MyAppLoginModule" flag="required" />
</application-policy>
web.xml:
<web-app
xmlns="http://java.sun.com/xml/ns/j2ee"
version="2.4"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<security-role>
<role-name>Administrator</role-name>
</security-role>
<security-role>
<role-name>IT_Operator</role-name>
</security-role>
<security-role>
<role-name>Auditor</role-name>
</security-role>
<ejb-ref>
<ejb-ref-name>ejb/ScriptAuditSystemEJB</ejb-ref-name>
<ejb-ref-type>Session</ejb-ref-type>
kineteque.myapp.ejb.session.scriptaudit.ScriptAuditSystemHome
kineteque.myapp.ejb.session.scriptaudit.ScriptAuditSystem
</ejb-ref>
</web-app>
ejb-jar.xml:
<ejb-jar
xmlns="http://java.sun.com/xml/ns/j2ee"
version="2.1"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/ejb-jar_2_1.xsd">
<enterprise-beans>
<ejb-name>ScriptAuditSystemEJB</ejb-name>
kineteque.myapp.ejb.session.scriptaudit.ScriptAuditSystemHome
kineteque.myapp.ejb.session.scriptaudit.ScriptAuditSystem
<ejb-class>kineteque.myapp.ejb.session.scriptaudit.ScriptAuditSystemBean</ejb-class>
<session-type>Stateless</session-type>
<transaction-type>Container</transaction-type>
<resource-ref>
MyDS JDBC reference
<res-ref-name>jdbc/MyDS</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
<security-identity>
<use-caller-identity/>
</security-identity>
</enterprise-beans>
<assembly-descriptor>
<security-role>
<role-name>Administrator</role-name>
</security-role>
<security-role>
<role-name>IT_Operator</role-name>
</security-role>
<security-role>
<role-name>Auditor</role-name>
</security-role>
<method-permission>
<role-name>Administrator</role-name>
<ejb-name>ScriptAuditSystemEJB</ejb-name>
<method-name>*</method-name>
</method-permission>
<method-permission>
<role-name>IT_Operator</role-name>
<ejb-name>ScriptAuditSystemEJB</ejb-name>
<method-name>*</method-name>
</method-permission>
<method-permission>
<role-name>Auditor</role-name>
<ejb-name>ScriptAuditSystemEJB</ejb-name>
<method-name>*</method-name>
</method-permission>
<container-transaction>
Transaction attributes for 'ScriptAuditSystemEJB' methods
<ejb-name>ScriptAuditSystemEJB</ejb-name>
<method-name>*</method-name>
<trans-attribute>Required</trans-attribute>
</container-transaction>
</assembly-descriptor>
</ejb-jar>
jboss-app.xml:
<jboss-app>
<security-domain>java:/jaas/kineteque-security</security-domain>
</jboss-app>
jboss-web.xml:
<jboss-web>
<security-domain>java:/jaas/kineteque-security</security-domain>
<resource-ref>
<res-ref-name>jdbc/MyDS/res-ref-name>
<jndi-name>java:/MyDS</jndi-name>
</resource-ref>
<ejb-ref-name>ejb/ScriptAuditSystemEJB</ejb-ref-name>
<jndi-name>ScriptAuditSystemEJB</jndi-name>
</ejb-ref>
</jboss-web>
application.xml:
<application
xmlns="http://java.sun.com/xml/ns/j2ee"
version="1.4"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/application_1_4.xsd">
MyApp
<display-name>MyApp</display-name>
myapp-ejb.jar
<web-uri>MyApp.war</web-uri>
<context-root>myapp</context-root>
<security-role>
<role-name>Administrator</role-name>
</security-role>
<security-role>
<role-name>IT_Operator</role-name>
</security-role>
<security-role>
<role-name>Auditor</role-name>
</security-role>
jboss.xml:
<!DOCTYPE jboss PUBLIC
"-//JBoss//DTD JBOSS 4.0//EN"
"http://www.jboss.org/j2ee/dtd/jboss_4_0.dtd">
<security-domain>java:/jaas/infonet-security</security-domain>
<enterprise-beans>
<ejb-name>ScriptAuditSystemEJB</ejb-name>
<jndi-name>ScriptAuditSystemEJB</jndi-name>
<resource-ref>
<res-ref-name>jdbc/AppEvents</res-ref-name>
<jndi-name>java:/AppEvents</jndi-name>
</resource-ref>
</enterprise-beans>