Fields Summary |
---|
protected Map | cacheThe cache of SingleSignOnEntry instances for authenticated Principals,
keyed by the cookie value that is used to select them. |
protected static String | infoDescriptive information about this Valve implementation. |
protected org.apache.catalina.util.LifecycleSupport | lifecycleThe lifecycle event support for this component. |
private boolean | requireReauthenticationIndicates 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 Map | reverseThe cache of single sign on identifiers, keyed by the Session that is
associated with them. |
protected static final org.apache.catalina.util.StringManager | smThe string manager for this package. |
protected boolean | startedComponent started flag. |
private String | cookieDomainOptional SSO cookie domain. |
Methods Summary |
---|
public void | addLifecycleListener(org.apache.catalina.LifecycleListener listener)Add a lifecycle event listener to this component.
lifecycle.addLifecycleListener(listener);
|
protected void | associate(java.lang.String ssoId, org.apache.catalina.Session session)Associate the specified single sign on identifier with the
specified Session.
if (containerLog.isDebugEnabled())
containerLog.debug("Associate sso id " + ssoId + " with session " + session);
SingleSignOnEntry sso = lookup(ssoId);
if (sso != null)
sso.addSession(this, session);
synchronized (reverse) {
reverse.put(session, ssoId);
}
|
protected void | deregister(java.lang.String ssoId, org.apache.catalina.Session session)Deregister the specified session. If it is the last session,
then also get rid of the single sign on identifier
synchronized (reverse) {
reverse.remove(session);
}
SingleSignOnEntry sso = lookup(ssoId);
if ( sso == null )
return;
sso.removeSession( session );
// see if we are the last session, if so blow away ssoId
Session sessions[] = sso.findSessions();
if ( sessions == null || sessions.length == 0 ) {
synchronized (cache) {
sso = (SingleSignOnEntry) cache.remove(ssoId);
}
}
|
protected void | deregister(java.lang.String ssoId)Deregister the specified single sign on identifier, and invalidate
any associated sessions.
if (containerLog.isDebugEnabled())
containerLog.debug("Deregistering sso id '" + ssoId + "'");
// Look up and remove the corresponding SingleSignOnEntry
SingleSignOnEntry sso = null;
synchronized (cache) {
sso = (SingleSignOnEntry) cache.remove(ssoId);
}
if (sso == null)
return;
// Expire any associated sessions
Session sessions[] = sso.findSessions();
for (int i = 0; i < sessions.length; i++) {
if (containerLog.isTraceEnabled())
containerLog.trace(" Invalidating session " + sessions[i]);
// Remove from reverse cache first to avoid recursion
synchronized (reverse) {
reverse.remove(sessions[i]);
}
// Invalidate this session
sessions[i].expire();
}
// 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
|
public org.apache.catalina.LifecycleListener[] | findLifecycleListeners()Get the lifecycle listeners associated with this lifecycle. If this
Lifecycle has no listeners registered, a zero-length array is returned.
return lifecycle.findLifecycleListeners();
|
public java.lang.String | getCookieDomain()Returns the optional cookie domain.
May return null.
// ------------------------------------------------------------- Properties
return cookieDomain;
|
public java.lang.String | getInfo()Return descriptive information about this Valve implementation.
return (info);
|
public boolean | getRequireReauthentication()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
return requireReauthentication;
|
public void | invoke(org.apache.catalina.connector.Request request, org.apache.catalina.connector.Response response)Perform single-sign-on support processing for this request.
request.removeNote(Constants.REQ_SSOID_NOTE);
// Has a valid user already been authenticated?
if (containerLog.isDebugEnabled())
containerLog.debug("Process request for '" + request.getRequestURI() + "'");
if (request.getUserPrincipal() != null) {
if (containerLog.isDebugEnabled())
containerLog.debug(" Principal '" + request.getUserPrincipal().getName() +
"' has already been authenticated");
getNext().invoke(request, response);
return;
}
// Check for the single sign on cookie
if (containerLog.isDebugEnabled())
containerLog.debug(" Checking for SSO cookie");
Cookie cookie = null;
Cookie cookies[] = request.getCookies();
if (cookies == null)
cookies = new Cookie[0];
for (int i = 0; i < cookies.length; i++) {
if (Constants.SINGLE_SIGN_ON_COOKIE.equals(cookies[i].getName())) {
cookie = cookies[i];
break;
}
}
if (cookie == null) {
if (containerLog.isDebugEnabled())
containerLog.debug(" SSO cookie is not present");
getNext().invoke(request, response);
return;
}
// Look up the cached Principal associated with this cookie value
if (containerLog.isDebugEnabled())
containerLog.debug(" Checking for cached principal for " + cookie.getValue());
SingleSignOnEntry entry = lookup(cookie.getValue());
if (entry != null) {
if (containerLog.isDebugEnabled())
containerLog.debug(" Found cached principal '" +
(entry.getPrincipal() != null ? entry.getPrincipal().getName() : "") + "' with auth type '" +
entry.getAuthType() + "'");
request.setNote(Constants.REQ_SSOID_NOTE, cookie.getValue());
// Only set security elements if reauthentication is not required
if (!getRequireReauthentication()) {
request.setAuthType(entry.getAuthType());
request.setUserPrincipal(entry.getPrincipal());
}
} else {
if (containerLog.isDebugEnabled())
containerLog.debug(" No cached principal found, erasing SSO cookie");
cookie.setMaxAge(0);
response.addCookie(cookie);
}
// Invoke the next Valve in our pipeline
getNext().invoke(request, response);
|
protected SingleSignOnEntry | lookup(java.lang.String ssoId)Look up and return the cached SingleSignOn entry associated with this
sso id value, if there is one; otherwise return null .
synchronized (cache) {
return ((SingleSignOnEntry) cache.get(ssoId));
}
|
protected boolean | reauthenticate(java.lang.String ssoId, org.apache.catalina.Realm realm, org.apache.catalina.connector.Request request)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
{@link Request#setAuthType Request.setAuthType()} and
{@link Request#setUserPrincipal Request.setUserPrincipal()}
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(username, entry.getPassword());
if (reauthPrincipal != null) {
reauthenticated = true;
// Bind the authorization credentials to the request
request.setAuthType(entry.getAuthType());
request.setUserPrincipal(reauthPrincipal);
}
}
}
return reauthenticated;
|
protected void | register(java.lang.String ssoId, java.security.Principal principal, java.lang.String authType, java.lang.String username, java.lang.String password)Register the specified Principal as being associated with the specified
value for the single sign on identifier.
if (containerLog.isDebugEnabled())
containerLog.debug("Registering sso id '" + ssoId + "' for user '" +
(principal != null ? principal.getName() : "") + "' with auth type '" + authType + "'");
synchronized (cache) {
cache.put(ssoId, new SingleSignOnEntry(principal, authType,
username, password));
}
|
public void | removeLifecycleListener(org.apache.catalina.LifecycleListener listener)Remove a lifecycle event listener from this component.
lifecycle.removeLifecycleListener(listener);
|
protected void | removeSession(java.lang.String ssoId, org.apache.catalina.Session session)Remove a single Session from a SingleSignOn. Called when
a session is timed out and no longer active.
if (containerLog.isDebugEnabled())
containerLog.debug("Removing session " + session.toString() + " from sso id " +
ssoId );
// 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(reverse) {
reverse.remove(session);
}
// If there are not sessions left in the SingleSignOnEntry,
// deregister the entry.
if (entry.findSessions().length == 0) {
deregister(ssoId);
}
|
public void | sessionEvent(org.apache.catalina.SessionEvent event)Acknowledge the occurrence of the specified 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);
}
|
public void | setCookieDomain(java.lang.String cookieDomain)Sets the domain to be used for sso cookies.
if (cookieDomain != null && cookieDomain.trim().length() == 0) {
cookieDomain = null;
}
this.cookieDomain = cookieDomain;
|
public void | setRequireReauthentication(boolean required)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
{@link AuthenticatorBase#reauthenticateFromSSO 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.
this.requireReauthentication = required;
|
public void | start()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.
// Validate and update our current component state
if (started)
throw new LifecycleException
(sm.getString("authenticator.alreadyStarted"));
lifecycle.fireLifecycleEvent(START_EVENT, null);
started = true;
|
public void | stop()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.
// Validate and update our current component state
if (!started)
throw new LifecycleException
(sm.getString("authenticator.notStarted"));
lifecycle.fireLifecycleEvent(STOP_EVENT, null);
started = false;
|
public java.lang.String | toString()Return a String rendering of this object.
StringBuffer sb = new StringBuffer("SingleSignOn[");
if (container == null )
sb.append("Container is null");
else
sb.append(container.getName());
sb.append("]");
return (sb.toString());
|
protected void | update(java.lang.String ssoId, java.security.Principal principal, java.lang.String authType, java.lang.String username, java.lang.String password)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.
SingleSignOnEntry sso = lookup(ssoId);
if (sso != null && !sso.getCanReauthenticate()) {
if (containerLog.isDebugEnabled())
containerLog.debug("Update sso id " + ssoId + " to auth type " + authType);
synchronized(sso) {
sso.updateCredentials(principal, authType, username, password);
}
}
|