Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  /*
   * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
   *
   * Copyright (c) 1997-2012 Oracle and/or its affiliates. All rights reserved.
   *
   * The contents of this file are subject to the terms of either the GNU
   * General Public License Version 2 only ("GPL") or the Common Development
   * and Distribution License("CDDL") (collectively, the "License").  You
   * may not use this file except in compliance with the License.  You can
  * obtain a copy of the License at
  * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
  * or packager/legal/LICENSE.txt.  See the License for the specific
  * language governing permissions and limitations under the License.
  *
  * When distributing the software, include this License Header Notice in each
  * file and include the License file at packager/legal/LICENSE.txt.
  *
  * GPL Classpath Exception:
  * Oracle designates this particular file as subject to the "Classpath"
  * exception as provided by Oracle in the GPL Version 2 section of the License
  * file that accompanied this code.
  *
  * Modifications:
  * If applicable, add the following below the License Header, with the fields
  * enclosed by brackets [] replaced by your own identifying information:
  * "Portions Copyright [year] [name of copyright owner]"
  *
  * Contributor(s):
  * If you wish your version of this file to be governed by only the CDDL or
  * only the GPL Version 2, indicate your decision by adding "[Contributor]
  * elects to include this software in this distribution under the [CDDL or GPL
  * Version 2] license."  If you don't indicate a single choice of license, a
  * recipient has the option to distribute your version of this file under
  * either the CDDL, the GPL Version 2 or to extend the choice of license to
  * its licensees as provided above.  However, if you add GPL Version 2 code
  * and therefore, elected the GPL Version 2 license, then the option applies
  * only if the new code is made subject to such option by the copyright
  * holder.
  */
 
 package com.sun.enterprise.security.web;
 
 
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.

Author(s):
Jyri Virkki (first implementation)
Jean-Francois Arcand
 
 public class GlassFishSingleSignOn
     extends SingleSignOn
    
CR 6411114 (Lifecycle implementation moved to ValveBase) implements Lifecycle, SessionListener, Runnable, SingleSignOnMBean {
 
     // START CR 6411114
     implements RunnableSingleSignOnMBean {
     // END CR 6411114
 
     // ----------------------------------------------------- Instance Variables
 
    
The log used by this class.
 
     private static final Logger logger = .....;
 
     @LogMessageInfo(
             message = "Process session destroyed on {0}",
             level = "FINE")
     private static final String SESSION_DESTROYED = "AS-WEB-00219";
 
     @LogMessageInfo(
             message = "Process request for '{0}'",
             level = "FINE")
     private static final String REQUEST_PROCESSED = "AS-WEB-00220";
 
     @LogMessageInfo(
             message = "Principal '{0}' has already been authenticated",
             level = "FINE")
     private static final String PRINCIPAL_ALREADY_AUTHENTICATED = "AS-WEB-00221";
 
            message = "Checking for SSO cookie",
            level = "FINE")
    private static final String CHECKING_SSO_COOKIE = "AS-WEB-00222";
            message = "SSO cookie is not present",
            level = "FINE")
    private static final String SSO_COOKIE_NOT_PRESENT = "AS-WEB-00223";
            message = "No realm configured for this application, SSO does not apply",
            level = "FINE")
    private static final String NO_REALM_CONFIGURED = "AS-WEB-00224";
            message = "This application uses realm '{0}'",
            level = "FINE")
    private static final String APP_REALM = "AS-WEB-00225";
            message = "Checking for cached principal for {0}",
            level = "FINE")
    private static final String CHECKING_CACHED_PRINCIPAL = "AS-WEB-00226";
            message = "Found cached principal '{0}' with auth type '{1}' in realm '{2}'",
            level = "FINE")
    private static final String FOUND_CACHED_PRINCIPAL = "AS-WEB-00227";
            message = "Ignoring SSO entry which does not match application realm '{0}'",
            level = "FINE")
    private static final String IGNORING_SSO = "AS-WEB-00228";
            message = "No cached principal found, erasing SSO cookie",
            level = "FINE")
    private static final String NO_CACHED_PRINCIPAL_FOUND = "AS-WEB-00229";
            message = "Deregistering sso id '{0}'",
            level = "FINE")
    private static final String DEREGISTER_SSO = "AS-WEB-00230";
            message = "SSO expiration started. Current entries: {0}",
            level = "FINE")
    private static final String SSO_EXPIRATION_STARTED = "AS-WEB-00231";
            message = "SSO cache will expire {0} entries",
            level = "FINE")
    private static final String SSO_CACHE_EXPIRE = "AS-WEB-00232";
            message = "SSO expiration removing entry: {0}",
            level = "FINE")
    private static final String SSO_EXPRIRATION_REMOVING_ENTRY = "AS-WEB-00233";
            message = "Caught exception during SingleSignOn expiration",
            level = "WARNING")
    private static final String EXCEPTION_DURING_SSO_EXPIRATION = "AS-WEB-00234";
            message = "Removing session {0} from sso id {1}",
            level = "FINE")
    private static final String REMOVE_SESSION_FROM_SSO = "AS-WEB-00235";

    
The background thread.
    private Thread thread = null;

    
The background thread completion semaphore.
    private boolean threadDone = false;
        
    
The interval (in seconds) between checks for expired sessions.
    private int ssoReapInterval = 60;

    
Max idle time (in seconds) for SSO entries before being elegible for purging. A value less than zero indicates that SSO entries are supposed to never expire.
    private int ssoMaxInactive = 300;
    //-------------------------------------------------------------- Monitoring
    
    
Number of cache hits
    private AtomicInteger hitCount = new AtomicInteger(0);
    
    
Number of cache misses
    private AtomicInteger missCount = new AtomicInteger(0);
    
    // ------------------------------------------------------------- Properties


    
Return expire thread interval (seconds)
    public int getReapInterval() {
        
        return this.;
        
    }

        
    
Set expire thread interval (seconds)
    public void setReapInterval(int t) {
        this. = t;
    }


    
Return max idle time for SSO entries (seconds)
    public int getMaxInactive() {
        
        return this.;
    }

    
Set max idle time for SSO entries (seconds)
    public void setMaxInactive(int t) {
        this. = t;
    }
    // ------------------------------------------------------ Lifecycle Methods


    
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
    @Override
    public void start() throws LifecycleException {
        // START CR 6411114
        if ()            // Ignore multiple starts
            return;
        // END CR 6411114
        super.start();
        // Start the background reaper thread
        threadStart();
    }


    
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
    @Override
    public void stop() throws LifecycleException {

        
CR 6411114 super.stop();
        // START CR 6411114
        if (!)       // Ignore stop if not started
            return;
        // END CR 6411114
        // Stop the background reaper thread
        threadStop();
        // START CR 6411114
        super.stop();
        // END CR 6411114
    }
    // ------------------------------------------------ SessionListener Methods


    
Acknowledge the occurrence of the specified event.

Parameters:
event SessionEvent that has occurred
    @Override
    public void sessionEvent(SessionEvent event) {
        // We only care about session destroyed events
        if (!..equals(event.getType()))
            return;
        // Look up the single session id associated with this session (if any)
        Session session = event.getSession();
        //S1AS8 6155481 START
        if (.isLoggable(.)) {
            .log(.session);
        }
        //S1AS8 6155481 END
        String ssoId = session.getSsoId();
        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.hasExpired()) {
            removeSession(ssoIdsession);
        } else {
            // The session was logged out.
            // Deregister this single session id, invalidating 
            // associated sessions
            deregister(ssoId);
        }
    }
    // ---------------------------------------------------------- Valve Methods


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

Parameters:
request The servlet request we are processing
response The servlet response we are creating
context The valve context used to invoke the next valve in the current processing pipeline
Throws:
IOException if an input/output error occurs
ServletException if a servlet error occurs

    
IASRI 4665318 public void invoke(Request request, Response response, ValveContext context) throws IOException, ServletException {
    // START OF IASRI 4665318
    @Override
    public int invoke(Request requestResponse response)
        throws IOExceptionServletException {
    // END OF IASRI 4665318
        // If this is not an HTTP request and response, just pass them on
        /* GlassFish 6386229
        if (!(request instanceof HttpRequest) ||
                !(response instanceof HttpResponse)) {
            // START OF IASRI 4665318
            // context.invokeNext(request, response);
            // return;
            return INVOKE_NEXT;
            // END OF IASRI 4665318
        }
        */
        HttpServletRequest hreq = (HttpServletRequestrequest.getRequest();
        HttpServletResponse hres =
                        (HttpServletResponseresponse.getResponse();
        request.removeNote(.);
        request.removeNote(.);
        // Has a valid user already been authenticated?
        //S1AS8 6155481 START
        if (.isLoggable(.)) {
        }
        if (hreq.getUserPrincipal() != null) {
            //S1AS8 6155481 START            
            if (.isLoggable(.)) {
                .log(.hreq.getUserPrincipal().getName());
            }
            // START OF IASRI 4665318
            // context.invokeNext(request, response);
            // return;
            return ;
            // END OF IASRI 4665318
        }
        // Check for the single sign on cookie
        //S1AS8 6155481 START
        if (.isLoggable(.)) {
            .log(.);
        }
        Cookie cookies[] = hreq.getCookies();
        if (cookies == null) {
            return ;
        }
        Cookie cookie = null;
        Cookie versionCookie = null;
        for (Cookie c : cookies) {
            if (..equals(c.getName())) {
                cookie = c;
            } else if (..equals(c.getName())) {
                versionCookie = c;
            }
            if (cookie != null && versionCookie != null) {
                break;
            }
        }
        if (cookie == null) {
            //S1AS8 6155481 START    
            if (.isLoggable(.)) {
                .log(.);
            }
            //S1AS8 6155481 END
            // START OF IASRI 4665318
            // context.invokeNext(request, response);
            // return;
            return ;
            // END OF IASRI 4665318
        }
        // Get the realm associated with the app of this request.
        // If there is no realm available, do not process SSO.
        Realm realm = request.getContext().getRealm();
        if (realm == null) {
            //S1AS8 6155481 START             
            if (.isLoggable(.)) {
                .log(.);
            }
            //S1AS8 6155481 END            
            // START OF IASRI 4665318
            // context.invokeNext(request, response);
            // return;
            return ;
            // END OF IASRI 4665318
        }
         
        String realmName = realm.getRealmName();
        if (realmName == null) {
            //S1AS8 6155481 START             
            if (.isLoggable(.)) {
                .log(.);
            }
            //S1AS8 6155481 END            
            // START OF IASRI 4665318
            // context.invokeNext(request, response);
            // return;
            return ;
            // END OF IASRI 4665318
        }
         
        if ( >= 1) {
            //S1AS8 6155481 START             
            if (.isLoggable(.)) {
                .log(.);
            }
         }
        //S1AS8 6155481 END         
        // Look up the cached Principal associated with this cookie value
        //S1AS8 6155481 START         
        if (.isLoggable(.)) {
            .log(.);
        }
        long version = 0;
        if (isVersioningSupported() && versionCookie != null) {
            version = Long.parseLong(versionCookie.getValue());
        }
        SingleSignOnEntry entry = lookup(cookie.getValue(), version);
        if (entry != null) {
            if (.isLoggable(.)) {
                .log(.,
                        new Object[]{entry.getPrincipal().getName(), entry.getAuthType(), entry.getRealmName()});
            }
            //S1AS8 6155481 END            
            // only use this SSO identity if it was set in the same realm
            if (entry.getRealmName().equals(realmName)) {
                request.setNote(.cookie.getValue());
                ((HttpRequestrequest).setAuthType(entry.getAuthType());
                ((HttpRequestrequest).setUserPrincipal(entry.getPrincipal());
                // Touch the SSO entry access time
                entry.setLastAccessTime(System.currentTimeMillis());
                if (isVersioningSupported()) {
                    long ver = entry.incrementAndGetVersion();
                    request.setNote(.,
                            Long.valueOf(ver));
                }
                // update hit atomic counter
                .incrementAndGet();
            } else {
                //S1AS8 6155481 START                 
                if (.isLoggable(.)) {
                    .log(.realmName);
                }
                // consider this a cache miss, update atomic counter
                .incrementAndGet();
            }
        } else {
            if (.isLoggable(.)) {
                .log(.);
            }
            cookie.setMaxAge(0);
            hres.addCookie(cookie);
            //update miss atomic counter
            .incrementAndGet();
        }
        //S1AS8 6155481 END
        // Invoke the next Valve in our pipeline
        // START OF IASRI 4665318
        // context.invokeNext(request, response);
        // return;
        return ;
        // END OF IASRI 4665318
    }
    // -------------------------------------------------------- Package Methods


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

Parameters:
ssoId Single sign on identifier to deregister
    protected void deregister(String ssoId) {
        //S1AS8 6155481 START        
        if (.isLoggable(.)) {
            .log(.);
        }
        //S1AS8 6155481 END 
        // Look up and remove the corresponding SingleSignOnEntry
        SingleSignOnEntry sso = null;
        synchronized () {
            sso = (SingleSignOnEntry.remove(ssoId);
        }
        if (sso == null)
            return;
        // Expire any associated sessions
        sso.expireSessions();
        // 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 Methods


    
Invalidate all SSO cache entries that have expired.
    private void processExpires() {
        if ( < 0) {
            // SSO entries are supposed to never expire
            return;
        }
        long tooOld = System.currentTimeMillis() -  * 1000L;
        //S1AS8 6155481 START
        if (.isLoggable(.)) {
            .log(..size());
        }
        //S1AS8 6155481 END 
        ArrayList<Stringremovals = new ArrayList<String>(.size()/2);
        
        // build list of removal targets
        // Note that only those SSO entries which are NOT associated with
        // any session are elegible for removal here.
        // Currently no session association ever happens so this covers all
        // SSO entries. However, this should be addressed separately.
        try {
            synchronized () {
                Iterator<Stringit = .keySet().iterator();
                while (it.hasNext()) {
                    String key = it.next();
                    SingleSignOnEntry sso = (SingleSignOnEntry.get(key);
                    if (sso.isEmpty() && sso.getLastAccessTime() < tooOld) {
                        removals.add(key);
                    }
                }
            }
            int removalCount = removals.size();
            //S1AS8 6155481 START            
            if (.isLoggable(.)) {
                .log(.removalCount);
            }
            //S1AS8 6155481 END
            // deregister any elegible sso entries
            for (int i=0; i < removalCounti++) {
                //S1AS8 6155481 START                
                if (.isLoggable(.)) {
                    .log(.removals.get(i));
                }
                deregister(removals.get(i));
            }
            //S1AS8 6155481 END
        } catch (Throwable e) { // don't let thread die
        }
    }


    
Sleep for the duration specified by the ssoReapInterval property.
    private void threadSleep() {
        try {
            Thread.sleep( * 1000L);
        } catch (InterruptedException e) {
            ;
        }
    }

        
   
Start the background thread that will periodically check for SSO timeouts.
    private void threadStart() {
        if ( != null)
            return;
         = false;
        String threadName = "SingleSignOnExpiration";
         = new Thread(thisthreadName);
        .setDaemon(true);
        .start();
    }


    
Stop the background thread that is periodically checking for SSO timeouts.
    private void threadStop() {
        if ( == null)
            return;
         = true;
        .interrupt();
        try {
            .join();
        } catch (InterruptedException e) {
            ;
        }
         = null;
    }
    // ------------------------------------------------------ Background Thread


    
The background thread that checks for SSO timeouts and shutdown.
    public void run() {
        // Loop until the termination semaphore is set
        while (!) {
            threadSleep();
            processExpires();
        }
    }
        
    
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) {
        if (.isLoggable(.)) {
            .log(.new Object[]{session.toString(), ssoId});
        }
        // Get a reference to the SingleSignOn
        SingleSignOnEntry entry = lookup(ssoId);
        if (entry == null)
            return;
        // Remove the inactive session from SingleSignOnEntry
        entry.removeSession(session);
        // If there are not sessions left in the SingleSignOnEntry,
        // deregister the entry.
        if (entry.isEmpty()) {
            deregister(ssoId);
        }
    }
    
    //-------------------------------------------------- Monitoring Support
    
    
Gets the number of sessions participating in SSO

Returns:
Number of sessions participating in SSO
    public int getActiveSessionCount() {
        return .size();
    }

    
    
Gets the number of SSO cache hits

Returns:
Number of SSO cache hits
    public int getHitCount() {
        return .intValue();
    }

    
    
Gets the number of SSO cache misses

Returns:
Number of SSO cache misses
    public int getMissCount() {
        return .intValue();
    }
New to GrepCode? Check out our FAQ X