blob: c18e187dc1a308250360d305d47ebd13e378522e [file] [log] [blame]
// Copyright 2011 Google Inc.
//
// Licensed 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 com.google.enterprise.secmgr.authncontroller;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableCollection;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Maps;
import com.google.enterprise.secmgr.common.GCookie;
import com.google.enterprise.secmgr.common.SecurityManagerUtil;
import com.google.enterprise.secmgr.common.SessionUtil;
import com.google.enterprise.secmgr.config.AuthnMechanism;
import com.google.enterprise.secmgr.config.CredentialGroup;
import com.google.enterprise.secmgr.config.SecurityManagerConfig;
import com.google.enterprise.secmgr.identity.Verification;
import org.joda.time.DateTimeUtils;
import org.joda.time.format.ISODateTimeFormat;
import java.net.URL;
import java.util.Map;
import javax.annotation.CheckReturnValue;
import javax.annotation.Nonnegative;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.annotation.ParametersAreNonnullByDefault;
import javax.annotation.concurrent.GuardedBy;
import javax.annotation.concurrent.Immutable;
/**
* An immutable snapshot of the session's state.
*/
@Immutable
@ParametersAreNonnullByDefault
public final class SessionSnapshot {
@Nonnull private final String sessionId;
@Nonnull private final SecurityManagerConfig config;
@Nullable private final URL authnEntryUrl;
@Nonnull private final ImmutableCollection<GCookie> userAgentCookies;
@Nonnull private final AuthnSessionState state;
@Nonnegative private final long timeStamp;
@Nonnull private final SessionView unspecializedView;
@GuardedBy("itself")
@Nonnull private final Map<AuthnMechanism, SessionView> savedMechanismViews;
@GuardedBy("itself")
@Nonnull private final Map<CredentialGroup, SessionView> savedCredentialGroupViews;
private SessionSnapshot(String sessionId, SecurityManagerConfig config,
@Nullable URL authnEntryUrl, ImmutableCollection<GCookie> userAgentCookies,
AuthnSessionState state, @Nonnegative long timeStamp) {
this.sessionId = sessionId;
this.config = config;
this.authnEntryUrl = authnEntryUrl;
this.userAgentCookies = userAgentCookies;
this.state = state;
this.timeStamp = timeStamp;
unspecializedView = SessionView.create(this);
savedMechanismViews = Maps.newHashMap();
savedCredentialGroupViews = Maps.newHashMap();
}
static SessionSnapshot make(String sessionId, SecurityManagerConfig config,
@Nullable URL authnEntryUrl, ImmutableCollection<GCookie> userAgentCookies,
AuthnSessionState state) {
return new SessionSnapshot(sessionId, config, authnEntryUrl, userAgentCookies,
state, DateTimeUtils.currentTimeMillis());
}
@VisibleForTesting
public static SessionSnapshot make(SecurityManagerConfig config, AuthnSessionState state) {
return make(SessionUtil.generateId(), config, null, ImmutableList.<GCookie>of(), state);
}
SessionSnapshot withNewUserAgentCookies(ImmutableCollection<GCookie> userAgentCookies) {
return new SessionSnapshot(sessionId, config, authnEntryUrl, userAgentCookies,
state, timeStamp);
}
@CheckReturnValue
@Nonnull
public String getSessionId() {
return sessionId;
}
@CheckReturnValue
@Nonnull
public SecurityManagerConfig getConfig() {
return config;
}
@CheckReturnValue
@Nullable
URL getAuthnEntryUrl() {
return authnEntryUrl;
}
@CheckReturnValue
@Nonnull
ImmutableCollection<GCookie> getUserAgentCookies() {
return userAgentCookies;
}
@CheckReturnValue
@Nonnull
public AuthnSessionState getState() {
return state;
}
@CheckReturnValue
@Nonnegative
long getTimeStamp() {
return timeStamp;
}
/**
* Gets a view of this snapshot specialized for a given authentication
* mechanism.
*
* @param mechanism An authentication mechanism.
* @return A mechanism view of this snapshot.
*/
@CheckReturnValue
@Nonnull
public SessionView getView(AuthnMechanism mechanism) {
synchronized (savedMechanismViews) {
SessionView view = savedMechanismViews.get(mechanism);
if (view == null) {
view = SessionView.create(this, mechanism);
savedMechanismViews.put(mechanism, view);
}
return view;
}
}
/**
* Gets a view of this snapshot specialized for a given credential group.
*
* @param credentialGroup A credential group.
* @return A credential-group view of this snapshot.
*/
@CheckReturnValue
@Nonnull
public SessionView getView(CredentialGroup credentialGroup) {
synchronized (savedCredentialGroupViews) {
SessionView view = savedCredentialGroupViews.get(credentialGroup);
if (view == null) {
view = SessionView.create(this, credentialGroup);
savedCredentialGroupViews.put(credentialGroup, view);
}
return view;
}
}
/**
* Gets an unspecialized view of this snapshot.
*
* @return An unspecialized view of this snapshot.
*/
@CheckReturnValue
@Nonnull
public SessionView getView() {
return unspecializedView;
}
/**
* Gets the expiration time for this snapshot.
*
* @return The expiration time.
*/
@CheckReturnValue
public long getExpirationTime() {
SessionView view = getView();
return view.isSatisfied()
? Verification.minimumExpirationTime(view.getVerifications())
: timeStamp;
}
/**
* Get a "primary verified view". This is a view containing a principal
* that's been verified, with preference given to the default credential
* group's view, if possible.
*
* <p>The primary verified view is intended for use by the GSA, and this
* method is only called when generating output for the GSA. It should
* <b>never</b> be used for any other purpose.
*
* @return The primary verified view, or null if there isn't one.
*/
public SessionView getPrimaryVerifiedView() {
SessionView winner = null;
for (CredentialGroup credentialGroup : getConfig().getCredentialGroups()) {
SessionView view = getView(credentialGroup);
if (view.hasVerifiedPrincipal()) {
if (credentialGroup.isDefault()) {
return view;
}
if (winner == null) {
winner = view;
}
}
}
return winner;
}
@CheckReturnValue
@Nonnull
public String logMessage(String format, Object... args) {
return SecurityManagerUtil.sessionLogMessage(sessionId, String.format(format, args));
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("{SessionSnapshot taken at ");
builder.append(ISODateTimeFormat.dateTime().print(timeStamp));
builder.append(" of session ");
builder.append(sessionId);
builder.append("}");
return builder.toString();
}
}