Remove AuthMethod and add access token to RestApi

Authentication for API calls will be handled using an access token
in the "Authorization: OAuth access_token" style. Browsers do not
use this when making requests unless they use an XmlHttpRequest.
If the value used as the access_token is not available cross-site
then the API call cannot be made by hijacking attempts.

Change-Id: I33654bcaa247cb95a57b03d2df112ca95e970185
This commit is contained in:
Shawn O. Pearce
2012-11-12 12:38:30 -08:00
parent e649d848dc
commit bbeb2a96e4
22 changed files with 88 additions and 146 deletions

View File

@@ -23,7 +23,7 @@ import java.util.List;
public class HostPageData { public class HostPageData {
public Account account; public Account account;
public AccountDiffPreference accountDiffPref; public AccountDiffPreference accountDiffPref;
public String xsrfToken; public String accessToken;
public GerritConfig config; public GerritConfig config;
public Theme theme; public Theme theme;
public List<String> plugins; public List<String> plugins;

View File

@@ -93,7 +93,7 @@ public class Gerrit implements EntryPoint {
private static HostPageData.Theme myTheme; private static HostPageData.Theme myTheme;
private static Account myAccount; private static Account myAccount;
private static AccountDiffPreference myAccountDiffPref; private static AccountDiffPreference myAccountDiffPref;
private static String xsrfToken; private static String accessToken;
private static MorphingTabPanel menuLeft; private static MorphingTabPanel menuLeft;
private static LinkMenuBar menuRight; private static LinkMenuBar menuRight;
@@ -239,6 +239,11 @@ public class Gerrit implements EntryPoint {
return myAccount; return myAccount;
} }
/** @return access token to prove user identity during REST API calls. */
public static String getAccessToken() {
return accessToken;
}
/** @return the currently signed in users's diff preferences; null if no diff preferences defined for the account */ /** @return the currently signed in users's diff preferences; null if no diff preferences defined for the account */
public static AccountDiffPreference getAccountDiffPreference() { public static AccountDiffPreference getAccountDiffPreference() {
return myAccountDiffPref; return myAccountDiffPref;
@@ -333,7 +338,7 @@ public class Gerrit implements EntryPoint {
static void deleteSessionCookie() { static void deleteSessionCookie() {
myAccount = null; myAccount = null;
myAccountDiffPref = null; myAccountDiffPref = null;
xsrfToken = null; accessToken = null;
refreshMenuBar(); refreshMenuBar();
// If the cookie was HttpOnly, this request to delete it will // If the cookie was HttpOnly, this request to delete it will
@@ -383,7 +388,7 @@ public class Gerrit implements EntryPoint {
myTheme = result.theme; myTheme = result.theme;
if (result.account != null) { if (result.account != null) {
myAccount = result.account; myAccount = result.account;
xsrfToken = result.xsrfToken; accessToken = result.accessToken;
} }
if (result.accountDiffPref != null) { if (result.accountDiffPref != null) {
myAccountDiffPref = result.accountDiffPref; myAccountDiffPref = result.accountDiffPref;
@@ -530,7 +535,7 @@ public class Gerrit implements EntryPoint {
JsonUtil.setDefaultXsrfManager(new XsrfManager() { JsonUtil.setDefaultXsrfManager(new XsrfManager() {
@Override @Override
public String getToken(JsonDefTarget proxy) { public String getToken(JsonDefTarget proxy) {
return xsrfToken; return accessToken;
} }
@Override @Override

View File

@@ -14,6 +14,7 @@
package com.google.gerrit.client.rpc; package com.google.gerrit.client.rpc;
import com.google.gerrit.client.Gerrit;
import com.google.gerrit.client.RpcStatus; import com.google.gerrit.client.RpcStatus;
import com.google.gwt.core.client.GWT; import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.JavaScriptObject; import com.google.gwt.core.client.JavaScriptObject;
@@ -161,6 +162,9 @@ public class RestApi {
public <T extends JavaScriptObject> void send(final AsyncCallback<T> cb) { public <T extends JavaScriptObject> void send(final AsyncCallback<T> cb) {
RequestBuilder req = new RequestBuilder(RequestBuilder.GET, url.toString()); RequestBuilder req = new RequestBuilder(RequestBuilder.GET, url.toString());
req.setHeader("Accept", JsonConstants.JSON_TYPE); req.setHeader("Accept", JsonConstants.JSON_TYPE);
if (Gerrit.getAccessToken() != null) {
req.setHeader("Authorization", "OAuth " + Gerrit.getAccessToken());
}
req.setCallback(new MyRequestCallback<T>(cb)); req.setCallback(new MyRequestCallback<T>(cb));
try { try {
RpcStatus.INSTANCE.onRpcStart(); RpcStatus.INSTANCE.onRpcStart();

View File

@@ -25,7 +25,6 @@ import com.google.gerrit.server.AccessPath;
import com.google.gerrit.server.AnonymousUser; import com.google.gerrit.server.AnonymousUser;
import com.google.gerrit.server.CurrentUser; import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.IdentifiedUser; import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.account.AuthMethod;
import com.google.gerrit.server.account.AuthResult; import com.google.gerrit.server.account.AuthResult;
import com.google.gerrit.server.cache.CacheModule; import com.google.gerrit.server.cache.CacheModule;
import com.google.gerrit.server.config.AuthConfig; import com.google.gerrit.server.config.AuthConfig;
@@ -34,6 +33,8 @@ import com.google.inject.Module;
import com.google.inject.Provider; import com.google.inject.Provider;
import com.google.inject.servlet.RequestScoped; import com.google.inject.servlet.RequestScoped;
import org.eclipse.jgit.http.server.GitSmartHttpTools;
import javax.servlet.http.Cookie; import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
@@ -65,9 +66,8 @@ public final class CacheBasedWebSession implements WebSession {
private final AuthConfig authConfig; private final AuthConfig authConfig;
private final Provider<AnonymousUser> anonymousProvider; private final Provider<AnonymousUser> anonymousProvider;
private final IdentifiedUser.RequestFactory identified; private final IdentifiedUser.RequestFactory identified;
private AccessPath accessPath = AccessPath.WEB_UI; private AccessPath accessPath;
private Cookie outCookie; private Cookie outCookie;
private AuthMethod authMethod;
private Key key; private Key key;
private Val val; private Val val;
@@ -85,7 +85,17 @@ public final class CacheBasedWebSession implements WebSession {
this.anonymousProvider = anonymousProvider; this.anonymousProvider = anonymousProvider;
this.identified = identified; this.identified = identified;
final String cookie = readCookie(); String cookie = request.getHeader("Authorization");
if (cookie != null && cookie.startsWith("OAuth ")) {
cookie = cookie.substring("OAuth ".length());
accessPath = AccessPath.REST_API;
} else if (cookie != null && GitSmartHttpTools.isGitClient(request)) {
accessPath = AccessPath.GIT;
} else {
cookie = readCookie();
accessPath = AccessPath.WEB_BROWSER;
}
if (cookie != null) { if (cookie != null) {
key = new Key(cookie); key = new Key(cookie);
val = manager.get(key); val = manager.get(key);
@@ -93,7 +103,6 @@ public final class CacheBasedWebSession implements WebSession {
key = null; key = null;
val = null; val = null;
} }
authMethod = isSignedIn() ? AuthMethod.COOKIE : AuthMethod.NONE;
if (isSignedIn() && val.needsCookieRefresh()) { if (isSignedIn() && val.needsCookieRefresh()) {
// Cookie is more than half old. Send the cookie again to the // Cookie is more than half old. Send the cookie again to the
@@ -124,14 +133,8 @@ public final class CacheBasedWebSession implements WebSession {
return val != null; return val != null;
} }
public String getToken() { public String getAccessToken() {
return isSignedIn() ? val.getXsrfToken() : null; return isSignedIn() ? key.getToken() : null;
}
public boolean isTokenValid(final String inputToken) {
return isSignedIn() //
&& val.getXsrfToken() != null //
&& val.getXsrfToken().equals(inputToken);
} }
public AccountExternalId.Key getLastLoginExternalId() { public AccountExternalId.Key getLastLoginExternalId() {
@@ -145,8 +148,7 @@ public final class CacheBasedWebSession implements WebSession {
return anonymousProvider.get(); return anonymousProvider.get();
} }
public void login(final AuthResult res, final AuthMethod meth, public void login(final AuthResult res, final boolean rememberMe) {
final boolean rememberMe) {
final Account.Id id = res.getAccountId(); final Account.Id id = res.getAccountId();
final AccountExternalId.Key identity = res.getExternalId(); final AccountExternalId.Key identity = res.getExternalId();
@@ -155,22 +157,14 @@ public final class CacheBasedWebSession implements WebSession {
} }
key = manager.createKey(id); key = manager.createKey(id);
val = manager.createVal(key, id, rememberMe, identity, null); val = manager.createVal(key, id, rememberMe, identity);
saveCookie(); saveCookie();
authMethod = meth;
}
/** Change the access path from the default of {@link AccessPath#WEB_UI}. */
public void setAccessPath(AccessPath path) {
accessPath = path;
} }
/** Set the user account for this current request only. */ /** Set the user account for this current request only. */
public void setUserAccountId(Account.Id id, AuthMethod method) { public void setUserAccountId(Account.Id id) {
key = new Key("id:" + id); key = new Key("id:" + id);
val = new Val(id, 0, false, null, "", 0); val = new Val(id, 0, false, null, 0);
authMethod = method;
} }
public void logout() { public void logout() {
@@ -217,8 +211,4 @@ public final class CacheBasedWebSession implements WebSession {
private static boolean isSecure(final HttpServletRequest req) { private static boolean isSecure(final HttpServletRequest req) {
return req.isSecure() || "https".equals(req.getScheme()); return req.isSecure() || "https".equals(req.getScheme());
} }
public AuthMethod getAuthMethod() {
return authMethod;
}
} }

View File

@@ -19,7 +19,6 @@ import static javax.servlet.http.HttpServletResponse.SC_UNAUTHORIZED;
import com.google.gerrit.server.account.AccountCache; import com.google.gerrit.server.account.AccountCache;
import com.google.gerrit.server.account.AccountState; import com.google.gerrit.server.account.AccountState;
import com.google.gerrit.server.account.AuthMethod;
import com.google.gerrit.server.config.GerritServerConfig; import com.google.gerrit.server.config.GerritServerConfig;
import com.google.inject.Inject; import com.google.inject.Inject;
import com.google.inject.Provider; import com.google.inject.Provider;
@@ -100,9 +99,7 @@ class ContainerAuthFilter implements Filter {
rsp.sendError(SC_UNAUTHORIZED); rsp.sendError(SC_UNAUTHORIZED);
return false; return false;
} }
session.get().setUserAccountId( session.get().setUserAccountId(who.getAccount().getId());
who.getAccount().getId(),
AuthMethod.PASSWORD);
return true; return true;
} }
} }

View File

@@ -18,7 +18,6 @@ import com.google.common.cache.Cache;
import com.google.gerrit.common.data.Capable; import com.google.gerrit.common.data.Capable;
import com.google.gerrit.reviewdb.client.Project; import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.reviewdb.server.ReviewDb; import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.AccessPath;
import com.google.gerrit.server.AnonymousUser; import com.google.gerrit.server.AnonymousUser;
import com.google.gerrit.server.IdentifiedUser; import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.cache.CacheModule; import com.google.gerrit.server.cache.CacheModule;
@@ -178,12 +177,10 @@ public class GitOverHttpServlet extends GitServlet {
static class UploadFactory implements UploadPackFactory<HttpServletRequest> { static class UploadFactory implements UploadPackFactory<HttpServletRequest> {
private final TransferConfig config; private final TransferConfig config;
private final Provider<WebSession> session;
@Inject @Inject
UploadFactory(TransferConfig tc, Provider<WebSession> session) { UploadFactory(TransferConfig tc) {
this.config = tc; this.config = tc;
this.session = session;
} }
@Override @Override
@@ -191,7 +188,6 @@ public class GitOverHttpServlet extends GitServlet {
UploadPack up = new UploadPack(repo); UploadPack up = new UploadPack(repo);
up.setPackConfig(config.getPackConfig()); up.setPackConfig(config.getPackConfig());
up.setTimeout(config.getTimeout()); up.setTimeout(config.getTimeout());
session.get().setAccessPath(AccessPath.GIT);
return up; return up;
} }
} }
@@ -241,14 +237,11 @@ public class GitOverHttpServlet extends GitServlet {
static class ReceiveFactory implements ReceivePackFactory<HttpServletRequest> { static class ReceiveFactory implements ReceivePackFactory<HttpServletRequest> {
private final AsyncReceiveCommits.Factory factory; private final AsyncReceiveCommits.Factory factory;
private final Provider<WebSession> session;
private final TransferConfig config; private final TransferConfig config;
@Inject @Inject
ReceiveFactory(AsyncReceiveCommits.Factory factory, ReceiveFactory(AsyncReceiveCommits.Factory factory, TransferConfig config) {
Provider<WebSession> session, TransferConfig config) {
this.factory = factory; this.factory = factory;
this.session = session;
this.config = config; this.config = config;
} }
@@ -269,7 +262,6 @@ public class GitOverHttpServlet extends GitServlet {
rp.setTimeout(config.getTimeout()); rp.setTimeout(config.getTimeout());
rp.setMaxObjectSizeLimit(config.getMaxObjectSizeLimit()); rp.setMaxObjectSizeLimit(config.getMaxObjectSizeLimit());
req.setAttribute(ATT_RC, rc); req.setAttribute(ATT_RC, rc);
session.get().setAccessPath(AccessPath.GIT);
return rp; return rp;
} }
} }

View File

@@ -77,7 +77,7 @@ class HttpLogoutServlet extends HttpServlet {
protected void doGet(final HttpServletRequest req, protected void doGet(final HttpServletRequest req,
final HttpServletResponse rsp) throws IOException { final HttpServletResponse rsp) throws IOException {
final String sid = webSession.get().getToken(); final String sid = webSession.get().getAccessToken();
final CurrentUser currentUser = webSession.get().getCurrentUser(); final CurrentUser currentUser = webSession.get().getCurrentUser();
final String what = "sign out"; final String what = "sign out";
final long when = System.currentTimeMillis(); final long when = System.currentTimeMillis();

View File

@@ -22,7 +22,6 @@ import com.google.gerrit.server.account.AccountCache;
import com.google.gerrit.server.account.AccountException; import com.google.gerrit.server.account.AccountException;
import com.google.gerrit.server.account.AccountManager; import com.google.gerrit.server.account.AccountManager;
import com.google.gerrit.server.account.AccountState; import com.google.gerrit.server.account.AccountState;
import com.google.gerrit.server.account.AuthMethod;
import com.google.gerrit.server.account.AuthRequest; import com.google.gerrit.server.account.AuthRequest;
import com.google.gerrit.server.account.AuthResult; import com.google.gerrit.server.account.AuthResult;
import com.google.gerrit.server.config.AuthConfig; import com.google.gerrit.server.config.AuthConfig;
@@ -143,8 +142,7 @@ class ProjectBasicAuthFilter implements Filter {
try { try {
AuthResult whoAuthResult = accountManager.authenticate(whoAuth); AuthResult whoAuthResult = accountManager.authenticate(whoAuth);
session.get().setUserAccountId(whoAuthResult.getAccountId(), session.get().setUserAccountId(whoAuthResult.getAccountId());
AuthMethod.PASSWORD);
return true; return true;
} catch (AccountException e) { } catch (AccountException e) {
log.warn("Authentication failed for " + username, e); log.warn("Authentication failed for " + username, e);

View File

@@ -22,7 +22,6 @@ import static javax.servlet.http.HttpServletResponse.SC_UNAUTHORIZED;
import com.google.gerrit.server.account.AccountCache; import com.google.gerrit.server.account.AccountCache;
import com.google.gerrit.server.account.AccountState; import com.google.gerrit.server.account.AccountState;
import com.google.gerrit.server.account.AuthMethod;
import com.google.gerrit.server.config.CanonicalWebUrl; import com.google.gerrit.server.config.CanonicalWebUrl;
import com.google.gerrit.server.config.GerritServerConfig; import com.google.gerrit.server.config.GerritServerConfig;
import com.google.gwtjsonrpc.server.SignedToken; import com.google.gwtjsonrpc.server.SignedToken;
@@ -165,9 +164,7 @@ class ProjectDigestFilter implements Filter {
if (expect.equals(response)) { if (expect.equals(response)) {
try { try {
if (tokens.checkToken(nonce, "") != null) { if (tokens.checkToken(nonce, "") != null) {
session.get().setUserAccountId( session.get().setUserAccountId(who.getAccount().getId());
who.getAccount().getId(),
AuthMethod.PASSWORD);
return true; return true;
} else { } else {

View File

@@ -20,6 +20,8 @@ import static javax.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
import com.google.common.base.Objects; import com.google.common.base.Objects;
import com.google.common.base.Strings; import com.google.common.base.Strings;
import com.google.gerrit.extensions.annotations.RequiresCapability; import com.google.gerrit.extensions.annotations.RequiresCapability;
import com.google.gerrit.server.AccessPath;
import com.google.gerrit.server.AnonymousUser;
import com.google.gerrit.server.CurrentUser; import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.IdentifiedUser; import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.account.CapabilityControl; import com.google.gerrit.server.account.CapabilityControl;
@@ -90,8 +92,11 @@ public abstract class RestApiServlet extends HttpServlet {
res.setHeader("Content-Disposition", "attachment"); res.setHeader("Content-Disposition", "attachment");
try { try {
checkUserSession(req);
checkRequiresCapability(); checkRequiresCapability();
super.service(req, res); super.service(req, res);
} catch (InvalidAuthException err) {
sendError(res, SC_FORBIDDEN, err.getMessage());
} catch (RequireCapabilityException err) { } catch (RequireCapabilityException err) {
sendError(res, SC_FORBIDDEN, err.getMessage()); sendError(res, SC_FORBIDDEN, err.getMessage());
} catch (Error err) { } catch (Error err) {
@@ -101,6 +106,18 @@ public abstract class RestApiServlet extends HttpServlet {
} }
} }
private void checkUserSession(HttpServletRequest req)
throws InvalidAuthException {
CurrentUser user = currentUser.get();
if (user instanceof AnonymousUser) {
if (!"GET".equals(req.getMethod())) {
throw new InvalidAuthException("Authentication required");
}
} else if (user.getAccessPath() != AccessPath.REST_API) {
throw new InvalidAuthException("Invalid authentication method");
}
}
private void checkRequiresCapability() throws RequireCapabilityException { private void checkRequiresCapability() throws RequireCapabilityException {
RequiresCapability rc = getClass().getAnnotation(RequiresCapability.class); RequiresCapability rc = getClass().getAnnotation(RequiresCapability.class);
if (rc != null) { if (rc != null) {
@@ -229,4 +246,11 @@ public abstract class RestApiServlet extends HttpServlet {
super(msg); super(msg);
} }
} }
@SuppressWarnings("serial") // Never serialized or thrown out of this class.
private static class InvalidAuthException extends Exception {
public InvalidAuthException(String msg) {
super(msg);
}
}
} }

View File

@@ -16,31 +16,22 @@ package com.google.gerrit.httpd;
import com.google.gerrit.reviewdb.client.Account; import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.AccountExternalId; import com.google.gerrit.reviewdb.client.AccountExternalId;
import com.google.gerrit.server.AccessPath;
import com.google.gerrit.server.CurrentUser; import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.account.AuthMethod;
import com.google.gerrit.server.account.AuthResult; import com.google.gerrit.server.account.AuthResult;
public interface WebSession { public interface WebSession {
public AuthMethod getAuthMethod();
public boolean isSignedIn(); public boolean isSignedIn();
public String getToken(); public String getAccessToken();
public boolean isTokenValid(String inputToken);
public AccountExternalId.Key getLastLoginExternalId(); public AccountExternalId.Key getLastLoginExternalId();
public CurrentUser getCurrentUser(); public CurrentUser getCurrentUser();
public void login(AuthResult res, AuthMethod meth, boolean rememberMe); public void login(AuthResult res, boolean rememberMe);
/** Change the access path from the default of {@link AccessPath#WEB_UI}. */
public void setAccessPath(AccessPath path);
/** Set the user account for this current request only. */ /** Set the user account for this current request only. */
public void setUserAccountId(Account.Id id, AuthMethod method); public void setUserAccountId(Account.Id id);
public void logout(); public void logout();
} }

View File

@@ -90,13 +90,11 @@ class WebSessionManager {
final Account.Id who = val.getAccountId(); final Account.Id who = val.getAccountId();
final boolean remember = val.isPersistentCookie(); final boolean remember = val.isPersistentCookie();
final AccountExternalId.Key lastLogin = val.getExternalId(); 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, Val createVal(final Key key, final Account.Id who, final boolean remember,
final AccountExternalId.Key lastLogin, String xsrfToken) { final AccountExternalId.Key lastLogin) {
// Refresh the cookie every hour or when it is half-expired. // Refresh the cookie every hour or when it is half-expired.
// This reduces the odds that the user session will be kicked // This reduces the odds that the user session will be kicked
// early but also avoids us needing to refresh the cookie on // early but also avoids us needing to refresh the cookie on
@@ -109,17 +107,7 @@ class WebSessionManager {
final long refreshCookieAt = now + refresh; final long refreshCookieAt = now + refresh;
final long expiresAt = now + sessionMaxAgeMillis; final long expiresAt = now + sessionMaxAgeMillis;
if (xsrfToken == null) { Val val = new Val(who, refreshCookieAt, remember, lastLogin, expiresAt);
// 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, expiresAt);
self.put(key.token, val); self.put(key.token, val);
return val; return val;
} }
@@ -182,18 +170,15 @@ class WebSessionManager {
private transient long refreshCookieAt; private transient long refreshCookieAt;
private transient boolean persistentCookie; private transient boolean persistentCookie;
private transient AccountExternalId.Key externalId; private transient AccountExternalId.Key externalId;
private transient String xsrfToken;
private transient long expiresAt; private transient long expiresAt;
Val(final Account.Id accountId, final long refreshCookieAt, 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,
final long expiresAt) { final long expiresAt) {
this.accountId = accountId; this.accountId = accountId;
this.refreshCookieAt = refreshCookieAt; this.refreshCookieAt = refreshCookieAt;
this.persistentCookie = persistentCookie; this.persistentCookie = persistentCookie;
this.externalId = externalId; this.externalId = externalId;
this.xsrfToken = xsrfToken;
this.expiresAt = expiresAt; this.expiresAt = expiresAt;
} }
@@ -213,10 +198,6 @@ class WebSessionManager {
return persistentCookie; return persistentCookie;
} }
String getXsrfToken() {
return xsrfToken;
}
private void writeObject(final ObjectOutputStream out) throws IOException { private void writeObject(final ObjectOutputStream out) throws IOException {
writeVarInt32(out, 1); writeVarInt32(out, 1);
writeVarInt32(out, accountId.get()); writeVarInt32(out, accountId.get());
@@ -232,9 +213,6 @@ class WebSessionManager {
writeString(out, externalId.get()); writeString(out, externalId.get());
} }
writeVarInt32(out, 5);
writeString(out, xsrfToken);
writeVarInt32(out, 6); writeVarInt32(out, 6);
writeFixInt64(out, expiresAt); writeFixInt64(out, expiresAt);
@@ -260,7 +238,7 @@ class WebSessionManager {
externalId = new AccountExternalId.Key(readString(in)); externalId = new AccountExternalId.Key(readString(in));
continue; continue;
case 5: case 5:
xsrfToken = readString(in); readString(in);
continue; continue;
case 6: case 6:
expiresAt = readFixInt64(in); expiresAt = readFixInt64(in);

View File

@@ -24,7 +24,6 @@ import com.google.gerrit.reviewdb.client.AccountExternalId;
import com.google.gerrit.reviewdb.server.ReviewDb; import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.account.AccountException; import com.google.gerrit.server.account.AccountException;
import com.google.gerrit.server.account.AccountManager; import com.google.gerrit.server.account.AccountManager;
import com.google.gerrit.server.account.AuthMethod;
import com.google.gerrit.server.account.AuthRequest; import com.google.gerrit.server.account.AuthRequest;
import com.google.gerrit.server.account.AuthResult; import com.google.gerrit.server.account.AuthResult;
import com.google.gwtorm.server.OrmException; import com.google.gwtorm.server.OrmException;
@@ -114,7 +113,7 @@ public class BecomeAnyAccountLoginServlet extends HttpServlet {
} }
if (res != null) { if (res != null) {
webSession.get().login(res, AuthMethod.BACKDOOR, false); webSession.get().login(res, false);
final StringBuilder rdr = new StringBuilder(); final StringBuilder rdr = new StringBuilder();
rdr.append(req.getContextPath()); rdr.append(req.getContextPath());
if (IS_DEV && req.getParameter("gwt.codesvr") != null) { if (IS_DEV && req.getParameter("gwt.codesvr") != null) {

View File

@@ -19,7 +19,6 @@ import com.google.gerrit.httpd.HtmlDomUtil;
import com.google.gerrit.httpd.WebSession; import com.google.gerrit.httpd.WebSession;
import com.google.gerrit.server.account.AccountException; import com.google.gerrit.server.account.AccountException;
import com.google.gerrit.server.account.AccountManager; import com.google.gerrit.server.account.AccountManager;
import com.google.gerrit.server.account.AuthMethod;
import com.google.gerrit.server.account.AuthRequest; import com.google.gerrit.server.account.AuthRequest;
import com.google.gerrit.server.account.AuthResult; import com.google.gerrit.server.account.AuthResult;
import com.google.gerrit.server.config.AuthConfig; import com.google.gerrit.server.config.AuthConfig;
@@ -136,8 +135,7 @@ class HttpLoginServlet extends HttpServlet {
} }
rdr.append(token); rdr.append(token);
webSession.get().login(arsp, AuthMethod.COOKIE, webSession.get().login(arsp, true /* persistent cookie */);
true /* persistent cookie */);
rsp.sendRedirect(rdr.toString()); rsp.sendRedirect(rdr.toString());
} }

View File

@@ -17,7 +17,6 @@ package com.google.gerrit.httpd.auth.container;
import com.google.gerrit.httpd.WebSession; import com.google.gerrit.httpd.WebSession;
import com.google.gerrit.server.account.AccountException; import com.google.gerrit.server.account.AccountException;
import com.google.gerrit.server.account.AccountManager; import com.google.gerrit.server.account.AccountManager;
import com.google.gerrit.server.account.AuthMethod;
import com.google.gerrit.server.account.AuthRequest; import com.google.gerrit.server.account.AuthRequest;
import com.google.gerrit.server.account.AuthResult; import com.google.gerrit.server.account.AuthResult;
import com.google.inject.Inject; import com.google.inject.Inject;
@@ -85,7 +84,7 @@ class HttpsClientSslCertAuthFilter implements Filter {
log.error(err, e); log.error(err, e);
throw new ServletException(err, e); throw new ServletException(err, e);
} }
webSession.get().login(arsp, AuthMethod.COOKIE, true); webSession.get().login(arsp, true);
chain.doFilter(req, rsp); chain.doFilter(req, rsp);
} }

View File

@@ -21,7 +21,6 @@ import com.google.gerrit.reviewdb.client.AuthType;
import com.google.gerrit.server.account.AccountException; import com.google.gerrit.server.account.AccountException;
import com.google.gerrit.server.account.AccountManager; import com.google.gerrit.server.account.AccountManager;
import com.google.gerrit.server.account.AccountUserNameException; import com.google.gerrit.server.account.AccountUserNameException;
import com.google.gerrit.server.account.AuthMethod;
import com.google.gerrit.server.account.AuthRequest; import com.google.gerrit.server.account.AuthRequest;
import com.google.gerrit.server.account.AuthResult; import com.google.gerrit.server.account.AuthResult;
import com.google.gerrit.server.auth.AuthenticationUnavailableException; import com.google.gerrit.server.auth.AuthenticationUnavailableException;
@@ -87,8 +86,7 @@ class UserPassAuthServiceImpl implements UserPassAuthService {
result.success = true; result.success = true;
result.isNew = res.isNew(); result.isNew = res.isNew();
webSession.get().login(res, AuthMethod.PASSWORD, webSession.get().login(res, true /* persistent cookie */);
true /* persistent cookie */);
callback.onSuccess(result); callback.onSuccess(result);
} }
} }

View File

@@ -178,8 +178,8 @@ public class HostPageServlet extends HttpServlet {
json(((IdentifiedUser) user).getAccount(), w); json(((IdentifiedUser) user).getAccount(), w);
w.write(";"); w.write(";");
w.write(HPD_ID + ".xsrfToken="); w.write(HPD_ID + ".accessToken=");
json(session.get().getToken(), w); json(session.get().getAccessToken(), w);
w.write(";"); w.write(";");
w.write(HPD_ID + ".accountDiffPref="); w.write(HPD_ID + ".accountDiffPref=");

View File

@@ -131,7 +131,7 @@ final class GerritJsonServlet extends JsonServlet<GerritJsonServlet.GerritCall>
} }
Audit note = (Audit) method.getAnnotation(Audit.class); Audit note = (Audit) method.getAnnotation(Audit.class);
if (note != null) { if (note != null) {
final String sid = call.getWebSession().getToken(); final String sid = call.getWebSession().getAccessToken();
final CurrentUser username = call.getWebSession().getCurrentUser(); final CurrentUser username = call.getWebSession().getCurrentUser();
final List<Object> args = final List<Object> args =
extractParams(note, call); extractParams(note, call);
@@ -249,7 +249,7 @@ final class GerritJsonServlet extends JsonServlet<GerritJsonServlet.GerritCall>
} else { } else {
// The session must exist, and must be using this token. // The session must exist, and must be using this token.
// //
return session.isSignedIn() && session.isTokenValid(keyIn); return session.isSignedIn() && keyIn.equals(session.getAccessToken());
} }
} }

View File

@@ -26,7 +26,6 @@ import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.UrlEncoded; import com.google.gerrit.server.UrlEncoded;
import com.google.gerrit.server.account.AccountException; import com.google.gerrit.server.account.AccountException;
import com.google.gerrit.server.account.AccountManager; import com.google.gerrit.server.account.AccountManager;
import com.google.gerrit.server.account.AuthMethod;
import com.google.gerrit.server.config.AuthConfig; import com.google.gerrit.server.config.AuthConfig;
import com.google.gerrit.server.config.CanonicalWebUrl; import com.google.gerrit.server.config.CanonicalWebUrl;
import com.google.gerrit.server.config.ConfigUtil; import com.google.gerrit.server.config.ConfigUtil;
@@ -417,7 +416,7 @@ class OpenIdServiceImpl implements OpenIdService {
lastId.setMaxAge(0); lastId.setMaxAge(0);
} }
rsp.addCookie(lastId); rsp.addCookie(lastId);
webSession.get().login(arsp, AuthMethod.COOKIE, remember); webSession.get().login(arsp, remember);
if (arsp.isNew() && claimedIdentifier != null) { if (arsp.isNew() && claimedIdentifier != null) {
final com.google.gerrit.server.account.AuthRequest linkReq = final com.google.gerrit.server.account.AuthRequest linkReq =
new com.google.gerrit.server.account.AuthRequest( new com.google.gerrit.server.account.AuthRequest(
@@ -431,7 +430,7 @@ class OpenIdServiceImpl implements OpenIdService {
case LINK_IDENTIY: { case LINK_IDENTIY: {
arsp = accountManager.link(identifiedUser.get().getAccountId(), areq); arsp = accountManager.link(identifiedUser.get().getAccountId(), areq);
webSession.get().login(arsp, AuthMethod.COOKIE, remember); webSession.get().login(arsp, remember);
callback(false, req, rsp); callback(false, req, rsp);
break; break;
} }

View File

@@ -19,8 +19,11 @@ public enum AccessPath {
/** An unknown access path, probably should not be special. */ /** An unknown access path, probably should not be special. */
UNKNOWN, UNKNOWN,
/** Access through the web UI. */ /** Access through the REST API. */
WEB_UI, REST_API,
/** Access by a web cookie. This path is not protected like REST_API. */
WEB_BROWSER,
/** Access through an SSH command that is not invoked by Git. */ /** Access through an SSH command that is not invoked by Git. */
SSH_COMMAND, SSH_COMMAND,

View File

@@ -1,30 +0,0 @@
// Copyright (C) 2012 The Android Open Source Project
//
// 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.gerrit.server.account;
/** Method by which a user has authenticated for a given request. */
public enum AuthMethod {
/** The user is not authenticated */
NONE,
/** The user is authenticated via a cookie. */
COOKIE,
/** The user authenticated with a password for this request. */
PASSWORD,
/** The user has used a credentialess development feature to login. */
BACKDOOR;
}

View File

@@ -218,7 +218,7 @@ public class RefControl {
} }
boolean owner; boolean owner;
switch (getCurrentUser().getAccessPath()) { switch (getCurrentUser().getAccessPath()) {
case WEB_UI: case REST_API:
owner = isOwner(); owner = isOwner();
break; break;
@@ -285,7 +285,7 @@ public class RefControl {
} }
switch (getCurrentUser().getAccessPath()) { switch (getCurrentUser().getAccessPath()) {
case WEB_UI: case REST_API:
return isOwner() || canPushWithForce(); return isOwner() || canPushWithForce();
case GIT: case GIT: