Store SSH keys in git
The public SSH keys of a user are now stored in an authorized_keys file in the All-Users repository in the refs/users/CD/ABCD branch of the user. Storing SSH keys in an authorized_keys file is the standard way for SSH to store public keys. Each key is stored on a separate line. The order of the keys in the file determines the sequence numbers of the keys. Invalid keys are marked with the prefix '# INVALID'. To keep the sequence numbers intact when a key is deleted, a '# DELETED' line is inserted at the position where the key was deleted. Other comment lines are ignored on read, and are not written back when the file is modified. Supporting a 2-step live migration for a multi-master Gerrit installation is not needed since the googlesource.com instances do not use SSH and there are no other multi-master installations. On creation of an SSH key, RFC 4716 style keys need to be converted to OpenSSH style keys. Also before adding a key it should be checked that the key is parseable. Both of this requires classes from SSH libs that are only available in the SSH layer. This is why the SSH key creation must be done there. So far this was done in SshKeyCacheImpl, but since SshKeyCacheImpl needs VersionedAuthorizedKeys to load keys and to mark keys as invalid, VersionedAuthorizedKeys cannot not depend on SshKeyCacheImpl as this would be a cyclic dependency. Instead split out the SSH key creation from SshKeyCacheImpl into SshKeyCreatorImpl. This way SshKeyCacheImpl depends on VersionedAuthorizedKeys and VersionedAuthorizedKeys depends on SshKeyCreatorImpl, and there is no dependency circle. Change-Id: I8fcc3c0f27e034fc2c8e8ae3612068099075467d Signed-off-by: Edwin Kempin <ekempin@google.com>
This commit is contained in:
@@ -22,13 +22,12 @@ import com.google.gerrit.reviewdb.client.Account;
|
||||
import com.google.gerrit.reviewdb.client.AccountExternalId;
|
||||
import com.google.gerrit.reviewdb.client.AccountGroup;
|
||||
import com.google.gerrit.reviewdb.client.AccountGroupMember;
|
||||
import com.google.gerrit.reviewdb.client.AccountSshKey;
|
||||
import com.google.gerrit.reviewdb.server.ReviewDb;
|
||||
import com.google.gerrit.server.account.AccountByEmailCache;
|
||||
import com.google.gerrit.server.account.AccountCache;
|
||||
import com.google.gerrit.server.account.GroupCache;
|
||||
import com.google.gerrit.server.account.VersionedAuthorizedKeys;
|
||||
import com.google.gerrit.server.ssh.SshKeyCache;
|
||||
import com.google.gwtorm.server.OrmException;
|
||||
import com.google.gwtorm.server.SchemaFactory;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Singleton;
|
||||
@@ -47,18 +46,23 @@ import java.util.Map;
|
||||
public class AccountCreator {
|
||||
private final Map<String, TestAccount> accounts;
|
||||
|
||||
private SchemaFactory<ReviewDb> reviewDbProvider;
|
||||
private GroupCache groupCache;
|
||||
private SshKeyCache sshKeyCache;
|
||||
private AccountCache accountCache;
|
||||
private AccountByEmailCache byEmailCache;
|
||||
private final SchemaFactory<ReviewDb> reviewDbProvider;
|
||||
private final VersionedAuthorizedKeys.Accessor authorizedKeys;
|
||||
private final GroupCache groupCache;
|
||||
private final SshKeyCache sshKeyCache;
|
||||
private final AccountCache accountCache;
|
||||
private final AccountByEmailCache byEmailCache;
|
||||
|
||||
@Inject
|
||||
AccountCreator(SchemaFactory<ReviewDb> schema, GroupCache groupCache,
|
||||
SshKeyCache sshKeyCache, AccountCache accountCache,
|
||||
AccountCreator(SchemaFactory<ReviewDb> schema,
|
||||
VersionedAuthorizedKeys.Accessor authorizedKeys,
|
||||
GroupCache groupCache,
|
||||
SshKeyCache sshKeyCache,
|
||||
AccountCache accountCache,
|
||||
AccountByEmailCache byEmailCache) {
|
||||
accounts = new HashMap<>();
|
||||
reviewDbProvider = schema;
|
||||
this.authorizedKeys = authorizedKeys;
|
||||
this.groupCache = groupCache;
|
||||
this.sshKeyCache = sshKeyCache;
|
||||
this.accountCache = accountCache;
|
||||
@@ -66,17 +70,14 @@ public class AccountCreator {
|
||||
}
|
||||
|
||||
public synchronized TestAccount create(String username, String email,
|
||||
String fullName, String... groups)
|
||||
throws OrmException, UnsupportedEncodingException, JSchException {
|
||||
String fullName, String... groups) throws Exception {
|
||||
TestAccount account = accounts.get(username);
|
||||
if (account != null) {
|
||||
return account;
|
||||
}
|
||||
try (ReviewDb db = reviewDbProvider.open()) {
|
||||
Account.Id id = new Account.Id(db.nextAccountId());
|
||||
KeyPair sshKey = genSshKey();
|
||||
AccountSshKey key =
|
||||
new AccountSshKey(new AccountSshKey.Id(id, 1), publicKey(sshKey, email));
|
||||
|
||||
AccountExternalId extUser =
|
||||
new AccountExternalId(id, new AccountExternalId.Key(
|
||||
AccountExternalId.SCHEME_USERNAME, username));
|
||||
@@ -95,8 +96,6 @@ public class AccountCreator {
|
||||
a.setPreferredEmail(email);
|
||||
db.accounts().insert(Collections.singleton(a));
|
||||
|
||||
db.accountSshKeys().insert(Collections.singleton(key));
|
||||
|
||||
if (groups != null) {
|
||||
for (String n : groups) {
|
||||
AccountGroup.NameKey k = new AccountGroup.NameKey(n);
|
||||
@@ -107,7 +106,10 @@ public class AccountCreator {
|
||||
}
|
||||
}
|
||||
|
||||
KeyPair sshKey = genSshKey();
|
||||
authorizedKeys.addKey(id, publicKey(sshKey, email));
|
||||
sshKeyCache.evict(username);
|
||||
|
||||
accountCache.evictByUsername(username);
|
||||
byEmailCache.evict(email);
|
||||
|
||||
@@ -118,35 +120,29 @@ public class AccountCreator {
|
||||
}
|
||||
}
|
||||
|
||||
public TestAccount create(String username, String group)
|
||||
throws OrmException, UnsupportedEncodingException, JSchException {
|
||||
public TestAccount create(String username, String group) throws Exception {
|
||||
return create(username, null, username, group);
|
||||
}
|
||||
|
||||
public TestAccount create(String username)
|
||||
throws UnsupportedEncodingException, OrmException, JSchException {
|
||||
public TestAccount create(String username) throws Exception {
|
||||
return create(username, null, username, (String[]) null);
|
||||
}
|
||||
|
||||
public TestAccount admin()
|
||||
throws UnsupportedEncodingException, OrmException, JSchException {
|
||||
public TestAccount admin() throws Exception {
|
||||
return create("admin", "admin@example.com", "Administrator",
|
||||
"Administrators");
|
||||
}
|
||||
|
||||
public TestAccount admin2()
|
||||
throws UnsupportedEncodingException, OrmException, JSchException {
|
||||
public TestAccount admin2() throws Exception {
|
||||
return create("admin2", "admin2@example.com", "Administrator2",
|
||||
"Administrators");
|
||||
}
|
||||
|
||||
public TestAccount user()
|
||||
throws UnsupportedEncodingException, OrmException, JSchException {
|
||||
public TestAccount user() throws Exception {
|
||||
return create("user", "user@example.com", "User");
|
||||
}
|
||||
|
||||
public TestAccount user2()
|
||||
throws UnsupportedEncodingException, OrmException, JSchException {
|
||||
public TestAccount user2() throws Exception {
|
||||
return create("user2", "user2@example.com", "User2");
|
||||
}
|
||||
|
||||
@@ -169,6 +165,6 @@ public class AccountCreator {
|
||||
throws UnsupportedEncodingException {
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
sshKey.writePublicKey(out, comment);
|
||||
return out.toString(US_ASCII.name());
|
||||
return out.toString(US_ASCII.name()).trim();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user