Invalid sshkeys cache entries when the sshUserName changes
Currently the sshUserName property of an account, which also is the
key into the sshkeys cache, is tied to the account's preferred email
address. If the preferred email address changes, the sshUserName
might have changed, and we may need to flush the cache to ensure that
a prior negative cache entry (such as from a failed login attempt) is
cleared out and can honor the user's current keys.
This fixes a situation I had to troubleshoot today where the user was
getting denied at `repo upload` as their preferred email address (and
hence sshUserName) did not match the value set in user.email in the
local .git/config, so `repo upload` caused a negative cache entry for
that name to be inserted into the sshkeys cache. When the user
updated their preferred email address to match user.email, the
negative cache entry was still hung, denying login attempts until the
user deleted and readded the same public key again.
Signed-off-by: Shawn O. Pearce <sop@google.com>
diff --git a/src/main/java/com/google/gerrit/server/AccountSecurityImpl.java b/src/main/java/com/google/gerrit/server/AccountSecurityImpl.java
index 1efd2ea..a0696de 100644
--- a/src/main/java/com/google/gerrit/server/AccountSecurityImpl.java
+++ b/src/main/java/com/google/gerrit/server/AccountSecurityImpl.java
@@ -38,8 +38,6 @@
import com.google.gwtorm.client.OrmException;
import com.google.gwtorm.client.Transaction;
-import net.sf.ehcache.constructs.blocking.SelfPopulatingCache;
-
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.spearce.jgit.lib.PersonIdent;
@@ -139,10 +137,15 @@
}
private void uncacheSshKeys(final Account.Id me, final ReviewDb db) {
- final SelfPopulatingCache c = server.getSshKeysCache();
final Account a = Common.getAccountCache().get(me, db);
- if (a != null && a.getSshUserName() != null) {
- c.remove(a.getSshUserName());
+ if (a != null) {
+ uncacheSshKeys(a.getSshUserName());
+ }
+ }
+
+ private void uncacheSshKeys(final String userName) {
+ if (userName != null) {
+ server.getSshKeysCache().remove(userName);
}
}
@@ -219,6 +222,7 @@
run(callback, new Action<Account>() {
public Account run(ReviewDb db) throws OrmException, Failure {
final Account me = db.accounts().get(Common.getAccountId());
+ final String oldUser = me.getSshUserName();
me.setFullName(fullName);
me.setPreferredEmail(emailAddr);
if (Common.getGerritConfig().isUseContactInfo()) {
@@ -235,12 +239,23 @@
}
}
db.accounts().update(Collections.singleton(me));
+ if (!eq(oldUser, me.getSshUserName())) {
+ uncacheSshKeys(oldUser);
+ uncacheSshKeys(me.getSshUserName());
+ }
Common.getAccountCache().invalidate(me.getId());
return me;
}
});
}
+ private static boolean eq(final String a, final String b) {
+ if (a == null && b == null) {
+ return true;
+ }
+ return a != null && a.equals(b);
+ }
+
public void enterAgreement(final ContributorAgreement.Id id,
final AsyncCallback<VoidResult> callback) {
run(callback, new Action<VoidResult>() {