Last month I sent the following message, which details how I integrated the Tomcat and JBoss security systems. Scott Stark has written a new JBoss realm that work similar to mine. His new JBoss realm is available in CVS (I'm not sure where) and I think will be in the next release of JBoss. I have made some minor changes since I last posted the code. Dain Sundstrom ==================================================================== Recently, I have seen several posts asking how to integrate Tomcat and JBoss security. The current JBossRealm requires you to add users to both the tomcat and JBoss security systems or configure the tomcat JDBCRealm and JBoss DatabaseServerLoginModule to point to the same database table. This is all a big pain, so I wrote a new Tomcat interceptor which performs authentication and authorization via the JBoss JAAS code. The steps required to setup this interceptor follow. 1. Create the jar a. Copy the code (later in message) onto your machine. You can change the package if you like. b. Compile (requires servlet.jar webserver.jar jaas.jar jboss-jaas.jar jbosssx.jar) c. Jar it d. Copy it to jboss/lib/ext Here is the ant target I use. <target name="realm" depends="compile"> <delete file="${dist.home}/hypothermic-tomcat.jar" /> <jar jarfile="${dist.home}/hypothermic-tomcat.jar"> <fileset dir="${classes.home}" includes="com/hypothermic/security/*.class" /> </jar> <copy file="${dist.home}/hypothermic-tomcat.jar" todir="${jboss.lib}/ext" /> </target> 2. Secure your EJBs. a. ejb-jar.xml Mark your EJBs as protected. <assembly-descriptor> <method-permission> <role-name>user</role-name> <method> <ejb-name>YourBean</ejb-name> <method-name>*</method-name> </method> </method-permission> </assembly-descriptor> b. jboss.xml Set the authentication and authorization manager. <container-configurations> <container-configuration> <container-name>Standard CMP EntityBean</container-name> <role-mapping-manager>java:/jaas/other</role-mapping-manager> <authentication-module>java:/jaas/other</authentication-module> </container-configuration> </container-configurations> <enterprise-beans> <entity> <ejb-name>YourBean</ejb-name <container-name>Standard CMP EntityBean</container-name> </entity> </enterprise-beans> 3. Secure your WAR (web.xml) <security-constraint> <web-resource-collection> <web-resource-name>util</web-resource-name> <url-pattern>/protected/*</url-pattern> </web-resource-collection> <auth-constraint> <role-name>user</role-name> </auth-constraint> </security-constraint> <login-config> <auth-method>FORM</auth-method> <form-login-config> <form-login-page>/login.jsp</form-login-page> <form-error-page>/login.jsp</form-error-page> </form-login-config> </login-config> 4. Setup Tomcat a. add interceptor to server.xml immediately before the LoadOnStartupInterceptor <RequestInterceptor className="com.hypothermic.security.HypothermicRealm" /> You can also configure the interceptor here in the server.xml The following line turns off anonymous login. <RequestInterceptor className="com.hypothermic.security.HypothermicRealm" allowAnonymousLogin="false" /> b. Comment out all other security interceptors (SimpleRealm JbossRealm JDBCRealm). 5. Add your users to JBoss I hope I didn't leave out any steps. If you find any bugs or have any enhancements, please email me. -Dain Sundstrom ================================================================= package com.hypothermic.security; import org.apache.tomcat.core.Request; import org.apache.tomcat.core.Response; import org.apache.tomcat.core.Context; import org.apache.tomcat.util.SecurityTools; import org.apache.tomcat.core.BaseInterceptor; import org.jboss.security.SecurityAssociation; import org.jboss.security.SimplePrincipal; import org.jboss.security.auth.UsernamePasswordHandler; import javax.servlet.http.HttpSession; import javax.security.auth.Subject; import javax.security.auth.callback.CallbackHandler; import javax.security.auth.login.LoginContext; import javax.security.auth.login.LoginException; import java.security.Principal; import java.security.acl.Group; import java.util.Enumeration; import java.util.Iterator; import java.util.Set; import java.util.HashSet; import java.util.Hashtable; /** * Integrates Tomcat and Jboss security by redirecting Tomcat authentication and authorization * calls to the JBoss JAAS code. * @author Dain Sundstrom */ public class HypothermicRealm extends BaseInterceptor { private String subjectKey = "j_subject"; private String loginContextName = "other"; private boolean credentialsFromRequest = true; private boolean allowAnonymousLogin = true; private String anonymousUsername = "anonymous"; private String anonymousPassword = "anonymous"; /** * The key that is used to store the Subject in the session attributes. * @param subjectKey the key */ public void setSubjectKey(String subjectKey) { this.subjectKey = subjectKey; } /** * The name used by JAAS during Login for determining spi * @param loginContextName the name */ public void setLoginContextName(String loginContextName) { this.loginContextName = loginContextName; } /** * Should the request be checked for credentials. */ public void setCredentialsFromRequest(String credentialsFromRequest) { this.credentialsFromRequest = Boolean.valueOf(credentialsFromRequest).booleanValue(); } /** * Should all request be logged in anonymously */ public void setAllowAnonymousLogin(String allowAnonymousLogin) { this.allowAnonymousLogin = Boolean.valueOf(allowAnonymousLogin).booleanValue(); } /** * The username to use during anonymous login. */ public void setAnonymousUsername(String anonymousUsername) { this.anonymousUsername = anonymousUsername; } /** * The password to use during anonymous login. */ public void setAnonymousPassword(String anonymousPassword) { this.anonymousPassword = anonymousPassword; } /** * Authenticates user uning the JBoss JAAS code. * @param request the request * @param response the response */ public int authenticate(Request request, Response response){ HttpSession session = request.getSession(true); session.removeAttribute(subjectKey); // get the username and password Hashtable credentials = getCredentials(request); String username = (String)credentials.get("username"); String password = (String)credentials.get("password"); if(username != null && password != null) { try { // attempt to login via JAAS CallbackHandler handler = new UsernamePasswordHandler(username, password.toCharArray()); LoginContext loginContext = new LoginContext(loginContextName, handler); loginContext.login(); Subject subject = loginContext.getSubject(); if(subject != null) { // we are logged in // save the subject in the session session.setAttribute(subjectKey, subject); // set the remote user request.setRemoteUser(username); // set the auth method to way every was expected in the context... Context ctx = request.getContext(); if (ctx != null) { request.setAuthType(ctx.getAuthMethod()); } // Set the security association in JBoss SecurityAssociation.setPrincipal( new SimplePrincipal( username ) ); SecurityAssociation.setCredential( password.toCharArray() ); } } catch(LoginException e) { // Login Failed e.printStackTrace(); } } return 0; } /** * Determines if the user is a member of the requested roles. This authorization if * checked with the JBoss JAAS code. * @param request the request * @param response the response * @param roles the roles of which the user must belong. */ public int authorize( Request request, Response response, String roles[] ) { // if we are not authenticated, there is nothing to do. String user = request.getRemoteUser(); if(user==null) { return 401; } // if no roles are needed we are done if(roles==null || roles.length==0) { return 0; } // Get the Subject that was set during authentication. HttpSession session = request.getSession(true); Subject subject = (Subject)session.getAttribute(subjectKey); if(subject == null) { return 401; } // Get the roles to which this subject belongs. String userRoles[] = getRoles(subject); // Set the roles in the request. request.setUserRoles(userRoles); // Does this user belong to the proper roles? if(SecurityTools.haveRole(userRoles, roles)) { return 0; } // too bad not authorized return 401; } /** * Attempt to retrieve the user's credentials from the usual Tomcat * locations, and if that fails, attempt to get them directly from the request. * @param request the request */ protected Hashtable getCredentials(Request request) { Hashtable credentials; credentials = getCredentialsFromTomcat(request); if(credentials != null) { return credentials; } credentials = getCredentialsFromRequest(request); if(credentials != null) { return credentials; } credentials = getAnonymousCredentials(); if(credentials != null) { return credentials; } // too bad, return a valid hashtable with no entries return new Hashtable(); } protected Hashtable getCredentialsFromTomcat(Request request) { Hashtable credentials = new Hashtable(); SecurityTools.credentials(request, credentials); String username = (String)credentials.get("username"); String password = (String)credentials.get("password"); if(username != null && password != null) { System.out.println("Cool Got Credentials From Tomcat"); return credentials; } return null; } protected Hashtable getCredentialsFromRequest(Request request) { if(credentialsFromRequest) { String username = request.getParameter("j_username"); String password = request.getParameter("j_password"); if(username != null && password != null) { Hashtable credentials = new Hashtable(); credentials.put("username", username); credentials.put("password", password); HttpSession session = request.getSession(true); session.setAttribute( "j_username", username); session.setAttribute( "j_password", password); System.out.println("Cool Got Credentials >From Request"); return credentials; } } return null; } protected Hashtable getAnonymousCredentials() { if(allowAnonymousLogin) { if(anonymousUsername != null && anonymousPassword != null) { Hashtable credentials = new Hashtable(); credentials.put("username", anonymousUsername); credentials.put("password", anonymousPassword); System.out.println("Cool Got Anonymous Credentials"); return credentials; } } return null; } /** * Get the names of every role of which the subject is a member. * @param subject the subect */ protected String[] getRoles(Subject subject) { Set groups = subject.getPrincipals(Group.class); Iterator iterator = groups.iterator(); while(iterator.hasNext()) { Group group = (Group) iterator.next(); if("Roles".equals(group.getName())) { return getRoles(group); } } return new String[0]; } /** * Get the names of every group of which the group is a member. * @param group the group */ protected String[] getRoles(Group group) { Set roleSet = new HashSet(); getRoles(group, roleSet); // convert Set to String[]; String[] roles = new String[roleSet.size()]; roles = (String[])roleSet.toArray(roles); return roles; } /** * Adds the names of every group of which the group is a member to the set. * @param group the group * @param roleSet the set of group names */ protected void getRoles(Group group, Set roleSet) { Enumeration enum = group.members(); while(enum.hasMoreElements()) { Principal principal = (Principal)enum.nextElement(); if(principal instanceof Group) { getRoles((Group)principal, roleSet); } else { roleSet.add(principal.getName()); } } } } _______________________________________________ JBoss-user mailing list [EMAIL PROTECTED] http://lists.sourceforge.net/lists/listinfo/jboss-user