summaryrefslogtreecommitdiffstats
path: root/gerrit-httpd/src/main/java/com/google/gerrit/httpd/WebSessionManager.java
diff options
context:
space:
mode:
Diffstat (limited to 'gerrit-httpd/src/main/java/com/google/gerrit/httpd/WebSessionManager.java')
-rw-r--r--gerrit-httpd/src/main/java/com/google/gerrit/httpd/WebSessionManager.java54
1 files changed, 44 insertions, 10 deletions
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/WebSessionManager.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/WebSessionManager.java
index 43c99adc8e..55d0ca58df 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/WebSessionManager.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/WebSessionManager.java
@@ -14,6 +14,7 @@
package com.google.gerrit.httpd;
+import static com.google.gerrit.httpd.CacheBasedWebSession.MAX_AGE_MINUTES;
import static com.google.gerrit.server.ioutil.BasicSerialization.readFixInt64;
import static com.google.gerrit.server.ioutil.BasicSerialization.readString;
import static com.google.gerrit.server.ioutil.BasicSerialization.readVarInt32;
@@ -23,15 +24,19 @@ import static com.google.gerrit.server.ioutil.BasicSerialization.writeString;
import static com.google.gerrit.server.ioutil.BasicSerialization.writeVarInt32;
import static java.util.concurrent.TimeUnit.HOURS;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
-import static java.util.concurrent.TimeUnit.SECONDS;
+import static java.util.concurrent.TimeUnit.MINUTES;
-import com.google.gerrit.reviewdb.Account;
-import com.google.gerrit.reviewdb.AccountExternalId;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.AccountExternalId;
import com.google.gerrit.server.cache.Cache;
+import com.google.gerrit.server.config.ConfigUtil;
+import com.google.gerrit.server.config.GerritServerConfig;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import com.google.inject.name.Named;
+import org.eclipse.jgit.lib.Config;
+
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
@@ -47,13 +52,19 @@ class WebSessionManager {
return System.currentTimeMillis();
}
+ private final long sessionMaxAgeMillis;
private final SecureRandom prng;
private final Cache<Key, Val> self;
@Inject
- WebSessionManager(@Named(CACHE_NAME) final Cache<Key, Val> cache) {
+ WebSessionManager(@GerritServerConfig Config cfg,
+ @Named(CACHE_NAME) final Cache<Key, Val> cache) {
prng = new SecureRandom();
self = cache;
+
+ sessionMaxAgeMillis = MINUTES.toMillis(ConfigUtil.getTimeUnit(cfg,
+ "cache", CACHE_NAME, "maxAge",
+ MAX_AGE_MINUTES, MINUTES));
}
Key createKey(final Account.Id who) {
@@ -78,23 +89,33 @@ class WebSessionManager {
final Account.Id who = val.getAccountId();
final boolean remember = val.isPersistentCookie();
final AccountExternalId.Key lastLogin = val.getExternalId();
+ final String xsrfToken = val.getXsrfToken();
- return createVal(key, who, remember, lastLogin);
+ return createVal(key, who, remember, lastLogin, xsrfToken);
}
Val createVal(final Key key, final Account.Id who, final boolean remember,
- final AccountExternalId.Key lastLogin) {
+ final AccountExternalId.Key lastLogin, String xsrfToken) {
// Refresh the cookie every hour or when it is half-expired.
// This reduces the odds that the user session will be kicked
// early but also avoids us needing to refresh the cookie on
// every single request.
//
- final long halfAgeRefresh = self.getTimeToLive(MILLISECONDS) >>> 1;
+ final long halfAgeRefresh = sessionMaxAgeMillis >>> 1;
final long minRefresh = MILLISECONDS.convert(1, HOURS);
final long refresh = Math.min(halfAgeRefresh, minRefresh);
final long refreshCookieAt = now() + refresh;
- final Val val = new Val(who, refreshCookieAt, remember, lastLogin);
+ if (xsrfToken == null) {
+ // If we don't yet have a token for this session, establish one.
+ //
+ final int nonceLen = 20;
+ final byte[] rnd = new byte[nonceLen];
+ prng.nextBytes(rnd);
+ xsrfToken = CookieBase64.encode(rnd);
+ }
+
+ Val val = new Val(who, refreshCookieAt, remember, lastLogin, xsrfToken);
self.put(key, val);
return val;
}
@@ -104,7 +125,7 @@ class WebSessionManager {
// Client may store the cookie until we would remove it from our
// own cache, after which it will certainly be invalid.
//
- return (int) self.getTimeToLive(SECONDS);
+ return (int) MILLISECONDS.toSeconds(sessionMaxAgeMillis);
} else {
// Client should not store the cookie, as the user asked for us
// to not remember them long-term. Sending -1 as the age will
@@ -162,13 +183,16 @@ class WebSessionManager {
private transient long refreshCookieAt;
private transient boolean persistentCookie;
private transient AccountExternalId.Key externalId;
+ private transient String xsrfToken;
Val(final Account.Id accountId, final long refreshCookieAt,
- final boolean persistentCookie, final AccountExternalId.Key externalId) {
+ final boolean persistentCookie, final AccountExternalId.Key externalId,
+ final String xsrfToken) {
this.accountId = accountId;
this.refreshCookieAt = refreshCookieAt;
this.persistentCookie = persistentCookie;
this.externalId = externalId;
+ this.xsrfToken = xsrfToken;
}
Account.Id getAccountId() {
@@ -187,6 +211,10 @@ class WebSessionManager {
return persistentCookie;
}
+ String getXsrfToken() {
+ return xsrfToken;
+ }
+
private void writeObject(final ObjectOutputStream out) throws IOException {
writeVarInt32(out, 1);
writeVarInt32(out, accountId.get());
@@ -202,6 +230,9 @@ class WebSessionManager {
writeString(out, externalId.get());
}
+ writeVarInt32(out, 5);
+ writeString(out, xsrfToken);
+
writeVarInt32(out, 0);
}
@@ -223,6 +254,9 @@ class WebSessionManager {
case 4:
externalId = new AccountExternalId.Key(readString(in));
continue;
+ case 5:
+ xsrfToken = readString(in);
+ continue;
default:
throw new IOException("Unknown tag found in object: " + tag);
}