Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  /*
   * Licensed to the Apache Software Foundation (ASF) under one or more
   * contributor license agreements.  See the NOTICE file distributed with
   * this work for additional information regarding copyright ownership.
   * The ASF licenses this file to You under the Apache License, Version 2.0
   * (the "License"); you may not use this file except in compliance with
   * the License.  You may obtain a copy of the License at
   * 
   *      http://www.apache.org/licenses/LICENSE-2.0
  * 
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
 
 package org.apache.catalina.authenticator;
 
 
 import static org.jboss.web.CatalinaMessages.MESSAGES;
 
 
 
An Authenticator and Valve implementation of FORM BASED Authentication, as described in the Servlet API Specification, Version 2.2.

Author(s):
Craig R. McClanahan
Remy Maucherat
Version:
$Revision: 1703 $ $Date: 2011-04-13 15:25:47 +0200 (Wed, 13 Apr 2011) $
 
 
 public class FormAuthenticator
     extends AuthenticatorBase {
     
     // ----------------------------------------------------- Instance Variables
 

    
Descriptive information about this implementation.
 
     protected static final String info =
         "org.apache.catalina.authenticator.FormAuthenticator/1.0";

    
Character encoding to use to read the username and password parameters from the request. If not set, the encoding of the request body will be used.
 
     protected String characterEncoding = null;

    
Landing page to use if a user tries to access the login page directly or if the session times out during login. If not set, error responses will be sent instead.
 
     protected String landingPage = null;
 
 
     // ------------------------------------------------------------- Properties
 

    
Return descriptive information about this Valve implementation.
 
     public String getInfo() {
 
         return ();
 
     }


    
Return the character encoding to use to read the username and password.
    public String getCharacterEncoding() {
        return ;
    }

    
    
Set the character encoding to be used to read the username and password.
    public void setCharacterEncoding(String encoding) {
         = encoding;
    }


    
Return the landing page to use when FORM auth is mis-used.
    public String getLandingPage() {
        return ;
    }


    
Set the landing page to use when the FORM auth is mis-used.
    public void setLandingPage(String landingPage) {
        this. = landingPage;
    }
    // --------------------------------------------------------- Public Methods


    
Authenticate the user making this request, based on the specified login configuration. Return true if any specified constraint has been satisfied, or false if we have created a response challenge already.

Parameters:
request Request we are processing
response Response we are creating
config Login configuration describing how authentication should be performed
Throws:
java.io.IOException if an input/output error occurs
    public boolean authenticate(Request request,
                                HttpServletResponse response,
                                LoginConfig config)
        throws IOException {
        // References to objects we will need later
        Session session = null;
        // Have we already authenticated someone?
        Principal principal = request.getUserPrincipal();
        String ssoId = (Stringrequest.getNote(.);
        if (principal != null) {
            if (..isDebugEnabled())
                ..debug("Already authenticated '" +
                    principal.getName() + "'");
            // Associate the session with any existing SSO session
            if (ssoId != null)
                associate(ssoIdrequest.getSessionInternal(true));
            return (true);
        }
        // Is there an SSO session against which we can try to reauthenticate?
        if (ssoId != null) {
            if (..isDebugEnabled())
                ..debug("SSO Id " + ssoId + " set; attempting " +
                          "reauthentication");
            // Try to reauthenticate using data cached by SSO.  If this fails,
            // either the original SSO logon was of DIGEST or SSL (which
            // we can't reauthenticate ourselves because there is no
            // cached username and password), or the realm denied
            // the user's reauthentication for some reason.
            // In either case we have to prompt the user for a logon */
            if (reauthenticateFromSSO(ssoIdrequest))
                return true;
        }
        // Have we authenticated this user before but have caching disabled?
        if (!) {
            session = request.getSessionInternal(true);
            if (..isDebugEnabled())
                ..debug("Checking for reauthenticate in session " + session);
            String username =
                (Stringsession.getNote(.);
            String password =
                (Stringsession.getNote(.);
            if ((username != null) && (password != null)) {
                if (..isDebugEnabled())
                    ..debug("Reauthenticating username '" + username + "'");
                principal =
                    .getRealm().authenticate(usernamepassword);
                if (principal != null) {
                    session.setNote(.principal);
                    if (!matchRequest(request)) {
                        register(requestresponseprincipal,
                                 .,
                                 usernamepassword);
                        return (true);
                    }
                }
                if (..isDebugEnabled())
                    ..debug("Reauthentication failed, proceed normally");
            }
        }
        // Is this the re-submit of the original request URI after successful
        // authentication?  If so, forward the *original* request instead.
        if (matchRequest(request)) {
            session = request.getSessionInternal(true);
            if (..isDebugEnabled())
                ..debug("Restore request from session '"
                          + session.getIdInternal() 
                          + "'");
            principal = (Principal)
                session.getNote(.);
            register(requestresponseprincipal.,
                     (Stringsession.getNote(.),
                     (Stringsession.getNote(.));
            // If we're caching principals we no longer need the username
            // and password in the session, so remove them
            if () {
                session.removeNote(.);
                session.removeNote(.);
            }
            if (restoreRequest(requestsession)) {
                if (..isDebugEnabled())
                    ..debug("Proceed to restored request");
                return (true);
            } else {
                if (..isDebugEnabled())
                    ..debug("Restore of original request failed");
                response.sendError(.);
                return (false);
            }
        }
        // Acquire references to objects we will need to evaluate
        MessageBytes uriMB = MessageBytes.newInstance();
        CharChunk uriCC = uriMB.getCharChunk();
        uriCC.setLimit(-1);
        String contextPath = request.getContextPath();
        String requestURI = request.getDecodedRequestURI();
        // Is this the action request from the login page?
        boolean loginAction =
            requestURI.startsWith(contextPath) &&
            requestURI.endsWith(.);
        // No -- Save this request and redirect to the form login page
        if (!loginAction) {
            session = request.getSessionInternal(true);
            if (..isDebugEnabled())
                ..debug("Save request in session '" + session.getIdInternal() + "'");
            try {
                saveRequest(requestsession);
            } catch (IOException ioe) {
                ..debug("Request body too big to save during authentication");
                response.sendError(..requestBodyTooLarge());
                return (false);
            }
            forwardToLoginPage(requestresponseconfig);
            return (false);
        }
        // Yes -- Acknowledge the request, validate the specified credentials
        // and redirect to the error page if they are not correct
        request.getResponse().sendAcknowledgement();
        Realm realm = .getRealm();
        if ( != null) {
            request.setCharacterEncoding();
        }
        String username = request.getParameter(.);
        String password = request.getParameter(.);
            ..debug("Authenticating username '" + username + "'");
        principal = realm.authenticate(usernamepassword);
        if (principal == null) {
            forwardToErrorPage(requestresponseconfig);
            return (false);
        }
            ..debug("Authentication of '" + username + "' was successful");
        if (session == null)
            session = request.getSessionInternal(false);
        if (session == null) {
            if (getContainer().getLogger().isDebugEnabled())
                getContainer().getLogger().debug
                    ("User took so long to log on the session expired");
            if ( == null) {
                response.sendError(.,
                        .sessionTimeoutDuringAuthentication());
            } else {
                // Make the authenticator think the user originally requested
                // the landing page
                String uri = request.getContextPath() + ;
                SavedRequest saved = new SavedRequest();
                saved.setMethod("GET");
                saved.setRequestURI(uri);
                saved.setDecodedRequestURI(uri);
                request.getSessionInternal(true).setNote(
                        .saved);
                response.sendRedirect(response.encodeRedirectURL(uri));
            }
            return (false);
        }
        // Save the authenticated Principal in our session
        session.setNote(.principal);
        // Save the username and password as well
        session.setNote(.username);
        session.setNote(.password);
        // Redirect the user to the original request URI (which will cause
        // the original request to be restored)
        requestURI = savedRequestURL(session);
            ..debug("Redirecting to original '" + requestURI + "'");
        if (requestURI == null)
            if ( == null) {
                response.sendError(.,
                        .invalidFormLoginDirectReference());
            } else {
                // Make the authenticator think the user originally requested
                // the landing page
                String uri = request.getContextPath() + ;
                SavedRequest saved = new SavedRequest();
                saved.setMethod("GET");
                saved.setRequestURI(uri);
                saved.setDecodedRequestURI(uri);
                session.setNote(.saved);
                response.sendRedirect(response.encodeRedirectURL(uri));
            }
        else
            response.sendRedirect(response.encodeRedirectURL(requestURI));
        return (false);
    }
    // ------------------------------------------------------ Protected Methods


    
Called to forward to the login page

Parameters:
request Request we are processing
response Response we are creating
config Login configuration describing how authentication should be performed
Throws:
java.io.IOException If the forward to the login page fails and the call to java.io.IOException
    protected void forwardToLoginPage(Request requestHttpServletResponse responseLoginConfig config)
        throws IOException {
        if () {
            Session session = request.getSessionInternal(false);
            if (session != null) {
                Manager manager = request.getContext().getManager();
                manager.changeSessionId(sessionrequest.getRandom());
                request.changeSessionId(session.getId());
            }
        }
        // Always use GET for the login page, regardless of the method used
        String oldMethod = request.getMethod();
        request.getCoyoteRequest().method().setString("GET");
        RequestDispatcher disp =
            .getServletContext().getRequestDispatcher(config.getLoginPage());
        try {
            disp.forward(request.getRequest(), response);
        } catch (Throwable t) {
            String msg = .errorForwardingToFormLogin();
            ..warn(msgt);
            request.setAttribute(.t);
                    msg);
        } finally {
            // Restore original method so that it is written into access log
            request.getCoyoteRequest().method().setString(oldMethod);
        }
    }


    
Called to forward to the error page

Parameters:
request Request we are processing
response Response we are creating
config Login configuration describing how authentication should be performed
Throws:
java.io.IOException If the forward to the error page fails and the call to java.io.IOException
    protected void forwardToErrorPage(Request requestHttpServletResponse responseLoginConfig config)
        throws IOException {
        RequestDispatcher disp =
            .getServletContext().getRequestDispatcher(config.getErrorPage());
        try {
            disp.forward(request.getRequest(), response);
        } catch (Throwable t) {
            String msg = .errorForwardingToFormError();
            ..warn(msgt);
            request.setAttribute(.t);
                    msg);
        }
    }


    
Does this request match the saved one (so that it must be the redirect we signalled after successful authentication?

Parameters:
request The request to be verified
    protected boolean matchRequest(Request request) {
      // Has a session been created?
      Session session = request.getSessionInternal(false);
      if (session == null)
          return (false);
      // Is there a saved request?
      SavedRequest sreq = (SavedRequest)
          session.getNote(.);
      if (sreq == null)
          return (false);
      // Is there a saved principal?
      if (session.getNote(.) == null)
          return (false);
      // Does the request URI match?
      String decodedRequestURI = request.getDecodedRequestURI();
      if (decodedRequestURI == null)
          return (false);
      return (decodedRequestURI.equals(sreq.getDecodedRequestURI()));
    }


    
Restore the original request from information stored in our session. If the original request is no longer present (because the session timed out), return false; otherwise, return true.

Parameters:
request The request to be restored
session The session containing the saved information
    protected boolean restoreRequest(Request requestSession session)
        throws IOException {
        // Retrieve and remove the SavedRequest object from our session
        SavedRequest saved = (SavedRequest)
            session.getNote(.);
        session.removeNote(.);
        session.removeNote(.);
        if (saved == null)
            return (false);
        // Swallow any request body since we will be replacing it
        // Need to do this before headers are restored as AJP connector uses
        // content length header to determine how much data needs to be read for
        // request body
        byte[] buffer = new byte[4096];
        InputStream is = request.createInputStream();
        while (is.read(buffer) >= 0) {
            // Ignore request body
        }
        // Modify our current request to reflect the original one
        request.clearCookies();
        Iterator cookies = saved.getCookies();
        while (cookies.hasNext()) {
            request.addCookie((Cookiecookies.next());
        }
        String method = saved.getMethod();
        MimeHeaders rmh = request.getCoyoteRequest().getMimeHeaders();
        rmh.recycle();
        boolean cachable = "GET".equalsIgnoreCase(method) ||
                           "HEAD".equalsIgnoreCase(method);
        Iterator names = saved.getHeaderNames();
        while (names.hasNext()) {
            String name = (Stringnames.next();
            // The browser isn't expecting this conditional response now.
            // Assuming that it can quietly recover from an unexpected 412.
            // BZ 43687
            if(!("If-Modified-Since".equalsIgnoreCase(name) ||
                 (cachable && "If-None-Match".equalsIgnoreCase(name)))) {
                Iterator values = saved.getHeaderValues(name);
                while (values.hasNext()) {
                    rmh.addValue(name).setString( (String)values.next() );
                }
            }
        }
        
        request.clearLocales();
        Iterator locales = saved.getLocales();
        while (locales.hasNext()) {
            request.addLocale((Localelocales.next());
        }
        
        request.getCoyoteRequest().getParameters().recycle();
        
        
        ByteChunk body = saved.getBody();
        if (body != null) {
            request.resetBody();
            request.getCoyoteRequest().action(.body);
            // Set content type
            MessageBytes contentType = MessageBytes.newInstance();
            //If no content type specified, use default for POST
            String savedContentType = saved.getContentType();
            if (savedContentType == null && "POST".equalsIgnoreCase(method)) {
                savedContentType = "application/x-www-form-urlencoded";
            }
            contentType.setString(savedContentType);
            request.getCoyoteRequest().setContentType(contentType);
        } else {
            // Restore the parameters.
            Iterator params = saved.getParameterNames();
            while (params.hasNext()) {
                String name = (Stringparams.next();
                request.addParameter(name,
                        saved.getParameterValues(name));
            }
        }
        request.getCoyoteRequest().method().setString(method);
        request.getCoyoteRequest().queryString().setString
            (saved.getQueryString());
        request.getCoyoteRequest().requestURI().setString
            (saved.getRequestURI());
        return (true);
    }


    
Save the original request information into our session.

Parameters:
request The request to be saved
session The session to contain the saved information
Throws:
java.io.IOException
    protected void saveRequest(Request requestSession session)
        throws IOException {
        // Create and populate a SavedRequest object for this request
        SavedRequest saved = new SavedRequest();
        Cookie cookies[] = request.getCookies();
        if (cookies != null) {
            for (int i = 0; i < cookies.lengthi++)
                saved.addCookie(cookies[i]);
        }
        Enumeration names = request.getHeaderNames();
        while (names.hasMoreElements()) {
            String name = (Stringnames.nextElement();
            Enumeration values = request.getHeaders(name);
            while (values.hasMoreElements()) {
                String value = (Stringvalues.nextElement();
                saved.addHeader(namevalue);
            }
        }
        Enumeration locales = request.getLocales();
        while (locales.hasMoreElements()) {
            Locale locale = (Localelocales.nextElement();
            saved.addLocale(locale);
        }
        // May need to acknowledge a 100-continue expectation
        request.getResponse().sendAcknowledgement();
        ByteChunk body = new ByteChunk();
        body.setLimit(request.getConnector().getMaxSavePostSize());
        byte[] buffer = new byte[4096];
        int bytesRead;
        InputStream is = request.getInputStream();
        while ( (bytesRead = is.read(buffer) ) >= 0) {
            body.append(buffer, 0, bytesRead);
        }
        if (body.getLength() > 0) {
            saved.setContentType(request.getContentType());
            saved.setBody(body);
        }
        if (body.getLength() == 0) {
            // It means that parameters have already been parsed.
            Enumeration e = request.getParameterNames();
            for ( ; e.hasMoreElements() ;) {
                String name = (Stringe.nextElement();
                String[] val = request.getParameterValues(name);
                saved.addParameter(nameval);
            }
        }
        saved.setMethod(request.getMethod());
        saved.setQueryString(request.getQueryString());
        saved.setRequestURI(request.getRequestURI());
        saved.setDecodedRequestURI(request.getDecodedRequestURI());
        // Stash the SavedRequest in our session for later use
        session.setNote(.saved);
    }


    
Return the request URI (with the corresponding query string, if any) from the saved request so that we can redirect to it.

Parameters:
session Our current session
    protected String savedRequestURL(Session session) {
        SavedRequest saved =
            (SavedRequestsession.getNote(.);
        if (saved == null)
            return (null);
        StringBuilder sb = new StringBuilder(saved.getRequestURI());
        if (saved.getQueryString() != null) {
            sb.append('?');
            sb.append(saved.getQueryString());
        }
        return (sb.toString());
    }
New to GrepCode? Check out our FAQ X