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.Map;
 
 
A Valve that supports a "single sign on" user experience, where the security identity of a user who successfully authenticates to one web application is propogated to other web applications in the same security domain. For successful use, the following requirements must be met:
  • This Valve must be configured on the Container that represents a virtual host (typically an implementation of Host).
  • The Realm that contains the shared user and role information must be configured on the same Container (or a higher one), and not overridden at the web application level.
  • The web applications themselves must use one of the standard Authenticators found in the org.apache.catalina.authenticator package.

Author(s):
Craig R. McClanahan
Version:
$Revision: 1542 $ $Date: 2010-08-25 15:00:37 +0200 (Wed, 25 Aug 2010) $
 
 
 public class SingleSignOn
     extends ValveBase
     implements LifecycleSessionListener {
 
 
     // ----------------------------------------------------- Instance Variables
 

    
The cache of SingleSignOnEntry instances for authenticated Principals, keyed by the cookie value that is used to select them.
 
     protected Map<String,SingleSignOnEntrycache =
         new HashMap<String,SingleSignOnEntry>();


    
Descriptive information about this Valve implementation.
 
     protected static String info =
         "org.apache.catalina.authenticator.SingleSignOn";


    
The lifecycle event support for this component.
 
     protected LifecycleSupport lifecycle = new LifecycleSupport(this);

    
Indicates whether this valve should require a downstream Authenticator to reauthenticate each request, or if it itself can bind a UserPrincipal and AuthType object to the request.
    protected boolean requireReauthentication = false;

    
The cache of single sign on identifiers, keyed by the Session that is associated with them.
    protected Map<Session,Stringreverse = new HashMap<Session,String>();


    
Component started flag.
    protected boolean started = false;

    
Optional SSO cookie domain.
    protected String cookieDomain;

    
Optional SSO HTTP only.
    protected boolean cookieHttpOnly = true;
    // ------------------------------------------------------------- Properties
    public boolean isCookieHttpOnly() {
        return ;
    }
    public void setCookieHttpOnly(boolean cookieHttpOnly) {
        this. = cookieHttpOnly;
    }

    
Returns the optional cookie domain. May return null.

Returns:
The cookie domain
    public String getCookieDomain() {
        return ;
    }
    
    
Sets the domain to be used for sso cookies.

Parameters:
cookieDomain cookie domain name
    public void setCookieDomain(String cookieDomain) {
        if (cookieDomain != null && cookieDomain.trim().length() == 0) {
            cookieDomain = null;
        }
        this. = cookieDomain;
    }

    
Gets whether each request needs to be reauthenticated (by an Authenticator downstream in the pipeline) to the security Realm, or if this Valve can itself bind security info to the request based on the presence of a valid SSO entry without rechecking with the Realm

Returns:
true if it is required that a downstream Authenticator reauthenticate each request before calls to HttpServletRequest.setUserPrincipal() and HttpServletRequest.setAuthType() are made; false if the Valve can itself make those calls relying on the presence of a valid SingleSignOn entry associated with the request.
See also:
setRequireReauthentication(boolean)
    public boolean getRequireReauthentication()
    {
        return ;
    }


    
Sets whether each request needs to be reauthenticated (by an Authenticator downstream in the pipeline) to the security Realm, or if this Valve can itself bind security info to the request, based on the presence of a valid SSO entry, without rechecking with the Realm

If this property is false (the default), this Valve will bind a UserPrincipal and AuthType to the request if a valid SSO entry is associated with the request. It will not notify the security Realm of the incoming request.

This property should be set to true if the overall server configuration requires that the Realm reauthenticate each request thread. An example of such a configuration would be one where the Realm implementation provides security for both a web tier and an associated EJB tier, and needs to set security credentials on each request thread in order to support EJB access.

If this property is set to true, this Valve will set flags on the request notifying the downstream Authenticator that the request is associated with an SSO session. The Authenticator will then call its reauthenticateFromSSO method to attempt to reauthenticate the request to the Realm, using any credentials that were cached with this Valve.

The default value of this property is false, in order to maintain backward compatibility with previous versions of Tomcat.

Parameters:
required true if it is required that a downstream Authenticator reauthenticate each request before calls to HttpServletRequest.setUserPrincipal() and HttpServletRequest.setAuthType() are made; false if the Valve can itself make those calls relying on the presence of a valid SingleSignOn entry associated with the request.
See also:
AuthenticatorBase.reauthenticateFromSSO(java.lang.String,org.apache.catalina.connector.Request)
    public void setRequireReauthentication(boolean required)
    {
        this. = required;
    }
    // ------------------------------------------------------ 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(.valveAlreadyStarted());
         = true;
    }


    
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(.valveNotStarted());
        .fireLifecycleEvent(null);
         = false;
    }
    // ------------------------------------------------ SessionListener Methods


    
Acknowledge the occurrence of the specified event.

Parameters:
event SessionEvent that has occurred
    public void sessionEvent(SessionEvent event) {
        // We only care about session destroyed events
        if (!..equals(event.getType())
                && (!..equals(event.getType())))
            return;
        // Look up the single session id associated with this session (if any)
        Session session = event.getSession();
        String ssoId = null;
        synchronized () {
            ssoId = (String.get(session);
        }
        if (ssoId == null)
            return;
        // Was the session destroyed as the result of a timeout?
        // If so, we'll just remove the expired session from the
        // SSO.  If the session was logged out, we'll log out
        // of all session associated with the SSO.
        if (((session.getMaxInactiveInterval() > 0)
            && (System.currentTimeMillis() - session.getLastAccessedTimeInternal() >=
                session.getMaxInactiveInterval() * 1000)) 
            || (..equals(event.getType()))) {
            removeSession(ssoIdsession);
        } else {
            // The session was logged out.
            // Deregister this single session id, invalidating 
            // associated sessions
            deregister(ssoId);
        }
    }
    // ---------------------------------------------------------- Valve Methods


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


    
Perform single-sign-on support processing for this request.

Parameters:
request The servlet request we are processing
response The servlet response we are creating
Throws:
java.io.IOException if an input/output error occurs
javax.servlet.ServletException if a servlet error occurs
    public void invoke(Request requestResponse response)
        throws IOExceptionServletException {
        request.removeNote(.);
        // Has a valid user already been authenticated?
        if (request.getUserPrincipal() != null) {
            getNext().invoke(requestresponse);
            return;
        }
        // Check for the single sign on cookie
        Cookie cookie = null;
        Cookie cookies[] = request.getCookies();
        if (cookies == null)
            cookies = new Cookie[0];
        for (int i = 0; i < cookies.lengthi++) {
            if (..equals(cookies[i].getName())) {
                cookie = cookies[i];
                break;
            }
        }
        if (cookie == null) {
            getNext().invoke(requestresponse);
            return;
        }
        // Look up the cached Principal associated with this cookie value
        SingleSignOnEntry entry = lookup(cookie.getValue());
        if (entry != null) {
            request.setNote(.cookie.getValue());
            // Only set security elements if reauthentication is not required
            if (!getRequireReauthentication()) {
                request.setAuthType(entry.getAuthType());
                request.setUserPrincipal(entry.getPrincipal());
            }
        } else {
            cookie.setMaxAge(0);
            response.addCookie(cookie);
        }
        // Invoke the next Valve in our pipeline
        getNext().invoke(requestresponse);
    }
    // --------------------------------------------------------- Public Methods


    
Return a String rendering of this object.
    public String toString() {
        StringBuilder sb = new StringBuilder("SingleSignOn[");
        if ( == null )
            sb.append("Container is null");
        else
            sb.append(.getName());
        sb.append("]");
        return (sb.toString());
    }
    // ------------------------------------------------------ Protected Methods


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

Parameters:
ssoId Single sign on identifier
session Session to be associated
    public void associate(String ssoIdSession session) {
        SingleSignOnEntry sso = lookup(ssoId);
        if (sso != null)
            sso.addSession(thissession);
        synchronized () {
            .put(sessionssoId);
        }
    }

    
Deregister the specified session. If it is the last session, then also get rid of the single sign on identifier

Parameters:
ssoId Single sign on identifier
session Session to be deregistered
    protected void deregister(String ssoIdSession session) {
        synchronized () {
            .remove(session);
        }
        SingleSignOnEntry sso = lookup(ssoId);
        if ( sso == null )
            return;
        sso.removeSessionsession );
        // see if we are the last session, if so blow away ssoId
        Session sessions[] = sso.findSessions();
        if ( sessions == null || sessions.length == 0 ) {
            synchronized () {
                sso = (SingleSignOnEntry.remove(ssoId);
            }
        }
    }


    
Deregister the specified single sign on identifier, and invalidate any associated sessions.

Parameters:
ssoId Single sign on identifier to deregister
    public void deregister(String ssoId) {
        // Look up and remove the corresponding SingleSignOnEntry
        SingleSignOnEntry sso = null;
        synchronized () {
            sso = (SingleSignOnEntry.remove(ssoId);
        }
        if (sso == null)
            return;
        // Expire any associated sessions
        Session sessions[] = sso.findSessions();
        for (int i = 0; i < sessions.lengthi++) {
            // Remove from reverse cache first to avoid recursion
            synchronized () {
                .remove(sessions[i]);
            }
            // Invalidate this session
            ClassLoader oldContextClassLoader = null;
            try {
                oldContextClassLoader = bindThread(sessions[i]);
                sessions[i].expire();
            } finally {
                if (oldContextClassLoader != null) {
                    unbindThread(sessions[i], oldContextClassLoader);
                }
            }
        }
        // NOTE:  Clients may still possess the old single sign on cookie,
        // but it will be removed on the next request since it is no longer
        // in the cache
    }
    protected ClassLoader bindThread(Session session) {
        Manager manager = session.getManager();
        Context context = null;
        ClassLoader contextClassLoader = null;
        ThreadBindingListener threadBindingListener = null;
        if (manager != null && manager.getContainer() != null 
                && manager.getContainer() instanceof Context) {
            context = (Contextmanager.getContainer();
        }
        if (context != null) {
            if (context.getLoader() != null && context.getLoader().getClassLoader() != null) {
                contextClassLoader = context.getLoader().getClassLoader();
            }
            threadBindingListener = context.getThreadBindingListener();
        }
        if (threadBindingListener == null || contextClassLoader == null) {
            return null;
        }
        if (.) {
            return AccessController.doPrivileged(new PrivilegedBind(contextClassLoaderthreadBindingListener));
        } else {
            ClassLoader oldContextClassLoader =
                    Thread.currentThread().getContextClassLoader();
            Thread.currentThread().setContextClassLoader(contextClassLoader);
            threadBindingListener.bind();
            return oldContextClassLoader;
        }
    }
    protected class PrivilegedBind implements PrivilegedAction<ClassLoader> {
        private ClassLoader contextClassLoader;
        PrivilegedBind(ClassLoader contextClassLoaderThreadBindingListener threadBindingListener) {
            this. = contextClassLoader;
            this. = threadBindingListener;
        }
        public ClassLoader run() {
            ClassLoader oldContextClassLoader =
                    Thread.currentThread().getContextClassLoader();
            Thread.currentThread().setContextClassLoader();
            .bind();
            return oldContextClassLoader;
        }
    }
    protected void unbindThread(Session sessionClassLoader oldContextClassLoader) {
        Manager manager = session.getManager();
        Context context = null;
        ThreadBindingListener threadBindingListener = null;
        if (manager != null && manager.getContainer() != null 
                && manager.getContainer() instanceof Context) {
            context = (Contextmanager.getContainer();
        }
        if (context != null) {
            threadBindingListener = context.getThreadBindingListener();
        }
        if (threadBindingListener == null) {
            return;
        }
        if (.) {
            AccessController.doPrivileged(new PrivilegedUnbind(oldContextClassLoaderthreadBindingListener));
        } else {
            threadBindingListener.unbind();
            Thread.currentThread().setContextClassLoader(oldContextClassLoader);
        }
    }
    protected class PrivilegedUnbind implements PrivilegedAction<Void> {
        private ClassLoader oldContextClassLoader;
        PrivilegedUnbind(ClassLoader oldContextClassLoaderThreadBindingListener threadBindingListener) {
            this. = oldContextClassLoader;
            this. = threadBindingListener;
        }
        public Void run() {
            .unbind();
            return null;
        }
    }

    
Logout the specified single sign on identifier from all sessions.

Parameters:
ssoId Single sign on identifier to logout
    public void removeLogin(String ssoId) {
        // Look up and remove the corresponding SingleSignOnEntry
        SingleSignOnEntry sso = null;
        synchronized () {
            sso = .get(ssoId);
        }
        if (sso == null)
            return;
        // Remove all authentication information from all associated sessions
        Session sessions[] = sso.findSessions();
        for (Session session : sessions) {
            session.setAuthType(null);
            session.setPrincipal(null);
            session.removeNote(.);
            session.removeNote(.);
        }
        // Reset SSO authentication
        sso.updateCredentials(nullnullnullnull);
    }


    
Attempts reauthentication to the given Realm using the credentials associated with the single sign-on session identified by argument ssoId.

If reauthentication is successful, the Principal and authorization type associated with the SSO session will be bound to the given Request object via calls to Request.setAuthType() and Request.setUserPrincipal()

Parameters:
ssoId identifier of SingleSignOn session with which the caller is associated
realm Realm implementation against which the caller is to be authenticated
request the request that needs to be authenticated
Returns:
true if reauthentication was successful, false otherwise.
    public boolean reauthenticate(String ssoIdRealm realm,
                                     Request request) {
        if (ssoId == null || realm == null)
            return false;
        boolean reauthenticated = false;
        SingleSignOnEntry entry = lookup(ssoId);
        if (entry != null && entry.getCanReauthenticate()) {
            
            String username = entry.getUsername();
            if (username != null) {
                Principal reauthPrincipal =
                        realm.authenticate(usernameentry.getPassword());                
                if (reauthPrincipal != null) {                    
                    reauthenticated = true;                    
                    // Bind the authorization credentials to the request
                    request.setAuthType(entry.getAuthType());
                    request.setUserPrincipal(reauthPrincipal);
                }
            }
        }
        return reauthenticated;
    }


    
Register the specified Principal as being associated with the specified value for the single sign on identifier.

Parameters:
ssoId Single sign on identifier to register
principal Associated user principal that is identified
authType Authentication type used to authenticate this user principal
username Username used to authenticate this user
password Password used to authenticate this user
    public void register(String ssoIdPrincipal principalString authType,
                  String usernameString password) {
        synchronized () {
            .put(ssoIdnew SingleSignOnEntry(principalauthType,
                                                   usernamepassword));
        }
    }


    
Updates any SingleSignOnEntry found under key ssoId with the given authentication data.

The purpose of this method is to allow an SSO entry that was established without a username/password combination (i.e. established following DIGEST or CLIENT_CERT authentication) to be updated with a username and password if one becomes available through a subsequent BASIC or FORM authentication. The SSO entry will then be usable for reauthentication.

NOTE: Only updates the SSO entry if a call to SingleSignOnEntry.getCanReauthenticate() returns false; otherwise, it is assumed that the SSO entry already has sufficient information to allow reauthentication and that no update is needed.

Parameters:
ssoId identifier of Single sign to be updated
principal the Principal returned by the latest call to Realm.authenticate.
authType the type of authenticator used (BASIC, CLIENT_CERT, DIGEST or FORM)
username the username (if any) used for the authentication
password the password (if any) used for the authentication
    public void update(String ssoIdPrincipal principalString authType,
                          String usernameString password) {
        SingleSignOnEntry sso = lookup(ssoId);
        if (sso != null && !sso.getCanReauthenticate()) {
            synchronized(sso) {
                sso.updateCredentials(principalauthTypeusernamepassword);
            }
        }
    }


    
Look up and return the cached SingleSignOn entry associated with this sso id value, if there is one; otherwise return null.

Parameters:
ssoId Single sign on identifier to look up
    protected SingleSignOnEntry lookup(String ssoId) {
        synchronized () {
            return ((SingleSignOnEntry.get(ssoId));
        }
    }

    
    
Remove a single Session from a SingleSignOn. Called when a session is timed out and no longer active.

Parameters:
ssoId Single sign on identifier from which to remove the session.
session the session to be removed.
    protected void removeSession(String ssoIdSession session) {
        // Get a reference to the SingleSignOn
        SingleSignOnEntry entry = lookup(ssoId);
        if (entry == null)
            return;
        // Remove the inactive session from SingleSignOnEntry
        entry.removeSession(session);
        // Remove the inactive session from the 'reverse' Map.
        synchronized() {
            .remove(session);
        }
        // If there are not sessions left in the SingleSignOnEntry,
        // deregister the entry.
        if (entry.findSessions().length == 0) {
            deregister(ssoId);
        }
    }
New to GrepCode? Check out our FAQ X