Merge branch 'stable-2.14' into stable-2.15
* stable-2.14: Deny access over HTTP for disabled accounts Bazel: Consistently use bazelisk during publishing of artifacts Change-Id: I16c6c00e61ef39cc27f40da1ac1822e419eb2f2c
This commit is contained in:
@@ -56,6 +56,7 @@ import com.google.gerrit.common.Nullable;
|
|||||||
import com.google.gerrit.common.TimeUtil;
|
import com.google.gerrit.common.TimeUtil;
|
||||||
import com.google.gerrit.common.data.GlobalCapability;
|
import com.google.gerrit.common.data.GlobalCapability;
|
||||||
import com.google.gerrit.common.data.Permission;
|
import com.google.gerrit.common.data.Permission;
|
||||||
|
import com.google.gerrit.extensions.api.accounts.AccountApi;
|
||||||
import com.google.gerrit.extensions.api.accounts.AccountInput;
|
import com.google.gerrit.extensions.api.accounts.AccountInput;
|
||||||
import com.google.gerrit.extensions.api.accounts.EmailInput;
|
import com.google.gerrit.extensions.api.accounts.EmailInput;
|
||||||
import com.google.gerrit.extensions.api.changes.AddReviewerInput;
|
import com.google.gerrit.extensions.api.changes.AddReviewerInput;
|
||||||
@@ -81,6 +82,7 @@ import com.google.gerrit.extensions.restapi.RestApiException;
|
|||||||
import com.google.gerrit.gpg.Fingerprint;
|
import com.google.gerrit.gpg.Fingerprint;
|
||||||
import com.google.gerrit.gpg.PublicKeyStore;
|
import com.google.gerrit.gpg.PublicKeyStore;
|
||||||
import com.google.gerrit.gpg.testutil.TestKey;
|
import com.google.gerrit.gpg.testutil.TestKey;
|
||||||
|
import com.google.gerrit.httpd.CacheBasedWebSession;
|
||||||
import com.google.gerrit.reviewdb.client.Account;
|
import com.google.gerrit.reviewdb.client.Account;
|
||||||
import com.google.gerrit.reviewdb.client.AccountGroup;
|
import com.google.gerrit.reviewdb.client.AccountGroup;
|
||||||
import com.google.gerrit.reviewdb.client.Change;
|
import com.google.gerrit.reviewdb.client.Change;
|
||||||
@@ -123,6 +125,14 @@ import java.util.Locale;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import org.apache.http.HttpResponse;
|
||||||
|
import org.apache.http.client.ClientProtocolException;
|
||||||
|
import org.apache.http.client.methods.HttpGet;
|
||||||
|
import org.apache.http.impl.client.BasicCookieStore;
|
||||||
|
import org.apache.http.impl.client.CloseableHttpClient;
|
||||||
|
import org.apache.http.impl.client.HttpClientBuilder;
|
||||||
import org.bouncycastle.bcpg.ArmoredOutputStream;
|
import org.bouncycastle.bcpg.ArmoredOutputStream;
|
||||||
import org.bouncycastle.openpgp.PGPPublicKey;
|
import org.bouncycastle.openpgp.PGPPublicKey;
|
||||||
import org.bouncycastle.openpgp.PGPPublicKeyRing;
|
import org.bouncycastle.openpgp.PGPPublicKeyRing;
|
||||||
@@ -181,6 +191,8 @@ public class AccountIT extends AbstractDaemonTest {
|
|||||||
private RegistrationHandle refUpdateCounterHandle;
|
private RegistrationHandle refUpdateCounterHandle;
|
||||||
private ExternalIdsUpdate externalIdsUpdate;
|
private ExternalIdsUpdate externalIdsUpdate;
|
||||||
private List<ExternalId> savedExternalIds;
|
private List<ExternalId> savedExternalIds;
|
||||||
|
private BasicCookieStore httpCookieStore;
|
||||||
|
private CloseableHttpClient httpclient;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void addAccountIndexEventCounter() {
|
public void addAccountIndexEventCounter() {
|
||||||
@@ -217,6 +229,16 @@ public class AccountIT extends AbstractDaemonTest {
|
|||||||
savedExternalIds.addAll(externalIds.byAccount(user.id));
|
savedExternalIds.addAll(externalIds.byAccount(user.id));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void createHttpClient() {
|
||||||
|
httpCookieStore = new BasicCookieStore();
|
||||||
|
httpclient =
|
||||||
|
HttpClientBuilder.create()
|
||||||
|
.disableRedirectHandling()
|
||||||
|
.setDefaultCookieStore(httpCookieStore)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
public void restoreExternalIds() throws Exception {
|
public void restoreExternalIds() throws Exception {
|
||||||
if (savedExternalIds != null) {
|
if (savedExternalIds != null) {
|
||||||
@@ -411,6 +433,43 @@ public class AccountIT extends AbstractDaemonTest {
|
|||||||
accountIndexedCounter.assertReindexOf(user);
|
accountIndexedCounter.assertReindexOf(user);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@GerritConfig(name = "auth.type", value = "DEVELOPMENT_BECOME_ANY_ACCOUNT")
|
||||||
|
public void activeUserGetSessionCookieOnLogin() throws Exception {
|
||||||
|
Integer accountId = accountIdApi().get()._accountId;
|
||||||
|
assertThat(accountIdApi().getActive()).isTrue();
|
||||||
|
|
||||||
|
webLogin(accountId);
|
||||||
|
assertThat(getCookiesNames()).contains(CacheBasedWebSession.ACCOUNT_COOKIE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@GerritConfig(name = "auth.type", value = "DEVELOPMENT_BECOME_ANY_ACCOUNT")
|
||||||
|
public void inactiveUserDoesNotGetCookieOnLogin() throws Exception {
|
||||||
|
Integer accountId = accountIdApi().get()._accountId;
|
||||||
|
accountIdApi().setActive(false);
|
||||||
|
assertThat(accountIdApi().getActive()).isFalse();
|
||||||
|
|
||||||
|
webLogin(accountId);
|
||||||
|
assertThat(getCookiesNames()).isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@GerritConfig(name = "auth.type", value = "DEVELOPMENT_BECOME_ANY_ACCOUNT")
|
||||||
|
public void userDeactivatedAfterLoginDoesNotGetCookie() throws Exception {
|
||||||
|
Integer accountId = accountIdApi().get()._accountId;
|
||||||
|
assertThat(accountIdApi().getActive()).isTrue();
|
||||||
|
|
||||||
|
webLogin(accountId);
|
||||||
|
assertThat(getCookiesNames()).contains(CacheBasedWebSession.ACCOUNT_COOKIE);
|
||||||
|
httpGetAndAssertStatus("accounts/self/detail", HttpServletResponse.SC_OK);
|
||||||
|
|
||||||
|
accountIdApi().setActive(false);
|
||||||
|
assertThat(accountIdApi().getActive()).isFalse();
|
||||||
|
|
||||||
|
httpGetAndAssertStatus("accounts/self/detail", HttpServletResponse.SC_FORBIDDEN);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void deactivateSelf() throws Exception {
|
public void deactivateSelf() throws Exception {
|
||||||
exception.expect(ResourceConflictException.class);
|
exception.expect(ResourceConflictException.class);
|
||||||
@@ -2371,4 +2430,28 @@ public class AccountIT extends AbstractDaemonTest {
|
|||||||
clear();
|
clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private AccountApi accountIdApi() throws RestApiException {
|
||||||
|
return gApi.accounts().id("user");
|
||||||
|
}
|
||||||
|
|
||||||
|
private Set<String> getCookiesNames() {
|
||||||
|
Set<String> cookieNames =
|
||||||
|
httpCookieStore.getCookies().stream()
|
||||||
|
.map(cookie -> cookie.getName())
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
return cookieNames;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void webLogin(Integer accountId) throws IOException, ClientProtocolException {
|
||||||
|
httpGetAndAssertStatus(
|
||||||
|
"login?account_id=" + accountId, HttpServletResponse.SC_MOVED_TEMPORARILY);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void httpGetAndAssertStatus(String urlPath, int expectedHttpStatus)
|
||||||
|
throws ClientProtocolException, IOException {
|
||||||
|
HttpGet httpGet = new HttpGet(canonicalWebUrl.get() + urlPath);
|
||||||
|
HttpResponse loginResponse = httpclient.execute(httpGet);
|
||||||
|
assertThat(loginResponse.getStatusLine().getStatusCode()).isEqualTo(expectedHttpStatus);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ package com.google.gerrit.httpd;
|
|||||||
|
|
||||||
import static java.util.concurrent.TimeUnit.HOURS;
|
import static java.util.concurrent.TimeUnit.HOURS;
|
||||||
|
|
||||||
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
import com.google.common.base.Strings;
|
import com.google.common.base.Strings;
|
||||||
import com.google.gerrit.common.Nullable;
|
import com.google.gerrit.common.Nullable;
|
||||||
import com.google.gerrit.common.data.HostPageData;
|
import com.google.gerrit.common.data.HostPageData;
|
||||||
@@ -28,6 +29,8 @@ 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.AccountCache;
|
||||||
|
import com.google.gerrit.server.account.AccountState;
|
||||||
import com.google.gerrit.server.account.AuthResult;
|
import com.google.gerrit.server.account.AuthResult;
|
||||||
import com.google.gerrit.server.account.externalids.ExternalId;
|
import com.google.gerrit.server.account.externalids.ExternalId;
|
||||||
import com.google.gerrit.server.config.AuthConfig;
|
import com.google.gerrit.server.config.AuthConfig;
|
||||||
@@ -41,7 +44,7 @@ import org.eclipse.jgit.http.server.GitSmartHttpTools;
|
|||||||
|
|
||||||
@RequestScoped
|
@RequestScoped
|
||||||
public abstract class CacheBasedWebSession implements WebSession {
|
public abstract class CacheBasedWebSession implements WebSession {
|
||||||
private static final String ACCOUNT_COOKIE = "GerritAccount";
|
@VisibleForTesting public static final String ACCOUNT_COOKIE = "GerritAccount";
|
||||||
protected static final long MAX_AGE_MINUTES = HOURS.toMinutes(12);
|
protected static final long MAX_AGE_MINUTES = HOURS.toMinutes(12);
|
||||||
|
|
||||||
private final HttpServletRequest request;
|
private final HttpServletRequest request;
|
||||||
@@ -51,6 +54,7 @@ public abstract class CacheBasedWebSession implements WebSession {
|
|||||||
private final Provider<AnonymousUser> anonymousProvider;
|
private final Provider<AnonymousUser> anonymousProvider;
|
||||||
private final IdentifiedUser.RequestFactory identified;
|
private final IdentifiedUser.RequestFactory identified;
|
||||||
private final EnumSet<AccessPath> okPaths = EnumSet.of(AccessPath.UNKNOWN);
|
private final EnumSet<AccessPath> okPaths = EnumSet.of(AccessPath.UNKNOWN);
|
||||||
|
private final AccountCache byIdCache;
|
||||||
private Cookie outCookie;
|
private Cookie outCookie;
|
||||||
|
|
||||||
private Key key;
|
private Key key;
|
||||||
@@ -63,13 +67,15 @@ public abstract class CacheBasedWebSession implements WebSession {
|
|||||||
WebSessionManager manager,
|
WebSessionManager manager,
|
||||||
AuthConfig authConfig,
|
AuthConfig authConfig,
|
||||||
Provider<AnonymousUser> anonymousProvider,
|
Provider<AnonymousUser> anonymousProvider,
|
||||||
IdentifiedUser.RequestFactory identified) {
|
IdentifiedUser.RequestFactory identified,
|
||||||
|
final AccountCache byIdCache) {
|
||||||
this.request = request;
|
this.request = request;
|
||||||
this.response = response;
|
this.response = response;
|
||||||
this.manager = manager;
|
this.manager = manager;
|
||||||
this.authConfig = authConfig;
|
this.authConfig = authConfig;
|
||||||
this.anonymousProvider = anonymousProvider;
|
this.anonymousProvider = anonymousProvider;
|
||||||
this.identified = identified;
|
this.identified = identified;
|
||||||
|
this.byIdCache = byIdCache;
|
||||||
|
|
||||||
if (request.getRequestURI() == null || !GitSmartHttpTools.isGitClient(request)) {
|
if (request.getRequestURI() == null || !GitSmartHttpTools.isGitClient(request)) {
|
||||||
String cookie = readCookie(request);
|
String cookie = readCookie(request);
|
||||||
@@ -86,6 +92,10 @@ public abstract class CacheBasedWebSession implements WebSession {
|
|||||||
authFromQueryParameter(token);
|
authFromQueryParameter(token);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (val != null && !checkAccountStatus(val.getAccountId())) {
|
||||||
|
val = null;
|
||||||
|
okPaths.clear();
|
||||||
|
}
|
||||||
if (val != null && val.needsCookieRefresh()) {
|
if (val != null && val.needsCookieRefresh()) {
|
||||||
// Session is more than half old; update cache entry with new expiration date.
|
// Session is more than half old; update cache entry with new expiration date.
|
||||||
val = manager.createVal(key, val);
|
val = manager.createVal(key, val);
|
||||||
@@ -178,6 +188,11 @@ public abstract class CacheBasedWebSession implements WebSession {
|
|||||||
manager.destroy(key);
|
manager.destroy(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!checkAccountStatus(id)) {
|
||||||
|
val = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
key = manager.createKey(id);
|
key = manager.createKey(id);
|
||||||
val = manager.createVal(key, id, rememberMe, identity, null, null);
|
val = manager.createVal(key, id, rememberMe, identity, null, null);
|
||||||
saveCookie();
|
saveCookie();
|
||||||
@@ -208,6 +223,11 @@ public abstract class CacheBasedWebSession implements WebSession {
|
|||||||
return val != null ? val.getSessionId() : null;
|
return val != null ? val.getSessionId() : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean checkAccountStatus(Account.Id id) {
|
||||||
|
AccountState accountState = byIdCache.get(id);
|
||||||
|
return accountState != null && accountState.getAccount().isActive();
|
||||||
|
}
|
||||||
|
|
||||||
private void saveCookie() {
|
private void saveCookie() {
|
||||||
if (response == null) {
|
if (response == null) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import com.google.gerrit.extensions.registration.DynamicItem;
|
|||||||
import com.google.gerrit.httpd.WebSessionManager.Val;
|
import com.google.gerrit.httpd.WebSessionManager.Val;
|
||||||
import com.google.gerrit.server.AnonymousUser;
|
import com.google.gerrit.server.AnonymousUser;
|
||||||
import com.google.gerrit.server.IdentifiedUser.RequestFactory;
|
import com.google.gerrit.server.IdentifiedUser.RequestFactory;
|
||||||
|
import com.google.gerrit.server.account.AccountCache;
|
||||||
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;
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
@@ -62,8 +63,15 @@ public class H2CacheBasedWebSession extends CacheBasedWebSession {
|
|||||||
@Named(WebSessionManager.CACHE_NAME) Cache<String, Val> cache,
|
@Named(WebSessionManager.CACHE_NAME) Cache<String, Val> cache,
|
||||||
AuthConfig authConfig,
|
AuthConfig authConfig,
|
||||||
Provider<AnonymousUser> anonymousProvider,
|
Provider<AnonymousUser> anonymousProvider,
|
||||||
RequestFactory identified) {
|
RequestFactory identified,
|
||||||
|
AccountCache byIdCache) {
|
||||||
super(
|
super(
|
||||||
request, response, managerFactory.create(cache), authConfig, anonymousProvider, identified);
|
request,
|
||||||
|
response,
|
||||||
|
managerFactory.create(cache),
|
||||||
|
authConfig,
|
||||||
|
anonymousProvider,
|
||||||
|
identified,
|
||||||
|
byIdCache);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user