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