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.
<!-- Define two security roles -->
<description>customer service employees</description>
<!-- Restrict access to all files in the /admin folder -->
<!-- Authorize the programmer and service roles -->
<!-- Use form-based authentication specifying the login and error forms -->
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<title>Murach's Java Servlets and JSP</title>
<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>
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.
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.
An IDE is no substitute for an Intelligent Developer.
Joined: Mar 31, 2012
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.
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.
Joined: Mar 31, 2012
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
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.