You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by bu...@apache.org on 2010/10/06 21:30:10 UTC

DO NOT REPLY [Bug 3839] Problem bookmarking login page

https://issues.apache.org/bugzilla/show_bug.cgi?id=3839

--- Comment #14 from Mark Morris <mm...@orgstrategies.com> 2010-10-06 15:29:58 EDT ---
I've been tracing through the Tomcat source code because of an "Invalid direct
reference to form login page" error our customers frequently get and here is
what was found (for Tomcat 5 and 6):

When you retrieve the login page for the first time, Tomcat initializes a field
that is needed for the actual login (a session.note entry). Unfortunately that
field is wiped out after the session expires or the server is rebooted. Also
Tomcat confuses the get request for http://<server>/j_security_check with the
actual login action (see further down for an explanation in extreme detail).

As a workaround for this error, we implemented the following at the end of our
login module (posted with permission from Organizational Strategies Inc):

    org.apache.catalina.connector.RequestFacade requestFacade =
(RequestFacade)request;
    org.apache.catalina.connector.Request tomcatRequest =
org.apache.catalina.connector.TomcatRequestFacadeAccessor.extractRequest(requestFacade);
    org.apache.catalina.Session tomcatSession =
tomcatRequest.getSessionInternal(false);
    org.apache.catalina.authenticator.SavedRequest saved = (SavedRequest)
tomcatSession.getNote(org.apache.catalina.authenticator.Constants.FORM_REQUEST_NOTE);
    if(saved==null){
        saved = new SavedRequest();
        saved.setRequestURI("/your/path/here");
        tomcatSession.setNote(Constants.FORM_REQUEST_NOTE, saved);
    }

    You will also need to make a TomcatRequestFacadeAccessor class (in package
org.apache.catalina.connector), jar it up and add that jar to Tomcat's
classpath. That class contains this method

    public static org.apache.catalina.connector.Request
extractRequest(RequestFacade facade){
        return facade.request;
    }


The above is just a quickly put-together workaround for the error.  We're
hoping someone will implement a permanent solution into the Tomcat codebase to
address this issue.  To assist with that below is an explanation of the error
in extreme detail


1) After rebooting everything and going to the login page for the first time,
the following code in
org.apache.catalina.authenticator.FormAuthenticator.authenticate() gets
executed:

            if (!loginAction) {
                session = request.getSessionInternal(true);
                if (log.isDebugEnabled())
                    log.debug("Save request in session '" +
session.getIdInternal() + "'");
                try {
                    saveRequest(request, session);
                } catch (IOException ioe) {
                    log.debug("Request body too big to save during
authentication");
                    response.sendError(HttpServletResponse.SC_FORBIDDEN,
                            sm.getString("authenticator.requestBodyTooBig"));
                    return (false);
                }
                forwardToLoginPage(request, response, config);
                return (false);
            }

            The loginAction flag is true when you press the login button;
however, the retrieving of the login page is NOT a loginAction so the above
block executes

2)  In that block of code, the call to saveRequest(request, session) eventually
executes the following line:
             session.setNote(Constants.FORM_REQUEST_NOTE, saved);

3) Later on when you press the login button, this code in
FormAuthenticator.java tries to use that session.note value:
            requestURI = savedRequestURL(session);
            and savedRequestURL returns the session.note value set when the
login page was originally retrieved:
                session.getNote(Constants.FORM_REQUEST_NOTE);

4) Unfortunately if the block of code from 1) is not executed, then the
session.note value won't be set, requestURI will be null and this will run,
giving you the "Invalid direct reference to form login page" error:
            requestURI = savedRequestURL(session);
                if (requestURI == null)
                    response.sendError(HttpServletResponse.SC_BAD_REQUEST,
                                      
sm.getString("authenticator.formlogin"));

5) The block of code from 1) won't execute and you'll get the "Invalid direct
reference to form login page" error in the following conditions:
        a) If the server is rebooted and the user already has a login window
open
        b) If the user's session times out and they already have a login window
open
        c) If they go directly to URL
http://<yourserver>/your/path/here/j_security_check (many users may have this
bookmarked because it's the browser URL you see after invalid logins)
                The reason this URL doesn't work is because the loginAction
flag toggling the block of code from 1) is set like this:
                    boolean loginAction =
                        requestURI.startsWith(contextPath) &&
                        requestURI.endsWith(Constants.FORM_ACTION);   //this is
"/j_security_check"
                and going to
http://<yourserver>/your/path/here/j_security_check will set loginAction to
true (Tomcat thinks you clicked the login button) - one way to fix this is to
make loginAction false for GET requests


Many thanks in advance for whoever makes the FormAuthenticator changes to fix
this.

Thanks,
Mark Morris.

-- 
Configure bugmail: https://issues.apache.org/bugzilla/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
You are the assignee for the bug.

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org