Tim Holloway wrote:There are 3 kinds of "paths".
2. Resource paths. Resource paths are relative to the root of a deployed WAR. For example, "/WEB-INF/classes/com/javaranch/Saloon.class" or "/images/moose.jpg". Oficially, a WAR is always in JAR (ZIP) format, so once again, this isn't, strictly speaking, a filesystem path, it's a directory path within the ZIP file. However, Tomcat also supports "exploded" (unzipped) WARs, in which case the directories and files in the WAR really are directories and files. However, Tomcat resolves resource paths the same way, regardless of whether the WAR was exploded or not. The default servlet uses a resource path extracted from the incoming URL. Note that the correct syntax for a webapp resource path is in absolute form (begins with "/"), although for resources, "/" means the root of the WAR, not the root of the server's filesystem.
3. Filesystem paths. Tomcat, like almost all other webapp servers, cannot directly serve up filesystem-path objects. Tomcat is a WEB server, not a FILE server. Plus, putting all or part of the server filesystem out on the open Internet where just anybody could access it would be a grave security risk. However, J2EE webapps can be configured to take a URL and convert it to a (absolute) filesystem path, then do something with what it finds there. For example, I could create a servlet called "CopyImageServlet", tell it that /var/lib/mywebapp/images" holds the image files and use it as an image upload/download directory, with the CopyImageServlet doing the work of copying data to/from that directory. Note:Never upload anything into a WAR. Always upload into a directory that's external to both Tomcat and the deployed webapps!
The absolute filesystem paths for WAR resources depends on how the appserver was configured. That is why it's better to use resource paths to resolve resources that are part of the deployed WAR itself, and externally-defined absolute filesystem paths for resources that are not part of the deployed WAR. Relative filesystem paths should be avoided.
Tim Holloway wrote:There's something odd here, but it's impossible to tell what it is. Check your Realm configuration and make sure that the login form isn't requesting secured resources or recursive resources.
Tim Holloway wrote:Probably you should set up your web.xml security rules so that the login/loginfail JSPs don't match any of the secured URLs. I think you're getting a infinite recursion on login. That is, in order to get to the login page, you have to be logged in, so it fetched the login page, but to access it you have to be logged in, and round and around and around!
Tim Holloway wrote:I'm not sure. However, I think your "page" JSP directive needs to be at the top. For one thing, content-type is an HTML header, and it usually causes an invalidstateexception when you try and set a header after you've already sent content.
Tim Holloway wrote:OK.
The login page fails because the "action" isn't supposed to be an encoded URL. It should just be simply "j_security_check".
The loginfail page should have a login form, just like the login page, not a link or form action on it. In fact, I usually just clone my loginpage and put a "Login failed, please login" message on it. If you actually put an explicit navigation directive there, you'll effectively be abandoning the login process and you'll lose your original URL request.
Tim Holloway wrote:You have the right idea. Technically, you don't "have to force a log in", though, since when the user requests a protected URL, the webapp server will do the forcing without any action on your part. That's what makes it extra-secure. Do-it-Yourself security systems usually forget to force a login - especially after a few maintenance cycles, but the webapp server doesn't.
I use form-based authentication almost exclusively, and it does work exactly as you're expecting, which is to say the same response as you'd see from BASIC authentication.
If you provide us with a copy of your login page, we should be able to see what's wrong with it.
Tim Holloway wrote:Welcome to the JavaRanch, Farag!
Regardless of which authentication scheme you wire into a J2EE webapp, the process is the same. When a user requests a protected URL (as defined by patterns in web.xml), the webapp server checks to see whether or not the user has already been authenticated. If so, the user's request proceeds.
If the user has not been authenticated, the user's URL request is placed "on hold", and the server's authentication processor takes over.
It is important to know that the authenticator is completely and entirely a process of the webapp server and its plug-in security (Realm) code. You cannot write a "login servlet" or servlet filter to participate in the authentication process. A lot of people fail to realize this, and think that just because their login page is a "jsp" that they can receive and process information at login time. The container will build the displayed login page using basic JSP processing, but the actual login processing is returned to a closed routine within the appserver itself whose sole function is to use the j_userid and j_password as arguments to the Realm's authenticate() method and instruct the Realm to set up a security context (UserPrincipal) if the Realm's authenticate() method returns "true".
Once authenticated, the original user URL request is taken "off hold" and processed as though the user had already been logged in. There are no events fired or other indications given to the webapp that login ever took place. Login is transparent. Therefore, you cannot know when a user has logged in and direct him/her to a specific login page. Which is actually good for those of us who like to form "bookmark" URLs that take us directly to secured functions within a webapp.
The other reason (besides bookmarkable secure URLs) that you don't get notified when a user logs in is that in the case of webapps secured with a Single Signon Realm, the actual login may have been done while working with an entirely different application, possibly on an entirely different server and even written in an entirely different programming language. All J2EE cares about is that whenever a user requests a secured URL, that URL is protected regardless of which direction the request came from or whatever other functions the user has been doing. This is critical, since one of the best ways to hack into a secured resource on a system that doesn't use the standard security system is to bypass the "normal" assumed processes.
Rob Spoor wrote:Are you using the right form action and name fields? They should be j_security_check for the form action and j_username and j_password for the username and password fields. See http://docs.oracle.com/javaee/1.4/tutorial/doc/Security5.html for more information.