Automatically make first user account administrator

The first user to authenticate is now placed into the Administrators
group, making it simpler to bootstrap the server by having at least
one user who can modify permissions through the web UI, or create a
Git repository over SSH.

Change-Id: I8b39caaa129b3d0f693e0227fc3669ef18ca0df0
Signed-off-by: Shawn O. Pearce <sop@google.com>
This commit is contained in:
Shawn O. Pearce 2009-11-17 17:43:25 -08:00
parent de98736af9
commit 82205a080f
3 changed files with 35 additions and 37 deletions

View File

@ -399,42 +399,10 @@ within the SSL enabled virtual host.
Administrator Setup
-------------------
Login to Gerrit through the web interface, so that a user account
is initialized for you.
Add your newly created account to the "Administrators" group,
so that you can manage the site through the web interface:
====
INSERT INTO account_group_members
(account_id, group_id)
VALUES (
(SELECT account_id FROM accounts
WHERE preferred_email='you@example.com'),
(SELECT admin_group_id FROM system_config)
);
====
You can also get your `account_id` from the web UI, under Settings,
if you don't want to use a SELECT subquery above, or your email
address wasn't prefilled automatically.
Group memberships are cached, so you need to either restart Gerrit,
or try flushing the caches over SSH.
Since SSH cache flushing requires being in the "Administrators"
group you may run into a chicken-and-egg problem, where you cannot
flush the cache to make yourself an administrator because you are
not yet an administrator. Therefore, restarting the application
is the recommended bootstrap technique.
To flush the server's caches over SSH, ensure you have an SSH key
(you can add one through the web UI under Settings, SSH Keys),
and then run:
====
ssh -p 29418 you@example.com gerrit flush-caches
====
Sign in to Gerrit through the web interface. The first user
to register or sign-in will be automatically placed into the
Administrators group. All subsequent users will be treated as
unprivileged users.
Project Setup

View File

@ -48,4 +48,6 @@ public interface AccountAccess extends Access<Account, Account.Id> {
ResultSet<Account> suggestBySshUserName(String nameA, String nameB, int limit)
throws OrmException;
@Query("LIMIT 1")
ResultSet<Account> anyAccounts() throws OrmException;
}

View File

@ -17,6 +17,9 @@ package com.google.gerrit.server.account;
import com.google.gerrit.common.auth.openid.OpenIdUrls;
import com.google.gerrit.reviewdb.Account;
import com.google.gerrit.reviewdb.AccountExternalId;
import com.google.gerrit.reviewdb.AccountGroup;
import com.google.gerrit.reviewdb.AccountGroupMember;
import com.google.gerrit.reviewdb.AccountGroupMemberAudit;
import com.google.gerrit.reviewdb.ReviewDb;
import com.google.gerrit.server.config.AuthConfig;
import com.google.gwtorm.client.OrmException;
@ -28,6 +31,7 @@ import com.google.inject.Singleton;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
/** Tracks authentication related details for user accounts. */
@Singleton
@ -37,16 +41,26 @@ public class AccountManager {
private final AccountByEmailCache byEmailCache;
private final AuthConfig authConfig;
private final Realm realm;
private final AtomicBoolean firstAccount;
@Inject
AccountManager(final SchemaFactory<ReviewDb> schema,
final AccountCache byIdCache, final AccountByEmailCache byEmailCache,
final AuthConfig authConfig, final Realm accountMapper) {
final AuthConfig authConfig, final Realm accountMapper)
throws OrmException {
this.schema = schema;
this.byIdCache = byIdCache;
this.byEmailCache = byEmailCache;
this.authConfig = authConfig;
this.realm = accountMapper;
firstAccount = new AtomicBoolean();
final ReviewDb db = schema.open();
try {
firstAccount.set(db.accounts().anyAccounts().toList().isEmpty());
} finally {
db.close();
}
}
/**
@ -246,6 +260,20 @@ public class AccountManager {
final Transaction txn = db.beginTransaction();
db.accounts().insert(Collections.singleton(account), txn);
db.accountExternalIds().insert(Collections.singleton(extId), txn);
if (firstAccount.get() && firstAccount.compareAndSet(true, false)) {
// This is the first user account on our site. Assume this user
// is going to be the site's administrator and just make them that
// to bootstrap the authentication database.
//
final AccountGroup.Id admin = authConfig.getAdministratorsGroup();
final AccountGroupMember m =
new AccountGroupMember(new AccountGroupMember.Key(newId, admin));
db.accountGroupMembers().insert(Collections.singleton(m), txn);
db.accountGroupMembersAudit().insert(
Collections.singleton(new AccountGroupMemberAudit(m, newId)), txn);
}
txn.commit();
byEmailCache.evict(account.getPreferredEmail());