Abstract group systems into GroupBackend interface.

Currently, every NameKey and UUID for a group is expected to be backed
by an entry in the AccountGroup table. In the future, the group
backend will be swapable by allowing implementations to scope
AccountGroup.UUIDs e.g. "ldap:<ldap identifier>". This change
adds a GroupBackend interface that abstracts the implementation details
of a group system with respect to looking up groups (editing and
creating are not supported), which should be used instead of GroupCache
when looking up by AccountGroup.UUID or name. GroupBackends scope which
AccountGroup.UUIDs they handle by implementing the handles() method for
a particular prefix. The UniversalGroupBackend is a GroupBackend that
delegates methods to the GroupBackend that handles() the UUID, using
DynamicSets. The InternalGroupBackend and LdapGroupBackend are
the first GroupBackend implementation. It should be possible to bind
many GroupBackends concurrently, unfortunately, the current
implementation of LdapGroupBackend.handles() overlaps with the
InternalGroupBackend.handles() (since they are both stored in the
database), so only one those implementations may be bound at once.

Change-Id: Ieda21916247084ebc2dffc9dd82d3e1230b9ab64
This commit is contained in:
Colby Ranger
2012-05-02 09:02:03 -07:00
parent 8363aa5144
commit 2ac82b021f
34 changed files with 965 additions and 234 deletions

View File

@@ -14,6 +14,7 @@
package com.google.gerrit.server;
import com.google.common.collect.ImmutableSet;
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.AccountDiffPreference;
import com.google.gerrit.reviewdb.client.AccountGroup;
@@ -24,8 +25,9 @@ import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.account.AccountCache;
import com.google.gerrit.server.account.AccountState;
import com.google.gerrit.server.account.CapabilityControl;
import com.google.gerrit.server.account.GroupBackend;
import com.google.gerrit.server.account.GroupMembership;
import com.google.gerrit.server.account.MaterializedGroupMembership;
import com.google.gerrit.server.account.ListGroupMembership;
import com.google.gerrit.server.account.Realm;
import com.google.gerrit.server.config.AnonymousCowardName;
import com.google.gerrit.server.config.AuthConfig;
@@ -46,13 +48,10 @@ import java.net.InetSocketAddress;
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.Iterator;
import java.util.List;
import java.util.Set;
import java.util.TimeZone;
@@ -70,7 +69,7 @@ public class IdentifiedUser extends CurrentUser {
private final Provider<String> canonicalUrl;
private final Realm realm;
private final AccountCache accountCache;
private final MaterializedGroupMembership.Factory groupMembershipFactory;
private final GroupBackend groupBackend;
@Inject
GenericFactory(
@@ -79,14 +78,14 @@ public class IdentifiedUser extends CurrentUser {
final @AnonymousCowardName String anonymousCowardName,
final @CanonicalWebUrl Provider<String> canonicalUrl,
final Realm realm, final AccountCache accountCache,
final MaterializedGroupMembership.Factory groupMembershipFactory) {
final GroupBackend groupBackend) {
this.capabilityControlFactory = capabilityControlFactory;
this.authConfig = authConfig;
this.anonymousCowardName = anonymousCowardName;
this.canonicalUrl = canonicalUrl;
this.realm = realm;
this.accountCache = accountCache;
this.groupMembershipFactory = groupMembershipFactory;
this.groupBackend = groupBackend;
}
public IdentifiedUser create(final Account.Id id) {
@@ -96,14 +95,14 @@ public class IdentifiedUser extends CurrentUser {
public IdentifiedUser create(Provider<ReviewDb> db, Account.Id id) {
return new IdentifiedUser(capabilityControlFactory, AccessPath.UNKNOWN,
authConfig, anonymousCowardName, canonicalUrl, realm, accountCache,
groupMembershipFactory, null, db, id);
groupBackend, null, db, id);
}
public IdentifiedUser create(AccessPath accessPath,
Provider<SocketAddress> remotePeerProvider, Account.Id id) {
return new IdentifiedUser(capabilityControlFactory, accessPath,
authConfig, anonymousCowardName, canonicalUrl, realm, accountCache,
groupMembershipFactory, remotePeerProvider, null, id);
groupBackend, remotePeerProvider, null, id);
}
}
@@ -121,7 +120,7 @@ public class IdentifiedUser extends CurrentUser {
private final Provider<String> canonicalUrl;
private final Realm realm;
private final AccountCache accountCache;
private final MaterializedGroupMembership.Factory groupMembershipFactory;
private final GroupBackend groupBackend;
private final Provider<SocketAddress> remotePeerProvider;
private final Provider<ReviewDb> dbProvider;
@@ -133,7 +132,7 @@ public class IdentifiedUser extends CurrentUser {
final @AnonymousCowardName String anonymousCowardName,
final @CanonicalWebUrl Provider<String> canonicalUrl,
final Realm realm, final AccountCache accountCache,
final MaterializedGroupMembership.Factory groupMembershipFactory,
final GroupBackend groupBackend,
final @RemotePeer Provider<SocketAddress> remotePeerProvider,
final Provider<ReviewDb> dbProvider) {
@@ -143,7 +142,7 @@ public class IdentifiedUser extends CurrentUser {
this.canonicalUrl = canonicalUrl;
this.realm = realm;
this.accountCache = accountCache;
this.groupMembershipFactory = groupMembershipFactory;
this.groupBackend = groupBackend;
this.remotePeerProvider = remotePeerProvider;
this.dbProvider = dbProvider;
@@ -153,40 +152,22 @@ public class IdentifiedUser extends CurrentUser {
final Account.Id id) {
return new IdentifiedUser(capabilityControlFactory, accessPath,
authConfig, anonymousCowardName, canonicalUrl, realm, accountCache,
groupMembershipFactory, remotePeerProvider, dbProvider, id);
groupBackend, remotePeerProvider, dbProvider, id);
}
}
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 static final GroupMembership registeredGroups =
new ListGroupMembership(ImmutableSet.of(
AccountGroup.ANONYMOUS_USERS,
AccountGroup.REGISTERED_USERS));
private final Provider<String> canonicalUrl;
private final Realm realm;
private final AccountCache accountCache;
private final MaterializedGroupMembership.Factory groupMembershipFactory;
private final AuthConfig authConfig;
private final GroupBackend groupBackend;
private final String anonymousCowardName;
@Nullable
@@ -210,14 +191,13 @@ public class IdentifiedUser extends CurrentUser {
final String anonymousCowardName,
final Provider<String> canonicalUrl,
final Realm realm, final AccountCache accountCache,
final MaterializedGroupMembership.Factory groupMembershipFactory,
final GroupBackend groupBackend,
@Nullable final Provider<SocketAddress> remotePeerProvider,
@Nullable final Provider<ReviewDb> dbProvider, final Account.Id id) {
super(capabilityControlFactory, accessPath);
this.canonicalUrl = canonicalUrl;
this.realm = realm;
this.accountCache = accountCache;
this.groupMembershipFactory = groupMembershipFactory;
this.groupBackend = groupBackend;
this.authConfig = authConfig;
this.anonymousCowardName = anonymousCowardName;
this.remotePeerProvider = remotePeerProvider;
@@ -225,7 +205,8 @@ public class IdentifiedUser extends CurrentUser {
this.accountId = id;
}
private AccountState state() {
// TODO(cranger): maybe get the state through the accountCache instead.
public AccountState state() {
if (state == null) {
state = accountCache.get(getAccountId());
}
@@ -272,12 +253,11 @@ public class IdentifiedUser extends CurrentUser {
public GroupMembership getEffectiveGroups() {
if (effectiveGroups == null) {
if (authConfig.isIdentityTrustable(state().getExternalIds())) {
effectiveGroups = realm.groups(state());
effectiveGroups = groupBackend.membershipsOf(this);
} else {
effectiveGroups = groupMembershipFactory.create(registeredGroups);
effectiveGroups = registeredGroups;
}
}
return effectiveGroups;
}