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:
@@ -0,0 +1,48 @@
|
||||
// Copyright (C) 2012 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.common.data;
|
||||
|
||||
import com.google.gerrit.reviewdb.client.AccountGroup;
|
||||
|
||||
/**
|
||||
* Group methods exposed by the GroupBackend.
|
||||
*/
|
||||
public class GroupDescription {
|
||||
/**
|
||||
* The Basic information required to be exposed by any Group.
|
||||
*/
|
||||
public interface Basic {
|
||||
/** @return the non-null UUID of the group. */
|
||||
AccountGroup.UUID getGroupUUID();
|
||||
|
||||
/** @return the non-null name of the group. */
|
||||
String getName();
|
||||
|
||||
/** @return whether the group is visible to all accounts. */
|
||||
boolean isVisibleToAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* The extended information exposed by internal groups backed by an
|
||||
* AccountGroup.
|
||||
*/
|
||||
public interface Internal extends Basic {
|
||||
/** @return the backing AccountGroup. */
|
||||
AccountGroup getAccountGroup();
|
||||
}
|
||||
|
||||
private GroupDescription() {
|
||||
}
|
||||
}
|
@@ -0,0 +1,60 @@
|
||||
// Copyright (C) 2012 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.common.data;
|
||||
|
||||
import com.google.gerrit.reviewdb.client.AccountGroup;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Utility class for building GroupDescription objects.
|
||||
*/
|
||||
public class GroupDescriptions {
|
||||
|
||||
@Nullable
|
||||
public static AccountGroup toAccountGroup(GroupDescription.Basic group) {
|
||||
if (group instanceof GroupDescription.Internal) {
|
||||
return ((GroupDescription.Internal) group).getAccountGroup();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static GroupDescription.Internal forAccountGroup(final AccountGroup group) {
|
||||
return new GroupDescription.Internal() {
|
||||
@Override
|
||||
public AccountGroup.UUID getGroupUUID() {
|
||||
return group.getGroupUUID();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return group.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isVisibleToAll() {
|
||||
return group.isVisibleToAll();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AccountGroup getAccountGroup() {
|
||||
return group;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private GroupDescriptions() {
|
||||
}
|
||||
}
|
@@ -23,6 +23,10 @@ public class GroupReference implements Comparable<GroupReference> {
|
||||
return new GroupReference(group.getGroupUUID(), group.getName());
|
||||
}
|
||||
|
||||
public static GroupReference forGroup(GroupDescription.Basic group) {
|
||||
return new GroupReference(group.getGroupUUID(), group.getName());
|
||||
}
|
||||
|
||||
protected String uuid;
|
||||
protected String name;
|
||||
|
||||
|
@@ -26,6 +26,7 @@ import com.google.gerrit.server.project.NoSuchChangeException;
|
||||
import com.google.gerrit.server.project.NoSuchProjectException;
|
||||
import com.google.gwtjsonrpc.common.AsyncCallback;
|
||||
import com.google.gwtorm.server.OrmException;
|
||||
import com.google.gwtorm.server.OrmRuntimeException;
|
||||
import com.google.inject.Provider;
|
||||
|
||||
/** Support for services which require a {@link ReviewDb} instance. */
|
||||
@@ -70,20 +71,14 @@ public class BaseServiceImplementation {
|
||||
callback.onFailure(new NoSuchEntityException());
|
||||
} catch (NoSuchGroupException e) {
|
||||
callback.onFailure(new NoSuchEntityException());
|
||||
|
||||
} catch (OrmException e) {
|
||||
if (e.getCause() instanceof Failure) {
|
||||
callback.onFailure(e.getCause().getCause());
|
||||
|
||||
} else if (e.getCause() instanceof CorruptEntityException) {
|
||||
callback.onFailure(e.getCause());
|
||||
|
||||
} else if (e.getCause() instanceof NoSuchEntityException) {
|
||||
callback.onFailure(e.getCause());
|
||||
|
||||
} else {
|
||||
callback.onFailure(e);
|
||||
} catch (OrmRuntimeException e) {
|
||||
Exception ex = e;
|
||||
if (e.getCause() instanceof OrmException) {
|
||||
ex = (OrmException) e.getCause();
|
||||
}
|
||||
handleOrmException(callback, ex);
|
||||
} catch (OrmException e) {
|
||||
handleOrmException(callback, e);
|
||||
} catch (Failure e) {
|
||||
if (e.getCause() instanceof NoSuchProjectException
|
||||
|| e.getCause() instanceof NoSuchChangeException) {
|
||||
@@ -95,6 +90,19 @@ public class BaseServiceImplementation {
|
||||
}
|
||||
}
|
||||
|
||||
private static <T> void handleOrmException(
|
||||
final AsyncCallback<T> callback, Exception e) {
|
||||
if (e.getCause() instanceof Failure) {
|
||||
callback.onFailure(e.getCause().getCause());
|
||||
} else if (e.getCause() instanceof CorruptEntityException) {
|
||||
callback.onFailure(e.getCause());
|
||||
} else if (e.getCause() instanceof NoSuchEntityException) {
|
||||
callback.onFailure(e.getCause());
|
||||
} else {
|
||||
callback.onFailure(e);
|
||||
}
|
||||
}
|
||||
|
||||
/** Exception whose cause is passed into onFailure. */
|
||||
public static class Failure extends Exception {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
@@ -14,6 +14,7 @@
|
||||
|
||||
package com.google.gerrit.httpd.rpc;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.gerrit.common.data.AccountInfo;
|
||||
import com.google.gerrit.common.data.GroupReference;
|
||||
import com.google.gerrit.common.data.ReviewerInfo;
|
||||
@@ -21,8 +22,6 @@ import com.google.gerrit.common.data.SuggestService;
|
||||
import com.google.gerrit.common.errors.NoSuchGroupException;
|
||||
import com.google.gerrit.reviewdb.client.Account;
|
||||
import com.google.gerrit.reviewdb.client.AccountExternalId;
|
||||
import com.google.gerrit.reviewdb.client.AccountGroup;
|
||||
import com.google.gerrit.reviewdb.client.AccountGroupName;
|
||||
import com.google.gerrit.reviewdb.client.Change;
|
||||
import com.google.gerrit.reviewdb.client.Project;
|
||||
import com.google.gerrit.reviewdb.server.ReviewDb;
|
||||
@@ -31,7 +30,7 @@ import com.google.gerrit.server.IdentifiedUser;
|
||||
import com.google.gerrit.server.account.AccountCache;
|
||||
import com.google.gerrit.server.account.AccountControl;
|
||||
import com.google.gerrit.server.account.AccountVisibility;
|
||||
import com.google.gerrit.server.account.GroupCache;
|
||||
import com.google.gerrit.server.account.GroupBackend;
|
||||
import com.google.gerrit.server.account.GroupControl;
|
||||
import com.google.gerrit.server.account.GroupMembers;
|
||||
import com.google.gerrit.server.config.GerritServerConfig;
|
||||
@@ -65,7 +64,7 @@ class SuggestServiceImpl extends BaseServiceImplementation implements
|
||||
private final AccountControl.Factory accountControlFactory;
|
||||
private final ChangeControl.Factory changeControlFactory;
|
||||
private final Config cfg;
|
||||
private final GroupCache groupCache;
|
||||
private final GroupBackend groupBackend;
|
||||
private final boolean suggestAccounts;
|
||||
|
||||
@Inject
|
||||
@@ -77,7 +76,7 @@ class SuggestServiceImpl extends BaseServiceImplementation implements
|
||||
final IdentifiedUser.GenericFactory identifiedUserFactory,
|
||||
final AccountControl.Factory accountControlFactory,
|
||||
final ChangeControl.Factory changeControlFactory,
|
||||
@GerritServerConfig final Config cfg, final GroupCache groupCache) {
|
||||
@GerritServerConfig final Config cfg, final GroupBackend groupBackend) {
|
||||
super(schema, currentUser);
|
||||
this.reviewDbProvider = schema;
|
||||
this.accountCache = accountCache;
|
||||
@@ -87,7 +86,7 @@ class SuggestServiceImpl extends BaseServiceImplementation implements
|
||||
this.accountControlFactory = accountControlFactory;
|
||||
this.changeControlFactory = changeControlFactory;
|
||||
this.cfg = cfg;
|
||||
this.groupCache = groupCache;
|
||||
this.groupBackend = groupBackend;
|
||||
|
||||
if ("OFF".equals(cfg.getString("suggest", null, "accounts"))) {
|
||||
this.suggestAccounts = false;
|
||||
@@ -177,32 +176,28 @@ class SuggestServiceImpl extends BaseServiceImplementation implements
|
||||
public void suggestAccountGroup(final String query, final int limit,
|
||||
final AsyncCallback<List<GroupReference>> callback) {
|
||||
run(callback, new Action<List<GroupReference>>() {
|
||||
public List<GroupReference> run(final ReviewDb db) throws OrmException {
|
||||
return suggestAccountGroup(db, query, limit);
|
||||
public List<GroupReference> run(final ReviewDb db) {
|
||||
return suggestAccountGroup(query, limit);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private List<GroupReference> suggestAccountGroup(final ReviewDb db,
|
||||
final String query, final int limit) throws OrmException {
|
||||
final String a = query;
|
||||
final String b = a + MAX_SUFFIX;
|
||||
final int max = 10;
|
||||
final int n = limit <= 0 ? max : Math.min(limit, max);
|
||||
List<GroupReference> r = new ArrayList<GroupReference>(n);
|
||||
for (AccountGroupName group : db.accountGroupNames().suggestByName(a, b, n)) {
|
||||
private List<GroupReference> suggestAccountGroup(final String query, final int limit) {
|
||||
final int n = limit <= 0 ? 10 : Math.min(limit, 10);
|
||||
List<GroupReference> out = Lists.newArrayListWithCapacity(n);
|
||||
for (GroupReference g : groupBackend.suggest(query)) {
|
||||
try {
|
||||
if (groupControlFactory.controlFor(group.getId()).isVisible()) {
|
||||
AccountGroup g = groupCache.get(group.getId());
|
||||
if (g != null && g.getGroupUUID() != null) {
|
||||
r.add(GroupReference.forGroup(g));
|
||||
if (groupControlFactory.controlFor(g.getUUID()).isVisible()) {
|
||||
out.add(g);
|
||||
if (out.size() == n) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (NoSuchGroupException e) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return r;
|
||||
return out;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -243,7 +238,7 @@ class SuggestServiceImpl extends BaseServiceImplementation implements
|
||||
reviewer.add(new ReviewerInfo(a));
|
||||
}
|
||||
final List<GroupReference> suggestedAccountGroups =
|
||||
suggestAccountGroup(db, query, limit);
|
||||
suggestAccountGroup(query, limit);
|
||||
for (final GroupReference g : suggestedAccountGroups) {
|
||||
if (suggestGroupAsReviewer(changeControl.getProject().getNameKey(), g)) {
|
||||
reviewer.add(new ReviewerInfo(g));
|
||||
|
@@ -18,6 +18,7 @@ import com.google.gerrit.common.data.GroupAdminService;
|
||||
import com.google.gerrit.common.data.GroupDetail;
|
||||
import com.google.gerrit.common.data.GroupList;
|
||||
import com.google.gerrit.common.data.GroupOptions;
|
||||
import com.google.gerrit.common.data.GroupReference;
|
||||
import com.google.gerrit.common.errors.InactiveAccountException;
|
||||
import com.google.gerrit.common.errors.NameAlreadyUsedException;
|
||||
import com.google.gerrit.common.errors.NoSuchAccountException;
|
||||
@@ -34,6 +35,8 @@ import com.google.gerrit.reviewdb.server.ReviewDb;
|
||||
import com.google.gerrit.server.IdentifiedUser;
|
||||
import com.google.gerrit.server.account.AccountCache;
|
||||
import com.google.gerrit.server.account.AccountResolver;
|
||||
import com.google.gerrit.server.account.GroupBackend;
|
||||
import com.google.gerrit.server.account.GroupBackends;
|
||||
import com.google.gerrit.server.account.GroupCache;
|
||||
import com.google.gerrit.server.account.GroupControl;
|
||||
import com.google.gerrit.server.account.GroupIncludeCache;
|
||||
@@ -44,7 +47,6 @@ import com.google.inject.Inject;
|
||||
import com.google.inject.Provider;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
@@ -53,6 +55,7 @@ class GroupAdminServiceImpl extends BaseServiceImplementation implements
|
||||
private final AccountCache accountCache;
|
||||
private final AccountResolver accountResolver;
|
||||
private final GroupCache groupCache;
|
||||
private final GroupBackend groupBackend;
|
||||
private final GroupIncludeCache groupIncludeCache;
|
||||
private final GroupControl.Factory groupControlFactory;
|
||||
|
||||
@@ -68,6 +71,7 @@ class GroupAdminServiceImpl extends BaseServiceImplementation implements
|
||||
final GroupIncludeCache groupIncludeCache,
|
||||
final AccountResolver accountResolver,
|
||||
final GroupCache groupCache,
|
||||
final GroupBackend groupBackend,
|
||||
final GroupControl.Factory groupControlFactory,
|
||||
final CreateGroup.Factory createGroupFactory,
|
||||
final RenameGroup.Factory renameGroupFactory,
|
||||
@@ -78,6 +82,7 @@ class GroupAdminServiceImpl extends BaseServiceImplementation implements
|
||||
this.groupIncludeCache = groupIncludeCache;
|
||||
this.accountResolver = accountResolver;
|
||||
this.groupCache = groupCache;
|
||||
this.groupBackend = groupBackend;
|
||||
this.groupControlFactory = groupControlFactory;
|
||||
this.createGroupFactory = createGroupFactory;
|
||||
this.renameGroupFactory = renameGroupFactory;
|
||||
@@ -140,13 +145,13 @@ class GroupAdminServiceImpl extends BaseServiceImplementation implements
|
||||
final AccountGroup group = db.accountGroups().get(groupId);
|
||||
assertAmGroupOwner(db, group);
|
||||
|
||||
AccountGroup owner =
|
||||
groupCache.get(new AccountGroup.NameKey(newOwnerName));
|
||||
GroupReference owner =
|
||||
GroupBackends.findExactSuggestion(groupBackend, newOwnerName);
|
||||
if (owner == null) {
|
||||
throw new Failure(new NoSuchEntityException());
|
||||
}
|
||||
|
||||
group.setOwnerGroupUUID(owner.getGroupUUID());
|
||||
group.setOwnerGroupUUID(owner.getUUID());
|
||||
db.accountGroups().update(Collections.singleton(group));
|
||||
groupCache.evict(group);
|
||||
return VoidResult.INSTANCE;
|
||||
@@ -179,7 +184,7 @@ class GroupAdminServiceImpl extends BaseServiceImplementation implements
|
||||
public GroupDetail run(ReviewDb db) throws OrmException, Failure,
|
||||
NoSuchGroupException {
|
||||
final GroupControl control = groupControlFactory.validateFor(groupId);
|
||||
if (control.getAccountGroup().getType() != AccountGroup.Type.INTERNAL) {
|
||||
if (groupCache.get(groupId).getType() != AccountGroup.Type.INTERNAL) {
|
||||
throw new Failure(new NameAlreadyUsedException());
|
||||
}
|
||||
|
||||
@@ -214,7 +219,7 @@ class GroupAdminServiceImpl extends BaseServiceImplementation implements
|
||||
public GroupDetail run(ReviewDb db) throws OrmException, Failure,
|
||||
NoSuchGroupException {
|
||||
final GroupControl control = groupControlFactory.validateFor(groupId);
|
||||
if (control.getAccountGroup().getType() != AccountGroup.Type.INTERNAL) {
|
||||
if (groupCache.get(groupId).getType() != AccountGroup.Type.INTERNAL) {
|
||||
throw new Failure(new NameAlreadyUsedException());
|
||||
}
|
||||
|
||||
@@ -247,7 +252,7 @@ class GroupAdminServiceImpl extends BaseServiceImplementation implements
|
||||
public VoidResult run(final ReviewDb db) throws OrmException,
|
||||
NoSuchGroupException, Failure {
|
||||
final GroupControl control = groupControlFactory.validateFor(groupId);
|
||||
if (control.getAccountGroup().getType() != AccountGroup.Type.INTERNAL) {
|
||||
if (groupCache.get(groupId).getType() != AccountGroup.Type.INTERNAL) {
|
||||
throw new Failure(new NameAlreadyUsedException());
|
||||
}
|
||||
|
||||
@@ -301,7 +306,7 @@ class GroupAdminServiceImpl extends BaseServiceImplementation implements
|
||||
public VoidResult run(final ReviewDb db) throws OrmException,
|
||||
NoSuchGroupException, Failure {
|
||||
final GroupControl control = groupControlFactory.validateFor(groupId);
|
||||
if (control.getAccountGroup().getType() != AccountGroup.Type.INTERNAL) {
|
||||
if (groupCache.get(groupId).getType() != AccountGroup.Type.INTERNAL) {
|
||||
throw new Failure(new NameAlreadyUsedException());
|
||||
}
|
||||
|
||||
|
@@ -22,9 +22,9 @@ import com.google.gerrit.common.data.ProjectAccess;
|
||||
import com.google.gerrit.common.errors.InvalidNameException;
|
||||
import com.google.gerrit.common.errors.NoSuchGroupException;
|
||||
import com.google.gerrit.httpd.rpc.Handler;
|
||||
import com.google.gerrit.reviewdb.client.AccountGroup;
|
||||
import com.google.gerrit.reviewdb.client.Project;
|
||||
import com.google.gerrit.server.account.GroupCache;
|
||||
import com.google.gerrit.server.account.GroupBackend;
|
||||
import com.google.gerrit.server.account.GroupBackends;
|
||||
import com.google.gerrit.server.git.MetaDataUpdate;
|
||||
import com.google.gerrit.server.git.ProjectConfig;
|
||||
import com.google.gerrit.server.project.NoSuchProjectException;
|
||||
@@ -60,7 +60,7 @@ class ChangeProjectAccess extends Handler<ProjectAccess> {
|
||||
private final ProjectAccessFactory.Factory projectAccessFactory;
|
||||
private final ProjectControl.Factory projectControlFactory;
|
||||
private final ProjectCache projectCache;
|
||||
private final GroupCache groupCache;
|
||||
private final GroupBackend groupBackend;
|
||||
private final MetaDataUpdate.User metaDataUpdateFactory;
|
||||
|
||||
private final Project.NameKey projectName;
|
||||
@@ -71,7 +71,7 @@ class ChangeProjectAccess extends Handler<ProjectAccess> {
|
||||
@Inject
|
||||
ChangeProjectAccess(final ProjectAccessFactory.Factory projectAccessFactory,
|
||||
final ProjectControl.Factory projectControlFactory,
|
||||
final ProjectCache projectCache, final GroupCache groupCache,
|
||||
final ProjectCache projectCache, final GroupBackend groupBackend,
|
||||
final MetaDataUpdate.User metaDataUpdateFactory,
|
||||
|
||||
@Assisted final Project.NameKey projectName,
|
||||
@@ -81,7 +81,7 @@ class ChangeProjectAccess extends Handler<ProjectAccess> {
|
||||
this.projectAccessFactory = projectAccessFactory;
|
||||
this.projectControlFactory = projectControlFactory;
|
||||
this.projectCache = projectCache;
|
||||
this.groupCache = groupCache;
|
||||
this.groupBackend = groupBackend;
|
||||
this.metaDataUpdateFactory = metaDataUpdateFactory;
|
||||
|
||||
this.projectName = projectName;
|
||||
@@ -198,12 +198,12 @@ class ChangeProjectAccess extends Handler<ProjectAccess> {
|
||||
private void lookupGroup(PermissionRule rule) throws NoSuchGroupException {
|
||||
GroupReference ref = rule.getGroup();
|
||||
if (ref.getUUID() == null) {
|
||||
AccountGroup.NameKey name = new AccountGroup.NameKey(ref.getName());
|
||||
AccountGroup group = groupCache.get(name);
|
||||
final GroupReference group =
|
||||
GroupBackends.findBestSuggestion(groupBackend, ref.getName());
|
||||
if (group == null) {
|
||||
throw new NoSuchGroupException(name);
|
||||
throw new NoSuchGroupException(ref.getName());
|
||||
}
|
||||
ref.setUUID(group.getGroupUUID());
|
||||
ref.setUUID(group.getUUID());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -23,7 +23,7 @@ import com.google.gerrit.common.errors.NoSuchGroupException;
|
||||
import com.google.gerrit.httpd.rpc.Handler;
|
||||
import com.google.gerrit.reviewdb.client.AccountGroup;
|
||||
import com.google.gerrit.reviewdb.client.Project;
|
||||
import com.google.gerrit.server.account.GroupCache;
|
||||
import com.google.gerrit.server.account.GroupBackend;
|
||||
import com.google.gerrit.server.account.GroupControl;
|
||||
import com.google.gerrit.server.config.AllProjectsName;
|
||||
import com.google.gerrit.server.git.GitRepositoryManager;
|
||||
@@ -51,7 +51,7 @@ class ProjectAccessFactory extends Handler<ProjectAccess> {
|
||||
ProjectAccessFactory create(@Assisted Project.NameKey name);
|
||||
}
|
||||
|
||||
private final GroupCache groupCache;
|
||||
private final GroupBackend groupBackend;
|
||||
private final ProjectCache projectCache;
|
||||
private final ProjectControl.Factory projectControlFactory;
|
||||
private final GroupControl.Factory groupControlFactory;
|
||||
@@ -62,7 +62,7 @@ class ProjectAccessFactory extends Handler<ProjectAccess> {
|
||||
private ProjectControl pc;
|
||||
|
||||
@Inject
|
||||
ProjectAccessFactory(final GroupCache groupCache,
|
||||
ProjectAccessFactory(final GroupBackend groupBackend,
|
||||
final ProjectCache projectCache,
|
||||
final ProjectControl.Factory projectControlFactory,
|
||||
final GroupControl.Factory groupControlFactory,
|
||||
@@ -70,7 +70,7 @@ class ProjectAccessFactory extends Handler<ProjectAccess> {
|
||||
final AllProjectsName allProjectsName,
|
||||
|
||||
@Assisted final Project.NameKey name) {
|
||||
this.groupCache = groupCache;
|
||||
this.groupBackend = groupBackend;
|
||||
this.projectCache = projectCache;
|
||||
this.projectControlFactory = projectControlFactory;
|
||||
this.groupControlFactory = groupControlFactory;
|
||||
@@ -94,7 +94,7 @@ class ProjectAccessFactory extends Handler<ProjectAccess> {
|
||||
try {
|
||||
config = ProjectConfig.read(md);
|
||||
|
||||
if (config.updateGroupNames(groupCache)) {
|
||||
if (config.updateGroupNames(groupBackend)) {
|
||||
md.setMessage("Update group names\n");
|
||||
if (config.commit(md)) {
|
||||
projectCache.evict(config.getProject());
|
||||
|
@@ -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;
|
||||
}
|
||||
|
||||
|
@@ -15,25 +15,20 @@
|
||||
package com.google.gerrit.server.account;
|
||||
|
||||
import com.google.gerrit.reviewdb.client.Account;
|
||||
import com.google.gerrit.reviewdb.client.AccountGroup;
|
||||
import com.google.gerrit.reviewdb.server.ReviewDb;
|
||||
import com.google.inject.Inject;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
|
||||
public class DefaultRealm implements Realm {
|
||||
private final EmailExpander emailExpander;
|
||||
private final AccountByEmailCache byEmail;
|
||||
private final MaterializedGroupMembership.Factory groupMembershipFactory;
|
||||
|
||||
@Inject
|
||||
DefaultRealm(final EmailExpander emailExpander,
|
||||
final AccountByEmailCache byEmail,
|
||||
final MaterializedGroupMembership.Factory groupMembershipFactory) {
|
||||
final AccountByEmailCache byEmail) {
|
||||
this.emailExpander = emailExpander;
|
||||
this.byEmail = byEmail;
|
||||
this.groupMembershipFactory = groupMembershipFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -64,11 +59,6 @@ public class DefaultRealm implements Realm {
|
||||
public void onCreateAccount(final AuthRequest who, final Account account) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public GroupMembership groups(final AccountState who) {
|
||||
return groupMembershipFactory.create(who.getInternalGroups());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Account.Id lookup(final String accountName) {
|
||||
if (emailExpander.canExpand(accountName)) {
|
||||
|
@@ -0,0 +1,49 @@
|
||||
// Copyright (C) 2012 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.server.account;
|
||||
|
||||
import com.google.gerrit.common.data.GroupDescription;
|
||||
import com.google.gerrit.common.data.GroupReference;
|
||||
import com.google.gerrit.reviewdb.client.AccountGroup;
|
||||
import com.google.gerrit.server.IdentifiedUser;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Implementations of GroupBackend provide lookup and membership accessors
|
||||
* to a group system.
|
||||
*/
|
||||
public interface GroupBackend {
|
||||
/** @return {@code true} if the backend can operate on the UUID. */
|
||||
boolean handles(AccountGroup.UUID uuid);
|
||||
|
||||
/**
|
||||
* Looks up a group in the backend. If the group does not exist, null is
|
||||
* returned.
|
||||
*
|
||||
* @param uuid the group identifier
|
||||
* @return the group
|
||||
*/
|
||||
@Nullable
|
||||
GroupDescription.Basic get(AccountGroup.UUID uuid);
|
||||
|
||||
/** @return suggestions for the group name sorted by name. */
|
||||
Collection<GroupReference> suggest(String name);
|
||||
|
||||
/** @return the group membership checker for the backend. */
|
||||
GroupMembership membershipsOf(IdentifiedUser user);
|
||||
}
|
@@ -0,0 +1,89 @@
|
||||
// Copyright (C) 2012 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.server.account;
|
||||
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.gerrit.common.data.GroupReference;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Comparator;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Utility class for dealing with a GroupBackend.
|
||||
*/
|
||||
public class GroupBackends {
|
||||
|
||||
public static final Comparator<GroupReference> GROUP_REF_NAME_COMPARATOR =
|
||||
new Comparator<GroupReference>() {
|
||||
@Override
|
||||
public int compare(GroupReference a, GroupReference b) {
|
||||
return a.getName().compareTo(b.getName());
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Runs {@link GroupBackend#suggest(String)} and filters the result to return
|
||||
* the best suggestion, or null if one does not exist.
|
||||
*
|
||||
* @param groupBackend the group backend
|
||||
* @param name the name for which to suggest groups
|
||||
* @return the best single GroupReference suggestion
|
||||
*/
|
||||
@Nullable
|
||||
public static GroupReference findBestSuggestion(
|
||||
GroupBackend groupBackend, String name) {
|
||||
Collection<GroupReference> refs = groupBackend.suggest(name);
|
||||
if (refs.size() == 1) {
|
||||
return Iterables.getOnlyElement(refs);
|
||||
}
|
||||
|
||||
for (GroupReference ref : refs) {
|
||||
if (isExactSuggestion(ref, name)) {
|
||||
return ref;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs {@link GroupBackend#suggest(String)} and filters the result to return
|
||||
* the exact suggestion, or null if one does not exist.
|
||||
*
|
||||
* @param groupBackend the group backend
|
||||
* @param name the name for which to suggest groups
|
||||
* @return the exact single GroupReference suggestion
|
||||
*/
|
||||
@Nullable
|
||||
public static GroupReference findExactSuggestion(
|
||||
GroupBackend groupBackend, String name) {
|
||||
Collection<GroupReference> refs = groupBackend.suggest(name);
|
||||
for (GroupReference ref : refs) {
|
||||
if (isExactSuggestion(ref, name)) {
|
||||
return ref;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/** Returns whether the GroupReference is an exact suggestion for the name. */
|
||||
public static boolean isExactSuggestion(GroupReference ref, String name) {
|
||||
return ref.getName().equalsIgnoreCase(name) || ref.getUUID().get().equals(name);
|
||||
}
|
||||
|
||||
private GroupBackends() {
|
||||
}
|
||||
}
|
@@ -14,6 +14,8 @@
|
||||
|
||||
package com.google.gerrit.server.account;
|
||||
|
||||
import com.google.gerrit.common.data.GroupDescription;
|
||||
import com.google.gerrit.common.data.GroupDescriptions;
|
||||
import com.google.gerrit.common.errors.NoSuchGroupException;
|
||||
import com.google.gerrit.reviewdb.client.Account;
|
||||
import com.google.gerrit.reviewdb.client.AccountGroup;
|
||||
@@ -27,11 +29,14 @@ public class GroupControl {
|
||||
public static class Factory {
|
||||
private final GroupCache groupCache;
|
||||
private final Provider<CurrentUser> user;
|
||||
private final GroupBackend groupBackend;
|
||||
|
||||
@Inject
|
||||
Factory(final GroupCache gc, final Provider<CurrentUser> cu) {
|
||||
Factory(final GroupCache gc, final Provider<CurrentUser> cu,
|
||||
final GroupBackend gb) {
|
||||
groupCache = gc;
|
||||
user = cu;
|
||||
groupBackend = gb;
|
||||
}
|
||||
|
||||
public GroupControl controlFor(final AccountGroup.Id groupId)
|
||||
@@ -45,7 +50,7 @@ public class GroupControl {
|
||||
|
||||
public GroupControl controlFor(final AccountGroup.UUID groupId)
|
||||
throws NoSuchGroupException {
|
||||
final AccountGroup group = groupCache.get(groupId);
|
||||
final GroupDescription.Basic group = groupBackend.get(groupId);
|
||||
if (group == null) {
|
||||
throw new NoSuchGroupException(groupId);
|
||||
}
|
||||
@@ -67,22 +72,22 @@ public class GroupControl {
|
||||
}
|
||||
|
||||
private final CurrentUser user;
|
||||
private final AccountGroup group;
|
||||
private final GroupDescription.Basic group;
|
||||
private Boolean isOwner;
|
||||
|
||||
GroupControl(CurrentUser who, AccountGroup gc) {
|
||||
GroupControl(CurrentUser who, GroupDescription.Basic gd) {
|
||||
user = who;
|
||||
group = gc;
|
||||
group = gd;
|
||||
}
|
||||
|
||||
GroupControl(CurrentUser who, AccountGroup ag) {
|
||||
this(who, GroupDescriptions.forAccountGroup(ag));
|
||||
}
|
||||
|
||||
public CurrentUser getCurrentUser() {
|
||||
return user;
|
||||
}
|
||||
|
||||
public AccountGroup getAccountGroup() {
|
||||
return group;
|
||||
}
|
||||
|
||||
/** Can this user see this group exists? */
|
||||
public boolean isVisible() {
|
||||
return group.isVisibleToAll()
|
||||
@@ -91,8 +96,11 @@ public class GroupControl {
|
||||
}
|
||||
|
||||
public boolean isOwner() {
|
||||
if (isOwner == null) {
|
||||
AccountGroup.UUID ownerUUID = group.getOwnerGroupUUID();
|
||||
AccountGroup accountGroup = GroupDescriptions.toAccountGroup(group);
|
||||
if (accountGroup == null) {
|
||||
isOwner = false;
|
||||
} else if (isOwner == null) {
|
||||
AccountGroup.UUID ownerUUID = accountGroup.getOwnerGroupUUID();
|
||||
isOwner = getCurrentUser().getEffectiveGroups().contains(ownerUUID)
|
||||
|| getCurrentUser().getCapabilities().canAdministrateServer();
|
||||
}
|
||||
|
@@ -14,6 +14,7 @@
|
||||
|
||||
package com.google.gerrit.server.account;
|
||||
|
||||
import com.google.gerrit.common.data.GroupDescription;
|
||||
import com.google.gerrit.common.data.GroupDetail;
|
||||
import com.google.gerrit.common.data.GroupReference;
|
||||
import com.google.gerrit.common.errors.NoSuchGroupException;
|
||||
@@ -40,6 +41,7 @@ public class GroupDetailFactory implements Callable<GroupDetail> {
|
||||
private final ReviewDb db;
|
||||
private final GroupControl.Factory groupControl;
|
||||
private final GroupCache groupCache;
|
||||
private final GroupBackend groupBackend;
|
||||
private final AccountInfoCacheFactory aic;
|
||||
private final GroupInfoCacheFactory gic;
|
||||
|
||||
@@ -49,12 +51,14 @@ public class GroupDetailFactory implements Callable<GroupDetail> {
|
||||
@Inject
|
||||
GroupDetailFactory(final ReviewDb db,
|
||||
final GroupControl.Factory groupControl, final GroupCache groupCache,
|
||||
final GroupBackend groupBackend,
|
||||
final AccountInfoCacheFactory.Factory accountInfoCacheFactory,
|
||||
final GroupInfoCacheFactory.Factory groupInfoCacheFactory,
|
||||
@Assisted final AccountGroup.Id groupId) {
|
||||
this.db = db;
|
||||
this.groupControl = groupControl;
|
||||
this.groupCache = groupCache;
|
||||
this.groupBackend = groupBackend;
|
||||
this.aic = accountInfoCacheFactory.create();
|
||||
this.gic = groupInfoCacheFactory.create();
|
||||
|
||||
@@ -64,10 +68,10 @@ public class GroupDetailFactory implements Callable<GroupDetail> {
|
||||
@Override
|
||||
public GroupDetail call() throws OrmException, NoSuchGroupException {
|
||||
control = groupControl.validateFor(groupId);
|
||||
final AccountGroup group = control.getAccountGroup();
|
||||
final AccountGroup group = groupCache.get(groupId);
|
||||
final GroupDetail detail = new GroupDetail();
|
||||
detail.setGroup(group);
|
||||
AccountGroup ownerGroup = groupCache.get(group.getOwnerGroupUUID());
|
||||
GroupDescription.Basic ownerGroup = groupBackend.get(group.getOwnerGroupUUID());
|
||||
if (ownerGroup != null) {
|
||||
detail.setOwnerGroup(GroupReference.forGroup(ownerGroup));
|
||||
}
|
||||
|
@@ -24,7 +24,6 @@ import java.util.Set;
|
||||
* the presence of a user in a particular group.
|
||||
*/
|
||||
public interface GroupMembership {
|
||||
|
||||
public static final GroupMembership EMPTY =
|
||||
new ListGroupMembership(Collections.<AccountGroup.UUID>emptySet());
|
||||
|
||||
@@ -45,7 +44,7 @@ public interface GroupMembership {
|
||||
* This may not return all groups the {@link #contains(AccountGroup.UUID)}
|
||||
* would return {@code true} for, but will at least contain all top level
|
||||
* groups. This restriction stems from the API of some group systems, which
|
||||
* make it expensive to enumate the members of a group.
|
||||
* make it expensive to enumerate the members of a group.
|
||||
*/
|
||||
Set<AccountGroup.UUID> getKnownGroups();
|
||||
}
|
||||
|
@@ -25,11 +25,12 @@ import java.util.Queue;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Creates a GroupMembership object from materialized collection of groups.
|
||||
* Creates a GroupMembership checker for the internal group system, which
|
||||
* starts with the seed groups and includes all child groups.
|
||||
*/
|
||||
public class MaterializedGroupMembership implements GroupMembership {
|
||||
public class IncludingGroupMembership implements GroupMembership {
|
||||
public interface Factory {
|
||||
MaterializedGroupMembership create(Iterable<AccountGroup.UUID> groupIds);
|
||||
IncludingGroupMembership create(Iterable<AccountGroup.UUID> groupIds);
|
||||
}
|
||||
|
||||
private final GroupIncludeCache groupIncludeCache;
|
||||
@@ -37,7 +38,7 @@ public class MaterializedGroupMembership implements GroupMembership {
|
||||
private final Queue<AccountGroup.UUID> groupQueue;
|
||||
|
||||
@Inject
|
||||
MaterializedGroupMembership(
|
||||
IncludingGroupMembership(
|
||||
GroupIncludeCache groupIncludeCache,
|
||||
@Assisted Iterable<AccountGroup.UUID> seedGroups) {
|
||||
this.groupIncludeCache = groupIncludeCache;
|
@@ -0,0 +1,90 @@
|
||||
// Copyright (C) 2012 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.server.account;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.gerrit.common.data.GroupDescription;
|
||||
import com.google.gerrit.common.data.GroupDescriptions;
|
||||
import com.google.gerrit.common.data.GroupReference;
|
||||
import com.google.gerrit.reviewdb.client.AccountGroup;
|
||||
import com.google.gerrit.server.IdentifiedUser;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Singleton;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* Implementation of GroupBackend for the internal group system.
|
||||
*/
|
||||
@Singleton
|
||||
public class InternalGroupBackend implements GroupBackend {
|
||||
private static final Function<AccountGroup, GroupReference> ACT_GROUP_TO_GROUP_REF =
|
||||
new Function<AccountGroup, GroupReference>() {
|
||||
@Override
|
||||
public GroupReference apply(AccountGroup group) {
|
||||
return GroupReference.forGroup(group);
|
||||
}
|
||||
};
|
||||
|
||||
private final GroupCache groupCache;
|
||||
private final IncludingGroupMembership.Factory groupMembershipFactory;
|
||||
|
||||
@Inject
|
||||
InternalGroupBackend(GroupCache groupCache,
|
||||
IncludingGroupMembership.Factory groupMembershipFactory) {
|
||||
this.groupCache = groupCache;
|
||||
this.groupMembershipFactory = groupMembershipFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handles(AccountGroup.UUID uuid) {
|
||||
return uuid.get().startsWith("global:")
|
||||
|| uuid.get().matches("[0-9a-f]{40}");
|
||||
}
|
||||
|
||||
@Override
|
||||
public GroupDescription.Internal get(AccountGroup.UUID uuid) {
|
||||
if (!handles(uuid)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
AccountGroup g = groupCache.get(uuid);
|
||||
if (g == null) {
|
||||
return null;
|
||||
}
|
||||
return GroupDescriptions.forAccountGroup(g);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<GroupReference> suggest(final String name) {
|
||||
Iterable<AccountGroup> filtered = Iterables.filter(groupCache.all(),
|
||||
new Predicate<AccountGroup>() {
|
||||
@Override
|
||||
public boolean apply(AccountGroup group) {
|
||||
// startsWithIgnoreCase
|
||||
return group.getName().regionMatches(true, 0, name, 0, name.length());
|
||||
}
|
||||
});
|
||||
return Lists.newArrayList(Iterables.transform(filtered, ACT_GROUP_TO_GROUP_REF));
|
||||
}
|
||||
|
||||
@Override
|
||||
public GroupMembership membershipsOf(IdentifiedUser user) {
|
||||
return groupMembershipFactory.create(user.state().getInternalGroups());
|
||||
}
|
||||
}
|
@@ -15,11 +15,8 @@
|
||||
package com.google.gerrit.server.account;
|
||||
|
||||
import com.google.gerrit.reviewdb.client.Account;
|
||||
import com.google.gerrit.reviewdb.client.AccountGroup;
|
||||
import com.google.gerrit.reviewdb.server.ReviewDb;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
public interface Realm {
|
||||
/** Can the end-user modify this field of their own account? */
|
||||
public boolean allowsEdit(Account.FieldName field);
|
||||
@@ -34,8 +31,6 @@ public interface Realm {
|
||||
|
||||
public void onCreateAccount(AuthRequest who, Account account);
|
||||
|
||||
public GroupMembership groups(AccountState who);
|
||||
|
||||
/**
|
||||
* Locate an account whose local username is the given account name.
|
||||
* <p>
|
||||
|
@@ -0,0 +1,161 @@
|
||||
// Copyright (C) 2012 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.server.account;
|
||||
|
||||
import static com.google.gerrit.server.account.GroupBackends.GROUP_REF_NAME_COMPARATOR;
|
||||
|
||||
import com.google.common.collect.ArrayListMultimap;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.Multimap;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.google.gerrit.common.data.GroupDescription;
|
||||
import com.google.gerrit.common.data.GroupReference;
|
||||
import com.google.gerrit.extensions.registration.DynamicSet;
|
||||
import com.google.gerrit.reviewdb.client.AccountGroup;
|
||||
import com.google.gerrit.server.IdentifiedUser;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Singleton;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Universal implementation of the GroupBackend that works with the injected
|
||||
* set of GroupBackends.
|
||||
*/
|
||||
@Singleton
|
||||
public class UniversalGroupBackend implements GroupBackend {
|
||||
private static final Logger log =
|
||||
LoggerFactory.getLogger(UniversalGroupBackend.class);
|
||||
|
||||
private final DynamicSet<GroupBackend> backends;
|
||||
|
||||
@Inject
|
||||
UniversalGroupBackend(DynamicSet<GroupBackend> backends) {
|
||||
this.backends = backends;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private GroupBackend backend(AccountGroup.UUID uuid) {
|
||||
if (uuid != null) {
|
||||
for (GroupBackend g : backends) {
|
||||
if (g.handles(uuid)) {
|
||||
return g;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handles(AccountGroup.UUID uuid) {
|
||||
return backend(uuid) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GroupDescription.Basic get(AccountGroup.UUID uuid) {
|
||||
GroupBackend b = backend(uuid);
|
||||
if (b == null) {
|
||||
log.warn("Unknown GroupBackend for UUID: " + uuid);
|
||||
return null;
|
||||
}
|
||||
return b.get(uuid);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<GroupReference> suggest(String name) {
|
||||
Set<GroupReference> groups = Sets.newTreeSet(GROUP_REF_NAME_COMPARATOR);
|
||||
for (GroupBackend g : backends) {
|
||||
groups.addAll(g.suggest(name));
|
||||
}
|
||||
return groups;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GroupMembership membershipsOf(IdentifiedUser user) {
|
||||
return new UniversalGroupMembership(user);
|
||||
}
|
||||
|
||||
private class UniversalGroupMembership implements GroupMembership {
|
||||
private final Map<GroupBackend, GroupMembership> memberships;
|
||||
|
||||
private UniversalGroupMembership(IdentifiedUser user) {
|
||||
ImmutableMap.Builder<GroupBackend, GroupMembership> builder =
|
||||
ImmutableMap.builder();
|
||||
for (GroupBackend g : backends) {
|
||||
builder.put(g, g.membershipsOf(user));
|
||||
}
|
||||
this.memberships = builder.build();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private GroupMembership membership(AccountGroup.UUID uuid) {
|
||||
if (uuid != null) {
|
||||
for (Map.Entry<GroupBackend, GroupMembership> m : memberships.entrySet()) {
|
||||
if (m.getKey().handles(uuid)) {
|
||||
return m.getValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(AccountGroup.UUID uuid) {
|
||||
GroupMembership m = membership(uuid);
|
||||
if (m == null) {
|
||||
log.warn("Unknown GroupMembership for UUID: " + uuid);
|
||||
return false;
|
||||
}
|
||||
return m.contains(uuid);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsAnyOf(Iterable<AccountGroup.UUID> uuids) {
|
||||
Multimap<GroupMembership, AccountGroup.UUID> lookups =
|
||||
ArrayListMultimap.create();
|
||||
for (AccountGroup.UUID uuid : uuids) {
|
||||
GroupMembership m = membership(uuid);
|
||||
if (m == null) {
|
||||
log.warn("Unknown GroupMembership for UUID: " + uuid);
|
||||
continue;
|
||||
}
|
||||
lookups.put(m, uuid);
|
||||
}
|
||||
for (Map.Entry<GroupMembership, Collection<AccountGroup.UUID>> entry :
|
||||
lookups.asMap().entrySet()) {
|
||||
if (entry.getKey().containsAnyOf(entry.getValue())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<AccountGroup.UUID> getKnownGroups() {
|
||||
Set<AccountGroup.UUID> groups = Sets.newHashSet();
|
||||
for (GroupMembership m : memberships.values()) {
|
||||
groups.addAll(m.getKnownGroups());
|
||||
}
|
||||
return groups;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,227 @@
|
||||
// Copyright (C) 2012 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.server.auth.ldap;
|
||||
|
||||
import static com.google.gerrit.server.account.GroupBackends.GROUP_REF_NAME_COMPARATOR;
|
||||
import static com.google.gerrit.server.auth.ldap.Helper.LDAP_UUID;
|
||||
import static com.google.gerrit.server.auth.ldap.LdapModule.GROUP_CACHE;
|
||||
import static com.google.gerrit.server.auth.ldap.LdapModule.GROUP_EXIST_CACHE;
|
||||
|
||||
import com.google.common.cache.LoadingCache;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.google.gerrit.common.data.GroupDescription;
|
||||
import com.google.gerrit.common.data.GroupReference;
|
||||
import com.google.gerrit.common.data.ParameterizedString;
|
||||
import com.google.gerrit.reviewdb.client.AccountExternalId;
|
||||
import com.google.gerrit.reviewdb.client.AccountGroup;
|
||||
import com.google.gerrit.server.CurrentUser;
|
||||
import com.google.gerrit.server.IdentifiedUser;
|
||||
import com.google.gerrit.server.account.GroupBackend;
|
||||
import com.google.gerrit.server.account.GroupMembership;
|
||||
import com.google.gerrit.server.account.ListGroupMembership;
|
||||
import com.google.gerrit.server.auth.ldap.Helper.LdapSchema;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Provider;
|
||||
import com.google.inject.name.Named;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
import javax.naming.InvalidNameException;
|
||||
import javax.naming.NamingException;
|
||||
import javax.naming.directory.DirContext;
|
||||
import javax.naming.ldap.LdapName;
|
||||
import javax.naming.ldap.Rdn;
|
||||
|
||||
/**
|
||||
* Implementation of GroupBackend for the LDAP group system.
|
||||
*/
|
||||
public class LdapGroupBackend implements GroupBackend {
|
||||
private static final Logger log = LoggerFactory.getLogger(LdapGroupBackend.class);
|
||||
|
||||
private static final String LDAP_NAME = "ldap/";
|
||||
private static final String GROUPNAME = "groupname";
|
||||
|
||||
private final Helper helper;
|
||||
private final LoadingCache<String, Set<AccountGroup.UUID>> membershipCache;
|
||||
private final LoadingCache<String, Boolean> existsCache;
|
||||
private final Provider<CurrentUser> userProvider;
|
||||
|
||||
@Inject
|
||||
LdapGroupBackend(
|
||||
Helper helper,
|
||||
@Named(GROUP_CACHE) LoadingCache<String, Set<AccountGroup.UUID>> membershipCache,
|
||||
@Named(GROUP_EXIST_CACHE) LoadingCache<String, Boolean> existsCache,
|
||||
Provider<CurrentUser> userProvider) {
|
||||
this.helper = helper;
|
||||
this.membershipCache = membershipCache;
|
||||
this.existsCache = existsCache;
|
||||
this.userProvider = userProvider;
|
||||
}
|
||||
|
||||
private static boolean isLdapUUID(AccountGroup.UUID uuid) {
|
||||
return uuid.get().startsWith(LDAP_UUID);
|
||||
}
|
||||
|
||||
private static GroupReference groupReference(LdapQuery.Result res)
|
||||
throws NamingException {
|
||||
return new GroupReference(
|
||||
new AccountGroup.UUID(LDAP_UUID + res.getDN()),
|
||||
LDAP_NAME + cnFor(res.getDN()));
|
||||
}
|
||||
|
||||
private static String cnFor(String dn) {
|
||||
try {
|
||||
LdapName name = new LdapName(dn);
|
||||
if (!name.isEmpty()) {
|
||||
String cn = name.get(name.size() - 1);
|
||||
int index = cn.indexOf('=');
|
||||
if (index >= 0) {
|
||||
cn = cn.substring(index + 1);
|
||||
}
|
||||
return cn;
|
||||
}
|
||||
} catch (InvalidNameException e) {
|
||||
log.warn("Cannot parse LDAP dn for cn", e);
|
||||
}
|
||||
return dn;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handles(AccountGroup.UUID uuid) {
|
||||
return isLdapUUID(uuid);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GroupDescription.Basic get(final AccountGroup.UUID uuid) {
|
||||
if (!handles(uuid)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String groupDn = uuid.get().substring(LDAP_UUID.length());
|
||||
CurrentUser user = userProvider.get();
|
||||
if (!(user instanceof IdentifiedUser)
|
||||
|| !membershipsOf((IdentifiedUser) user).contains(uuid)) {
|
||||
try {
|
||||
if (!existsCache.get(groupDn)) {
|
||||
return null;
|
||||
}
|
||||
} catch (ExecutionException e) {
|
||||
log.warn(String.format("Cannot lookup group %s in LDAP", groupDn), e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
final String name = LDAP_NAME + cnFor(groupDn);
|
||||
return new GroupDescription.Basic() {
|
||||
@Override
|
||||
public AccountGroup.UUID getGroupUUID() {
|
||||
return uuid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isVisibleToAll() {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<GroupReference> suggest(String name) {
|
||||
AccountGroup.UUID uuid = new AccountGroup.UUID(name);
|
||||
if (isLdapUUID(uuid)) {
|
||||
GroupDescription.Basic g = get(uuid);
|
||||
if (g == null) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
return Collections.singleton(GroupReference.forGroup(g));
|
||||
} else if (name.startsWith(LDAP_NAME)) {
|
||||
return suggestLdap(name.substring(LDAP_NAME.length()));
|
||||
}
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public GroupMembership membershipsOf(IdentifiedUser user) {
|
||||
String id = findId(user.state().getExternalIds());
|
||||
if (id == null) {
|
||||
return GroupMembership.EMPTY;
|
||||
}
|
||||
|
||||
try {
|
||||
return new ListGroupMembership(membershipCache.get(id));
|
||||
} catch (ExecutionException e) {
|
||||
log.warn(String.format("Cannot lookup membershipsOf %s in LDAP", id), e);
|
||||
return GroupMembership.EMPTY;
|
||||
}
|
||||
}
|
||||
|
||||
private static String findId(final Collection<AccountExternalId> ids) {
|
||||
for (final AccountExternalId i : ids) {
|
||||
if (i.isScheme(AccountExternalId.SCHEME_GERRIT)) {
|
||||
return i.getSchemeRest();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
private Set<GroupReference> suggestLdap(String name) {
|
||||
if (name.isEmpty()) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
Set<GroupReference> out = Sets.newTreeSet(GROUP_REF_NAME_COMPARATOR);
|
||||
try {
|
||||
DirContext ctx = helper.open();
|
||||
try {
|
||||
// Do exact lookups until there are at least 3 characters.
|
||||
name = Rdn.escapeValue(name) + ((name.length() >= 3) ? "*" : "");
|
||||
LdapSchema schema = helper.getSchema(ctx);
|
||||
ParameterizedString filter = ParameterizedString.asis(
|
||||
schema.groupPattern.replace(GROUPNAME, name).toString());
|
||||
Set<String> returnAttrs = Collections.<String>emptySet();
|
||||
Map<String, String> params = Collections.emptyMap();
|
||||
for (String groupBase : schema.groupBases) {
|
||||
LdapQuery query = new LdapQuery(
|
||||
groupBase, schema.groupScope, filter, returnAttrs);
|
||||
for (LdapQuery.Result res : query.query(ctx, params)) {
|
||||
out.add(groupReference(res));
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
try {
|
||||
ctx.close();
|
||||
} catch (NamingException e) {
|
||||
log.warn("Cannot close LDAP query handle", e);
|
||||
}
|
||||
}
|
||||
} catch (NamingException e) {
|
||||
log.warn("Cannot query LDAP for groups matching requested name", e);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
}
|
@@ -17,8 +17,10 @@ package com.google.gerrit.server.auth.ldap;
|
||||
import static java.util.concurrent.TimeUnit.HOURS;
|
||||
|
||||
import com.google.common.base.Optional;
|
||||
import com.google.gerrit.extensions.registration.DynamicSet;
|
||||
import com.google.gerrit.reviewdb.client.Account;
|
||||
import com.google.gerrit.reviewdb.client.AccountGroup;
|
||||
import com.google.gerrit.server.account.GroupBackend;
|
||||
import com.google.gerrit.server.account.Realm;
|
||||
import com.google.gerrit.server.cache.CacheModule;
|
||||
import com.google.inject.Scopes;
|
||||
@@ -29,6 +31,8 @@ import java.util.Set;
|
||||
public class LdapModule extends CacheModule {
|
||||
static final String USERNAME_CACHE = "ldap_usernames";
|
||||
static final String GROUP_CACHE = "ldap_groups";
|
||||
static final String GROUP_EXIST_CACHE = "ldap_group_existence";
|
||||
|
||||
|
||||
@Override
|
||||
protected void configure() {
|
||||
@@ -43,7 +47,15 @@ public class LdapModule extends CacheModule {
|
||||
new TypeLiteral<Optional<Account.Id>>() {})
|
||||
.loader(LdapRealm.UserLoader.class);
|
||||
|
||||
cache(GROUP_EXIST_CACHE,
|
||||
String.class,
|
||||
new TypeLiteral<Boolean>() {})
|
||||
.expireAfterWrite(1, HOURS)
|
||||
.loader(LdapRealm.ExistenceLoader.class);
|
||||
|
||||
bind(Realm.class).to(LdapRealm.class).in(Scopes.SINGLETON);
|
||||
bind(Helper.class);
|
||||
|
||||
DynamicSet.bind(binder(), GroupBackend.class).to(LdapGroupBackend.class);
|
||||
}
|
||||
}
|
||||
|
@@ -20,7 +20,6 @@ import com.google.common.base.Optional;
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.cache.LoadingCache;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.gerrit.common.data.ParameterizedString;
|
||||
import com.google.gerrit.reviewdb.client.Account;
|
||||
import com.google.gerrit.reviewdb.client.AccountExternalId;
|
||||
@@ -28,11 +27,8 @@ import com.google.gerrit.reviewdb.client.AccountGroup;
|
||||
import com.google.gerrit.reviewdb.client.AuthType;
|
||||
import com.google.gerrit.reviewdb.server.ReviewDb;
|
||||
import com.google.gerrit.server.account.AccountException;
|
||||
import com.google.gerrit.server.account.AccountState;
|
||||
import com.google.gerrit.server.account.AuthRequest;
|
||||
import com.google.gerrit.server.account.EmailExpander;
|
||||
import com.google.gerrit.server.account.GroupMembership;
|
||||
import com.google.gerrit.server.account.MaterializedGroupMembership;
|
||||
import com.google.gerrit.server.account.Realm;
|
||||
import com.google.gerrit.server.auth.AuthenticationUnavailableException;
|
||||
import com.google.gerrit.server.config.AuthConfig;
|
||||
@@ -48,8 +44,6 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
@@ -58,6 +52,8 @@ import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
import javax.naming.CompositeName;
|
||||
import javax.naming.Name;
|
||||
import javax.naming.NamingException;
|
||||
import javax.naming.directory.DirContext;
|
||||
|
||||
@@ -75,7 +71,6 @@ class LdapRealm implements Realm {
|
||||
private final Config config;
|
||||
|
||||
private final LoadingCache<String, Set<AccountGroup.UUID>> membershipCache;
|
||||
private final MaterializedGroupMembership.Factory groupMembershipFactory;
|
||||
|
||||
@Inject
|
||||
LdapRealm(
|
||||
@@ -84,15 +79,13 @@ class LdapRealm implements Realm {
|
||||
final EmailExpander emailExpander,
|
||||
@Named(LdapModule.GROUP_CACHE) final LoadingCache<String, Set<AccountGroup.UUID>> membershipCache,
|
||||
@Named(LdapModule.USERNAME_CACHE) final LoadingCache<String, Optional<Account.Id>> usernameCache,
|
||||
@GerritServerConfig final Config config,
|
||||
final MaterializedGroupMembership.Factory groupMembershipFactory) {
|
||||
@GerritServerConfig final Config config) {
|
||||
this.helper = helper;
|
||||
this.authConfig = authConfig;
|
||||
this.emailExpander = emailExpander;
|
||||
this.usernameCache = usernameCache;
|
||||
this.membershipCache = membershipCache;
|
||||
this.config = config;
|
||||
this.groupMembershipFactory = groupMembershipFactory;
|
||||
|
||||
this.readOnlyAccountFields = new HashSet<Account.FieldName>();
|
||||
|
||||
@@ -265,34 +258,6 @@ class LdapRealm implements Realm {
|
||||
usernameCache.put(who.getLocalUser(), Optional.of(account.getId()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public GroupMembership groups(final AccountState who) {
|
||||
String id = findId(who.getExternalIds());
|
||||
Set<AccountGroup.UUID> groups;
|
||||
if (id != null) {
|
||||
try {
|
||||
groups = membershipCache.get(id);
|
||||
} catch (ExecutionException e) {
|
||||
log.warn(String.format("Cannot lookup groups for %s in LDAP", id), e);
|
||||
groups = Collections.emptySet();
|
||||
}
|
||||
} else {
|
||||
groups = Collections.emptySet();
|
||||
}
|
||||
return groupMembershipFactory.create(Iterables.concat(
|
||||
groups,
|
||||
who.getInternalGroups()));
|
||||
}
|
||||
|
||||
private static String findId(final Collection<AccountExternalId> ids) {
|
||||
for (final AccountExternalId i : ids) {
|
||||
if (i.isScheme(AccountExternalId.SCHEME_GERRIT)) {
|
||||
return i.getSchemeRest();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Account.Id lookup(String accountName) {
|
||||
if (Strings.isNullOrEmpty(accountName)) {
|
||||
@@ -354,4 +319,33 @@ class LdapRealm implements Realm {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static class ExistenceLoader extends CacheLoader<String, Boolean> {
|
||||
private final Helper helper;
|
||||
|
||||
@Inject
|
||||
ExistenceLoader(final Helper helper) {
|
||||
this.helper = helper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean load(final String groupDn) throws Exception {
|
||||
final DirContext ctx = helper.open();
|
||||
try {
|
||||
Name compositeGroupName = new CompositeName().add(groupDn);
|
||||
try {
|
||||
ctx.getAttributes(compositeGroupName);
|
||||
return true;
|
||||
} catch (NamingException e) {
|
||||
return false;
|
||||
}
|
||||
} finally {
|
||||
try {
|
||||
ctx.close();
|
||||
} catch (NamingException e) {
|
||||
log.warn("Cannot close LDAP query handle", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -38,11 +38,14 @@ import com.google.gerrit.server.account.AccountVisibilityProvider;
|
||||
import com.google.gerrit.server.account.CapabilityControl;
|
||||
import com.google.gerrit.server.account.DefaultRealm;
|
||||
import com.google.gerrit.server.account.EmailExpander;
|
||||
import com.google.gerrit.server.account.GroupBackend;
|
||||
import com.google.gerrit.server.account.GroupCacheImpl;
|
||||
import com.google.gerrit.server.account.GroupIncludeCacheImpl;
|
||||
import com.google.gerrit.server.account.GroupInfoCacheFactory;
|
||||
import com.google.gerrit.server.account.MaterializedGroupMembership;
|
||||
import com.google.gerrit.server.account.IncludingGroupMembership;
|
||||
import com.google.gerrit.server.account.InternalGroupBackend;
|
||||
import com.google.gerrit.server.account.Realm;
|
||||
import com.google.gerrit.server.account.UniversalGroupBackend;
|
||||
import com.google.gerrit.server.auth.ldap.LdapModule;
|
||||
import com.google.gerrit.server.events.EventFactory;
|
||||
import com.google.gerrit.server.extensions.events.GitReferenceUpdated;
|
||||
@@ -130,12 +133,17 @@ public class GerritGlobalModule extends FactoryModule {
|
||||
factory(InternalUser.Factory.class);
|
||||
factory(ProjectNode.Factory.class);
|
||||
factory(ProjectState.Factory.class);
|
||||
factory(MaterializedGroupMembership.Factory.class);
|
||||
bind(PermissionCollection.Factory.class);
|
||||
bind(AccountVisibility.class)
|
||||
.toProvider(AccountVisibilityProvider.class)
|
||||
.in(SINGLETON);
|
||||
|
||||
factory(IncludingGroupMembership.Factory.class);
|
||||
bind(InternalGroupBackend.class).in(SINGLETON);
|
||||
bind(GroupBackend.class).to(UniversalGroupBackend.class).in(SINGLETON);
|
||||
DynamicSet.setOf(binder(), GroupBackend.class);
|
||||
DynamicSet.bind(binder(), GroupBackend.class).to(InternalGroupBackend.class);
|
||||
|
||||
bind(FileTypeRegistry.class).to(MimeUtilFileTypeRegistry.class);
|
||||
bind(ToolsCatalog.class);
|
||||
bind(EventFactory.class);
|
||||
|
@@ -15,7 +15,7 @@
|
||||
package com.google.gerrit.server.config;
|
||||
|
||||
import com.google.gerrit.reviewdb.client.AccountGroup;
|
||||
import com.google.gerrit.server.account.GroupCache;
|
||||
import com.google.gerrit.server.account.GroupBackend;
|
||||
import com.google.inject.Inject;
|
||||
|
||||
import org.eclipse.jgit.lib.Config;
|
||||
@@ -24,9 +24,9 @@ import java.util.Collections;
|
||||
|
||||
public class GitReceivePackGroupsProvider extends GroupSetProvider {
|
||||
@Inject
|
||||
public GitReceivePackGroupsProvider(GroupCache gc,
|
||||
public GitReceivePackGroupsProvider(GroupBackend gb,
|
||||
@GerritServerConfig Config config) {
|
||||
super(gc, config, "receive", null, "allowGroup");
|
||||
super(gb, config, "receive", null, "allowGroup");
|
||||
|
||||
// If no group was set, default to "registered users"
|
||||
//
|
||||
|
@@ -15,7 +15,7 @@
|
||||
package com.google.gerrit.server.config;
|
||||
|
||||
import com.google.gerrit.reviewdb.client.AccountGroup;
|
||||
import com.google.gerrit.server.account.GroupCache;
|
||||
import com.google.gerrit.server.account.GroupBackend;
|
||||
import com.google.inject.Inject;
|
||||
|
||||
import org.eclipse.jgit.lib.Config;
|
||||
@@ -25,9 +25,9 @@ import java.util.HashSet;
|
||||
|
||||
public class GitUploadPackGroupsProvider extends GroupSetProvider {
|
||||
@Inject
|
||||
public GitUploadPackGroupsProvider(GroupCache gc,
|
||||
public GitUploadPackGroupsProvider(GroupBackend gb,
|
||||
@GerritServerConfig Config config) {
|
||||
super(gc, config, "upload", null, "allowGroup");
|
||||
super(gb, config, "upload", null, "allowGroup");
|
||||
|
||||
// If no group was set, default to "registered users" and "anonymous"
|
||||
//
|
||||
|
@@ -15,8 +15,10 @@
|
||||
package com.google.gerrit.server.config;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.gerrit.common.data.GroupReference;
|
||||
import com.google.gerrit.reviewdb.client.AccountGroup;
|
||||
import com.google.gerrit.server.account.GroupCache;
|
||||
import com.google.gerrit.server.account.GroupBackend;
|
||||
import com.google.gerrit.server.account.GroupBackends;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Provider;
|
||||
|
||||
@@ -34,17 +36,17 @@ public abstract class GroupSetProvider implements
|
||||
protected Set<AccountGroup.UUID> groupIds;
|
||||
|
||||
@Inject
|
||||
protected GroupSetProvider(GroupCache groupCache,
|
||||
protected GroupSetProvider(GroupBackend groupBackend,
|
||||
@GerritServerConfig Config config, String section,
|
||||
String subsection, String name) {
|
||||
String[] groupNames = config.getStringList(section, subsection, name);
|
||||
ImmutableSet.Builder<AccountGroup.UUID> builder = ImmutableSet.builder();
|
||||
for (String n : groupNames) {
|
||||
AccountGroup g = groupCache.get(new AccountGroup.NameKey(n));
|
||||
if (g != null) {
|
||||
builder.add(g.getGroupUUID());
|
||||
} else {
|
||||
GroupReference g = GroupBackends.findBestSuggestion(groupBackend, n);
|
||||
if (g == null) {
|
||||
log.warn("Group \"{0}\" not in database, skipping.", n);
|
||||
} else {
|
||||
builder.add(g.getUUID());
|
||||
}
|
||||
}
|
||||
groupIds = builder.build();
|
||||
|
@@ -14,7 +14,7 @@
|
||||
|
||||
package com.google.gerrit.server.config;
|
||||
|
||||
import com.google.gerrit.server.account.GroupCache;
|
||||
import com.google.gerrit.server.account.GroupBackend;
|
||||
import com.google.inject.Inject;
|
||||
|
||||
import org.eclipse.jgit.lib.Config;
|
||||
@@ -32,8 +32,8 @@ import org.eclipse.jgit.lib.Config;
|
||||
*/
|
||||
public class ProjectOwnerGroupsProvider extends GroupSetProvider {
|
||||
@Inject
|
||||
public ProjectOwnerGroupsProvider(GroupCache gc,
|
||||
public ProjectOwnerGroupsProvider(GroupBackend gb,
|
||||
@GerritServerConfig final Config config) {
|
||||
super(gc, config, "repository", "*", "ownerGroup");
|
||||
super(gb, config, "repository", "*", "ownerGroup");
|
||||
}
|
||||
}
|
||||
|
@@ -21,6 +21,7 @@ import com.google.common.collect.Maps;
|
||||
import com.google.gerrit.common.data.AccessSection;
|
||||
import com.google.gerrit.common.data.ContributorAgreement;
|
||||
import com.google.gerrit.common.data.GlobalCapability;
|
||||
import com.google.gerrit.common.data.GroupDescription;
|
||||
import com.google.gerrit.common.data.GroupReference;
|
||||
import com.google.gerrit.common.data.Permission;
|
||||
import com.google.gerrit.common.data.PermissionRule;
|
||||
@@ -31,8 +32,9 @@ import com.google.gerrit.reviewdb.client.AccountProjectWatch.NotifyType;
|
||||
import com.google.gerrit.reviewdb.client.Project;
|
||||
import com.google.gerrit.reviewdb.client.Project.State;
|
||||
import com.google.gerrit.reviewdb.client.Project.SubmitType;
|
||||
import com.google.gerrit.server.account.GroupCache;
|
||||
import com.google.gerrit.server.account.GroupBackend;
|
||||
import com.google.gerrit.server.config.ConfigUtil;
|
||||
import com.google.gerrit.common.data.RefConfigSection;
|
||||
import com.google.gerrit.server.mail.Address;
|
||||
|
||||
import org.eclipse.jgit.errors.ConfigInvalidException;
|
||||
@@ -233,13 +235,13 @@ public class ProjectConfig extends VersionedMetaData {
|
||||
/**
|
||||
* Check all GroupReferences use current group name, repairing stale ones.
|
||||
*
|
||||
* @param groupCache cache to use when looking up group information by UUID.
|
||||
* @param groupBackend cache to use when looking up group information by UUID.
|
||||
* @return true if one or more group names was stale.
|
||||
*/
|
||||
public boolean updateGroupNames(GroupCache groupCache) {
|
||||
public boolean updateGroupNames(GroupBackend groupBackend) {
|
||||
boolean dirty = false;
|
||||
for (GroupReference ref : groupsByUUID.values()) {
|
||||
AccountGroup g = groupCache.get(ref.getUUID());
|
||||
GroupDescription.Basic g = groupBackend.get(ref.getUUID());
|
||||
if (g != null && !g.getName().equals(ref.getName())) {
|
||||
dirty = true;
|
||||
ref.setName(g.getName());
|
||||
|
@@ -16,6 +16,7 @@ package com.google.gerrit.server.mail;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.google.gerrit.common.data.GroupDescriptions;
|
||||
import com.google.gerrit.common.data.GroupReference;
|
||||
import com.google.gerrit.reviewdb.client.Account;
|
||||
import com.google.gerrit.reviewdb.client.AccountGroup;
|
||||
@@ -387,7 +388,8 @@ public abstract class ChangeEmail extends OutgoingEmail {
|
||||
private void add(Watchers matching, NotifyConfig nc, Project.NameKey project)
|
||||
throws OrmException, QueryParseException {
|
||||
for (GroupReference ref : nc.getGroups()) {
|
||||
AccountGroup group = args.groupCache.get(ref.getUUID());
|
||||
AccountGroup group =
|
||||
GroupDescriptions.toAccountGroup(args.groupBackend.get(ref.getUUID()));
|
||||
if (group == null) {
|
||||
log.warn(String.format(
|
||||
"Project %s has invalid group %s in notify section %s",
|
||||
|
@@ -20,7 +20,7 @@ import com.google.gerrit.server.IdentifiedUser;
|
||||
import com.google.gerrit.server.IdentifiedUser.GenericFactory;
|
||||
import com.google.gerrit.server.account.AccountCache;
|
||||
import com.google.gerrit.server.account.CapabilityControl;
|
||||
import com.google.gerrit.server.account.GroupCache;
|
||||
import com.google.gerrit.server.account.GroupBackend;
|
||||
import com.google.gerrit.server.config.AllProjectsName;
|
||||
import com.google.gerrit.server.config.CanonicalWebUrl;
|
||||
import com.google.gerrit.server.git.GitRepositoryManager;
|
||||
@@ -39,7 +39,7 @@ import javax.annotation.Nullable;
|
||||
class EmailArguments {
|
||||
final GitRepositoryManager server;
|
||||
final ProjectCache projectCache;
|
||||
final GroupCache groupCache;
|
||||
final GroupBackend groupBackend;
|
||||
final AccountCache accountCache;
|
||||
final PatchListCache patchListCache;
|
||||
final FromAddressGenerator fromAddressGenerator;
|
||||
@@ -58,7 +58,7 @@ class EmailArguments {
|
||||
|
||||
@Inject
|
||||
EmailArguments(GitRepositoryManager server, ProjectCache projectCache,
|
||||
GroupCache groupCache, AccountCache accountCache,
|
||||
GroupBackend groupBackend, AccountCache accountCache,
|
||||
PatchListCache patchListCache, FromAddressGenerator fromAddressGenerator,
|
||||
EmailSender emailSender, PatchSetInfoFactory patchSetInfoFactory,
|
||||
GenericFactory identifiedUserFactory,
|
||||
@@ -71,7 +71,7 @@ class EmailArguments {
|
||||
RuntimeInstance velocityRuntime) {
|
||||
this.server = server;
|
||||
this.projectCache = projectCache;
|
||||
this.groupCache = groupCache;
|
||||
this.groupBackend = groupBackend;
|
||||
this.accountCache = accountCache;
|
||||
this.patchListCache = patchListCache;
|
||||
this.fromAddressGenerator = fromAddressGenerator;
|
||||
|
@@ -15,6 +15,7 @@
|
||||
package com.google.gerrit.server.project;
|
||||
|
||||
import com.google.gerrit.common.data.AccessSection;
|
||||
import com.google.gerrit.common.data.GroupDescription;
|
||||
import com.google.gerrit.common.data.GroupReference;
|
||||
import com.google.gerrit.common.data.Permission;
|
||||
import com.google.gerrit.common.data.PermissionRule;
|
||||
@@ -26,7 +27,7 @@ import com.google.gerrit.reviewdb.client.Project;
|
||||
import com.google.gerrit.reviewdb.server.ReviewDb;
|
||||
import com.google.gerrit.server.GerritPersonIdent;
|
||||
import com.google.gerrit.server.IdentifiedUser;
|
||||
import com.google.gerrit.server.account.GroupCache;
|
||||
import com.google.gerrit.server.account.GroupBackend;
|
||||
import com.google.gerrit.server.config.ProjectOwnerGroups;
|
||||
import com.google.gerrit.server.extensions.events.GitReferenceUpdated;
|
||||
import com.google.gerrit.server.git.GitRepositoryManager;
|
||||
@@ -73,7 +74,7 @@ public class CreateProject {
|
||||
private final PersonIdent serverIdent;
|
||||
private CreateProjectArgs createProjectArgs;
|
||||
private ProjectCache projectCache;
|
||||
private GroupCache groupCache;
|
||||
private GroupBackend groupBackend;
|
||||
private MetaDataUpdate.User metaDataUpdateFactory;
|
||||
|
||||
@Inject
|
||||
@@ -82,8 +83,8 @@ public class CreateProject {
|
||||
GitReferenceUpdated referenceUpdated,
|
||||
DynamicSet<NewProjectCreatedListener> createdListener,
|
||||
ReviewDb db,
|
||||
@GerritPersonIdent PersonIdent personIdent, final GroupCache groupCache,
|
||||
final MetaDataUpdate.User metaDataUpdateFactory,
|
||||
@GerritPersonIdent PersonIdent personIdent, GroupBackend groupBackend,
|
||||
MetaDataUpdate.User metaDataUpdateFactory,
|
||||
@Assisted CreateProjectArgs createPArgs, ProjectCache pCache) {
|
||||
this.projectOwnerGroups = pOwnerGroups;
|
||||
this.currentUser = identifiedUser;
|
||||
@@ -93,7 +94,7 @@ public class CreateProject {
|
||||
this.serverIdent = personIdent;
|
||||
this.createProjectArgs = createPArgs;
|
||||
this.projectCache = pCache;
|
||||
this.groupCache = groupCache;
|
||||
this.groupBackend = groupBackend;
|
||||
this.metaDataUpdateFactory = metaDataUpdateFactory;
|
||||
}
|
||||
|
||||
@@ -187,9 +188,9 @@ public class CreateProject {
|
||||
final AccessSection all =
|
||||
config.getAccessSection(AccessSection.ALL, true);
|
||||
for (AccountGroup.UUID ownerId : createProjectArgs.ownerIds) {
|
||||
AccountGroup accountGroup = groupCache.get(ownerId);
|
||||
if (accountGroup != null) {
|
||||
GroupReference group = config.resolve(accountGroup);
|
||||
GroupDescription.Basic g = groupBackend.get(ownerId);
|
||||
if (g != null) {
|
||||
GroupReference group = config.resolve(GroupReference.forGroup(g));
|
||||
all.getPermission(Permission.OWNER, true).add(
|
||||
new PermissionRule(group));
|
||||
}
|
||||
|
@@ -16,6 +16,7 @@ package com.google.gerrit.server.query.change;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.gerrit.common.data.ApprovalTypes;
|
||||
import com.google.gerrit.common.data.GroupReference;
|
||||
import com.google.gerrit.reviewdb.client.Account;
|
||||
import com.google.gerrit.reviewdb.client.AccountGroup;
|
||||
import com.google.gerrit.reviewdb.client.Change;
|
||||
@@ -26,7 +27,8 @@ import com.google.gerrit.server.CurrentUser;
|
||||
import com.google.gerrit.server.IdentifiedUser;
|
||||
import com.google.gerrit.server.account.AccountResolver;
|
||||
import com.google.gerrit.server.account.CapabilityControl;
|
||||
import com.google.gerrit.server.account.GroupCache;
|
||||
import com.google.gerrit.server.account.GroupBackend;
|
||||
import com.google.gerrit.server.account.GroupBackends;
|
||||
import com.google.gerrit.server.config.AllProjectsName;
|
||||
import com.google.gerrit.server.git.GitRepositoryManager;
|
||||
import com.google.gerrit.server.patch.PatchListCache;
|
||||
@@ -105,7 +107,7 @@ public class ChangeQueryBuilder extends QueryBuilder<ChangeData> {
|
||||
final ChangeControl.Factory changeControlFactory;
|
||||
final ChangeControl.GenericFactory changeControlGenericFactory;
|
||||
final AccountResolver accountResolver;
|
||||
final GroupCache groupCache;
|
||||
final GroupBackend groupBackend;
|
||||
final ApprovalTypes approvalTypes;
|
||||
final AllProjectsName allProjectsName;
|
||||
final PatchListCache patchListCache;
|
||||
@@ -119,7 +121,8 @@ public class ChangeQueryBuilder extends QueryBuilder<ChangeData> {
|
||||
CapabilityControl.Factory capabilityControlFactory,
|
||||
ChangeControl.Factory changeControlFactory,
|
||||
ChangeControl.GenericFactory changeControlGenericFactory,
|
||||
AccountResolver accountResolver, GroupCache groupCache,
|
||||
AccountResolver accountResolver,
|
||||
GroupBackend groupBackend,
|
||||
ApprovalTypes approvalTypes,
|
||||
AllProjectsName allProjectsName,
|
||||
PatchListCache patchListCache,
|
||||
@@ -132,7 +135,7 @@ public class ChangeQueryBuilder extends QueryBuilder<ChangeData> {
|
||||
this.changeControlFactory = changeControlFactory;
|
||||
this.changeControlGenericFactory = changeControlGenericFactory;
|
||||
this.accountResolver = accountResolver;
|
||||
this.groupCache = groupCache;
|
||||
this.groupBackend = groupBackend;
|
||||
this.approvalTypes = approvalTypes;
|
||||
this.allProjectsName = allProjectsName;
|
||||
this.patchListCache = patchListCache;
|
||||
@@ -367,18 +370,11 @@ public class ChangeQueryBuilder extends QueryBuilder<ChangeData> {
|
||||
|
||||
// If its not an account, maybe its a group?
|
||||
//
|
||||
AccountGroup g = args.groupCache.get(new AccountGroup.NameKey(who));
|
||||
if (g != null) {
|
||||
return visibleto(new SingleGroupUser(args.capabilityControlFactory,
|
||||
g.getGroupUUID()));
|
||||
}
|
||||
|
||||
Collection<AccountGroup> matches =
|
||||
args.groupCache.get(new AccountGroup.ExternalNameKey(who));
|
||||
if (matches != null && !matches.isEmpty()) {
|
||||
Collection<GroupReference> suggestions = args.groupBackend.suggest(who);
|
||||
if (!suggestions.isEmpty()) {
|
||||
HashSet<AccountGroup.UUID> ids = new HashSet<AccountGroup.UUID>();
|
||||
for (AccountGroup group : matches) {
|
||||
ids.add(group.getGroupUUID());
|
||||
for (GroupReference ref : suggestions) {
|
||||
ids.add(ref.getUUID());
|
||||
}
|
||||
return visibleto(new SingleGroupUser(args.capabilityControlFactory, ids));
|
||||
}
|
||||
@@ -410,11 +406,11 @@ public class ChangeQueryBuilder extends QueryBuilder<ChangeData> {
|
||||
@Operator
|
||||
public Predicate<ChangeData> ownerin(String group)
|
||||
throws QueryParseException {
|
||||
AccountGroup g = args.groupCache.get(new AccountGroup.NameKey(group));
|
||||
GroupReference g = GroupBackends.findBestSuggestion(args.groupBackend, group);
|
||||
if (g == null) {
|
||||
throw error("Group " + group + " not found");
|
||||
}
|
||||
return new OwnerinPredicate(args.dbProvider, args.userFactory, g.getGroupUUID());
|
||||
return new OwnerinPredicate(args.dbProvider, args.userFactory, g.getUUID());
|
||||
}
|
||||
|
||||
@Operator
|
||||
@@ -431,11 +427,11 @@ public class ChangeQueryBuilder extends QueryBuilder<ChangeData> {
|
||||
@Operator
|
||||
public Predicate<ChangeData> reviewerin(String group)
|
||||
throws QueryParseException {
|
||||
AccountGroup g = args.groupCache.get(new AccountGroup.NameKey(group));
|
||||
GroupReference g = GroupBackends.findBestSuggestion(args.groupBackend, group);
|
||||
if (g == null) {
|
||||
throw error("Group " + group + " not found");
|
||||
}
|
||||
return new ReviewerinPredicate(args.dbProvider, args.userFactory, g.getGroupUUID());
|
||||
return new ReviewerinPredicate(args.dbProvider, args.userFactory, g.getUUID());
|
||||
}
|
||||
|
||||
@Operator
|
||||
|
@@ -26,7 +26,6 @@ import com.google.gerrit.reviewdb.client.PatchSetApproval;
|
||||
import com.google.gerrit.reviewdb.client.ApprovalCategory.Id;
|
||||
import com.google.gerrit.server.CurrentUser;
|
||||
import com.google.gerrit.server.IdentifiedUser;
|
||||
import com.google.gerrit.server.account.GroupCache;
|
||||
import com.google.gerrit.server.project.ChangeControl;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.assistedinject.Assisted;
|
||||
@@ -57,7 +56,7 @@ public class FunctionState {
|
||||
|
||||
@Inject
|
||||
FunctionState(final ApprovalTypes approvalTypes,
|
||||
final IdentifiedUser.GenericFactory userFactory, final GroupCache egc,
|
||||
final IdentifiedUser.GenericFactory userFactory,
|
||||
@Assisted final ChangeControl c, @Assisted final PatchSet.Id psId,
|
||||
@Assisted final Collection<PatchSetApproval> all) {
|
||||
this.approvalTypes = approvalTypes;
|
||||
|
@@ -14,8 +14,10 @@
|
||||
|
||||
package com.google.gerrit.sshd.args4j;
|
||||
|
||||
import com.google.gerrit.common.data.GroupReference;
|
||||
import com.google.gerrit.reviewdb.client.AccountGroup;
|
||||
import com.google.gerrit.server.account.GroupCache;
|
||||
import com.google.gerrit.server.account.GroupBackend;
|
||||
import com.google.gerrit.server.account.GroupBackends;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.assistedinject.Assisted;
|
||||
|
||||
@@ -27,25 +29,25 @@ import org.kohsuke.args4j.spi.Parameters;
|
||||
import org.kohsuke.args4j.spi.Setter;
|
||||
|
||||
public class AccountGroupUUIDHandler extends OptionHandler<AccountGroup.UUID> {
|
||||
private final GroupCache groupCache;
|
||||
private final GroupBackend groupBackend;
|
||||
|
||||
@Inject
|
||||
public AccountGroupUUIDHandler(final GroupCache groupCache,
|
||||
public AccountGroupUUIDHandler(final GroupBackend groupBackend,
|
||||
@Assisted final CmdLineParser parser, @Assisted final OptionDef option,
|
||||
@Assisted final Setter<AccountGroup.UUID> setter) {
|
||||
super(parser, option, setter);
|
||||
this.groupCache = groupCache;
|
||||
this.groupBackend = groupBackend;
|
||||
}
|
||||
|
||||
@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));
|
||||
final GroupReference group = GroupBackends.findBestSuggestion(groupBackend, n);
|
||||
if (group == null) {
|
||||
throw new CmdLineException(owner, "Group \"" + n + "\" does not exist");
|
||||
}
|
||||
setter.addValue(group.getGroupUUID());
|
||||
setter.addValue(group.getUUID());
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user