This week's book giveaway is in the Servlets forum.
We're giving away four copies of Murach's Java Servlets and JSP and have Joel Murach on-line!
See this thread for details.
The moose likes Tomcat and the fly likes Not getting <form-error-page> using <auth-method>FORM</auth-method> Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login


Win a copy of Murach's Java Servlets and JSP this week in the Servlets forum!
JavaRanch » Java Forums » Products » Tomcat
Bookmark "Not getting <form-error-page> using <auth-method>FORM</auth-method>" Watch "Not getting <form-error-page> using <auth-method>FORM</auth-method>" New topic
Author

Not getting <form-error-page> using <auth-method>FORM</auth-method>

Mike Tabak
Ranch Hand

Joined: Mar 31, 2012
Posts: 40
Hi all,

I am testing form authentification with a very simple app that just prints out a message if you authenticate. I am using MySQL as a database Realm. I define 2 user roles in my web.xml file and authorize them for access. When I run with the 2 roles in the web.xml file, all works fine. If I enter a bad username or password I get my <form-error-page> as expected. However, if I try to remove (comment out) one of the roles from web.xml, then try to use that role to login, instead of my <form-error-page> I get a Tomcat HTTP status 403 page, which is an access error, but I then navigate back to the login page and enter a valid credential, it too is rejected with the same Tomcat error page.

Here is my application context.xml file:

<?xml version="1.0" encoding="UTF-8"?>
<Context path="/ch17admin">

<!-- The following specifies a JDBC Realm connecting to the murach
database using the root and admin login. Then it uses the murach
database columns from the UserPass and UserRole tables -->

<Realm className="org.apache.catalina.realm.JDBCRealm" debug="99"
driverName="com.mysql.jdbc.Driver"
connectionURL="jdbc:mysql://localhost:3306/murach"
connectionName="root" connectionPassword="sesame"
userTable="UserPass" userNameCol="Username" userCredCol="Password"
userRoleTable="UserRole" roleNameCol="Rolename" />

</Context>

Here is my application web.xml file:

<?xml version="1.0" encoding="UTF-8"?>

<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5">

<!-- Define two security roles -->
<security-role>
<description>customer service employees</description>
<role-name>service</role-name>
</security-role>
<security-role>
<description>system administrator</description>
<role-name>programmer</role-name>
</security-role>

<!-- Restrict access to all files in the /admin folder -->
<security-constraint>
<web-resource-collection>
<web-resource-name>Protected Area</web-resource-name>
<url-pattern>/admin/*</url-pattern>
</web-resource-collection>
<!-- Authorize the programmer and service roles -->
<auth-constraint>
<role-name>service</role-name>
<!--<role-name>programmer</role-name> -->
</auth-constraint>
</security-constraint>

<!-- Use form-based authentication specifying the login and error forms -->
<login-config>
<auth-method>FORM</auth-method>
<form-login-config>
<form-login-page>/admin/login.html</form-login-page>
<form-error-page>/admin/login_error.html</form-error-page>
</form-login-config>
</login-config>

<!-- Use basic authentication -->
<!--
<login-config>
<auth-method>BASIC</auth-method>
<realm-name>Admin Login</realm-name>
</login-config>
-->
<session-config>
<session-timeout>30</session-timeout>
</session-config>

<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>

My login.html file:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>Murach's Java Servlets and JSP</title>
</head>

<body>
<h1>Admin Login Form</h1>
<p>Please enter your username and password to continue.</p>
<table cellspacing="5" border="0">
<form action="j_security_check" method="get">
<tr>
<td align="right">Username</td>
<td><input type="text" name="j_username"></td>
</tr>
<tr>
<td align="right">Password</td>
<td><input type="password" name="j_password"></td>
</tr>
<tr>
<td><input type="submit" value="Login"></td>
</tr>
</form>
</table>
</body>
</html>

My login_error.html file:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">

<html>
<head>
<title>Murach's Java Servlets and JSP</title>
</head>

<body>

<h1>Admin Login Form - Error</h1>
<p>You did not log in successfully.</p>
<p>Please check your username and password and try again.</p>
<p>If that doesn't work, you may need to <br>
implement the JDBC realm as described in chapter 17.</p>

<table cellspacing="5" border="0">
<form action="j_security_check" method="get">
<tr>
<td align="right">Username</td>
<td><input type="text" name="j_username"></td>
</tr>
<tr>
<td align="right">Password</td>
<td><input type="password" name="j_password"></td>
</tr>
<tr>
<td><input type="submit" value="Login"></td>
</tr>
</form>
</table>
</body>
</html>

As I said, when both roles are in the web.xml file and I enter a bad credential, I get my login_error.html file, but if I remove a role from the web.xml, say "programmer", and then try to log in with it I get a Tomcat HTTP status 403 page.

Anyone know the issue?
Thanks in advance
Mike

Tim Holloway
Saloon Keeper

Joined: Jun 25, 2001
Posts: 15950
    
  19

I'm not clear on what you are trying to do.

Roles are not something that are dynamically added or removed from the security system, so normally what you're describing isn't a problem.

I did get the impression that maybe you think that user's only have one role each, and that is not true. Each user can have zero or more roles defined for him/her/it/that/whatever.


Customer surveys are for companies who didn't pay proper attention to begin with.
Mike Tabak
Ranch Hand

Joined: Mar 31, 2012
Posts: 40
I know users can have more than one role. What I am saying is when I remove the programmer role from the web.xml file so it is no longer authorized to access the resources in /admin/ I would expect that the html page defined in the <form-error-page> tag would be displayed, but it is not. I get the Tomcat 403 page. If I leave the programmer role in, but use a bad password then I do get the html page defined in the <form-error-page> tag. I don't know why removing the programmer role from the web.xml and then trying to log in using that role does not also give the html page defined by the <form-error-page> tag.

Thanks
Mike
Tim Holloway
Saloon Keeper

Joined: Jun 25, 2001
Posts: 15950
    
  19

OK. Have patience, I'm working my way backwards here, because I'm still trying to map your terminology to mine. Specifically, "remove a role".

You do 2 primary role-related things in web.xml:

1. Define a role name (security-role elements)

2. Map a role or roles to one or more URL patterns.

If you define a role and don't map it, it doesn't really matter, but properly speaking, if you map a role and didn't define it, Tomcat should refuse to deploy the webapp because referenced information (the role) was not defined.

The WEB-INF/web.xml file is technically referred to as the "container-independent Deployment Descriptor". It pairs with the container-dependent Deployment Descriptor, which, for tomcat, is the webapp's Context definition. This DD is read as part of the process of deploying a webapp, digested, and used to build the webapp's run environment. In Tomcat, if you have the right settings, Tomcat may scan the WAR, detect changes in the web.xml, undeploy the current instance and deploy a new instance (which includes digesting the updated web.xml), but the process is a little "iffy", since there may be lint left over from the previous instance, not to mention work in progress. So only do hot updates if you're feeling brave. Otherwise use a control interface to stop the webapp, redeploy, and restart. Or restart Tomcat itself, which is the same net effect.

On a related matter, removing a user from a given role will not take effect immediately. The user's role set is captured when the user logs in and not updated for the duration of the session, regardless of changes to the backing store. This is partly because changing security rules while someone is in the middle of a secured operation could have unforeseen (and possibly unpleasant) side effects. So the user has to log out and back in again before the role changes are seen.
Mike Tabak
Ranch Hand

Joined: Mar 31, 2012
Posts: 40
Thanks for the reply, don't mean to sound impatient, just trying to get across what I'm doing. I am defining a security role, as you can see, and I am mapping it to a URL pattern. When I 'remove' the role, I tried two things (both in the web.xml file), first I just removed the mapping to the URL: the <role-name>programmer</role-name> line under the <security-role> tag. That should have disabled the programmer role from logging in, which it did, but I no longer go the login_error.html page described with the <form-error-page>/admin/login_error.html</form-error-page> line under the <login-config> tag. I get Tomcat's 403 resource restricted page.
I then removed the definition of the role: the <role-name>programmer</role-name> under the <security-role> tag. I got the same results. Each time I made a change I stopped and re-started Tomcat. According to the book I am using (Murach's Java Servlets and JSPs, 2nd Ed.) if I remove the programmer role, I should get the <form-error-page>/admin/login_error.html</form-error-page> just as if I entered a bad password for this role, but this is not happening.


Hope that better conveys what I'm doing
Thanks
Mike
Tim Holloway
Saloon Keeper

Joined: Jun 25, 2001
Posts: 15950
    
  19

OK. I think I understand better.

You cannot disable a user login just by removing a role from that user's identity. Like I said earlier, a user can have zero or more roles. There's no formal "disable user" in J2EE - they can either login or they cannot. They can login as long as the Realm will return a confirmation on an authenticate request (made by the login processor). That's normally a simple match on userid/password, but more ambitious authenticators can add match on "account enabled" as long as they have some sort of internal arrangement on what enables an account.

If you remove a user from role "programmer", then URLs that require role "programmer" will be rejected, whether or not a login was forced, since the login (authentication) process is completely transparent to the downstream functions such as authorization (role-checking) and application logic. By the time the authorization is done, authentication is guaranteed and the users roles are all known.

Or perhaps it's better if I put it another way. You cannot forbid a login based on role. Role only controls what you're authorized to do after login. The container login is triggered not by which URL you are accessing, but by whether or not the URL is role-protected at all. If there are no roles, it's a public resource and no login is needed. If not, and the user isn't already logged in, a login is forced. This prevents the too-common exploit where people bypass login URLs and jump directly to the stuff behind the wall.
Mike Partridge
Greenhorn

Joined: Dec 10, 2012
Posts: 1
@Mike Tabak - I'm trying to do the same thing; did you find a way to replace Tomcat's 403 error page when an authenticated user isn't authorized for a constrained URL?
 
I agree. Here's the link: http://aspose.com/file-tools
 
subject: Not getting <form-error-page> using <auth-method>FORM</auth-method>
 
Similar Threads
Login Exception when using JDBC Realm (Glassfish V3.1 + IceFaces 2 + MySQL)
one html is not getting constrained
security constraints - login doesnt work
Extremely slow initial servlet access
how to redirect to success page in tomcat using its lapd configuration