Use AccountGroup.UUID instead of Account.Id

By switching to the UUID we can have a globally unique identifier
for group membership throughout the server, even if group information
comes in from a different data source.

Change-Id: Icb49d6a6aff8e62864ac0f78ceedbe03f01de894
Signed-off-by: Shawn O. Pearce <sop@google.com>
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/SuggestServiceImpl.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/SuggestServiceImpl.java
index 8d438e8..b1c0dd0 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/SuggestServiceImpl.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/SuggestServiceImpl.java
@@ -20,7 +20,6 @@
 import com.google.gerrit.reviewdb.Account;
 import com.google.gerrit.reviewdb.AccountExternalId;
 import com.google.gerrit.reviewdb.AccountGroup;
-import com.google.gerrit.reviewdb.AccountGroup.Id;
 import com.google.gerrit.reviewdb.AccountGroupName;
 import com.google.gerrit.reviewdb.Project;
 import com.google.gerrit.reviewdb.ReviewDb;
@@ -158,10 +157,11 @@
         map.put(account.getId(), info);
         break;
       case SAME_GROUP: {
-        Set<AccountGroup.Id> usersGroups = groupsOf(account);
-        usersGroups.removeAll(authConfig.getRegisteredGroups());
+        Set<AccountGroup.UUID> usersGroups = groupsOf(account);
+        usersGroups.remove(AccountGroup.ANONYMOUS_USERS);
+        usersGroups.remove(AccountGroup.REGISTERED_USERS);
         usersGroups.remove(authConfig.getBatchUsersGroup());
-        for (AccountGroup.Id myGroup : currentUser.get().getEffectiveGroups()) {
+        for (AccountGroup.UUID myGroup : currentUser.get().getEffectiveGroups()) {
           if (usersGroups.contains(myGroup)) {
             map.put(account.getId(), info);
             break;
@@ -176,9 +176,9 @@
     }
   }
 
-  private Set<Id> groupsOf(Account account) {
+  private Set<AccountGroup.UUID> groupsOf(Account account) {
     IdentifiedUser user = userFactory.create(account.getId());
-    return new HashSet<AccountGroup.Id>(user.getEffectiveGroups());
+    return new HashSet<AccountGroup.UUID>(user.getEffectiveGroups());
   }
 
   public void suggestAccountGroup(final String query, final int limit,
@@ -189,7 +189,7 @@
         final String b = a + MAX_SUFFIX;
         final int max = 10;
         final int n = limit <= 0 ? max : Math.min(limit, max);
-        Set<AccountGroup.Id> memberOf = currentUser.get().getEffectiveGroups();
+        Set<AccountGroup.UUID> memberOf = currentUser.get().getEffectiveGroups();
         List<AccountGroupName> names = new ArrayList<AccountGroupName>(n);
         for (AccountGroupName group : db.accountGroupNames()
               .suggestByName(a, b, n)) {
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/account/AgreementInfoFactory.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/account/AgreementInfoFactory.java
index f638d48..4f62330 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/account/AgreementInfoFactory.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/account/AgreementInfoFactory.java
@@ -22,6 +22,7 @@
 import com.google.gerrit.reviewdb.ContributorAgreement;
 import com.google.gerrit.reviewdb.ReviewDb;
 import com.google.gerrit.server.IdentifiedUser;
+import com.google.gerrit.server.account.GroupCache;
 import com.google.inject.Inject;
 
 import java.util.ArrayList;
@@ -36,13 +37,16 @@
   }
 
   private final ReviewDb db;
+  private final GroupCache groupCache;
   private final IdentifiedUser user;
 
   private AgreementInfo info;
 
   @Inject
-  AgreementInfoFactory(final ReviewDb db, final IdentifiedUser user) {
+  AgreementInfoFactory(final ReviewDb db, final GroupCache groupCache,
+      final IdentifiedUser user) {
     this.db = db;
+    this.groupCache = groupCache;
     this.user = user;
   }
 
@@ -55,9 +59,14 @@
 
     final List<AccountGroupAgreement> groupAccepted =
         new ArrayList<AccountGroupAgreement>();
-    for (final AccountGroup.Id groupId : user.getEffectiveGroups()) {
+    for (final AccountGroup.UUID groupUUID : user.getEffectiveGroups()) {
+      AccountGroup group = groupCache.get(groupUUID);
+      if (group == null) {
+        continue;
+      }
+
       final List<AccountGroupAgreement> temp =
-          db.accountGroupAgreements().byGroup(groupId).toList();
+          db.accountGroupAgreements().byGroup(group.getId()).toList();
 
       Collections.reverse(temp);
 
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/account/GroupAdminServiceImpl.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/account/GroupAdminServiceImpl.java
index a564907..b1ed026 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/account/GroupAdminServiceImpl.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/account/GroupAdminServiceImpl.java
@@ -46,6 +46,7 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
 
@@ -281,7 +282,7 @@
               Collections.singleton(new AccountGroupIncludeAudit(m,
                   getAccountId())));
           db.accountGroupIncludes().insert(Collections.singleton(m));
-          groupIncludeCache.evictInclude(a.getId());
+          groupIncludeCache.evictInclude(a.getGroupUUID());
         }
 
         return groupDetailFactory.create(groupId).call();
@@ -361,6 +362,7 @@
         }
 
         final Account.Id me = getAccountId();
+        final Set<AccountGroup.Id> groupsToEvict = new HashSet<AccountGroup.Id>();
         for (final AccountGroupInclude.Key k : keys) {
           final AccountGroupInclude m =
               db.accountGroupIncludes().get(k);
@@ -385,9 +387,12 @@
                   Collections.singleton(audit));
             }
             db.accountGroupIncludes().delete(Collections.singleton(m));
-            groupIncludeCache.evictInclude(m.getIncludeId());
+            groupsToEvict.add(k.getIncludeId());
           }
         }
+        for (AccountGroup group : db.accountGroups().get(groupsToEvict)) {
+          groupIncludeCache.evictInclude(group.getGroupUUID());
+        }
         return VoidResult.INSTANCE;
       }
     });
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/account/MyGroupsFactory.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/account/MyGroupsFactory.java
index b3e993e..088fae2 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/account/MyGroupsFactory.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/account/MyGroupsFactory.java
@@ -42,10 +42,10 @@
 
   @Override
   public List<AccountGroup> call() throws Exception {
-    final Set<AccountGroup.Id> effective = user.getEffectiveGroups();
+    final Set<AccountGroup.UUID> effective = user.getEffectiveGroups();
     final int cnt = effective.size();
     final List<AccountGroup> groupList = new ArrayList<AccountGroup>(cnt);
-    for (final AccountGroup.Id groupId : effective) {
+    for (final AccountGroup.UUID groupId : effective) {
       groupList.add(groupCache.get(groupId));
     }
     Collections.sort(groupList, new Comparator<AccountGroup>() {
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/changedetail/PatchSetPublishDetailFactory.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/changedetail/PatchSetPublishDetailFactory.java
index 779475e..9b03b70 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/changedetail/PatchSetPublishDetailFactory.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/changedetail/PatchSetPublishDetailFactory.java
@@ -127,7 +127,7 @@
   }
 
   private void computeAllowed() {
-    final Set<AccountGroup.Id> am = user.getEffectiveGroups();
+    final Set<AccountGroup.UUID> am = user.getEffectiveGroups();
     final ProjectState pe = projectCache.get(change.getProject());
     for (ApprovalCategory.Id category : approvalTypes.getApprovalCategories()) {
       RefControl rc = pe.controlFor(user).controlForRef(change.getDest());
@@ -136,7 +136,7 @@
     }
   }
 
-  private void computeAllowed(final Set<AccountGroup.Id> am,
+  private void computeAllowed(final Set<AccountGroup.UUID> am,
       final List<RefRight> list, ApprovalCategory.Id category) {
 
     Set<ApprovalCategoryValue.Id> s = allowed.get(category);
@@ -146,7 +146,7 @@
     }
 
     for (final RefRight r : list) {
-      if (!am.contains(r.getAccountGroupId())) {
+      if (!am.contains(r.getAccountGroupUUID())) {
         continue;
       }
       final ApprovalType at =
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/RefRight.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/RefRight.java
index 97ee219..112922c 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/RefRight.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/RefRight.java
@@ -116,6 +116,8 @@
   @Column(id = 3)
   protected short maxValue;
 
+  protected transient AccountGroup.UUID groupUUID;
+
   protected RefRight() {
   }
 
@@ -123,11 +125,12 @@
     this.key = key;
   }
 
-  public RefRight(final RefRight refRight, final AccountGroup.Id groupId) {
+  public RefRight(final RefRight refRight, final AccountGroup.UUID groupId) {
     this(new RefRight.Key(refRight.getKey().projectName,
-        refRight.getKey().refPattern, refRight.getKey().categoryId, groupId));
+        refRight.getKey().refPattern, refRight.getKey().categoryId, null));
     setMinValue(refRight.getMinValue());
     setMaxValue(refRight.getMaxValue());
+    setAccountGroupUUID(groupId);
   }
 
   public RefRight.Key getKey() {
@@ -161,6 +164,14 @@
     return key.groupId;
   }
 
+  public AccountGroup.UUID getAccountGroupUUID() {
+    return groupUUID;
+  }
+
+  public void setAccountGroupUUID(AccountGroup.UUID uuid) {
+    groupUUID = uuid;
+  }
+
   public short getMinValue() {
     return minValue;
   }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/AnonymousUser.java b/gerrit-server/src/main/java/com/google/gerrit/server/AnonymousUser.java
index 1bd2066..3a450ed 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/AnonymousUser.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/AnonymousUser.java
@@ -34,8 +34,8 @@
   }
 
   @Override
-  public Set<AccountGroup.Id> getEffectiveGroups() {
-    return authConfig.getAnonymousGroups();
+  public Set<AccountGroup.UUID> getEffectiveGroups() {
+    return Collections.singleton(AccountGroup.ANONYMOUS_USERS);
   }
 
   @Override
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/CurrentUser.java b/gerrit-server/src/main/java/com/google/gerrit/server/CurrentUser.java
index 0d8d19a..512de00 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/CurrentUser.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/CurrentUser.java
@@ -56,7 +56,7 @@
    *
    * @return active groups for this user.
    */
-  public abstract Set<AccountGroup.Id> getEffectiveGroups();
+  public abstract Set<AccountGroup.UUID> getEffectiveGroups();
 
   /** Set of changes starred by this user. */
   public abstract Set<Change.Id> getStarredChanges();
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/IdentifiedUser.java b/gerrit-server/src/main/java/com/google/gerrit/server/IdentifiedUser.java
index e46957d..5fb5a7f 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/IdentifiedUser.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/IdentifiedUser.java
@@ -43,11 +43,14 @@
 import java.net.MalformedURLException;
 import java.net.SocketAddress;
 import java.net.URL;
+import java.util.AbstractSet;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Date;
 import java.util.HashSet;
 import java.util.LinkedList;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Queue;
 import java.util.Set;
@@ -139,6 +142,28 @@
   private static final Logger log =
       LoggerFactory.getLogger(IdentifiedUser.class);
 
+  private static final Set<AccountGroup.UUID> registeredGroups =
+      new AbstractSet<AccountGroup.UUID>() {
+        private final List<AccountGroup.UUID> groups =
+            Collections.unmodifiableList(Arrays.asList(new AccountGroup.UUID[] {
+                AccountGroup.ANONYMOUS_USERS, AccountGroup.REGISTERED_USERS}));
+
+        @Override
+        public boolean contains(Object o) {
+          return groups.contains(o);
+        }
+
+        @Override
+        public Iterator<AccountGroup.UUID> iterator() {
+          return groups.iterator();
+        }
+
+        @Override
+        public int size() {
+          return groups.size();
+        }
+      };
+
   private final Provider<String> canonicalUrl;
   private final Realm realm;
   private final AccountCache accountCache;
@@ -154,7 +179,7 @@
 
   private AccountState state;
   private Set<String> emailAddresses;
-  private Set<AccountGroup.Id> effectiveGroups;
+  private Set<AccountGroup.UUID> effectiveGroups;
   private Set<Change.Id> starredChanges;
   private Collection<AccountProjectWatch> notificationFilters;
 
@@ -217,14 +242,14 @@
   }
 
   @Override
-  public Set<AccountGroup.Id> getEffectiveGroups() {
+  public Set<AccountGroup.UUID> getEffectiveGroups() {
     if (effectiveGroups == null) {
-      Set<AccountGroup.Id> seedGroups;
+      Set<AccountGroup.UUID> seedGroups;
 
       if (authConfig.isIdentityTrustable(state().getExternalIds())) {
         seedGroups = realm.groups(state());
       } else {
-        seedGroups = authConfig.getRegisteredGroups();
+        seedGroups = registeredGroups;
       }
 
       effectiveGroups = getIncludedGroups(seedGroups);
@@ -233,14 +258,14 @@
     return effectiveGroups;
   }
 
-  private Set<AccountGroup.Id> getIncludedGroups(Set<AccountGroup.Id> seedGroups) {
-    Set<AccountGroup.Id> includes = new HashSet<AccountGroup.Id> (seedGroups);
-    Queue<AccountGroup.Id> groupQueue = new LinkedList<AccountGroup.Id> (seedGroups);
+  private Set<AccountGroup.UUID> getIncludedGroups(Set<AccountGroup.UUID> seedGroups) {
+    Set<AccountGroup.UUID> includes = new HashSet<AccountGroup.UUID> (seedGroups);
+    Queue<AccountGroup.UUID> groupQueue = new LinkedList<AccountGroup.UUID> (seedGroups);
 
     while (groupQueue.size() > 0) {
-      AccountGroup.Id id = groupQueue.remove();
+      AccountGroup.UUID id = groupQueue.remove();
 
-      for (final AccountGroup.Id groupId : groupIncludeCache.getByInclude(id)) {
+      for (final AccountGroup.UUID groupId : groupIncludeCache.getByInclude(id)) {
         if (includes.add(groupId)) {
           groupQueue.add(groupId);
         }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/PeerDaemonUser.java b/gerrit-server/src/main/java/com/google/gerrit/server/PeerDaemonUser.java
index 26dec09..a4a72a7 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/PeerDaemonUser.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/PeerDaemonUser.java
@@ -36,21 +36,21 @@
     PeerDaemonUser create(@Assisted SocketAddress peer);
   }
 
-  private final Set<AccountGroup.Id> effectiveGroups;
+  private final Set<AccountGroup.UUID> effectiveGroups;
   private final SocketAddress peer;
 
   @Inject
   protected PeerDaemonUser(AuthConfig authConfig, @Assisted SocketAddress peer) {
     super(AccessPath.SSH_COMMAND, authConfig);
 
-    final HashSet<AccountGroup.Id> g = new HashSet<AccountGroup.Id>();
+    final HashSet<AccountGroup.UUID> g = new HashSet<AccountGroup.UUID>();
     g.add(authConfig.getAdministratorsGroup());
     this.effectiveGroups = Collections.unmodifiableSet(g);
     this.peer = peer;
   }
 
   @Override
-  public Set<AccountGroup.Id> getEffectiveGroups() {
+  public Set<AccountGroup.UUID> getEffectiveGroups() {
     return effectiveGroups;
   }
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/ReplicationUser.java b/gerrit-server/src/main/java/com/google/gerrit/server/ReplicationUser.java
index 5c44bfe..afb8800 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/ReplicationUser.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/ReplicationUser.java
@@ -28,18 +28,18 @@
 
 public class ReplicationUser extends CurrentUser {
   /** Magic set of groups enabling read of any project and reference. */
-  public static final Set<AccountGroup.Id> EVERYTHING_VISIBLE =
-      Collections.unmodifiableSet(new HashSet<AccountGroup.Id>(0));
+  public static final Set<AccountGroup.UUID> EVERYTHING_VISIBLE =
+      Collections.unmodifiableSet(new HashSet<AccountGroup.UUID>(0));
 
   public interface Factory {
-    ReplicationUser create(@Assisted Set<AccountGroup.Id> authGroups);
+    ReplicationUser create(@Assisted Set<AccountGroup.UUID> authGroups);
   }
 
-  private final Set<AccountGroup.Id> effectiveGroups;
+  private final Set<AccountGroup.UUID> effectiveGroups;
 
   @Inject
   protected ReplicationUser(AuthConfig authConfig,
-      @Assisted Set<AccountGroup.Id> authGroups) {
+      @Assisted Set<AccountGroup.UUID> authGroups) {
     super(AccessPath.REPLICATION, authConfig);
 
     if (authGroups == EVERYTHING_VISIBLE) {
@@ -53,12 +53,12 @@
     }
   }
 
-  private static Set<AccountGroup.Id> copy(Set<AccountGroup.Id> groups) {
-    return Collections.unmodifiableSet(new HashSet<AccountGroup.Id>(groups));
+  private static Set<AccountGroup.UUID> copy(Set<AccountGroup.UUID> groups) {
+    return Collections.unmodifiableSet(new HashSet<AccountGroup.UUID>(groups));
   }
 
   @Override
-  public Set<AccountGroup.Id> getEffectiveGroups() {
+  public Set<AccountGroup.UUID> getEffectiveGroups() {
     return effectiveGroups;
   }
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountCacheImpl.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountCacheImpl.java
index 52ccc66..aea13c7 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountCacheImpl.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountCacheImpl.java
@@ -22,7 +22,6 @@
 import com.google.gerrit.server.cache.Cache;
 import com.google.gerrit.server.cache.CacheModule;
 import com.google.gerrit.server.cache.EntryCreator;
-import com.google.gerrit.server.config.AuthConfig;
 import com.google.gwtorm.client.OrmException;
 import com.google.gwtorm.client.SchemaFactory;
 import com.google.inject.Inject;
@@ -90,18 +89,13 @@
 
   static class ByIdLoader extends EntryCreator<Account.Id, AccountState> {
     private final SchemaFactory<ReviewDb> schema;
-    private final Set<AccountGroup.Id> registered;
-    private final Set<AccountGroup.Id> anonymous;
     private final GroupCache groupCache;
     private final Cache<String, Account.Id> byName;
 
     @Inject
-    ByIdLoader(SchemaFactory<ReviewDb> sf, AuthConfig auth,
-        GroupCache groupCache,
+    ByIdLoader(SchemaFactory<ReviewDb> sf, GroupCache groupCache,
         @Named(BYUSER_NAME) Cache<String, Account.Id> byUsername) {
       this.schema = sf;
-      this.registered = auth.getRegisteredGroups();
-      this.anonymous = auth.getAnonymousGroups();
       this.groupCache = groupCache;
       this.byName = byUsername;
     }
@@ -133,21 +127,18 @@
           Collections.unmodifiableCollection(db.accountExternalIds().byAccount(
               who).toList());
 
-      Set<AccountGroup.Id> internalGroups = new HashSet<AccountGroup.Id>();
+      Set<AccountGroup.UUID> internalGroups = new HashSet<AccountGroup.UUID>();
       for (AccountGroupMember g : db.accountGroupMembers().byAccount(who)) {
         final AccountGroup.Id groupId = g.getAccountGroupId();
         final AccountGroup group = groupCache.get(groupId);
         if (group != null && group.getType() == AccountGroup.Type.INTERNAL) {
-          internalGroups.add(groupId);
+          internalGroups.add(group.getGroupUUID());
         }
       }
 
-      if (internalGroups.isEmpty()) {
-        internalGroups = registered;
-      } else {
-        internalGroups.addAll(registered);
-        internalGroups = Collections.unmodifiableSet(internalGroups);
-      }
+      internalGroups.add(AccountGroup.REGISTERED_USERS);
+      internalGroups.add(AccountGroup.ANONYMOUS_USERS);
+      internalGroups = Collections.unmodifiableSet(internalGroups);
 
       return new AccountState(account, internalGroups, externalIds);
     }
@@ -156,6 +147,8 @@
     public AccountState missing(final Account.Id accountId) {
       final Account account = new Account(accountId);
       final Collection<AccountExternalId> ids = Collections.emptySet();
+      final Set<AccountGroup.UUID> anonymous =
+          Collections.singleton(AccountGroup.ANONYMOUS_USERS);
       return new AccountState(account, anonymous, ids);
     }
   }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountManager.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountManager.java
index 5cb8f36..a388eef 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountManager.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountManager.java
@@ -275,7 +275,9 @@
       // 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 AccountGroup.UUID uuid = authConfig.getAdministratorsGroup();
+      final AccountGroup g = db.accountGroups().byUUID(uuid).iterator().next();
+      final AccountGroup.Id admin = g.getId();
       final AccountGroupMember m =
           new AccountGroupMember(new AccountGroupMember.Key(newId, admin));
       db.accountGroupMembersAudit().insert(
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountState.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountState.java
index 9393227..1b036d8 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountState.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountState.java
@@ -26,11 +26,11 @@
 
 public class AccountState {
   private final Account account;
-  private final Set<AccountGroup.Id> internalGroups;
+  private final Set<AccountGroup.UUID> internalGroups;
   private final Collection<AccountExternalId> externalIds;
 
   public AccountState(final Account account,
-      final Set<AccountGroup.Id> actualGroups,
+      final Set<AccountGroup.UUID> actualGroups,
       final Collection<AccountExternalId> externalIds) {
     this.account = account;
     this.internalGroups = actualGroups;
@@ -89,7 +89,7 @@
   }
 
   /** The set of groups maintained directly within the Gerrit database. */
-  public Set<AccountGroup.Id> getInternalGroups() {
+  public Set<AccountGroup.UUID> getInternalGroups() {
     return internalGroups;
   }
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/DefaultRealm.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/DefaultRealm.java
index a836f54..77afb13 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/DefaultRealm.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/DefaultRealm.java
@@ -51,7 +51,7 @@
   }
 
   @Override
-  public Set<AccountGroup.Id> groups(final AccountState who) {
+  public Set<AccountGroup.UUID> groups(final AccountState who) {
     return who.getInternalGroups();
   }
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/GroupCacheImpl.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/GroupCacheImpl.java
index 9fdd69a..4d6dbc1 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/GroupCacheImpl.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/GroupCacheImpl.java
@@ -20,7 +20,6 @@
 import com.google.gerrit.server.cache.Cache;
 import com.google.gerrit.server.cache.CacheModule;
 import com.google.gerrit.server.cache.EntryCreator;
-import com.google.gerrit.server.config.AuthConfig;
 import com.google.gwtorm.client.SchemaFactory;
 import com.google.inject.Inject;
 import com.google.inject.Module;
@@ -113,12 +112,10 @@
 
   static class ByIdLoader extends EntryCreator<AccountGroup.Id, AccountGroup> {
     private final SchemaFactory<ReviewDb> schema;
-    private final AccountGroup.Id administrators;
 
     @Inject
-    ByIdLoader(final SchemaFactory<ReviewDb> sf, final AuthConfig authConfig) {
+    ByIdLoader(final SchemaFactory<ReviewDb> sf) {
       schema = sf;
-      administrators = authConfig.getAdministratorsGroup();
     }
 
     @Override
@@ -142,7 +139,6 @@
           new AccountGroup.NameKey("Deleted Group" + key.toString());
       final AccountGroup g = new AccountGroup(name, key, null);
       g.setType(AccountGroup.Type.SYSTEM);
-      g.setOwnerGroupId(administrators);
       return g;
     }
   }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/GroupIncludeCache.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/GroupIncludeCache.java
index 3088806..e5f73a3 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/GroupIncludeCache.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/GroupIncludeCache.java
@@ -20,8 +20,8 @@
 
 /** Tracks group inclusions in memory for efficient access. */
 public interface GroupIncludeCache {
-  public Collection<AccountGroup.Id> getByInclude(AccountGroup.Id groupId);
+  public Collection<AccountGroup.UUID> getByInclude(AccountGroup.UUID groupId);
 
-  public void evictInclude(AccountGroup.Id groupId);
+  public void evictInclude(AccountGroup.UUID groupId);
 }
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/GroupIncludeCacheImpl.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/GroupIncludeCacheImpl.java
index 76e9231..830d01c 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/GroupIncludeCacheImpl.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/GroupIncludeCacheImpl.java
@@ -21,16 +21,17 @@
 import com.google.gerrit.server.cache.CacheModule;
 import com.google.gerrit.server.cache.EntryCreator;
 import com.google.gwtorm.client.SchemaFactory;
-
 import com.google.inject.Inject;
 import com.google.inject.Module;
 import com.google.inject.Singleton;
 import com.google.inject.TypeLiteral;
 import com.google.inject.name.Named;
 
-import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
 
 /** Tracks group inclusions in memory for efficient access. */
 @Singleton
@@ -41,8 +42,8 @@
     return new CacheModule() {
       @Override
       protected void configure() {
-        final TypeLiteral<Cache<AccountGroup.Id, Collection<AccountGroup.Id>>> byInclude =
-            new TypeLiteral<Cache<AccountGroup.Id, Collection<AccountGroup.Id>>>() {};
+        final TypeLiteral<Cache<AccountGroup.UUID, Collection<AccountGroup.UUID>>> byInclude =
+            new TypeLiteral<Cache<AccountGroup.UUID, Collection<AccountGroup.UUID>>>() {};
         core(byInclude, BYINCLUDE_NAME).populateWith(ByIncludeLoader.class);
 
         bind(GroupIncludeCacheImpl.class);
@@ -51,23 +52,24 @@
     };
   }
 
-  private final Cache<AccountGroup.Id, Collection<AccountGroup.Id>> byInclude;
+  private final Cache<AccountGroup.UUID, Collection<AccountGroup.UUID>> byInclude;
 
   @Inject
   GroupIncludeCacheImpl(
-      @Named(BYINCLUDE_NAME) Cache<AccountGroup.Id, Collection<AccountGroup.Id>> byInclude) {
+      @Named(BYINCLUDE_NAME) Cache<AccountGroup.UUID, Collection<AccountGroup.UUID>> byInclude) {
     this.byInclude = byInclude;
   }
 
-  public Collection<AccountGroup.Id> getByInclude(final AccountGroup.Id groupId) {
+  public Collection<AccountGroup.UUID> getByInclude(AccountGroup.UUID groupId) {
     return byInclude.get(groupId);
   }
 
-  public void evictInclude(AccountGroup.Id groupId) {
+  public void evictInclude(AccountGroup.UUID groupId) {
     byInclude.remove(groupId);
   }
 
-  static class ByIncludeLoader extends EntryCreator<AccountGroup.Id, Collection<AccountGroup.Id>> {
+  static class ByIncludeLoader extends
+      EntryCreator<AccountGroup.UUID, Collection<AccountGroup.UUID>> {
     private final SchemaFactory<ReviewDb> schema;
 
     @Inject
@@ -76,14 +78,23 @@
     }
 
     @Override
-    public Collection<AccountGroup.Id> createEntry(final AccountGroup.Id key) throws Exception {
+    public Collection<AccountGroup.UUID> createEntry(final AccountGroup.UUID key) throws Exception {
       final ReviewDb db = schema.open();
       try {
-        ArrayList<AccountGroup.Id> groupArray = new ArrayList<AccountGroup.Id> ();
-        for (AccountGroupInclude agi : db.accountGroupIncludes().byInclude(key)) {
-          groupArray.add(agi.getGroupId());
+        List<AccountGroup> group = db.accountGroups().byUUID(key).toList();
+        if (group.size() != 1) {
+          return Collections.emptyList();
         }
 
+        Set<AccountGroup.Id> ids = new HashSet<AccountGroup.Id>();
+        for (AccountGroupInclude agi : db.accountGroupIncludes().byInclude(group.get(0).getId())) {
+          ids.add(agi.getGroupId());
+        }
+
+        Set<AccountGroup.UUID> groupArray = new HashSet<AccountGroup.UUID> ();
+        for (AccountGroup g : db.accountGroups().get(ids)) {
+          groupArray.add(g.getGroupUUID());
+        }
         return Collections.unmodifiableCollection(groupArray);
       } finally {
         db.close();
@@ -91,7 +102,7 @@
     }
 
     @Override
-    public Collection<AccountGroup.Id> missing(final AccountGroup.Id key) {
+    public Collection<AccountGroup.UUID> missing(final AccountGroup.UUID key) {
       return Collections.emptyList();
     }
   }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/PerformCreateGroup.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/PerformCreateGroup.java
index 8e54077..a017588 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/PerformCreateGroup.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/PerformCreateGroup.java
@@ -34,6 +34,7 @@
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.HashSet;
 import java.util.List;
 
 public class PerformCreateGroup {
@@ -160,8 +161,9 @@
     db.accountGroupIncludes().insert(includeList);
     db.accountGroupIncludesAudit().insert(includesAudit);
 
-    for (AccountGroup.Id includeId : groups) {
-      groupIncludeCache.evictInclude(includeId);
+    for (AccountGroup group : db.accountGroups().get(
+        new HashSet<AccountGroup.Id>(groups))) {
+      groupIncludeCache.evictInclude(group.getGroupUUID());
     }
   }
 }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/Realm.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/Realm.java
index e42d4ae..072f796 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/Realm.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/Realm.java
@@ -27,7 +27,7 @@
 
   public void onCreateAccount(AuthRequest who, Account account);
 
-  public Set<AccountGroup.Id> groups(AccountState who);
+  public Set<AccountGroup.UUID> groups(AccountState who);
 
   /**
    * Locate an account whose local username is the given account name.
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/auth/ldap/Helper.java b/gerrit-server/src/main/java/com/google/gerrit/server/auth/ldap/Helper.java
index 675202c..da4f63a 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/auth/ldap/Helper.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/auth/ldap/Helper.java
@@ -133,7 +133,7 @@
     }
   }
 
-  Set<AccountGroup.Id> queryForGroups(final DirContext ctx,
+  Set<AccountGroup.UUID> queryForGroups(final DirContext ctx,
       final String username, LdapQuery.Result account)
       throws NamingException, AccountException {
     final LdapSchema schema = getSchema(ctx);
@@ -175,12 +175,12 @@
       }
     }
 
-    final Set<AccountGroup.Id> actual = new HashSet<AccountGroup.Id>();
+    final Set<AccountGroup.UUID> actual = new HashSet<AccountGroup.UUID>();
     for (String dn : groupDNs) {
       for (AccountGroup group : groupCache
           .get(new AccountGroup.ExternalNameKey(dn))) {
         if (group.getType() == AccountGroup.Type.LDAP) {
-          actual.add(group.getId());
+          actual.add(group.getGroupUUID());
         }
       }
     }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/auth/ldap/LdapModule.java b/gerrit-server/src/main/java/com/google/gerrit/server/auth/ldap/LdapModule.java
index 810df28..d41fe82 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/auth/ldap/LdapModule.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/auth/ldap/LdapModule.java
@@ -32,8 +32,8 @@
 
   @Override
   protected void configure() {
-    final TypeLiteral<Cache<String, Set<AccountGroup.Id>>> groups =
-        new TypeLiteral<Cache<String, Set<AccountGroup.Id>>>() {};
+    final TypeLiteral<Cache<String, Set<AccountGroup.UUID>>> groups =
+        new TypeLiteral<Cache<String, Set<AccountGroup.UUID>>>() {};
     core(groups, GROUP_CACHE).maxAge(1, HOURS) //
         .populateWith(LdapRealm.MemberLoader.class);
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/auth/ldap/LdapRealm.java b/gerrit-server/src/main/java/com/google/gerrit/server/auth/ldap/LdapRealm.java
index de33b44..cd3f2c0 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/auth/ldap/LdapRealm.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/auth/ldap/LdapRealm.java
@@ -68,14 +68,14 @@
   private final Cache<String, Account.Id> usernameCache;
   private final Set<Account.FieldName> readOnlyAccountFields;
 
-  private final Cache<String, Set<AccountGroup.Id>> membershipCache;
+  private final Cache<String, Set<AccountGroup.UUID>> membershipCache;
 
   @Inject
   LdapRealm(
       final Helper helper,
       final AuthConfig authConfig,
       final EmailExpander emailExpander,
-      @Named(LdapModule.GROUP_CACHE) final Cache<String, Set<AccountGroup.Id>> membershipCache,
+      @Named(LdapModule.GROUP_CACHE) final Cache<String, Set<AccountGroup.UUID>> membershipCache,
       @Named(LdapModule.USERNAME_CACHE) final Cache<String, Account.Id> usernameCache,
       @GerritServerConfig final Config config) {
     this.helper = helper;
@@ -241,8 +241,8 @@
   }
 
   @Override
-  public Set<AccountGroup.Id> groups(final AccountState who) {
-    final HashSet<AccountGroup.Id> r = new HashSet<AccountGroup.Id>();
+  public Set<AccountGroup.UUID> groups(final AccountState who) {
+    final HashSet<AccountGroup.UUID> r = new HashSet<AccountGroup.UUID>();
     r.addAll(membershipCache.get(findId(who.getExternalIds())));
     r.addAll(who.getInternalGroups());
     return r;
@@ -324,7 +324,7 @@
     }
   }
 
-  static class MemberLoader extends EntryCreator<String, Set<AccountGroup.Id>> {
+  static class MemberLoader extends EntryCreator<String, Set<AccountGroup.UUID>> {
     private final Helper helper;
 
     @Inject
@@ -333,7 +333,7 @@
     }
 
     @Override
-    public Set<AccountGroup.Id> createEntry(final String username)
+    public Set<AccountGroup.UUID> createEntry(final String username)
         throws Exception {
       final DirContext ctx = helper.open();
       try {
@@ -348,7 +348,7 @@
     }
 
     @Override
-    public Set<AccountGroup.Id> missing(final String key) {
+    public Set<AccountGroup.UUID> missing(final String key) {
       return Collections.emptySet();
     }
   }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/AuthConfig.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/AuthConfig.java
index 16a6a7c..a747ea4 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/config/AuthConfig.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/AuthConfig.java
@@ -29,9 +29,7 @@
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
-import java.util.HashSet;
 import java.util.List;
-import java.util.Set;
 
 /** Authentication related settings from {@code gerrit.config}. */
 @Singleton
@@ -45,10 +43,8 @@
   private final boolean cookieSecure;
   private final SignedToken emailReg;
 
-  private final AccountGroup.Id administratorGroup;
-  private final Set<AccountGroup.Id> anonymousGroups;
-  private final Set<AccountGroup.Id> registeredGroups;
-  private final AccountGroup.Id batchUsersGroup;
+  private final AccountGroup.UUID administratorGroup;
+  private final AccountGroup.UUID batchUsersGroup;
 
   private final boolean allowGoogleAccountUpgrade;
 
@@ -64,13 +60,8 @@
     cookieSecure = cfg.getBoolean("auth", "cookiesecure", false);
     emailReg = new SignedToken(5 * 24 * 60 * 60, s.registerEmailPrivateKey);
 
-    final HashSet<AccountGroup.Id> r = new HashSet<AccountGroup.Id>(2);
-    r.add(s.anonymousGroupId);
-    r.add(s.registeredGroupId);
-    registeredGroups = Collections.unmodifiableSet(r);
-    anonymousGroups = Collections.singleton(s.anonymousGroupId);
-    administratorGroup = s.adminGroupId;
-    batchUsersGroup = s.batchUsersGroupId;
+    administratorGroup = s.adminGroupUUID;
+    batchUsersGroup = s.batchUsersGroupUUID;
 
     if (authType == AuthType.OPENID) {
       allowGoogleAccountUpgrade =
@@ -127,25 +118,15 @@
   }
 
   /** Identity of the magic group with full powers. */
-  public AccountGroup.Id getAdministratorsGroup() {
+  public AccountGroup.UUID getAdministratorsGroup() {
     return administratorGroup;
   }
 
   /** Identity of the group whose service is degraded to lower priority. */
-  public AccountGroup.Id getBatchUsersGroup() {
+  public AccountGroup.UUID getBatchUsersGroup() {
     return batchUsersGroup;
   }
 
-  /** Groups that all users, including anonymous users, belong to. */
-  public Set<AccountGroup.Id> getAnonymousGroups() {
-    return anonymousGroups;
-  }
-
-  /** Groups that all users who have created an account belong to. */
-  public Set<AccountGroup.Id> getRegisteredGroups() {
-    return registeredGroups;
-  }
-
   /** OpenID identities which the server permits for authentication. */
   public List<OpenIdProviderPattern> getAllowedOpenIDs() {
     return allowedOpenIDs;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/ConfigUtil.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/ConfigUtil.java
index f24dcc5..3c102ba 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/config/ConfigUtil.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/ConfigUtil.java
@@ -310,10 +310,10 @@
    * @return the actual groups resolved from the database. If no groups are
    *         found, returns an empty {@code Set}, never {@code null}.
    */
-  public static Set<AccountGroup.Id> groupsFor(
+  public static Set<AccountGroup.UUID> groupsFor(
       SchemaFactory<ReviewDb> dbfactory, String[] groupNames, Logger log,
       String groupNotFoundWarning) {
-    final Set<AccountGroup.Id> result = new HashSet<AccountGroup.Id>();
+    final Set<AccountGroup.UUID> result = new HashSet<AccountGroup.UUID>();
     try {
       final ReviewDb db = dbfactory.open();
       try {
@@ -322,9 +322,16 @@
               db.accountGroupNames().get(new AccountGroup.NameKey(name));
           if (group == null) {
             log.warn(MessageFormat.format(groupNotFoundWarning, name));
-          } else {
-            result.add(group.getId());
+            continue;
           }
+
+          AccountGroup ag = db.accountGroups().get(group.getId());
+          if (ag == null) {
+            log.warn(MessageFormat.format(groupNotFoundWarning, name));
+            continue;
+          }
+
+          result.add(ag.getGroupUUID());
         }
       } finally {
         db.close();
@@ -345,7 +352,7 @@
    * @return the actual groups resolved from the database. If no groups are
    *         found, returns an empty {@code Set}, never {@code null}.
    */
-  public static Set<AccountGroup.Id> groupsFor(
+  public static Set<AccountGroup.UUID> groupsFor(
       SchemaFactory<ReviewDb> dbfactory, String[] groupNames, Logger log) {
     return groupsFor(dbfactory, groupNames, log,
         "Group \"{0}\" not in database, skipping.");
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/GitReceivePackGroupsProvider.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/GitReceivePackGroupsProvider.java
index 9af6d62..1c13b9e 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/config/GitReceivePackGroupsProvider.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/GitReceivePackGroupsProvider.java
@@ -22,21 +22,17 @@
 import org.eclipse.jgit.lib.Config;
 
 import java.util.Collections;
-import java.util.HashSet;
 
 public class GitReceivePackGroupsProvider extends GroupSetProvider {
   @Inject
   public GitReceivePackGroupsProvider(@GerritServerConfig Config config,
-      AuthConfig authConfig, SchemaFactory<ReviewDb> db) {
+      SchemaFactory<ReviewDb> db) {
     super(config, db, "receive", null, "allowGroup");
 
     // If no group was set, default to "registered users"
     //
     if (groupIds.isEmpty()) {
-      HashSet<AccountGroup.Id> all = new HashSet<AccountGroup.Id>();
-      all.addAll(authConfig.getRegisteredGroups());
-      all.removeAll(authConfig.getAnonymousGroups());
-      groupIds = Collections.unmodifiableSet(all);
+      groupIds = Collections.singleton(AccountGroup.REGISTERED_USERS);
     }
   }
 }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/GitUploadPackGroupsProvider.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/GitUploadPackGroupsProvider.java
index bfb09a5..65e6900 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/config/GitUploadPackGroupsProvider.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/GitUploadPackGroupsProvider.java
@@ -27,15 +27,15 @@
 public class GitUploadPackGroupsProvider extends GroupSetProvider {
   @Inject
   public GitUploadPackGroupsProvider(@GerritServerConfig Config config,
-      AuthConfig authConfig, SchemaFactory<ReviewDb> db) {
+      SchemaFactory<ReviewDb> db) {
     super(config, db, "upload", null, "allowGroup");
 
     // If no group was set, default to "registered users" and "anonymous"
     //
     if (groupIds.isEmpty()) {
-      HashSet<AccountGroup.Id> all = new HashSet<AccountGroup.Id>();
-      all.addAll(authConfig.getRegisteredGroups());
-      all.addAll(authConfig.getAnonymousGroups());
+      HashSet<AccountGroup.UUID> all = new HashSet<AccountGroup.UUID>();
+      all.add(AccountGroup.REGISTERED_USERS);
+      all.add(AccountGroup.ANONYMOUS_USERS);
       groupIds = Collections.unmodifiableSet(all);
     }
   }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/GroupSetProvider.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/GroupSetProvider.java
index 373fdb5..6ff977f 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/config/GroupSetProvider.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/GroupSetProvider.java
@@ -30,11 +30,11 @@
 import java.util.Set;
 
 public abstract class GroupSetProvider implements
-    Provider<Set<AccountGroup.Id>> {
+    Provider<Set<AccountGroup.UUID>> {
   private static final Logger log =
       LoggerFactory.getLogger(GroupSetProvider.class);
 
-  protected Set<AccountGroup.Id> groupIds;
+  protected Set<AccountGroup.UUID> groupIds;
 
   @Inject
   protected GroupSetProvider(@GerritServerConfig Config config,
@@ -44,7 +44,7 @@
   }
 
   @Override
-  public Set<AccountGroup.Id> get() {
+  public Set<AccountGroup.UUID> get() {
     return groupIds;
   }
 }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/ProjectCreatorGroupsProvider.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/ProjectCreatorGroupsProvider.java
index 381c914..e58e8bf 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/config/ProjectCreatorGroupsProvider.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/ProjectCreatorGroupsProvider.java
@@ -15,7 +15,6 @@
 package com.google.gerrit.server.config;
 
 import com.google.gerrit.reviewdb.ReviewDb;
-import com.google.gerrit.reviewdb.SystemConfig;
 import com.google.gwtorm.client.SchemaFactory;
 import com.google.inject.Inject;
 
@@ -37,11 +36,11 @@
 public class ProjectCreatorGroupsProvider extends GroupSetProvider {
   @Inject
   public ProjectCreatorGroupsProvider(@GerritServerConfig final Config config,
-      final SystemConfig systemConfig, final SchemaFactory<ReviewDb> db) {
+      final AuthConfig authConfig, final SchemaFactory<ReviewDb> db) {
     super(config, db, "repository", "*", "createGroup");
 
     if (groupIds.isEmpty()) {
-      groupIds = Collections.singleton(systemConfig.adminGroupId);
+      groupIds = Collections.singleton(authConfig.getAdministratorsGroup());
     }
   }
 }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/ProjectOwnerGroupsProvider.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/ProjectOwnerGroupsProvider.java
index c457d73..4d5ad0c 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/config/ProjectOwnerGroupsProvider.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/ProjectOwnerGroupsProvider.java
@@ -37,7 +37,7 @@
 public class ProjectOwnerGroupsProvider extends GroupSetProvider {
   @Inject
   public ProjectOwnerGroupsProvider(
-      @ProjectCreatorGroups final Set<AccountGroup.Id> creatorGroups,
+      @ProjectCreatorGroups final Set<AccountGroup.UUID> creatorGroups,
       @GerritServerConfig final Config config, final SchemaFactory<ReviewDb> db) {
     super(config, db, "repository", "*", "ownerGroup");
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/PushReplication.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/PushReplication.java
index 9db9e44..295a143 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/PushReplication.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/PushReplication.java
@@ -354,7 +354,7 @@
 
       String[] authGroupNames =
           cfg.getStringList("remote", rc.getName(), "authGroup");
-      final Set<AccountGroup.Id> authGroups;
+      final Set<AccountGroup.UUID> authGroups;
       if (authGroupNames.length > 0) {
         authGroups = ConfigUtil.groupsFor(db, authGroupNames, //
             log, "Group \"{0}\" not in database, removing from authGroup");
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/ReceiveCommits.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/ReceiveCommits.java
index 67f9929..13ac173 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/ReceiveCommits.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/ReceiveCommits.java
@@ -40,6 +40,7 @@
 import com.google.gerrit.server.GerritPersonIdent;
 import com.google.gerrit.server.IdentifiedUser;
 import com.google.gerrit.server.account.AccountResolver;
+import com.google.gerrit.server.account.GroupCache;
 import com.google.gerrit.server.config.CanonicalWebUrl;
 import com.google.gerrit.server.config.TrackingFooters;
 import com.google.gerrit.server.mail.CreateChangeSender;
@@ -145,6 +146,7 @@
   private final ChangeHookRunner hooks;
   private final GitRepositoryManager repoManager;
   private final ProjectCache projectCache;
+  private final GroupCache groupCache;
   private final String canonicalWebUrl;
   private final PersonIdent gerritIdent;
   private final TrackingFooters trackingFooters;
@@ -181,6 +183,7 @@
       final ChangeHookRunner hooks,
       final ProjectCache projectCache,
       final GitRepositoryManager repoManager,
+      final GroupCache groupCache,
       @CanonicalWebUrl @Nullable final String canonicalWebUrl,
       @GerritPersonIdent final PersonIdent gerritIdent,
       final TrackingFooters trackingFooters,
@@ -199,6 +202,7 @@
     this.hooks = hooks;
     this.projectCache = projectCache;
     this.repoManager = repoManager;
+    this.groupCache = groupCache;
     this.canonicalWebUrl = canonicalWebUrl;
     this.gerritIdent = gerritIdent;
     this.trackingFooters = trackingFooters;
@@ -417,9 +421,14 @@
     AbstractAgreement bestAgreement = null;
     ContributorAgreement bestCla = null;
 
-    OUTER: for (AccountGroup.Id groupId : currentUser.getEffectiveGroups()) {
+    OUTER: for (AccountGroup.UUID groupUUID : currentUser.getEffectiveGroups()) {
+      AccountGroup group = groupCache.get(groupUUID);
+      if (group == null) {
+        continue;
+      }
+
       final List<AccountGroupAgreement> temp =
-          db.accountGroupAgreements().byGroup(groupId).toList();
+          db.accountGroupAgreements().byGroup(group.getId()).toList();
 
       Collections.reverse(temp);
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/mail/ChangeEmail.java b/gerrit-server/src/main/java/com/google/gerrit/server/mail/ChangeEmail.java
index f5a7870..ebbe686 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/mail/ChangeEmail.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/mail/ChangeEmail.java
@@ -69,8 +69,8 @@
 
     /** Is the from user in an email squelching group? */
     final IdentifiedUser user =  args.identifiedUserFactory.create(id);
-    final Set<AccountGroup.Id> gids = user.getEffectiveGroups();
-    for (final AccountGroup.Id gid : gids) {
+    final Set<AccountGroup.UUID> gids = user.getEffectiveGroups();
+    for (final AccountGroup.UUID gid : gids) {
       if (args.groupCache.get(gid).isEmailOnlyAuthors()) {
         emailOnlyAuthors = true;
         break;
@@ -273,11 +273,11 @@
   }
 
   /** Get the groups which own the project. */
-  protected Set<AccountGroup.Id> getProjectOwners() {
+  protected Set<AccountGroup.UUID> getProjectOwners() {
     final ProjectState r;
 
     r = args.projectCache.get(change.getProject());
-    return r != null ? r.getOwners() : Collections.<AccountGroup.Id> emptySet();
+    return r != null ? r.getOwners() : Collections.<AccountGroup.UUID> emptySet();
   }
 
   /** TO or CC all vested parties (change owner, patch set uploader, author). */
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/mail/CreateChangeSender.java b/gerrit-server/src/main/java/com/google/gerrit/server/mail/CreateChangeSender.java
index c14ff1b..8bb68df 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/mail/CreateChangeSender.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/mail/CreateChangeSender.java
@@ -20,6 +20,7 @@
 import com.google.gerrit.reviewdb.AccountProjectWatch;
 import com.google.gerrit.reviewdb.Change;
 import com.google.gerrit.reviewdb.AccountProjectWatch.NotifyType;
+import com.google.gerrit.server.account.GroupCache;
 import com.google.gerrit.server.ssh.SshInfo;
 import com.google.gwtorm.client.OrmException;
 import com.google.inject.Inject;
@@ -34,10 +35,13 @@
     public CreateChangeSender create(Change change);
   }
 
+  private final GroupCache groupCache;
+
   @Inject
   public CreateChangeSender(EmailArguments ea, SshInfo sshInfo,
-      @Assisted Change c) {
+      GroupCache groupCache, @Assisted Change c) {
     super(ea, sshInfo, c);
+    this.groupCache = groupCache;
   }
 
   @Override
@@ -52,10 +56,13 @@
       // Try to mark interested owners with a TO and not a BCC line.
       //
       final Set<Account.Id> owners = new HashSet<Account.Id>();
-      for (AccountGroup.Id g : getProjectOwners()) {
-        for (AccountGroupMember m : args.db.get().accountGroupMembers()
-            .byGroup(g)) {
-          owners.add(m.getAccountId());
+      for (AccountGroup.UUID uuid : getProjectOwners()) {
+        AccountGroup group = groupCache.get(uuid);
+        if (group != null) {
+          for (AccountGroupMember m : args.db.get().accountGroupMembers()
+              .byGroup(group.getId())) {
+            owners.add(m.getAccountId());
+          }
         }
       }
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/AccessControlModule.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/AccessControlModule.java
index 1e2e7f4..64e5299 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/AccessControlModule.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/AccessControlModule.java
@@ -33,19 +33,19 @@
 public class AccessControlModule extends FactoryModule {
   @Override
   protected void configure() {
-    bind(new TypeLiteral<Set<AccountGroup.Id>>() {}) //
+    bind(new TypeLiteral<Set<AccountGroup.UUID>>() {}) //
         .annotatedWith(ProjectCreatorGroups.class) //
         .toProvider(ProjectCreatorGroupsProvider.class).in(SINGLETON);
 
-    bind(new TypeLiteral<Set<AccountGroup.Id>>() {}) //
+    bind(new TypeLiteral<Set<AccountGroup.UUID>>() {}) //
         .annotatedWith(ProjectOwnerGroups.class) //
         .toProvider(ProjectOwnerGroupsProvider.class).in(SINGLETON);
 
-    bind(new TypeLiteral<Set<AccountGroup.Id>>() {}) //
+    bind(new TypeLiteral<Set<AccountGroup.UUID>>() {}) //
         .annotatedWith(GitUploadPackGroups.class) //
         .toProvider(GitUploadPackGroupsProvider.class).in(SINGLETON);
 
-    bind(new TypeLiteral<Set<AccountGroup.Id>>() {}) //
+    bind(new TypeLiteral<Set<AccountGroup.UUID>>() {}) //
         .annotatedWith(GitReceivePackGroups.class) //
         .toProvider(GitReceivePackGroupsProvider.class).in(SINGLETON);
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectCacheImpl.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectCacheImpl.java
index 99b7a67..c8a1f7f 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectCacheImpl.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectCacheImpl.java
@@ -14,6 +14,7 @@
 
 package com.google.gerrit.server.project;
 
+import com.google.gerrit.reviewdb.AccountGroup;
 import com.google.gerrit.reviewdb.Project;
 import com.google.gerrit.reviewdb.RefRight;
 import com.google.gerrit.reviewdb.ReviewDb;
@@ -34,8 +35,11 @@
 
 import java.util.Collection;
 import java.util.Collections;
+import java.util.HashSet;
 import java.util.Iterator;
+import java.util.Map;
 import java.util.NoSuchElementException;
+import java.util.Set;
 import java.util.SortedSet;
 import java.util.TreeSet;
 import java.util.concurrent.locks.Lock;
@@ -191,9 +195,27 @@
           cfg.load(git);
 
           final Project p = cfg.getProject();
-          final Collection<RefRight> rights =
-              Collections.unmodifiableCollection(db.refRights().byProject(key)
-                  .toList());
+
+          Collection<RefRight> rights = db.refRights().byProject(key).toList();
+
+          Set<AccountGroup.Id> groupIds = new HashSet<AccountGroup.Id>();
+          for (RefRight r : rights) {
+            groupIds.add(r.getAccountGroupId());
+          }
+          Map<AccountGroup.Id, AccountGroup> groupsById =
+              db.accountGroups().toMap(db.accountGroups().get(groupIds));
+
+          for (RefRight r : rights) {
+            AccountGroup group = groupsById.get(r.getAccountGroupId());
+            if (group != null) {
+              r.setAccountGroupUUID(group.getGroupUUID());
+            } else {
+              r.setAccountGroupUUID(new AccountGroup.UUID("DELETED_GROUP_"
+                  + r.getAccountGroupId().get()));
+            }
+          }
+          rights = Collections.unmodifiableCollection(rights);
+
           return projectStateFactory.create(p, rights);
         } finally {
           git.close();
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectControl.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectControl.java
index 25778a6..c84b1f5 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectControl.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectControl.java
@@ -101,16 +101,16 @@
     ProjectControl create(CurrentUser who, ProjectState ps);
   }
 
-  private final Set<AccountGroup.Id> uploadGroups;
-  private final Set<AccountGroup.Id> receiveGroups;
+  private final Set<AccountGroup.UUID> uploadGroups;
+  private final Set<AccountGroup.UUID> receiveGroups;
 
   private final RefControl.Factory refControlFactory;
   private final CurrentUser user;
   private final ProjectState state;
 
   @Inject
-  ProjectControl(@GitUploadPackGroups Set<AccountGroup.Id> uploadGroups,
-      @GitReceivePackGroups Set<AccountGroup.Id> receiveGroups,
+  ProjectControl(@GitUploadPackGroups Set<AccountGroup.UUID> uploadGroups,
+      @GitReceivePackGroups Set<AccountGroup.UUID> receiveGroups,
       final RefControl.Factory refControlFactory,
       @Assisted CurrentUser who, @Assisted ProjectState ps) {
     this.uploadGroups = uploadGroups;
@@ -197,10 +197,10 @@
   // TODO (anatol.pomazau): Try to merge this method with similar RefRightsForPattern#canPerform
   private boolean canPerformOnAnyRef(ApprovalCategory.Id actionId,
       short requireValue) {
-    final Set<AccountGroup.Id> groups = user.getEffectiveGroups();
+    final Set<AccountGroup.UUID> groups = user.getEffectiveGroups();
 
     for (final RefRight pr : state.getAllRights(actionId, true)) {
-      if (groups.contains(pr.getAccountGroupId())
+      if (groups.contains(pr.getAccountGroupUUID())
           && pr.getMaxValue() >= requireValue) {
         return true;
       }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectState.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectState.java
index 0b8e83a..5456769a 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectState.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectState.java
@@ -46,7 +46,7 @@
 
   private final Project project;
   private final Collection<RefRight> localRights;
-  private final Set<AccountGroup.Id> localOwners;
+  private final Set<AccountGroup.UUID> localOwners;
 
   private volatile Collection<RefRight> inheritedRights;
 
@@ -75,12 +75,12 @@
     this.project = project;
     this.localRights = rights;
 
-    final HashSet<AccountGroup.Id> groups = new HashSet<AccountGroup.Id>();
+    final HashSet<AccountGroup.UUID> groups = new HashSet<AccountGroup.UUID>();
     for (final RefRight right : rights) {
       if (ApprovalCategory.OWN.equals(right.getApprovalCategoryId())
           && right.getMaxValue() > 0
           && right.getRefPattern().equals(RefRight.ALL)) {
-        groups.add(right.getAccountGroupId());
+        groups.add(right.getAccountGroupUUID());
       }
     }
     localOwners = Collections.unmodifiableSet(groups);
@@ -216,7 +216,7 @@
    *         are no local owners the local owners of the nearest parent project
    *         that has local owners are returned
    */
-  public Set<AccountGroup.Id> getOwners() {
+  public Set<AccountGroup.UUID> getOwners() {
     if (!localOwners.isEmpty() || isSpecialWildProject()
         || project.getParent() == null) {
       return localOwners;
@@ -237,11 +237,11 @@
    *         owners) and all groups to which the owner privilege for 'refs/*' is
    *         assigned for one of the parent projects (the inherited owners).
    */
-  public Set<AccountGroup.Id> getAllOwners() {
-    final HashSet<AccountGroup.Id> owners = new HashSet<AccountGroup.Id>();
+  public Set<AccountGroup.UUID> getAllOwners() {
+    final HashSet<AccountGroup.UUID> owners = new HashSet<AccountGroup.UUID>();
     for (final RefRight right : getAllRights(ApprovalCategory.OWN, true)) {
       if (right.getMaxValue() > 0 && right.getRefPattern().equals(RefRight.ALL)) {
-        owners.add(right.getAccountGroupId());
+        owners.add(right.getAccountGroupUUID());
       }
     }
     return Collections.unmodifiableSet(owners);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/RefControl.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/RefControl.java
index 8ddf585..617ff2a 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/RefControl.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/RefControl.java
@@ -68,7 +68,6 @@
     RefControl create(ProjectControl projectControl, String ref);
   }
 
-  private final SystemConfig systemConfig;
   private final ProjectControl projectControl;
   private final String refName;
 
@@ -76,10 +75,8 @@
   private Boolean canForgeCommitter;
 
   @Inject
-  protected RefControl(final SystemConfig systemConfig,
-      @Assisted final ProjectControl projectControl,
+  protected RefControl(@Assisted final ProjectControl projectControl,
       @Assisted String ref) {
-    this.systemConfig = systemConfig;
     if (isRE(ref)) {
       ref = shortestExample(ref);
 
@@ -270,7 +267,7 @@
   public short normalize(ApprovalCategory.Id category, short score) {
     short minAllowed = 0, maxAllowed = 0;
     for (RefRight r : getApplicableRights(category)) {
-      if (getCurrentUser().getEffectiveGroups().contains(r.getAccountGroupId())) {
+      if (getCurrentUser().getEffectiveGroups().contains(r.getAccountGroupUUID())) {
         minAllowed = (short) Math.min(minAllowed, r.getMinValue());
         maxAllowed = (short) Math.max(maxAllowed, r.getMaxValue());
       }
@@ -320,9 +317,9 @@
      * @param groups The groups of the user
      * @return The allowed value for this ref for all the specified groups
      */
-    private boolean allowedValueForRef(Set<AccountGroup.Id> groups, short level) {
+    private boolean allowedValueForRef(Set<AccountGroup.UUID> groups, short level) {
       for (RefRight right : rights) {
-        if (groups.contains(right.getAccountGroupId())
+        if (groups.contains(right.getAccountGroupUUID())
             && right.getMaxValue() >= level) {
           return true;
         }
@@ -332,7 +329,7 @@
   }
 
   boolean canPerform(ApprovalCategory.Id actionId, short level) {
-    final Set<AccountGroup.Id> groups = getCurrentUser().getEffectiveGroups();
+    final Set<AccountGroup.UUID> groups = getCurrentUser().getEffectiveGroups();
 
     List<RefRight> allRights = new ArrayList<RefRight>();
     allRights.addAll(getAllRights(actionId));
@@ -538,9 +535,9 @@
    */
   private Set<RefRight> resolveOwnerGroups(final RefRight refRight) {
     final Set<RefRight> resolvedRefRights = new HashSet<RefRight>();
-    if (refRight.getAccountGroupId().equals(systemConfig.ownerGroupId)) {
-      for (final AccountGroup.Id ownerGroup : getProjectState().getAllOwners()) {
-        if (!ownerGroup.equals(systemConfig.ownerGroupId)) {
+    if (AccountGroup.PROJECT_OWNERS.equals(refRight.getAccountGroupUUID())) {
+      for (final AccountGroup.UUID ownerGroup : getProjectState().getAllOwners()) {
+        if (!AccountGroup.PROJECT_OWNERS.equals(ownerGroup)) {
           resolvedRefRights.add(new RefRight(refRight, ownerGroup));
         }
       }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeQueryBuilder.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeQueryBuilder.java
index d62befc..074ad19 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeQueryBuilder.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeQueryBuilder.java
@@ -344,15 +344,15 @@
     //
     AccountGroup g = args.groupCache.get(new AccountGroup.NameKey(who));
     if (g != null) {
-      return visibleto(new SingleGroupUser(args.authConfig, g.getId()));
+      return visibleto(new SingleGroupUser(args.authConfig, g.getGroupUUID()));
     }
 
     Collection<AccountGroup> matches =
         args.groupCache.get(new AccountGroup.ExternalNameKey(who));
     if (matches != null && !matches.isEmpty()) {
-      HashSet<AccountGroup.Id> ids = new HashSet<AccountGroup.Id>();
+      HashSet<AccountGroup.UUID> ids = new HashSet<AccountGroup.UUID>();
       for (AccountGroup group : matches) {
-        ids.add(group.getId());
+        ids.add(group.getGroupUUID());
       }
       return visibleto(new SingleGroupUser(args.authConfig, ids));
     }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/SingleGroupUser.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/SingleGroupUser.java
index 2fb6694..1c37ac4 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/SingleGroupUser.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/SingleGroupUser.java
@@ -26,19 +26,19 @@
 import java.util.Set;
 
 final class SingleGroupUser extends CurrentUser {
-  private final Set<AccountGroup.Id> groups;
+  private final Set<AccountGroup.UUID> groups;
 
-  SingleGroupUser(AuthConfig authConfig, AccountGroup.Id groupId) {
+  SingleGroupUser(AuthConfig authConfig, AccountGroup.UUID groupId) {
     this(authConfig, Collections.singleton(groupId));
   }
 
-  SingleGroupUser(AuthConfig authConfig, Set<AccountGroup.Id> groups) {
+  SingleGroupUser(AuthConfig authConfig, Set<AccountGroup.UUID> groups) {
     super(AccessPath.UNKNOWN, authConfig);
     this.groups = groups;
   }
 
   @Override
-  public Set<AccountGroup.Id> getEffectiveGroups() {
+  public Set<AccountGroup.UUID> getEffectiveGroups() {
     return groups;
   }
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/workflow/CategoryFunction.java b/gerrit-server/src/main/java/com/google/gerrit/server/workflow/CategoryFunction.java
index 67003932..232974a 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/workflow/CategoryFunction.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/workflow/CategoryFunction.java
@@ -94,7 +94,7 @@
       final FunctionState state) {
     RefControl rc = state.controlFor(user);
     for (final RefRight pr : rc.getApplicableRights(at.getCategory().getId())) {
-      if (user.getEffectiveGroups().contains(pr.getAccountGroupId())
+      if (user.getEffectiveGroups().contains(pr.getAccountGroupUUID())
           && (pr.getMinValue() < 0 || pr.getMaxValue() > 0)) {
         return true;
       }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/workflow/FunctionState.java b/gerrit-server/src/main/java/com/google/gerrit/server/workflow/FunctionState.java
index 36a52e2..30ff6a3 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/workflow/FunctionState.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/workflow/FunctionState.java
@@ -147,7 +147,7 @@
     //
     short minAllowed = 0, maxAllowed = 0;
     for (final RefRight r : rc.getApplicableRights(a.getCategoryId())) {
-      final AccountGroup.Id grp = r.getAccountGroupId();
+      final AccountGroup.UUID grp = r.getAccountGroupUUID();
       if (user.getEffectiveGroups().contains(grp)) {
         minAllowed = (short) Math.min(minAllowed, r.getMinValue());
         maxAllowed = (short) Math.max(maxAllowed, r.getMaxValue());
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/workflow/SubmitFunction.java b/gerrit-server/src/main/java/com/google/gerrit/server/workflow/SubmitFunction.java
index f0a00ff..7e2f42b 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/workflow/SubmitFunction.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/workflow/SubmitFunction.java
@@ -45,7 +45,7 @@
     if (valid(at, state)) {
       RefControl rc = state.controlFor(user);
       for (final RefRight pr : rc.getApplicableRights(at.getCategory().getId())) {
-        if (user.getEffectiveGroups().contains(pr.getAccountGroupId())
+        if (user.getEffectiveGroups().contains(pr.getAccountGroupUUID())
             && pr.getMaxValue() > 0) {
           return true;
         }
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/mail/FromAddressGeneratorProviderTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/mail/FromAddressGeneratorProviderTest.java
index f819dac..6d56b4a 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/mail/FromAddressGeneratorProviderTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/mail/FromAddressGeneratorProviderTest.java
@@ -278,7 +278,7 @@
     account.setFullName(name);
     account.setPreferredEmail(email);
     final AccountState s =
-        new AccountState(account, Collections.<AccountGroup.Id> emptySet(),
+        new AccountState(account, Collections.<AccountGroup.UUID> emptySet(),
             Collections.<AccountExternalId> emptySet());
     return s;
   }
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/project/RefControlTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/project/RefControlTest.java
index 58e645e..a2d849f 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/project/RefControlTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/project/RefControlTest.java
@@ -45,8 +45,10 @@
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 
 public class RefControlTest extends TestCase {
@@ -188,25 +190,24 @@
 
   private final Project.NameKey local = new Project.NameKey("test");
   private final Project.NameKey parent = new Project.NameKey("parent");
-  private final AccountGroup.Id admin = new AccountGroup.Id(1);
-  private final AccountGroup.Id anonymous = new AccountGroup.Id(2);
-  private final AccountGroup.Id registered = new AccountGroup.Id(3);
-  private final AccountGroup.Id owners = new AccountGroup.Id(4);
+  private final AccountGroup.UUID admin = new AccountGroup.UUID("test.admin");
+  private final AccountGroup.UUID anonymous = AccountGroup.ANONYMOUS_USERS;
+  private final AccountGroup.UUID registered = AccountGroup.REGISTERED_USERS;
 
-  private final AccountGroup.Id devs = new AccountGroup.Id(5);
-  private final AccountGroup.Id fixers = new AccountGroup.Id(6);
+  private final AccountGroup.UUID devs = new AccountGroup.UUID("test.devs");
+  private final AccountGroup.UUID fixers = new AccountGroup.UUID("test.fixers");
 
   private final SystemConfig systemConfig;
   private final AuthConfig authConfig;
   private final AnonymousUser anonymousUser;
 
+  private final Map<AccountGroup.UUID, AccountGroup.Id> groupIds =
+      new HashMap<AccountGroup.UUID, AccountGroup.Id>();
+
   public RefControlTest() {
     systemConfig = SystemConfig.create();
-    systemConfig.adminGroupId = admin;
-    systemConfig.anonymousGroupId = anonymous;
-    systemConfig.registeredGroupId = registered;
-    systemConfig.ownerGroupId = owners;
-    systemConfig.batchUsersGroupId = anonymous;
+    systemConfig.adminGroupUUID = admin;
+    systemConfig.batchUsersGroupUUID = anonymous;
     try {
       byte[] bin = "abcdefghijklmnopqrstuvwxyz".getBytes("UTF-8");
       systemConfig.registerEmailPrivateKey = Base64.encodeBase64String(bin);
@@ -249,15 +250,22 @@
   }
 
   private void grant(Project.NameKey project, ApprovalCategory.Id categoryId,
-      AccountGroup.Id group, String ref, int maxValue) {
+      AccountGroup.UUID group, String ref, int maxValue) {
     grant(project, categoryId, group, ref, maxValue, maxValue);
   }
 
-  private void grant(Project.NameKey project, ApprovalCategory.Id categoryId, AccountGroup.Id group,
-      String ref, int minValue, int maxValue) {
+  private void grant(Project.NameKey project, ApprovalCategory.Id categoryId,
+      AccountGroup.UUID groupUUID, String ref, int minValue, int maxValue) {
+    AccountGroup.Id groupId = groupIds.get(groupUUID);
+    if (groupId == null) {
+      groupId = new AccountGroup.Id(groupIds.size() + 1);
+      groupIds.put(groupUUID, groupId);
+    }
+
     RefRight right =
         new RefRight(new RefRight.Key(project, new RefPattern(ref),
-            categoryId, group));
+            categoryId, groupId));
+    right.setAccountGroupUUID(groupUUID);
     right.setMinValue((short) minValue);
     right.setMaxValue((short) maxValue);
 
@@ -270,15 +278,15 @@
     }
   }
 
-  private ProjectControl user(AccountGroup.Id... memberOf) {
+  private ProjectControl user(AccountGroup.UUID... memberOf) {
     RefControl.Factory refControlFactory = new RefControl.Factory() {
       @Override
       public RefControl create(final ProjectControl projectControl, final String ref) {
-        return new RefControl(systemConfig, projectControl, ref);
+        return new RefControl(projectControl, ref);
       }
     };
-    return new ProjectControl(Collections.<AccountGroup.Id> emptySet(),
-        Collections.<AccountGroup.Id> emptySet(), refControlFactory,
+    return new ProjectControl(Collections.<AccountGroup.UUID> emptySet(),
+        Collections.<AccountGroup.UUID> emptySet(), refControlFactory,
         new MockUser(memberOf), newProjectState());
   }
 
@@ -295,17 +303,17 @@
   }
 
   private class MockUser extends CurrentUser {
-    private final Set<AccountGroup.Id> groups;
+    private final Set<AccountGroup.UUID> groups;
 
-    MockUser(AccountGroup.Id[] groupId) {
+    MockUser(AccountGroup.UUID[] groupId) {
       super(AccessPath.UNKNOWN, RefControlTest.this.authConfig);
-      groups = new HashSet<AccountGroup.Id>(Arrays.asList(groupId));
+      groups = new HashSet<AccountGroup.UUID>(Arrays.asList(groupId));
       groups.add(registered);
       groups.add(anonymous);
     }
 
     @Override
-    public Set<AccountGroup.Id> getEffectiveGroups() {
+    public Set<AccountGroup.UUID> getEffectiveGroups() {
       return groups;
     }
 
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshModule.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshModule.java
index 5b8edf0..61e8bfb 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshModule.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshModule.java
@@ -32,6 +32,7 @@
 import com.google.gerrit.server.project.ProjectControl;
 import com.google.gerrit.server.ssh.SshInfo;
 import com.google.gerrit.sshd.args4j.AccountGroupIdHandler;
+import com.google.gerrit.sshd.args4j.AccountGroupUUIDHandler;
 import com.google.gerrit.sshd.args4j.AccountIdHandler;
 import com.google.gerrit.sshd.args4j.PatchSetIdHandler;
 import com.google.gerrit.sshd.args4j.ProjectControlHandler;
@@ -117,6 +118,7 @@
 
     registerOptionHandler(Account.Id.class, AccountIdHandler.class);
     registerOptionHandler(AccountGroup.Id.class, AccountGroupIdHandler.class);
+    registerOptionHandler(AccountGroup.UUID.class, AccountGroupUUIDHandler.class);
     registerOptionHandler(PatchSet.Id.class, PatchSetIdHandler.class);
     registerOptionHandler(ProjectControl.class, ProjectControlHandler.class);
     registerOptionHandler(SocketAddress.class, SocketAddressHandler.class);
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/args4j/AccountGroupUUIDHandler.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/args4j/AccountGroupUUIDHandler.java
new file mode 100644
index 0000000..583a44d
--- /dev/null
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/args4j/AccountGroupUUIDHandler.java
@@ -0,0 +1,57 @@
+// Copyright (C) 2009 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.sshd.args4j;
+
+import com.google.gerrit.reviewdb.AccountGroup;
+import com.google.gerrit.server.account.GroupCache;
+import com.google.inject.Inject;
+import com.google.inject.assistedinject.Assisted;
+
+import org.kohsuke.args4j.CmdLineException;
+import org.kohsuke.args4j.CmdLineParser;
+import org.kohsuke.args4j.OptionDef;
+import org.kohsuke.args4j.spi.OptionHandler;
+import org.kohsuke.args4j.spi.Parameters;
+import org.kohsuke.args4j.spi.Setter;
+
+public class AccountGroupUUIDHandler extends OptionHandler<AccountGroup.UUID> {
+  private final GroupCache groupCache;
+
+  @SuppressWarnings("unchecked")
+  @Inject
+  public AccountGroupUUIDHandler(final GroupCache groupCache,
+      @Assisted final CmdLineParser parser, @Assisted final OptionDef option,
+      @Assisted final Setter setter) {
+    super(parser, option, setter);
+    this.groupCache = groupCache;
+  }
+
+  @Override
+  public final int parseArguments(final Parameters params)
+      throws CmdLineException {
+    final String n = params.getParameter(0);
+    final AccountGroup group = groupCache.get(new AccountGroup.NameKey(n));
+    if (group == null) {
+      throw new CmdLineException(owner, "Group \"" + n + "\" does not exist");
+    }
+    setter.addValue(group.getGroupUUID());
+    return 1;
+  }
+
+  @Override
+  public final String getDefaultMetaVariable() {
+    return "GROUP";
+  }
+}
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/CreateProject.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/CreateProject.java
index 4dec3b7..117445f 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/CreateProject.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/CreateProject.java
@@ -23,6 +23,7 @@
 import com.google.gerrit.reviewdb.Project.SubmitType;
 import com.google.gerrit.server.GerritPersonIdent;
 import com.google.gerrit.server.IdentifiedUser;
+import com.google.gerrit.server.account.GroupCache;
 import com.google.gerrit.server.config.ProjectCreatorGroups;
 import com.google.gerrit.server.config.ProjectOwnerGroups;
 import com.google.gerrit.server.git.GitRepositoryManager;
@@ -64,7 +65,7 @@
   private String projectName;
 
   @Option(name = "--owner", aliases = {"-o"}, usage = "owner(s) of project")
-  private List<AccountGroup.Id> ownerIds;
+  private List<AccountGroup.UUID> ownerIds;
 
   @Option(name = "--parent", aliases = {"-p"}, metaVar = "NAME", usage = "parent project")
   private ProjectControl newParent;
@@ -105,12 +106,15 @@
   private ProjectCache projectCache;
 
   @Inject
+  private GroupCache groupCache;
+
+  @Inject
   @ProjectCreatorGroups
-  private Set<AccountGroup.Id> projectCreatorGroups;
+  private Set<AccountGroup.UUID> projectCreatorGroups;
 
   @Inject
   @ProjectOwnerGroups
-  private Set<AccountGroup.Id> projectOwnerGroups;
+  private Set<AccountGroup.UUID> projectOwnerGroups;
 
   @Inject
   private IdentifiedUser currentUser;
@@ -202,10 +206,12 @@
       ConfigInvalidException {
 
     List<RefRight> access = new ArrayList<RefRight>();
-    for (AccountGroup.Id ownerId : ownerIds) {
+    for (AccountGroup.UUID ownerId : ownerIds) {
+      AccountGroup group = groupCache.get(ownerId);
+
       final RefRight.Key prk =
           new RefRight.Key(nameKey, new RefRight.RefPattern(
-              RefRight.ALL), ApprovalCategory.OWN, ownerId);
+              RefRight.ALL), ApprovalCategory.OWN, group.getId());
       final RefRight pr = new RefRight(prk);
       pr.setMaxValue((short) 1);
       pr.setMinValue((short) 1);
@@ -251,9 +257,9 @@
 
     if (ownerIds != null && !ownerIds.isEmpty()) {
       ownerIds =
-          new ArrayList<AccountGroup.Id>(new HashSet<AccountGroup.Id>(ownerIds));
+          new ArrayList<AccountGroup.UUID>(new HashSet<AccountGroup.UUID>(ownerIds));
     } else {
-      ownerIds = new ArrayList<AccountGroup.Id>(projectOwnerGroups);
+      ownerIds = new ArrayList<AccountGroup.UUID>(projectOwnerGroups);
     }
 
     while (branch.startsWith("/")) {