You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@tomcat.apache.org by Denis Cossutta <de...@gmail.com> on 2008/02/17 17:19:08 UTC

Interaction between Standalone Tomcat Web application and Jboss EJB application

I have the following situation (I try to simplify it):

   1. I have a standalone Apache Tomcat server (5.5.26), on which is
   running a web application:


   - A Welcome jsp page (Welcome.jsp) and 2 Servlets: CalculatorServlet
   and MyProtectedServlet
   - The CalculatorSevlet servlet has to access remotly a stateless
   session bean on a JBoss application server:

            Properties env = new Properties();
            env.put(Context.INITIAL_CONTEXT_FACTORY,"
org.jnp.interfaces.NamingContextFactory");
            env.put(Context.URL_PKG_PREFIXES, "org.jnp.interfaces");
            env.put(Context.PROVIDER_URL, "localhost:1099");
            Context c = new InitialContext(env);
            MyCalculatorRemote calculator = c.lookup
("MyCalculatorBean/remote");
            int result = calculator.sum(a, b);

   1. I have a standalone JBoss server (version 4.2.2), on which is
   running an EJB3 application


   - A Stateless session bean (MyCalculatorBean), which exposes a sum(nt
   a, int b) method through the remote interface:

         @Stateless
         @SecurityDomain("MyRealm")
         public class MyCalculatorBean implements MyCalculatorRemote {

                 @RolesAllowed("math")
                 public Integer sum(int a, int b) {
                           return a + b;
                  }
          }

   - The Session bean is defined under the jboss security domain called
   "MyRealm", which is defined in the jboss login-config.xml and in fact
   uses a MySql database for authentication and authorization:

             <application-policy name = "MyRealm">
                <authentication>
                    <login-module code = "
org.jboss.security.auth.spi.DatabaseServerLoginModule" flag = "required">
                         <module-option name = "debug">true</module-option>
                         <module-option name =
"dsJndiName">java:/MysqlDS</module-option>
                         <module-option name = "principalsQuery">SELECT
PASSWORD FROM USERS WHERE EMAIL=?</module-option>
                         <module-option name = "rolesQuery">SELECT ROLE,
'Roles' FROM ROLES WHERE EMAIL=?</module-option>
                   </login-module>
               </authentication>
            </application-policy>

   - The method sum(int a, int b) of the Session bean can be called only
   by authenticated users with "math" role:

                 @RolesAllowed("math")
                 public Integer sum(int a, int b) {
                           return a + b;
                  }

Since the Session bean is secured with jboss security mechanism, which is
based on JAAS, to access the bean I have to setup JAAS authentication on the
web application (Single sign on authentication):

   - I defined a JAASRealm in the Tomcat server.xml

         <Context path="/MyWebApplication" docBase="/MyWebApplication">

                  <Resource name="jdbc/MyDB" auth="Container" type="
javax.sql.DataSource"
                      maxActive="100" maxIdle="30" maxWait="10000"
                      username="root" password="admin" driverClassName="
org.gjt.mm.mysql.Driver"
                      url="jdbc:mysql://localhost/mydb?autoReconnect=true"/>


                 <Realm className="org.apache.catalina.realm.JAASRealm"
                     appName="MyRealm"
                     userClassNames="org.jboss.security.SimplePrincipal"

                     roleClassNames="org.jboss.security.SimpleGroup"
                     debug="99"/>

         </Context>

   - I defined a login.config file to be used by the JAASRealm; the file
   defines the login module to be used for jaas authentication and I define to
   use the JBoss DatabaseServerLoginModule (I imported the jboss security
   library into the tomcat common/lib folder):

                MyRealm{

org.jboss.security.auth.spi.DatabaseServerLoginModulesufficient
debug="true"
                      dsJndiName="java:comp/env/jdbc/MyDB"
                      principalsQuery="select password from users where
email=?"
                      rolesQuery="select role, 'Roles' from roles where
email=?";
                      };


   - I set up Tomcat to specify the location of the login.config file,
   changing the catalina.bat script:

             set JAVA_OPTS=%JAVA_OPTS% -
Djava.security.auth.login.config==%CATALINA_HOME%/conf/login.config

   - I set up the web.xml of my web application to define the login
   configuration and the security constrains like follows:

<security-constraint>
        <display-name>Constraint</display-name>
        <web-resource-collection>
            <web-resource-name>Proteced Servlet</web-resource-name>
            <description/>
            <url-pattern>/MyProtectedServlet</url-pattern>
            <http-method>GET</http-method>
            <http-method>POST</http-method>
            <http-method>HEAD</http-method>
            <http-method>PUT</http-method>
            <http-method>OPTIONS</http-method>
            <http-method>TRACE</http-method>
            <http-method>DELETE</http-method>
        </web-resource-collection>
        <auth-constraint>
            <description>Auth</description>
            <role-name>math</role-name>
        </auth-constraint>
        </security-constraint>
    <login-config>
        <auth-method>FORM</auth-method>
        <realm-name>MyRealm</realm-name>
        <form-login-config>
            <form-login-page>/login.jsp</form-login-page>
            <form-error-page>/error.jsp</form-error-page>
            </form-login-config>
        </login-config>
    <security-role>
        <description>Math role</description>
        <role-name>math</role-name>
    </security-role>

   - I defined finally the login.jsp page as required for jaas
   authentication:

<html>
    <head>
    <title>Login Page</title>
    <form action='j_security_check' name="loginForm" method="POST">
    <table border="0" cellspacing="5">
    <tr>
        <th align="right">Username:</th>
        <td align="left"><input type="text" name="j_username"
id="username"></td>
    </tr>
    <tr>
        <th align="right">Password:</th>
        <td align="left"><input type="password" name="j_password"
id="password"></td>
    </tr>
    <tr>
        <td align="right"><input type="submit" value="Log In"></td>
        <td align="left"><input type="reset"></td>
    </tr>
    </table>
    </form>
</html>

Now, the flow is the following one:

   - I acces the web application root
   (http:\\localhost:8081\MyWebApplicaiton) through the web browser and it
   displays the Welcom page (Welcome.jsp)
   - I click on a link on the Welcome page to the MyProtectedServlet
   - Since the MyProtectedServlet is a protected resource I'm redirected
   to the login page
   - I enter my credentials in the login page form and submit
   - the browser displays the MyProtectedServlet which has a link to the
   MyServlet servelt
   - Clicking on the link, I'm redirect to MyServlet, which calls the
   remote session bean (passing automatically the Principal of the logged in
   user, which is supposed to be stored in the HttpServletRequest) and the
   result of the call is displayed on the page

Unfortunatelly I have to following issues trying to accomplish this process:

   1. When submitting my credentials through the login page, I'm
   authenticated correctly (I'm not rediredted to the error.jsp page) but
   I receive a standard http error message saying that I'm not allowed to
   access the MyProtectedServlet (access denied): i'm sure that the
   authentication goes well, since the Princiapl is stored in the context and I
   also tried to debug the DatabaseServerLoginModule and I saw that the right
   role ("math") is retrieved and returned; the problem is that the role is not
   stored in the context, since if I try, after the authentication, to call the
   isUserInRole("math") method, it returns false
   2. I tried to access directly the MyServlet servlet after the
   authentication (i.e. firstly I try to access the MyProtectedServlet,
   than I get the login page, than I submit the credentials, than I get the
   Access denied Http message, and finally I access directly the MyServlet
   servlet ). Doing some debugging I discovered that just before calling the
   remote session bean method, the principal of the logged in user is stored in
   the HTTPServletRequest. But when it performes the remote call I get an
   EJBAccessException saying "No matching username found in principals" and I
   discovered the reason of this problem is that on JBoss side the Principal
   name (username) is null. This means that the Principal is not passed to
   JBoss context through the request
   3. I wanted to investigate more on this aspect and I tried to access
   the remote session bean as the web application was a standalone java
   application, putting programmatically the principal and the credentials int
   the lookup context, but I have always the same error message
   (EJBAccessException saying "No matching username found in principals", on
   JBoss side the Principal name (username) is null):

            Properties env = new Properties();
            env.put(Context.INITIAL_CONTEXT_FACTORY,"
org.jnp.interfaces.NamingContextFactory");
            env.put(Context.URL_PKG_PREFIXES, "org.jnp.interfaces");
            env.put(Context.PROVIDER_URL, "localhost:1099");
            env.put(Context.SECURITY_PRINCIPAL, "denis.cossutta@my.it");
            env.put(Context.SECURITY_CREDENTIALS, "250494");

            Context c = new InitialContext(env);
            MyCalculatorRemote calculator = c.lookup
("MyCalculatorBean/remote");
            int result = calculator.sum(2, 3);

Has anyone of you any idea of why I have this problems and how to solve them
because I'm really blocked. Thank you in advice for any suggestion