📄 singlesignon.java
字号:
/*
* 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 java.io.IOException;
import java.security.Principal;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import org.apache.catalina.Lifecycle;
import org.apache.catalina.LifecycleException;
import org.apache.catalina.LifecycleListener;
import org.apache.catalina.Realm;
import org.apache.catalina.Session;
import org.apache.catalina.SessionEvent;
import org.apache.catalina.SessionListener;
import org.apache.catalina.connector.Request;
import org.apache.catalina.connector.Response;
import org.apache.catalina.util.LifecycleSupport;
import org.apache.catalina.util.StringManager;
import org.apache.catalina.valves.ValveBase;
/**
* A <strong>Valve</strong> 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:
* <ul>
* <li>This Valve must be configured on the Container that represents a
* virtual host (typically an implementation of <code>Host</code>).</li>
* <li>The <code>Realm</code> 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.</li>
* <li>The web applications themselves must use one of the standard
* Authenticators found in the
* <code>org.apache.catalina.authenticator</code> package.</li>
* </ul>
*
* @author Craig R. McClanahan
* @version $Revision: 500629 $ $Date: 2007-01-27 22:32:52 +0100 (sam., 27 janv. 2007) $
*/
public class SingleSignOn
extends ValveBase
implements Lifecycle, SessionListener {
// ----------------------------------------------------- Instance Variables
/**
* The cache of SingleSignOnEntry instances for authenticated Principals,
* keyed by the cookie value that is used to select them.
*/
protected Map cache = new HashMap();
/**
* 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.
*/
private boolean requireReauthentication = false;
/**
* The cache of single sign on identifiers, keyed by the Session that is
* associated with them.
*/
protected Map reverse = new HashMap();
/**
* The string manager for this package.
*/
protected final static StringManager sm =
StringManager.getManager(Constants.Package);
/**
* Component started flag.
*/
protected boolean started = false;
/**
* Optional SSO cookie domain.
*/
private String cookieDomain;
// ------------------------------------------------------------- Properties
/**
* Returns the optional cookie domain.
* May return null.
*
* @return The cookie domain
*/
public String getCookieDomain() {
return cookieDomain;
}
/**
* Sets the domain to be used for sso cookies.
*
* @param cookieDomain cookie domain name
*/
public void setCookieDomain(String cookieDomain) {
if (cookieDomain != null && cookieDomain.trim().length() == 0) {
cookieDomain = null;
}
this.cookieDomain = cookieDomain;
}
/**
* Gets whether each request needs to be reauthenticated (by an
* Authenticator downstream in the pipeline) to the security
* <code>Realm</code>, 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 <code>Realm</code..
*
* @return <code>true</code> if it is required that a downstream
* Authenticator reauthenticate each request before calls to
* <code>HttpServletRequest.setUserPrincipal()</code>
* and <code>HttpServletRequest.setAuthType()</code> are made;
* <code>false</code> if the <code>Valve</code> can itself make
* those calls relying on the presence of a valid SingleSignOn
* entry associated with the request.
*
* @see #setRequireReauthentication
*/
public boolean getRequireReauthentication()
{
return requireReauthentication;
}
/**
* Sets whether each request needs to be reauthenticated (by an
* Authenticator downstream in the pipeline) to the security
* <code>Realm</code>, 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 <code>Realm</code.
* <p>
* If this property is <code>false</code> (the default), this
* <code>Valve</code> 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 <code>Realm</code> of the incoming request.
* <p>
* This property should be set to <code>true</code> if the overall server
* configuration requires that the <code>Realm</code> reauthenticate each
* request thread. An example of such a configuration would be one where
* the <code>Realm</code> 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.
* <p>
* If this property is set to <code>true</code>, 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
* {@link AuthenticatorBase#reauthenticateFromSSO reauthenticateFromSSO}
* method to attempt to reauthenticate the request to the
* <code>Realm</code>, using any credentials that were cached with this
* Valve.
* <p>
* The default value of this property is <code>false</code>, in order
* to maintain backward compatibility with previous versions of Tomcat.
*
* @param required <code>true</code> if it is required that a downstream
* Authenticator reauthenticate each request before calls
* to <code>HttpServletRequest.setUserPrincipal()</code>
* and <code>HttpServletRequest.setAuthType()</code> are
* made; <code>false</code> if the <code>Valve</code> can
* itself make those calls relying on the presence of a
* valid SingleSignOn entry associated with the request.
*
* @see AuthenticatorBase#reauthenticateFromSSO
*/
public void setRequireReauthentication(boolean required)
{
this.requireReauthentication = required;
}
// ------------------------------------------------------ Lifecycle Methods
/**
* Add a lifecycle event listener to this component.
*
* @param listener The listener to add
*/
public void addLifecycleListener(LifecycleListener listener) {
lifecycle.addLifecycleListener(listener);
}
/**
* Get the lifecycle listeners associated with this lifecycle. If this
* Lifecycle has no listeners registered, a zero-length array is returned.
*/
public LifecycleListener[] findLifecycleListeners() {
return lifecycle.findLifecycleListeners();
}
/**
* Remove a lifecycle event listener from this component.
*
* @param listener The listener to remove
*/
public void removeLifecycleListener(LifecycleListener listener) {
lifecycle.removeLifecycleListener(listener);
}
/**
* Prepare for the beginning of active use of the public methods of this
* component. This method should be called after <code>configure()</code>,
* and before any of the public methods of the component are utilized.
*
* @exception 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 (started)
throw new LifecycleException
(sm.getString("authenticator.alreadyStarted"));
lifecycle.fireLifecycleEvent(START_EVENT, null);
started = 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.
*
* @exception 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 (!started)
throw new LifecycleException
(sm.getString("authenticator.notStarted"));
lifecycle.fireLifecycleEvent(STOP_EVENT, null);
started = false;
}
// ------------------------------------------------ SessionListener Methods
/**
* Acknowledge the occurrence of the specified event.
*
* @param event SessionEvent that has occurred
*/
public void sessionEvent(SessionEvent event) {
// We only care about session destroyed events
if (!Session.SESSION_DESTROYED_EVENT.equals(event.getType())
&& (!Session.SESSION_PASSIVATED_EVENT.equals(event.getType())))
return;
// Look up the single session id associated with this session (if any)
Session session = event.getSession();
if (containerLog.isDebugEnabled())
containerLog.debug("Process session destroyed on " + session);
String ssoId = null;
synchronized (reverse) {
ssoId = (String) reverse.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))
|| (Session.SESSION_PASSIVATED_EVENT.equals(event.getType()))) {
removeSession(ssoId, session);
} 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 (info);
}
/**
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -