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

Reply via email to