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;
 
 import java.util.Date;
 
 
Basic implementation of the Valve interface that enforces the <security-constraint> elements in the web application deployment descriptor. This functionality is implemented as a Valve so that it can be ommitted in environments that do not require these features. Individual implementations of each supported authentication method can subclass this base class as required.

USAGE CONSTRAINT: When this class is utilized, the Context to which it is attached (or a parent Container in a hierarchy) must have an associated Realm that can be used for authenticating users and enumerating the roles to which they have been assigned.

USAGE CONSTRAINT: This Valve is only useful when processing HTTP requests. Requests of any other type will simply be passed through.

Author(s):
Craig R. McClanahan
Version:
$Revision: 1848 $ $Date: 2011-10-11 17:29:56 +0200 (Tue, 11 Oct 2011) $
 
 
 
 public abstract class AuthenticatorBase
     extends ValveBase
     implements AuthenticatorLifecycle {
 
 
     // ----------------------------------------------------- Instance Variables
 
    
Authentication header
 
     protected static final String AUTH_HEADER_NAME = "WWW-Authenticate";

    
Default authentication realm name.
 
     protected static final String REALM_NAME = "Authentication required";

    
The number of random bytes to include when generating a session identifier.
 
     protected static final int SESSION_ID_BYTES = 18;


    
Should we cache authenticated Principals if the request is part of an HTTP session?
    protected boolean cache = true;


    
Should the session ID, if any, be changed upon a successful authentication to prevent a session fixation attack?
    protected boolean changeSessionIdOnAuthentication = 
        Boolean.valueOf(System.getProperty("org.apache.catalina.authenticator.AuthenticatorBase.CHANGE_SESSIONID_ON_AUTH""false")).booleanValue();


    
Should the session ID, if any, be changed upon a successful authentication to prevent a session fixation attack?
    protected boolean unregisterSsoOnLogout = 
        Boolean.valueOf(System.getProperty("org.apache.catalina.authenticator.AuthenticatorBase.UNREGISTER_SSO_ON_LOGOUT""false")).booleanValue();

    
Should a session always be used once a user is authenticated? This may offer some performance benefits since the session can then be used to cache the authenticated Principal, hence removing the need to authenticate the user via the Realm on every request. This may be of help for combinations such as BASIC authentication used with the JNDIRealm or DataSourceRealms. However there will also be the performance cost of creating and GC'ing the session. By default, a session will not be created.
    protected boolean alwaysUseSession =
        Boolean.valueOf(System.getProperty("org.apache.catalina.authenticator.AuthenticatorBase.ALWAYS_USE_SESSION""false")).booleanValue();


    
The Context to which this Valve is attached.
    protected Context context = null;


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

    
Flag to determine if we disable proxy caching, or leave the issue up to the webapp developer.
    protected boolean disableProxyCaching = true;

    
Flag to determine if we disable proxy caching with headers incompatible with IE
    protected boolean securePagesWithPragma = true;
    
    
The lifecycle event support for this component.
    protected LifecycleSupport lifecycle = new LifecycleSupport(this);


    
The SingleSignOn implementation in our request processing chain, if there is one.
    protected SingleSignOn sso = null;


    
Has this component been started?
    protected boolean started = false;


    
"Expires" header always set to Date(1), so generate once only
    private static final String DATE_ONE =
                              .)).format(new Date(1));
    // ------------------------------------------------------------- Properties


    
Return the cache authenticated Principals flag.
    public boolean getCache() {
        return (this.);
    }


    
Set the cache authenticated Principals flag.

Parameters:
cache The new cache flag
    public void setCache(boolean cache) {
        this. = cache;
    }
    public boolean isChangeSessionIdOnAuthentication() {
        return ;
    }
            boolean changeSessionIdOnAuthentication) {
        this. = changeSessionIdOnAuthentication;
    }
    public boolean isUnregisterSsoOnLogout() {
        return ;
    }
    public void setUnregisterSsoOnLogout(boolean unregisterSsoOnLogout) {
        this. = unregisterSsoOnLogout;
    }


    
Return the Container to which this Valve is attached.
    public Container getContainer() {
        return (this.);
    }


    
Set the Container to which this Valve is attached.

Parameters:
container The container to which we are attached
    public void setContainer(Container container) {
        if (!(container instanceof Context))
            throw .authenticatorNeedsContext();
        super.setContainer(container);
        this. = (Contextcontainer;
    }


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


    
Return the flag that states if we add headers to disable caching by proxies.
    public boolean getDisableProxyCaching() {
        return ;
    }

    
Set the value of the flag that states if we add headers to disable caching by proxies.

Parameters:
nocache true if we add headers to disable proxy caching, false if we leave the headers alone.
    public void setDisableProxyCaching(boolean nocache) {
         = nocache;
    }
    
    
Return the flag that states, if proxy caching is disabled, what headers we add to disable the caching.
    public boolean getSecurePagesWithPragma() {
        return ;
    }

    
Set the value of the flag that states what headers we add to disable proxy caching.

Parameters:
securePagesWithPragma true if we add headers which are incompatible with downloading office documents in IE under SSL but which fix a caching problem in Mozilla.
    public void setSecurePagesWithPragma(boolean securePagesWithPragma) {
        this. = securePagesWithPragma;
    }    
    // --------------------------------------------------------- Public Methods


    
API login.

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 requestHttpServletResponse response)
        throws IOExceptionServletException {
        return authenticate(requestresponsethis..getLoginConfig());
    }
    public void login(Request requestString usernameString password)
        throws ServletException {
        
        // Is there an SSO session against which we can try to reauthenticate?
        String ssoId = (Stringrequest.getNote(.);
        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;
        }
        Realm realm = .getRealm();
        Principal principal = realm.authenticate(usernamepassword);
        if (principal != null) {
            register(requestrequest.getResponseFacade(), principal.,
                     usernamepassword);
        }
    }
    
    public void logout(Request request)
        throws ServletException {
        unregister(requestrequest.getResponseFacade());
    }
    
    
Enforce the security restrictions in the web application deployment descriptor of our associated Context.

Parameters:
request Request to be processed
response Response to be processed
Throws:
java.io.IOException if an input/output error occurs
javax.servlet.ServletException if thrown by a processing element
    public void invoke(Request requestResponse response)
        throws IOExceptionServletException {
            ..debug("Security checking request " +
                request.getMethod() + " " + request.getRequestURI());
        LoginConfig config = this..getLoginConfig();
        // Have we got a cached authenticated Principal to record?
        if () {
            Principal principal = request.getUserPrincipal();
            if (principal == null) {
                Session session = request.getSessionInternal(false);
                if (session != null) {
                    principal = session.getPrincipal();
                    if (principal != null) {
                        if (..isDebugEnabled())
                            ..debug("We have cached auth type " +
                                session.getAuthType() +
                                " for principal " +
                                session.getPrincipal());
                        request.setAuthType(session.getAuthType());
                        request.setUserPrincipal(principal);
                    }
                }
            }
        }
        // Special handling for form-based logins to deal with the case
        // where the login form (and therefore the "j_security_check" URI
        // to which it submits) might be outside the secured area
        String contextPath = this..getPath();
        String requestURI = request.getDecodedRequestURI();
        if (requestURI.startsWith(contextPath) &&
            requestURI.endsWith(.)) {
            if (!authenticate(requestresponseconfig)) {
                if (..isDebugEnabled())
                    ..debug(" Failed authenticate() test ??" + requestURI );
                return;
            }
        }
        Realm realm = this..getRealm();
        // Is this request URI subject to a security constraint?
        SecurityConstraint [] constraints
            = realm.findSecurityConstraints(requestthis.);
       
        if ((constraints == null/* &&
            (!Constants.FORM_METHOD.equals(config.getAuthMethod())) */ ) {
            if (..isDebugEnabled())
                ..debug(" Not subject to any constraint");
            getNext().invoke(requestresponse);
            return;
        }
        // Make sure that constrained resources are not cached by web proxies
        // or browsers as caching can provide a security hole
        if ( && 
            // Note: Disabled for Mozilla FORM support over SSL 
            // (improper caching issue)
            //!request.isSecure() &&
            !"POST".equalsIgnoreCase(request.getMethod())) {
            if () {
                // Note: These cause problems with downloading office docs
                // from IE under SSL and may not be needed for newer Mozilla
                // clients.
                response.setHeader("Pragma""No-cache");
                response.setHeader("Cache-Control""no-cache");
            } else {
                response.setHeader("Cache-Control""private");
            }
            response.setHeader("Expires");
        }
        int i;
        // Enforce any user data constraint for this security constraint
        if (..isDebugEnabled()) {
            ..debug(" Calling hasUserDataPermission()");
        }
        if (!realm.hasUserDataPermission(requestresponse,
                                         constraints)) {
            if (..isDebugEnabled()) {
                ..debug(" Failed hasUserDataPermission() test");
            }
            /*
             * ASSERT: Authenticator already set the appropriate
             * HTTP status code, so we do not have to do anything special
             */
            return;
        }
        // Since authenticate modifies the response on failure,
        // we have to check for allow-from-all first.
        boolean authRequired = true;
        for(i=0; i < constraints.length && authRequiredi++) {
            if(!constraints[i].getAuthConstraint()) {
                authRequired = false;
            } else if(!constraints[i].getAllRoles()) {
                String [] roles = constraints[i].findAuthRoles();
                if(roles == null || roles.length == 0) {
                    authRequired = false;
                }
            }
        }
             
        if(authRequired) {  
            if (..isDebugEnabled()) {
                ..debug(" Calling authenticate()");
            }
            if (!authenticate(requestresponseconfig)) {
                if (..isDebugEnabled()) {
                    ..debug(" Failed authenticate() test");
                }
                /*
                 * ASSERT: Authenticator already set the appropriate
                 * HTTP status code, so we do not have to do anything
                 * special
                 */
                return;
            } 
        }
    
        if (..isDebugEnabled()) {
            ..debug(" Calling accessControl()");
        }
        if (!realm.hasResourcePermission(requestresponse,
                                         constraints,
                                         this.)) {
            if (..isDebugEnabled()) {
                ..debug(" Failed accessControl() test");
            }
            /*
             * ASSERT: AccessControl method has already set the
             * appropriate HTTP status code, so we do not have to do
             * anything special
             */
            return;
        }
    
        // Any and all specified constraints have been satisfied
        if (..isDebugEnabled()) {
            ..debug(" Successfully passed all security constraints");
        }
        getNext().invoke(requestresponse);
    }
    // ------------------------------------------------------ Protected Methods




    
Associate the specified single sign on identifier with the specified Session.

Parameters:
ssoId Single sign on identifier
session Session to be associated
    protected void associate(String ssoIdSession session) {
        if ( == null)
            return;
        .associate(ssoIdsession);
    }


    
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
    protected abstract boolean authenticate(Request request,
                                            HttpServletResponse response,
                                            LoginConfig config)
        throws IOException;


    
Generate and return a new session identifier for the cookie that identifies an SSO principal.
    protected synchronized String generateSessionId(Random random) {
        byte[] bytes = new byte[];
        random.nextBytes(bytes);
        // Encode the result
        char[] id = ManagerBase.encode(bytes);
        return String.valueOf(id);
    }


    
Attempts reauthentication to the Realm using the credentials included in argument entry.

Parameters:
ssoId identifier of SingleSignOn session with which the caller is associated
request the request that needs to be authenticated
    protected boolean reauthenticateFromSSO(String ssoIdRequest request) {
        if ( == null || ssoId == null)
            return false;
        boolean reauthenticated = false;
        Container parent = getContainer();
        if (parent != null) {
            Realm realm = parent.getRealm();
            if (realm != null) {
                reauthenticated = .reauthenticate(ssoIdrealmrequest);
            }
        }
        if (reauthenticated) {
            associate(ssoIdrequest.getSessionInternal(true));
            if (..isDebugEnabled()) {
                ..debug(" Reauthenticated cached principal '" +
                          request.getUserPrincipal().getName() +
                          "' with auth type '" +  request.getAuthType() + "'");
            }
        }
        return reauthenticated;
    }


    
Register an authenticated Principal and authentication type in our request, in the current session (if there is one), and with our SingleSignOn valve, if there is one. Set the appropriate cookie to be returned.

Parameters:
request The servlet request we are processing
response The servlet response we are generating
principal The authenticated Principal to be registered
authType The authentication type to be registered
username Username used to authenticate (if any)
password Password used to authenticate (if any)
    protected void register(Request requestHttpServletResponse response,
                            Principal principalString authType,
                            String usernameString password) {
            ..debug("Authenticated '" + principal.getName() + "' with type '"
                + authType + "'");
        // Cache the authentication information in our request
        request.setAuthType(authType);
        request.setUserPrincipal(principal);
        Session session = request.getSessionInternal(false);
        if (session != null) {
            if () {
                Manager manager = request.getContext().getManager();
                manager.changeSessionId(sessionrequest.getRandom());
                request.changeSessionId(session.getId());
            }
        } else if () {
            session = request.getSessionInternal(true);
        }
        // Cache the authentication information in our session, if any
        if () {
            if (session != null) {
                session.setAuthType(authType);
                session.setPrincipal(principal);
                if (username != null)
                    session.setNote(.username);
                else
                    session.removeNote(.);
                if (password != null)
                    session.setNote(.password);
                else
                    session.removeNote(.);
            }
        }
        // Construct a cookie to be returned to the client
        if ( == null)
            return;
        // Only create a new SSO entry if the SSO did not already set a note
        // for an existing entry (as it would do with subsequent requests
        // for DIGEST and SSL authenticated contexts)
        String ssoId = (Stringrequest.getNote(.);
        if (ssoId == null) {
            // Construct a cookie to be returned to the client
            ssoId = generateSessionId(request.getRandom());
            Cookie cookie = new Cookie(.ssoId);
            cookie.setMaxAge(-1);
            cookie.setPath("/");
            
            // Bugzilla 41217
            cookie.setSecure(request.isSecure());
            if (.isCookieHttpOnly()) {
                cookie.setHttpOnly(true);
            }
            // Bugzilla 34724
            String ssoDomain = .getCookieDomain();
            if(ssoDomain != null) {
                cookie.setDomain(ssoDomain);
            }
            response.addCookie(cookie);
            // Register this principal with our SSO valve
            .register(ssoIdprincipalauthTypeusernamepassword);
            request.setNote(.ssoId);
        } else {
            // Update the SSO session with the latest authentication data
            .update(ssoIdprincipalauthTypeusernamepassword);
        }
        // Fix for Bug 10040
        // Always associate a session with a new SSO reqistration.
        // SSO entries are only removed from the SSO registry map when
        // associated sessions are destroyed; if a new SSO entry is created
        // above for this request and the user never revisits the context, the
        // SSO entry will never be cleared if we don't associate the session
        if (session == null)
            session = request.getSessionInternal(true);
        .associate(ssoIdsession);
    }


    
Register an authenticated Principal and authentication type in our request, in the current session (if there is one), and with our SingleSignOn valve, if there is one. Set the appropriate cookie to be returned.

Parameters:
request The servlet request we are processing
response The servlet response we are generating
principal The authenticated Principal to be registered
authType The authentication type to be registered
username Username used to authenticate (if any)
password Password used to authenticate (if any)
    protected void unregister(Request requestHttpServletResponse response) {
        // Remove the authentication information from our request
        request.setAuthType(null);
        request.setUserPrincipal(null);
        Session session = request.getSessionInternal(false);
        // Cache the authentication information in our session, if any
        if ( && session != null) {
            session.setAuthType(null);
            session.setPrincipal(null);
            session.removeNote(.);
            session.removeNote(.);
        }
        // Construct a cookie to be returned to the client
        if ( == null)
            return;
        String ssoId = (Stringrequest.getNote(.);
        if (ssoId != null) {
            // Update the SSO session with the latest authentication data
            if () {
                request.removeNote(.);
                .deregister(ssoId);
            } else {
                if ( && session != null) {
                    .removeLogin(ssoId);
                }
            }
        }
    }
    // ------------------------------------------------------ Lifecycle Methods


    
Add a lifecycle event listener to this component.

Parameters:
listener The listener to add
    public void addLifecycleListener(LifecycleListener listener) {
        .addLifecycleListener(listener);
    }


    
Get the lifecycle listeners associated with this lifecycle. If this Lifecycle has no listeners registered, a zero-length array is returned.
        return .findLifecycleListeners();
    }


    
Remove a lifecycle event listener from this component.

Parameters:
listener The listener to remove
    public void removeLifecycleListener(LifecycleListener listener) {
        .removeLifecycleListener(listener);
    }


    
Prepare for the beginning of active use of the public methods of this component. This method should be called after configure(), and before any of the public methods of the component are utilized.

Throws:
org.apache.catalina.LifecycleException if this component detects a fatal error that prevents this component from being used
    public void start() throws LifecycleException {
        // Validate and update our current component state
        if ()
            throw new LifecycleException(.authenticatorAlreadyStarted());
         = true;
        // Look up the SingleSignOn implementation in our request processing
        // path, if there is one
        Container parent = .getParent();
        while (( == null) && (parent != null)) {
            if (!(parent instanceof Pipeline)) {
                parent = parent.getParent();
                continue;
            }
            Valve valves[] = ((Pipelineparent).getValves();
            for (int i = 0; i < valves.lengthi++) {
                if (valves[iinstanceof SingleSignOn) {
                     = (SingleSignOnvalves[i];
                    break;
                }
            }
            if ( == null)
                parent = parent.getParent();
        }
        if (..isDebugEnabled()) {
            if ( != null)
                ..debug("Found SingleSignOn Valve at " + );
            else
                ..debug("No SingleSignOn Valve is present");
        }
    }


    
Gracefully terminate the active use of the public methods of this component. This method should be the last one called on a given instance of this component.

Throws:
org.apache.catalina.LifecycleException if this component detects a fatal error that needs to be reported
    public void stop() throws LifecycleException {
        // Validate and update our current component state
        if (!)
            throw new LifecycleException(.authenticatorNotStarted());
        .fireLifecycleEvent(null);
         = false;
         = null;
    }
New to GrepCode? Check out our FAQ X