Make administrator, create-project a global capability
This gets rid of the special entries in system_config and gerrit.config related to who the Administrators group is, or which groups are permitted to create new projects on this server. An interesting side effect of this change is admins can now actually remove the blessed Administrators group and run the server entirely without it. Fine grained rules can be used for most permissions, and direct access to the All-Projects.git repository can be used for cases where the "Administrate Site" override power is needed. Another benefit is the 'Create Project' capability is now dynamic, and can be modified at runtime without a server restart. Bug: issue 742 Change-Id: I44702010a4a521fd67d986d5b20411002c9481dd
This commit is contained in:
@@ -37,11 +37,8 @@ on the remote system to create the empty repository.
|
||||
|
||||
ACCESS
|
||||
------
|
||||
Caller must be a member of any of the groups defined by
|
||||
`repository.*.createGroup` in gerrit.config.
|
||||
|
||||
If there is no such declaration, caller is required to be a member
|
||||
of the privileged 'Administrators' group.
|
||||
Caller must be a member of the privileged 'Administrators' group,
|
||||
or have been granted the 'Create Project' global capability.
|
||||
|
||||
SCRIPTING
|
||||
---------
|
||||
@@ -70,9 +67,7 @@ OPTIONS
|
||||
Several groups can be specified on the command line.
|
||||
+
|
||||
Defaults to what is specified by `repository.*.ownerGroup`
|
||||
in gerrit.config. If no such declaration(s) exist,
|
||||
`repository.*.createGroup` will be used. If they don't exist,
|
||||
`Administrators` will be used.
|
||||
in gerrit.config.
|
||||
|
||||
--parent::
|
||||
-p::
|
||||
|
||||
@@ -900,6 +900,15 @@ the path string `"$\{basePath}/$\{project_name}.git"`.
|
||||
+
|
||||
If relative, the path is resolved relative to `'$site_path'`.
|
||||
|
||||
[[gerrit.allProjects]]gerrit.allProjects::
|
||||
+
|
||||
Name of the permissions-only project defining global server
|
||||
access controls and settings. These are inherited into every
|
||||
other project managed by the running server. The name is
|
||||
relative to `gerrit.basePath`.
|
||||
+
|
||||
Defaults to `All-Projects` if not set.
|
||||
|
||||
[[gerrit.canonicalWebUrl]]gerrit.canonicalWebUrl::
|
||||
+
|
||||
The default URL for Gerrit to be accessed through.
|
||||
@@ -1498,15 +1507,11 @@ If no groups are added, any user will be allowed to execute
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Repositories in this sense are the same as projects.
|
||||
|
||||
In the following example configuration the `Administrators` and the
|
||||
`Registered Users` groups are set to be the ones to be allowed to
|
||||
create projects matching `*` (any project). `Registered Users` is
|
||||
set to be the default owner of new projects.
|
||||
In the following example configuration `Registered Users` is set
|
||||
to be the default owner of new projects.
|
||||
|
||||
----
|
||||
[repository "*"]
|
||||
createGroup = Administrators
|
||||
createGroup = Registered Users
|
||||
ownerGroup = Registered Users
|
||||
----
|
||||
|
||||
@@ -1514,24 +1519,11 @@ set to be the default owner of new projects.
|
||||
Currently only the repository name `*` is supported.
|
||||
This is a wildcard designating all repositories.
|
||||
|
||||
[[repository.name.createGroup]]repository.<name>.createGroup::
|
||||
+
|
||||
A name of a group which exists in the database. Zero, one or many
|
||||
groups are allowed. Each on its own line. Groups which don't exist
|
||||
in the database are ignored.
|
||||
+
|
||||
If no groups are declared (or only non-existing ones), the default
|
||||
value `Administrators` is used.
|
||||
|
||||
[[repository.name.ownerGroup]]repository.<name>.ownerGroup::
|
||||
+
|
||||
A name of a group which exists in the database. Zero, one or many
|
||||
groups are allowed. Each on its own line. Groups which don't exist
|
||||
in the database are ignored.
|
||||
+
|
||||
If no groups are declared (or only non-existing ones), it defaults
|
||||
to whatever is declared by `repository.<name>.createGroup` (including
|
||||
any fallback to `Administrators`.)
|
||||
|
||||
[[sendemail]]Section sendemail
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -19,12 +19,26 @@ import java.util.List;
|
||||
|
||||
/** Server wide capabilities. Represented as {@link Permission} objects. */
|
||||
public class GlobalCapability {
|
||||
/** Can create any group on the server. */
|
||||
public static final String CREATE_GROUP = "createGroup";
|
||||
/**
|
||||
* Denotes the server's administrators.
|
||||
* <p>
|
||||
* This is similar to UNIX root, or Windows SYSTEM account. Any user that
|
||||
* has this capability can perform almost any other action, or can grant
|
||||
* themselves the power to perform any other action on the site. Most of
|
||||
* the other capabilities and permissions fall-back to the predicate
|
||||
* "OR user has capablity ADMINISTRATE_SERVER".
|
||||
*/
|
||||
public static final String ADMINISTRATE_SERVER = "administrateServer";
|
||||
|
||||
/** Can create any account on the server. */
|
||||
public static final String CREATE_ACCOUNT = "createAccount";
|
||||
|
||||
/** Can create any group on the server. */
|
||||
public static final String CREATE_GROUP = "createGroup";
|
||||
|
||||
/** Can create any project on the server. */
|
||||
public static final String CREATE_PROJECT = "createProject";
|
||||
|
||||
/** Can flush any cache except the active web_sessions cache. */
|
||||
public static final String FLUSH_CACHES = "flushCaches";
|
||||
|
||||
@@ -50,8 +64,10 @@ public class GlobalCapability {
|
||||
|
||||
static {
|
||||
NAMES_LC = new ArrayList<String>();
|
||||
NAMES_LC.add(CREATE_GROUP.toLowerCase());
|
||||
NAMES_LC.add(ADMINISTRATE_SERVER.toLowerCase());
|
||||
NAMES_LC.add(CREATE_ACCOUNT.toLowerCase());
|
||||
NAMES_LC.add(CREATE_GROUP.toLowerCase());
|
||||
NAMES_LC.add(CREATE_PROJECT.toLowerCase());
|
||||
NAMES_LC.add(FLUSH_CACHES.toLowerCase());
|
||||
NAMES_LC.add(KILL_TASK.toLowerCase());
|
||||
NAMES_LC.add(QUERY_LIMIT.toLowerCase());
|
||||
|
||||
@@ -33,6 +33,7 @@ public class Permission implements Comparable<Permission> {
|
||||
public static final String SUBMIT = "submit";
|
||||
|
||||
private static final List<String> NAMES_LC;
|
||||
private static final int labelIndex;
|
||||
|
||||
static {
|
||||
NAMES_LC = new ArrayList<String>();
|
||||
@@ -47,6 +48,8 @@ public class Permission implements Comparable<Permission> {
|
||||
NAMES_LC.add(PUSH_TAG.toLowerCase());
|
||||
NAMES_LC.add(LABEL.toLowerCase());
|
||||
NAMES_LC.add(SUBMIT.toLowerCase());
|
||||
|
||||
labelIndex = NAMES_LC.indexOf(Permission.LABEL);
|
||||
}
|
||||
|
||||
/** @return true if the name is recognized as a permission name. */
|
||||
@@ -189,13 +192,18 @@ public class Permission implements Comparable<Permission> {
|
||||
@Override
|
||||
public int compareTo(Permission b) {
|
||||
int cmp = index(this) - index(b);
|
||||
if (cmp == 0) getName().compareTo(b.getName());
|
||||
if (cmp == 0) {
|
||||
cmp = getName().compareTo(b.getName());
|
||||
}
|
||||
return cmp;
|
||||
}
|
||||
|
||||
private static int index(Permission a) {
|
||||
String lc = a.isLabel() ? Permission.LABEL : a.getName().toLowerCase();
|
||||
int index = NAMES_LC.indexOf(lc);
|
||||
if (a.isLabel()) {
|
||||
return labelIndex;
|
||||
}
|
||||
|
||||
int index = NAMES_LC.indexOf(a.getName().toLowerCase());
|
||||
return 0 <= index ? index : NAMES_LC.size();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,6 +45,7 @@ import com.google.gwt.user.client.ui.HTMLPanel;
|
||||
import com.google.gwt.user.client.ui.ValueListBox;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class AccessSectionEditor extends Composite implements
|
||||
@@ -176,6 +177,8 @@ public class AccessSectionEditor extends Composite implements
|
||||
|
||||
@Override
|
||||
public void setValue(AccessSection value) {
|
||||
Collections.sort(value.getPermissions());
|
||||
|
||||
this.value = value;
|
||||
this.readOnly = !editing || !projectAccess.isOwnerOf(value);
|
||||
|
||||
|
||||
@@ -119,8 +119,10 @@ errorsMustBeFixed = Errors must be fixed before committing changes.
|
||||
|
||||
# Capability Names
|
||||
capabilityNames = \
|
||||
administrateServer, \
|
||||
createAccount, \
|
||||
createGroup, \
|
||||
createProject, \
|
||||
flushCaches, \
|
||||
killTask, \
|
||||
queryLimit, \
|
||||
@@ -128,8 +130,10 @@ capabilityNames = \
|
||||
viewCaches, \
|
||||
viewConnections, \
|
||||
viewQueue
|
||||
administrateServer = Administrate Server
|
||||
createAccount = Create Account
|
||||
createGroup = Create Group
|
||||
createProject = Create Project
|
||||
flushCaches = Flush Caches
|
||||
killTask = Kill Task
|
||||
queryLimit = Query Limit
|
||||
|
||||
@@ -18,12 +18,11 @@ import com.google.gerrit.common.data.ApprovalTypes;
|
||||
import com.google.gerrit.common.data.GerritConfig;
|
||||
import com.google.gerrit.common.data.GitwebLink;
|
||||
import com.google.gerrit.reviewdb.Account;
|
||||
import com.google.gerrit.reviewdb.Project;
|
||||
import com.google.gerrit.server.account.Realm;
|
||||
import com.google.gerrit.server.config.AllProjectsName;
|
||||
import com.google.gerrit.server.config.AuthConfig;
|
||||
import com.google.gerrit.server.config.DownloadSchemeConfig;
|
||||
import com.google.gerrit.server.config.GerritServerConfig;
|
||||
import com.google.gerrit.server.config.WildProjectName;
|
||||
import com.google.gerrit.server.contact.ContactStore;
|
||||
import com.google.gerrit.server.mail.EmailSender;
|
||||
import com.google.gerrit.server.ssh.SshInfo;
|
||||
@@ -50,7 +49,7 @@ class GerritConfigProvider implements Provider<GerritConfig> {
|
||||
private final AuthConfig authConfig;
|
||||
private final DownloadSchemeConfig schemeConfig;
|
||||
private final GitWebConfig gitWebConfig;
|
||||
private final Project.NameKey wildProject;
|
||||
private final AllProjectsName wildProject;
|
||||
private final SshInfo sshInfo;
|
||||
private final ApprovalTypes approvalTypes;
|
||||
|
||||
@@ -61,7 +60,7 @@ class GerritConfigProvider implements Provider<GerritConfig> {
|
||||
@Inject
|
||||
GerritConfigProvider(final Realm r, @GerritServerConfig final Config gsc,
|
||||
final AuthConfig ac, final GitWebConfig gwc,
|
||||
@WildProjectName final Project.NameKey wp, final SshInfo si,
|
||||
final AllProjectsName wp, final SshInfo si,
|
||||
final ApprovalTypes at, final ContactStore cs, final ServletContext sc,
|
||||
final DownloadSchemeConfig dc) {
|
||||
realm = r;
|
||||
|
||||
@@ -298,7 +298,7 @@ public class ChangeListServiceImpl extends BaseServiceImplementation implements
|
||||
int maxLimit = currentUser.get().getCapabilities()
|
||||
.getRange(GlobalCapability.QUERY_LIMIT)
|
||||
.getMax();
|
||||
if (maxLimit == 0) {
|
||||
if (maxLimit <= 0) {
|
||||
throw new InvalidQueryException("Search Disabled");
|
||||
}
|
||||
return 0 < pageSize && pageSize <= maxLimit ? pageSize : maxLimit;
|
||||
|
||||
@@ -94,7 +94,7 @@ class GroupAdminServiceImpl extends BaseServiceImplementation implements
|
||||
public GroupList run(ReviewDb db) throws OrmException {
|
||||
final IdentifiedUser user = identifiedUser.get();
|
||||
final List<AccountGroup> list;
|
||||
if (user.isAdministrator()) {
|
||||
if (user.getCapabilities().canAdministrateServer()) {
|
||||
list = db.accountGroups().all().toList();
|
||||
} else {
|
||||
list = new ArrayList<AccountGroup>();
|
||||
|
||||
@@ -24,7 +24,7 @@ import com.google.gerrit.reviewdb.AccountGroup;
|
||||
import com.google.gerrit.reviewdb.Project;
|
||||
import com.google.gerrit.server.account.GroupCache;
|
||||
import com.google.gerrit.server.account.GroupControl;
|
||||
import com.google.gerrit.server.config.WildProjectName;
|
||||
import com.google.gerrit.server.config.AllProjectsName;
|
||||
import com.google.gerrit.server.git.MetaDataUpdate;
|
||||
import com.google.gerrit.server.git.ProjectConfig;
|
||||
import com.google.gerrit.server.project.NoSuchProjectException;
|
||||
@@ -54,7 +54,7 @@ class ProjectAccessFactory extends Handler<ProjectAccess> {
|
||||
private final ProjectControl.Factory projectControlFactory;
|
||||
private final GroupControl.Factory groupControlFactory;
|
||||
private final MetaDataUpdate.Server metaDataUpdateFactory;
|
||||
private final Project.NameKey wildProject;
|
||||
private final AllProjectsName allProjectsName;
|
||||
|
||||
private final Project.NameKey projectName;
|
||||
private ProjectControl pc;
|
||||
@@ -65,8 +65,7 @@ class ProjectAccessFactory extends Handler<ProjectAccess> {
|
||||
final ProjectControl.Factory projectControlFactory,
|
||||
final GroupControl.Factory groupControlFactory,
|
||||
final MetaDataUpdate.Server metaDataUpdateFactory,
|
||||
@WildProjectName final Project.NameKey wildProject,
|
||||
|
||||
final AllProjectsName allProjectsName,
|
||||
|
||||
@Assisted final Project.NameKey name) {
|
||||
this.groupCache = groupCache;
|
||||
@@ -74,7 +73,7 @@ class ProjectAccessFactory extends Handler<ProjectAccess> {
|
||||
this.projectControlFactory = projectControlFactory;
|
||||
this.groupControlFactory = groupControlFactory;
|
||||
this.metaDataUpdateFactory = metaDataUpdateFactory;
|
||||
this.wildProject = wildProject;
|
||||
this.allProjectsName = allProjectsName;
|
||||
|
||||
this.projectName = name;
|
||||
}
|
||||
@@ -180,7 +179,7 @@ class ProjectAccessFactory extends Handler<ProjectAccess> {
|
||||
final ProjectAccess detail = new ProjectAccess();
|
||||
detail.setRevision(config.getRevision().name());
|
||||
|
||||
if (projectName.equals(wildProject)) {
|
||||
if (projectName.equals(allProjectsName)) {
|
||||
if (pc.isOwner()) {
|
||||
ownerOf.add(AccessSection.GLOBAL_CAPABILITIES);
|
||||
}
|
||||
@@ -190,7 +189,7 @@ class ProjectAccessFactory extends Handler<ProjectAccess> {
|
||||
detail.setInheritsFrom(config.getProject().getParent());
|
||||
|
||||
} else {
|
||||
detail.setInheritsFrom(wildProject);
|
||||
detail.setInheritsFrom(allProjectsName);
|
||||
}
|
||||
|
||||
detail.setLocal(local);
|
||||
|
||||
@@ -49,6 +49,19 @@ public final class Project {
|
||||
return get().compareTo(other.get());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return get().hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object b) {
|
||||
if (b instanceof NameKey) {
|
||||
return get().equals(((NameKey) b).get());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Parse a Project.NameKey out of a string representation. */
|
||||
public static NameKey parse(final String str) {
|
||||
final NameKey r = new NameKey();
|
||||
|
||||
@@ -62,32 +62,32 @@ public final class SystemConfig {
|
||||
@Column(id = 3, notNull = false)
|
||||
public transient String sitePath;
|
||||
|
||||
/** Identity of the administration group; those with full access. */
|
||||
@Column(id = 4)
|
||||
public AccountGroup.Id adminGroupId;
|
||||
@Column(id = 10)
|
||||
public AccountGroup.UUID adminGroupUUID;
|
||||
|
||||
/** Identity of the anonymous group, which permits anyone. */
|
||||
@Column(id = 5)
|
||||
public AccountGroup.Id anonymousGroupId;
|
||||
|
||||
/** Identity of the registered users group, which permits anyone. */
|
||||
@Column(id = 6)
|
||||
public AccountGroup.Id registeredGroupId;
|
||||
|
||||
/** Identity of the project */
|
||||
@Column(id = 7)
|
||||
public Project.NameKey wildProjectName;
|
||||
|
||||
/** Identity of the batch users group */
|
||||
@Column(id = 8)
|
||||
public AccountGroup.Id batchUsersGroupId;
|
||||
@Column(id = 11)
|
||||
public AccountGroup.UUID batchUsersGroupUUID;
|
||||
|
||||
/** Identity of the owner group, which permits any project owner. */
|
||||
@Column(id = 9)
|
||||
|
||||
// DO NOT LOOK BELOW THIS LINE. These fields have all been deleted,
|
||||
// but survive to support schema upgrade code.
|
||||
|
||||
/** DEPRECATED DO NOT USE */
|
||||
@Column(id = 4, notNull = false)
|
||||
public AccountGroup.Id adminGroupId;
|
||||
/** DEPRECATED DO NOT USE */
|
||||
@Column(id = 10, notNull = false)
|
||||
public AccountGroup.UUID adminGroupUUID;
|
||||
/** DEPRECATED DO NOT USE */
|
||||
@Column(id = 5, notNull = false)
|
||||
public AccountGroup.Id anonymousGroupId;
|
||||
/** DEPRECATED DO NOT USE */
|
||||
@Column(id = 6, notNull = false)
|
||||
public AccountGroup.Id registeredGroupId;
|
||||
/** DEPRECATED DO NOT USE */
|
||||
@Column(id = 7, notNull = false)
|
||||
public Project.NameKey wildProjectName;
|
||||
/** DEPRECATED DO NOT USE */
|
||||
@Column(id = 9, notNull = false)
|
||||
public AccountGroup.Id ownerGroupId;
|
||||
|
||||
protected SystemConfig() {
|
||||
|
||||
@@ -77,10 +77,6 @@ public abstract class CurrentUser {
|
||||
return getEffectiveGroups().contains(authConfig.getBatchUsersGroup());
|
||||
}
|
||||
|
||||
public boolean isAdministrator() {
|
||||
return getEffectiveGroups().contains(authConfig.getAdministratorsGroup());
|
||||
}
|
||||
|
||||
/** Capabilities available to this user account. */
|
||||
public CapabilityControl getCapabilities() {
|
||||
CapabilityControl ctl = capabilities;
|
||||
|
||||
@@ -25,7 +25,6 @@ import com.google.inject.assistedinject.Assisted;
|
||||
import java.net.SocketAddress;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/** Identity of a peer daemon process that isn't this JVM. */
|
||||
@@ -37,23 +36,18 @@ public class PeerDaemonUser extends CurrentUser {
|
||||
PeerDaemonUser create(@Assisted SocketAddress peer);
|
||||
}
|
||||
|
||||
private final Set<AccountGroup.UUID> effectiveGroups;
|
||||
private final SocketAddress peer;
|
||||
|
||||
@Inject
|
||||
protected PeerDaemonUser(CapabilityControl.Factory capabilityControlFactory,
|
||||
AuthConfig authConfig, @Assisted SocketAddress peer) {
|
||||
super(capabilityControlFactory, AccessPath.SSH_COMMAND, authConfig);
|
||||
|
||||
final HashSet<AccountGroup.UUID> g = new HashSet<AccountGroup.UUID>();
|
||||
g.add(authConfig.getAdministratorsGroup());
|
||||
this.effectiveGroups = Collections.unmodifiableSet(g);
|
||||
this.peer = peer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<AccountGroup.UUID> getEffectiveGroups() {
|
||||
return effectiveGroups;
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -15,6 +15,9 @@
|
||||
package com.google.gerrit.server.account;
|
||||
|
||||
import com.google.gerrit.common.auth.openid.OpenIdUrls;
|
||||
import com.google.gerrit.common.data.AccessSection;
|
||||
import com.google.gerrit.common.data.GlobalCapability;
|
||||
import com.google.gerrit.common.data.Permission;
|
||||
import com.google.gerrit.common.errors.InvalidUserNameException;
|
||||
import com.google.gerrit.common.errors.NameAlreadyUsedException;
|
||||
import com.google.gerrit.reviewdb.Account;
|
||||
@@ -25,6 +28,7 @@ import com.google.gerrit.reviewdb.AccountGroupMemberAudit;
|
||||
import com.google.gerrit.reviewdb.ReviewDb;
|
||||
import com.google.gerrit.server.IdentifiedUser;
|
||||
import com.google.gerrit.server.config.AuthConfig;
|
||||
import com.google.gerrit.server.project.ProjectCache;
|
||||
import com.google.gwtorm.client.OrmException;
|
||||
import com.google.gwtorm.client.SchemaFactory;
|
||||
import com.google.inject.Inject;
|
||||
@@ -51,6 +55,7 @@ public class AccountManager {
|
||||
private final Realm realm;
|
||||
private final IdentifiedUser.GenericFactory userFactory;
|
||||
private final ChangeUserName.Factory changeUserNameFactory;
|
||||
private final ProjectCache projectCache;
|
||||
private final AtomicBoolean firstAccount;
|
||||
|
||||
@Inject
|
||||
@@ -58,7 +63,8 @@ public class AccountManager {
|
||||
final AccountCache byIdCache, final AccountByEmailCache byEmailCache,
|
||||
final AuthConfig authConfig, final Realm accountMapper,
|
||||
final IdentifiedUser.GenericFactory userFactory,
|
||||
final ChangeUserName.Factory changeUserNameFactory) throws OrmException {
|
||||
final ChangeUserName.Factory changeUserNameFactory,
|
||||
final ProjectCache projectCache) throws OrmException {
|
||||
this.schema = schema;
|
||||
this.byIdCache = byIdCache;
|
||||
this.byEmailCache = byEmailCache;
|
||||
@@ -66,6 +72,7 @@ public class AccountManager {
|
||||
this.realm = accountMapper;
|
||||
this.userFactory = userFactory;
|
||||
this.changeUserNameFactory = changeUserNameFactory;
|
||||
this.projectCache = projectCache;
|
||||
|
||||
firstAccount = new AtomicBoolean();
|
||||
final ReviewDb db = schema.open();
|
||||
@@ -275,11 +282,16 @@ public class AccountManager {
|
||||
// is going to be the site's administrator and just make them that
|
||||
// to bootstrap the authentication database.
|
||||
//
|
||||
final AccountGroup.UUID uuid = authConfig.getAdministratorsGroup();
|
||||
Permission admin = projectCache.getAllProjects()
|
||||
.getConfig()
|
||||
.getAccessSection(AccessSection.GLOBAL_CAPABILITIES)
|
||||
.getPermission(GlobalCapability.ADMINISTRATE_SERVER);
|
||||
|
||||
final AccountGroup.UUID uuid = admin.getRules().get(0).getGroup().getUUID();
|
||||
final AccountGroup g = db.accountGroups().byUUID(uuid).iterator().next();
|
||||
final AccountGroup.Id admin = g.getId();
|
||||
final AccountGroup.Id adminId = g.getId();
|
||||
final AccountGroupMember m =
|
||||
new AccountGroupMember(new AccountGroupMember.Key(newId, admin));
|
||||
new AccountGroupMember(new AccountGroupMember.Key(newId, adminId));
|
||||
db.accountGroupMembersAudit().insert(
|
||||
Collections.singleton(new AccountGroupMemberAudit(m, newId)));
|
||||
db.accountGroupMembers().insert(Collections.singleton(m));
|
||||
|
||||
@@ -21,10 +21,8 @@ import com.google.gerrit.common.data.Permission;
|
||||
import com.google.gerrit.common.data.PermissionRange;
|
||||
import com.google.gerrit.common.data.PermissionRule;
|
||||
import com.google.gerrit.reviewdb.AccountGroup;
|
||||
import com.google.gerrit.reviewdb.Project;
|
||||
import com.google.gerrit.server.CurrentUser;
|
||||
import com.google.gerrit.server.config.WildProjectName;
|
||||
import com.google.gerrit.server.project.NoSuchProjectException;
|
||||
import com.google.gerrit.server.PeerDaemonUser;
|
||||
import com.google.gerrit.server.project.ProjectCache;
|
||||
import com.google.gerrit.server.project.ProjectState;
|
||||
import com.google.inject.Inject;
|
||||
@@ -47,15 +45,11 @@ public class CapabilityControl {
|
||||
private final CurrentUser user;
|
||||
private Map<String, List<PermissionRule>> permissions;
|
||||
|
||||
private Boolean canAdministrateServer;
|
||||
|
||||
@Inject
|
||||
CapabilityControl(
|
||||
@WildProjectName Project.NameKey wp,
|
||||
ProjectCache projectCache,
|
||||
@Assisted CurrentUser currentUser) throws NoSuchProjectException {
|
||||
state = projectCache.get(wp);
|
||||
if (state == null) {
|
||||
throw new NoSuchProjectException(wp);
|
||||
}
|
||||
CapabilityControl(ProjectCache projectCache, @Assisted CurrentUser currentUser) {
|
||||
state = projectCache.getAllProjects();
|
||||
user = currentUser;
|
||||
}
|
||||
|
||||
@@ -64,44 +58,67 @@ public class CapabilityControl {
|
||||
return user;
|
||||
}
|
||||
|
||||
/** @return true if the user can administer this server. */
|
||||
public boolean canAdministrateServer() {
|
||||
if (canAdministrateServer == null) {
|
||||
canAdministrateServer = user instanceof PeerDaemonUser
|
||||
|| canPerform(GlobalCapability.ADMINISTRATE_SERVER);
|
||||
}
|
||||
return canAdministrateServer;
|
||||
}
|
||||
|
||||
/** @return true if the user can create an account for another user. */
|
||||
public boolean canCreateAccount() {
|
||||
return canPerform(GlobalCapability.CREATE_ACCOUNT) || user.isAdministrator();
|
||||
return canPerform(GlobalCapability.CREATE_ACCOUNT)
|
||||
|| canAdministrateServer();
|
||||
}
|
||||
|
||||
/** @return true if the user can create a group. */
|
||||
public boolean canCreateGroup() {
|
||||
return canPerform(GlobalCapability.CREATE_GROUP) || user.isAdministrator();
|
||||
return canPerform(GlobalCapability.CREATE_GROUP)
|
||||
|| canAdministrateServer();
|
||||
}
|
||||
|
||||
/** @return true if the user can create a group. */
|
||||
public boolean canCreateProject() {
|
||||
return canPerform(GlobalCapability.CREATE_PROJECT)
|
||||
|| canAdministrateServer();
|
||||
}
|
||||
|
||||
/** @return true if the user can kill any running task. */
|
||||
public boolean canKillTask() {
|
||||
return canPerform(GlobalCapability.KILL_TASK) || user.isAdministrator();
|
||||
return canPerform(GlobalCapability.KILL_TASK)
|
||||
|| canAdministrateServer();
|
||||
}
|
||||
|
||||
/** @return true if the user can view the server caches. */
|
||||
public boolean canViewCaches() {
|
||||
return canPerform(GlobalCapability.VIEW_CACHES) || user.isAdministrator();
|
||||
return canPerform(GlobalCapability.VIEW_CACHES)
|
||||
|| canAdministrateServer();
|
||||
}
|
||||
|
||||
/** @return true if the user can flush the server's caches. */
|
||||
public boolean canFlushCaches() {
|
||||
return canPerform(GlobalCapability.FLUSH_CACHES) || user.isAdministrator();
|
||||
return canPerform(GlobalCapability.FLUSH_CACHES)
|
||||
|| canAdministrateServer();
|
||||
}
|
||||
|
||||
/** @return true if the user can view open connections. */
|
||||
public boolean canViewConnections() {
|
||||
return canPerform(GlobalCapability.VIEW_CONNECTIONS) || user.isAdministrator();
|
||||
return canPerform(GlobalCapability.VIEW_CONNECTIONS)
|
||||
|| canAdministrateServer();
|
||||
}
|
||||
|
||||
/** @return true if the user can view the entire queue. */
|
||||
public boolean canViewQueue() {
|
||||
return canPerform(GlobalCapability.VIEW_QUEUE) || user.isAdministrator();
|
||||
return canPerform(GlobalCapability.VIEW_QUEUE)
|
||||
|| canAdministrateServer();
|
||||
}
|
||||
|
||||
/** @return true if the user can force replication to any configured destination. */
|
||||
public boolean canStartReplication() {
|
||||
return canPerform(GlobalCapability.START_REPLICATION) || user.isAdministrator();
|
||||
return canPerform(GlobalCapability.START_REPLICATION)
|
||||
|| canAdministrateServer();
|
||||
}
|
||||
|
||||
/** True if the user has this permission. Works only for non labels. */
|
||||
|
||||
@@ -97,7 +97,7 @@ public class GroupControl {
|
||||
AccountGroup g = groupCache.get(group.getOwnerGroupId());
|
||||
AccountGroup.UUID ownerUUID = g != null ? g.getGroupUUID() : null;
|
||||
isOwner = getCurrentUser().getEffectiveGroups().contains(ownerUUID)
|
||||
|| getCurrentUser().isAdministrator();
|
||||
|| getCurrentUser().getCapabilities().canAdministrateServer();
|
||||
}
|
||||
return isOwner;
|
||||
}
|
||||
|
||||
@@ -15,19 +15,11 @@
|
||||
package com.google.gerrit.server.config;
|
||||
|
||||
import com.google.gerrit.reviewdb.Project;
|
||||
import com.google.gerrit.reviewdb.SystemConfig;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Provider;
|
||||
|
||||
public class WildProjectNameProvider implements Provider<Project.NameKey> {
|
||||
private final Project.NameKey name;
|
||||
|
||||
@Inject
|
||||
WildProjectNameProvider(final SystemConfig config) {
|
||||
name = config.wildProjectName;
|
||||
}
|
||||
|
||||
public Project.NameKey get() {
|
||||
return name;
|
||||
/** Special name of the project that all projects derive from. */
|
||||
@SuppressWarnings("serial")
|
||||
public class AllProjectsName extends Project.NameKey {
|
||||
public AllProjectsName(String name) {
|
||||
super(name);
|
||||
}
|
||||
}
|
||||
@@ -14,20 +14,26 @@
|
||||
|
||||
package com.google.gerrit.server.config;
|
||||
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Provider;
|
||||
|
||||
import com.google.gerrit.reviewdb.Project;
|
||||
import com.google.inject.BindingAnnotation;
|
||||
import org.eclipse.jgit.lib.Config;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
public class AllProjectsNameProvider implements Provider<AllProjectsName> {
|
||||
public static final String DEFAULT = "All-Projects";
|
||||
|
||||
/**
|
||||
* Marker on a {@link Project.NameKey} for the current wildcard project.
|
||||
* <p>
|
||||
* This is the name of the project whose rights inherit into every other project
|
||||
* in the system.
|
||||
*/
|
||||
@Retention(RUNTIME)
|
||||
@BindingAnnotation
|
||||
public @interface WildProjectName {
|
||||
private final AllProjectsName name;
|
||||
|
||||
@Inject
|
||||
AllProjectsNameProvider(@GerritServerConfig Config cfg) {
|
||||
String n = cfg.getString("gerrit", null, "allProjects");
|
||||
if (n == null || n.isEmpty()) {
|
||||
n = DEFAULT;
|
||||
}
|
||||
name = new AllProjectsName(n);
|
||||
}
|
||||
|
||||
public AllProjectsName get() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
@@ -43,7 +43,6 @@ public class AuthConfig {
|
||||
private final boolean cookieSecure;
|
||||
private final SignedToken emailReg;
|
||||
|
||||
private final AccountGroup.UUID administratorGroup;
|
||||
private final AccountGroup.UUID batchUsersGroup;
|
||||
|
||||
private final boolean allowGoogleAccountUpgrade;
|
||||
@@ -60,7 +59,6 @@ public class AuthConfig {
|
||||
cookieSecure = cfg.getBoolean("auth", "cookiesecure", false);
|
||||
emailReg = new SignedToken(5 * 24 * 60 * 60, s.registerEmailPrivateKey);
|
||||
|
||||
administratorGroup = s.adminGroupUUID;
|
||||
batchUsersGroup = s.batchUsersGroupUUID;
|
||||
|
||||
if (authType == AuthType.OPENID) {
|
||||
@@ -117,11 +115,6 @@ public class AuthConfig {
|
||||
return allowGoogleAccountUpgrade;
|
||||
}
|
||||
|
||||
/** Identity of the magic group with full powers. */
|
||||
public AccountGroup.UUID getAdministratorsGroup() {
|
||||
return administratorGroup;
|
||||
}
|
||||
|
||||
/** Identity of the group whose service is degraded to lower priority. */
|
||||
public AccountGroup.UUID getBatchUsersGroup() {
|
||||
return batchUsersGroup;
|
||||
|
||||
@@ -133,8 +133,6 @@ public class GerritGlobalModule extends FactoryModule {
|
||||
break;
|
||||
}
|
||||
|
||||
bind(Project.NameKey.class).annotatedWith(WildProjectName.class)
|
||||
.toProvider(WildProjectNameProvider.class).in(SINGLETON);
|
||||
bind(ApprovalTypes.class).toProvider(ApprovalTypesProvider.class).in(
|
||||
SINGLETON);
|
||||
bind(EmailExpander.class).toProvider(EmailExpanderProvider.class).in(
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
// Copyright (C) 2010 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.config;
|
||||
|
||||
import com.google.inject.BindingAnnotation;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
|
||||
/**
|
||||
* Marker on a {@code Set<AccountGroup.Id>} for the configured groups with
|
||||
* permission to create projects.
|
||||
*/
|
||||
@Retention(RUNTIME)
|
||||
@BindingAnnotation
|
||||
public @interface ProjectCreatorGroups {
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
// Copyright (C) 2010 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.config;
|
||||
|
||||
import com.google.gerrit.reviewdb.ReviewDb;
|
||||
import com.google.gwtorm.client.SchemaFactory;
|
||||
import com.google.inject.Inject;
|
||||
|
||||
import org.eclipse.jgit.lib.Config;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
/**
|
||||
* Provider of the group(s) which are allowed to create new projects. Currently
|
||||
* only supports {@code createGroup} declarations in the {@code "*"} repository,
|
||||
* like so:
|
||||
*
|
||||
* <pre>
|
||||
* [repository "*"]
|
||||
* createGroup = Registered Users
|
||||
* createGroup = Administrators
|
||||
* </pre>
|
||||
*/
|
||||
public class ProjectCreatorGroupsProvider extends GroupSetProvider {
|
||||
@Inject
|
||||
public ProjectCreatorGroupsProvider(@GerritServerConfig final Config config,
|
||||
final AuthConfig authConfig, final SchemaFactory<ReviewDb> db) {
|
||||
super(config, db, "repository", "*", "createGroup");
|
||||
|
||||
if (groupIds.isEmpty()) {
|
||||
groupIds = Collections.singleton(authConfig.getAdministratorsGroup());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,15 +14,12 @@
|
||||
|
||||
package com.google.gerrit.server.config;
|
||||
|
||||
import com.google.gerrit.reviewdb.AccountGroup;
|
||||
import com.google.gerrit.reviewdb.ReviewDb;
|
||||
import com.google.gwtorm.client.SchemaFactory;
|
||||
import com.google.inject.Inject;
|
||||
|
||||
import org.eclipse.jgit.lib.Config;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Provider of the group(s) which should become owners of a newly created
|
||||
* project. Currently only supports {@code ownerGroup} declarations in the
|
||||
@@ -37,12 +34,7 @@ import java.util.Set;
|
||||
public class ProjectOwnerGroupsProvider extends GroupSetProvider {
|
||||
@Inject
|
||||
public ProjectOwnerGroupsProvider(
|
||||
@ProjectCreatorGroups final Set<AccountGroup.UUID> creatorGroups,
|
||||
@GerritServerConfig final Config config, final SchemaFactory<ReviewDb> db) {
|
||||
super(config, db, "repository", "*", "ownerGroup");
|
||||
|
||||
if (groupIds.isEmpty()) {
|
||||
groupIds = creatorGroups;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -336,7 +336,7 @@ public abstract class ChangeEmail extends OutgoingEmail {
|
||||
}
|
||||
|
||||
for (AccountProjectWatch w : args.db.get().accountProjectWatches()
|
||||
.byProject(args.wildProject)) {
|
||||
.byProject(args.allProjectsName)) {
|
||||
if (!projectWatchers.contains(w.getAccountId())) {
|
||||
add(matching, w);
|
||||
}
|
||||
|
||||
@@ -14,15 +14,14 @@
|
||||
|
||||
package com.google.gerrit.server.mail;
|
||||
|
||||
import com.google.gerrit.reviewdb.Project;
|
||||
import com.google.gerrit.reviewdb.ReviewDb;
|
||||
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.GroupCache;
|
||||
import com.google.gerrit.server.config.AllProjectsName;
|
||||
import com.google.gerrit.server.config.CanonicalWebUrl;
|
||||
import com.google.gerrit.server.config.SitePaths;
|
||||
import com.google.gerrit.server.config.WildProjectName;
|
||||
import com.google.gerrit.server.git.GitRepositoryManager;
|
||||
import com.google.gerrit.server.patch.PatchListCache;
|
||||
import com.google.gerrit.server.patch.PatchSetInfoFactory;
|
||||
@@ -45,7 +44,7 @@ class EmailArguments {
|
||||
final PatchSetInfoFactory patchSetInfoFactory;
|
||||
final IdentifiedUser.GenericFactory identifiedUserFactory;
|
||||
final Provider<String> urlProvider;
|
||||
final Project.NameKey wildProject;
|
||||
final AllProjectsName allProjectsName;
|
||||
|
||||
final ChangeQueryBuilder.Factory queryBuilder;
|
||||
final Provider<ChangeQueryRewriter> queryRewriter;
|
||||
@@ -59,7 +58,7 @@ class EmailArguments {
|
||||
EmailSender emailSender, PatchSetInfoFactory patchSetInfoFactory,
|
||||
GenericFactory identifiedUserFactory,
|
||||
@CanonicalWebUrl @Nullable Provider<String> urlProvider,
|
||||
@WildProjectName Project.NameKey wildProject,
|
||||
AllProjectsName allProjectsName,
|
||||
ChangeQueryBuilder.Factory queryBuilder,
|
||||
Provider<ChangeQueryRewriter> queryRewriter, Provider<ReviewDb> db,
|
||||
SitePaths site) {
|
||||
@@ -73,7 +72,7 @@ class EmailArguments {
|
||||
this.patchSetInfoFactory = patchSetInfoFactory;
|
||||
this.identifiedUserFactory = identifiedUserFactory;
|
||||
this.urlProvider = urlProvider;
|
||||
this.wildProject = wildProject;
|
||||
this.allProjectsName = allProjectsName;
|
||||
this.queryBuilder = queryBuilder;
|
||||
this.queryRewriter = queryRewriter;
|
||||
this.db = db;
|
||||
|
||||
@@ -22,8 +22,6 @@ import com.google.gerrit.server.config.GitReceivePackGroups;
|
||||
import com.google.gerrit.server.config.GitReceivePackGroupsProvider;
|
||||
import com.google.gerrit.server.config.GitUploadPackGroups;
|
||||
import com.google.gerrit.server.config.GitUploadPackGroupsProvider;
|
||||
import com.google.gerrit.server.config.ProjectCreatorGroups;
|
||||
import com.google.gerrit.server.config.ProjectCreatorGroupsProvider;
|
||||
import com.google.gerrit.server.config.ProjectOwnerGroups;
|
||||
import com.google.gerrit.server.config.ProjectOwnerGroupsProvider;
|
||||
import com.google.inject.TypeLiteral;
|
||||
@@ -33,10 +31,6 @@ import java.util.Set;
|
||||
public class AccessControlModule extends FactoryModule {
|
||||
@Override
|
||||
protected void configure() {
|
||||
bind(new TypeLiteral<Set<AccountGroup.UUID>>() {}) //
|
||||
.annotatedWith(ProjectCreatorGroups.class) //
|
||||
.toProvider(ProjectCreatorGroupsProvider.class).in(SINGLETON);
|
||||
|
||||
bind(new TypeLiteral<Set<AccountGroup.UUID>>() {}) //
|
||||
.annotatedWith(ProjectOwnerGroups.class) //
|
||||
.toProvider(ProjectOwnerGroupsProvider.class).in(SINGLETON);
|
||||
|
||||
@@ -161,7 +161,7 @@ public class ChangeControl {
|
||||
return isOwner() // owner (aka creator) of the change can abandon
|
||||
|| getRefControl().isOwner() // branch owner can abandon
|
||||
|| getProjectControl().isOwner() // project owner can abandon
|
||||
|| getCurrentUser().isAdministrator() // site administers are god
|
||||
|| getCurrentUser().getCapabilities().canAdministrateServer() // site administers are god
|
||||
;
|
||||
}
|
||||
|
||||
@@ -216,7 +216,7 @@ public class ChangeControl {
|
||||
//
|
||||
if (getRefControl().isOwner() // branch owner
|
||||
|| getProjectControl().isOwner() // project owner
|
||||
|| getCurrentUser().isAdministrator()) {
|
||||
|| getCurrentUser().getCapabilities().canAdministrateServer()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,9 @@ import com.google.gerrit.reviewdb.Project;
|
||||
|
||||
/** Cache of project information, including access rights. */
|
||||
public interface ProjectCache {
|
||||
/** @return the parent state for all projects on this server. */
|
||||
public ProjectState getAllProjects();
|
||||
|
||||
/**
|
||||
* Get the cached data for a project by its unique name.
|
||||
*
|
||||
|
||||
@@ -18,6 +18,7 @@ import com.google.gerrit.reviewdb.Project;
|
||||
import com.google.gerrit.server.cache.Cache;
|
||||
import com.google.gerrit.server.cache.CacheModule;
|
||||
import com.google.gerrit.server.cache.EntryCreator;
|
||||
import com.google.gerrit.server.config.AllProjectsName;
|
||||
import com.google.gerrit.server.config.ConfigUtil;
|
||||
import com.google.gerrit.server.config.GerritServerConfig;
|
||||
import com.google.gerrit.server.git.GitRepositoryManager;
|
||||
@@ -66,6 +67,7 @@ public class ProjectCacheImpl implements ProjectCache {
|
||||
};
|
||||
}
|
||||
|
||||
private final AllProjectsName allProjectsName;
|
||||
private final Cache<Project.NameKey, ProjectState> byName;
|
||||
private final Cache<ListKey,SortedSet<Project.NameKey>> list;
|
||||
private final Lock listLock;
|
||||
@@ -73,9 +75,11 @@ public class ProjectCacheImpl implements ProjectCache {
|
||||
|
||||
@Inject
|
||||
ProjectCacheImpl(
|
||||
final AllProjectsName allProjectsName,
|
||||
@Named(CACHE_NAME) final Cache<Project.NameKey, ProjectState> byName,
|
||||
@Named(CACHE_LIST) final Cache<ListKey, SortedSet<Project.NameKey>> list,
|
||||
@GerritServerConfig final Config serverConfig) {
|
||||
this.allProjectsName = allProjectsName;
|
||||
this.byName = byName;
|
||||
this.list = list;
|
||||
this.listLock = new ReentrantLock(true /* fair */);
|
||||
@@ -102,6 +106,17 @@ public class ProjectCacheImpl implements ProjectCache {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProjectState getAllProjects() {
|
||||
ProjectState state = get(allProjectsName);
|
||||
if (state == null) {
|
||||
// This should never occur, the server must have this
|
||||
// project to process anything.
|
||||
throw new IllegalStateException("Missing project " + allProjectsName);
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the cached data for a project by its unique name.
|
||||
*
|
||||
|
||||
@@ -180,13 +180,13 @@ public class ProjectControl {
|
||||
/** Is this user a project owner? Ownership does not imply {@link #isVisible()} */
|
||||
public boolean isOwner() {
|
||||
return controlForRef(AccessSection.ALL).isOwner()
|
||||
|| getCurrentUser().isAdministrator();
|
||||
|| getCurrentUser().getCapabilities().canAdministrateServer();
|
||||
}
|
||||
|
||||
/** Does this user have ownership on at least one reference name? */
|
||||
public boolean isOwnerAnyRef() {
|
||||
return canPerformOnAnyRef(Permission.OWNER)
|
||||
|| getCurrentUser().isAdministrator();
|
||||
|| getCurrentUser().getCapabilities().canAdministrateServer();
|
||||
}
|
||||
|
||||
/** @return true if the user can upload to at least one reference */
|
||||
|
||||
@@ -22,7 +22,7 @@ import com.google.gerrit.reviewdb.AccountGroup;
|
||||
import com.google.gerrit.reviewdb.Project;
|
||||
import com.google.gerrit.rules.PrologEnvironment;
|
||||
import com.google.gerrit.server.CurrentUser;
|
||||
import com.google.gerrit.server.config.WildProjectName;
|
||||
import com.google.gerrit.server.config.AllProjectsName;
|
||||
import com.google.gerrit.server.git.GitRepositoryManager;
|
||||
import com.google.gerrit.server.git.ProjectConfig;
|
||||
import com.google.inject.Inject;
|
||||
@@ -52,7 +52,7 @@ public class ProjectState {
|
||||
ProjectState create(ProjectConfig config);
|
||||
}
|
||||
|
||||
private final Project.NameKey wildProject;
|
||||
private final boolean isAllProjects;
|
||||
private final ProjectCache projectCache;
|
||||
private final ProjectControl.AssistedFactory projectControlFactory;
|
||||
private final PrologEnvironment.Factory envFactory;
|
||||
@@ -67,13 +67,13 @@ public class ProjectState {
|
||||
@Inject
|
||||
protected ProjectState(
|
||||
final ProjectCache projectCache,
|
||||
@WildProjectName final Project.NameKey wildProject,
|
||||
final AllProjectsName allProjectsName,
|
||||
final ProjectControl.AssistedFactory projectControlFactory,
|
||||
final PrologEnvironment.Factory envFactory,
|
||||
final GitRepositoryManager gitMgr,
|
||||
@Assisted final ProjectConfig config) {
|
||||
this.projectCache = projectCache;
|
||||
this.wildProject = wildProject;
|
||||
this.isAllProjects = config.getProject().getNameKey().equals(allProjectsName);
|
||||
this.projectControlFactory = projectControlFactory;
|
||||
this.envFactory = envFactory;
|
||||
this.gitMgr = gitMgr;
|
||||
@@ -160,7 +160,7 @@ public class ProjectState {
|
||||
|
||||
/** Get the rights this project inherits. */
|
||||
public Collection<AccessSection> getInheritedAccessSections() {
|
||||
if (isWildProject()) {
|
||||
if (isAllProjects) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@@ -178,12 +178,9 @@ public class ProjectState {
|
||||
}
|
||||
}
|
||||
|
||||
// Wild project is the parent, or the root of the tree
|
||||
// The root of the tree is the special "All-Projects" case.
|
||||
if (parent == null) {
|
||||
ProjectState s = projectCache.get(wildProject);
|
||||
if (s != null) {
|
||||
inherited.addAll(s.getLocalAccessSections());
|
||||
}
|
||||
inherited.addAll(projectCache.getAllProjects().getLocalAccessSections());
|
||||
}
|
||||
|
||||
return inherited;
|
||||
@@ -205,7 +202,7 @@ public class ProjectState {
|
||||
*/
|
||||
public Set<AccountGroup.UUID> getOwners() {
|
||||
Project.NameKey parentName = getProject().getParent();
|
||||
if (!localOwners.isEmpty() || parentName == null || isWildProject()) {
|
||||
if (!localOwners.isEmpty() || parentName == null || isAllProjects) {
|
||||
return localOwners;
|
||||
}
|
||||
|
||||
@@ -247,8 +244,4 @@ public class ProjectState {
|
||||
public ProjectControl controlFor(final CurrentUser user) {
|
||||
return projectControlFactory.create(user, this);
|
||||
}
|
||||
|
||||
private boolean isWildProject() {
|
||||
return wildProject.equals(getProject().getNameKey());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,7 +106,7 @@ public class RefControl {
|
||||
// calls us to find out if there is ownership of all references in
|
||||
// order to determine project level ownership.
|
||||
//
|
||||
owner = getCurrentUser().isAdministrator();
|
||||
owner = getCurrentUser().getCapabilities().canAdministrateServer();
|
||||
|
||||
} else {
|
||||
owner = getProjectControl().isOwner();
|
||||
|
||||
@@ -24,8 +24,9 @@ import com.google.gerrit.reviewdb.ReviewDb;
|
||||
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.config.WildProjectName;
|
||||
import com.google.gerrit.server.config.AllProjectsName;
|
||||
import com.google.gerrit.server.git.GitRepositoryManager;
|
||||
import com.google.gerrit.server.patch.PatchListCache;
|
||||
import com.google.gerrit.server.project.ChangeControl;
|
||||
@@ -98,12 +99,13 @@ public class ChangeQueryBuilder extends QueryBuilder<ChangeData> {
|
||||
final Provider<ReviewDb> dbProvider;
|
||||
final Provider<ChangeQueryRewriter> rewriter;
|
||||
final IdentifiedUser.GenericFactory userFactory;
|
||||
final CapabilityControl.Factory capabilityControlFactory;
|
||||
final ChangeControl.Factory changeControlFactory;
|
||||
final ChangeControl.GenericFactory changeControlGenericFactory;
|
||||
final AccountResolver accountResolver;
|
||||
final GroupCache groupCache;
|
||||
final ApprovalTypes approvalTypes;
|
||||
final Project.NameKey wildProjectName;
|
||||
final AllProjectsName allProjectsName;
|
||||
final PatchListCache patchListCache;
|
||||
final GitRepositoryManager repoManager;
|
||||
final ProjectCache projectCache;
|
||||
@@ -112,23 +114,25 @@ public class ChangeQueryBuilder extends QueryBuilder<ChangeData> {
|
||||
Arguments(Provider<ReviewDb> dbProvider,
|
||||
Provider<ChangeQueryRewriter> rewriter,
|
||||
IdentifiedUser.GenericFactory userFactory,
|
||||
CapabilityControl.Factory capabilityControlFactory,
|
||||
ChangeControl.Factory changeControlFactory,
|
||||
ChangeControl.GenericFactory changeControlGenericFactory,
|
||||
AccountResolver accountResolver, GroupCache groupCache,
|
||||
ApprovalTypes approvalTypes,
|
||||
@WildProjectName Project.NameKey wildProjectName,
|
||||
AllProjectsName allProjectsName,
|
||||
PatchListCache patchListCache,
|
||||
GitRepositoryManager repoManager,
|
||||
ProjectCache projectCache) {
|
||||
this.dbProvider = dbProvider;
|
||||
this.rewriter = rewriter;
|
||||
this.userFactory = userFactory;
|
||||
this.capabilityControlFactory = capabilityControlFactory;
|
||||
this.changeControlFactory = changeControlFactory;
|
||||
this.changeControlGenericFactory = changeControlGenericFactory;
|
||||
this.accountResolver = accountResolver;
|
||||
this.groupCache = groupCache;
|
||||
this.approvalTypes = approvalTypes;
|
||||
this.wildProjectName = wildProjectName;
|
||||
this.allProjectsName = allProjectsName;
|
||||
this.patchListCache = patchListCache;
|
||||
this.repoManager = repoManager;
|
||||
this.projectCache = projectCache;
|
||||
@@ -341,7 +345,8 @@ public class ChangeQueryBuilder extends QueryBuilder<ChangeData> {
|
||||
//
|
||||
AccountGroup g = args.groupCache.get(new AccountGroup.NameKey(who));
|
||||
if (g != null) {
|
||||
return visibleto(new SingleGroupUser(g.getGroupUUID()));
|
||||
return visibleto(new SingleGroupUser(args.capabilityControlFactory,
|
||||
g.getGroupUUID()));
|
||||
}
|
||||
|
||||
Collection<AccountGroup> matches =
|
||||
@@ -351,7 +356,7 @@ public class ChangeQueryBuilder extends QueryBuilder<ChangeData> {
|
||||
for (AccountGroup group : matches) {
|
||||
ids.add(group.getGroupUUID());
|
||||
}
|
||||
return visibleto(new SingleGroupUser(ids));
|
||||
return visibleto(new SingleGroupUser(args.capabilityControlFactory, ids));
|
||||
}
|
||||
|
||||
throw error("No user or group matches \"" + who + "\".");
|
||||
|
||||
@@ -39,7 +39,7 @@ public class ChangeQueryRewriter extends QueryRewriter<ChangeData> {
|
||||
new InvalidProvider<ReviewDb>(), //
|
||||
new InvalidProvider<ChangeQueryRewriter>(), //
|
||||
null, null, null, null, null, null, null, //
|
||||
null, null, null), null));
|
||||
null, null, null, null), null));
|
||||
|
||||
private final Provider<ReviewDb> dbProvider;
|
||||
|
||||
|
||||
@@ -79,7 +79,7 @@ class IsWatchedByPredicate extends OperatorPredicate<ChangeData> {
|
||||
Project.NameKey project = change.getDest().getParentKey();
|
||||
List<Predicate<ChangeData>> list = rules.get(project);
|
||||
if (list == null) {
|
||||
list = rules.get(args.wildProjectName);
|
||||
list = rules.get(args.allProjectsName);
|
||||
}
|
||||
if (list != null) {
|
||||
for (Predicate<ChangeData> p : list) {
|
||||
|
||||
@@ -19,6 +19,7 @@ import com.google.gerrit.reviewdb.AccountProjectWatch;
|
||||
import com.google.gerrit.reviewdb.Change;
|
||||
import com.google.gerrit.server.AccessPath;
|
||||
import com.google.gerrit.server.CurrentUser;
|
||||
import com.google.gerrit.server.account.CapabilityControl;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
@@ -27,12 +28,14 @@ import java.util.Set;
|
||||
final class SingleGroupUser extends CurrentUser {
|
||||
private final Set<AccountGroup.UUID> groups;
|
||||
|
||||
SingleGroupUser(AccountGroup.UUID groupId) {
|
||||
this(Collections.singleton(groupId));
|
||||
SingleGroupUser(CapabilityControl.Factory capabilityControlFactory,
|
||||
AccountGroup.UUID groupId) {
|
||||
this(capabilityControlFactory, Collections.singleton(groupId));
|
||||
}
|
||||
|
||||
SingleGroupUser(Set<AccountGroup.UUID> groups) {
|
||||
super(null, AccessPath.UNKNOWN, null);
|
||||
SingleGroupUser(CapabilityControl.Factory capabilityControlFactory,
|
||||
Set<AccountGroup.UUID> groups) {
|
||||
super(capabilityControlFactory, AccessPath.UNKNOWN, null);
|
||||
this.groups = groups;
|
||||
}
|
||||
|
||||
@@ -55,9 +58,4 @@ final class SingleGroupUser extends CurrentUser {
|
||||
public boolean isBatchUser() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAdministrator() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ package com.google.gerrit.server.schema;
|
||||
|
||||
import com.google.gerrit.common.Version;
|
||||
import com.google.gerrit.common.data.AccessSection;
|
||||
import com.google.gerrit.common.data.GlobalCapability;
|
||||
import com.google.gerrit.common.data.Permission;
|
||||
import com.google.gerrit.common.data.PermissionRule;
|
||||
import com.google.gerrit.reviewdb.AccountGroup;
|
||||
@@ -28,6 +29,7 @@ import com.google.gerrit.reviewdb.ReviewDb;
|
||||
import com.google.gerrit.reviewdb.SystemConfig;
|
||||
import com.google.gerrit.server.GerritPersonIdent;
|
||||
import com.google.gerrit.server.account.GroupUUID;
|
||||
import com.google.gerrit.server.config.AllProjectsName;
|
||||
import com.google.gerrit.server.config.SitePath;
|
||||
import com.google.gerrit.server.config.SitePaths;
|
||||
import com.google.gerrit.server.git.GitRepositoryManager;
|
||||
@@ -56,13 +58,11 @@ import java.util.Collections;
|
||||
|
||||
/** Creates the current database schema and populates initial code rows. */
|
||||
public class SchemaCreator {
|
||||
private static final Project.NameKey DEFAULT_WILD_NAME =
|
||||
new Project.NameKey("All-Projects");
|
||||
|
||||
private final @SitePath
|
||||
File site_path;
|
||||
|
||||
private final GitRepositoryManager mgr;
|
||||
private final AllProjectsName allProjectsName;
|
||||
private final PersonIdent serverUser;
|
||||
|
||||
private final int versionNbr;
|
||||
@@ -76,17 +76,22 @@ public class SchemaCreator {
|
||||
private AccountGroup owners;
|
||||
|
||||
@Inject
|
||||
public SchemaCreator(final SitePaths site,
|
||||
@Current final SchemaVersion version, final GitRepositoryManager mgr,
|
||||
@GerritPersonIdent final PersonIdent au) {
|
||||
this(site.site_path, version, mgr, au);
|
||||
public SchemaCreator(SitePaths site,
|
||||
@Current SchemaVersion version,
|
||||
GitRepositoryManager mgr,
|
||||
AllProjectsName allProjectsName,
|
||||
@GerritPersonIdent PersonIdent au) {
|
||||
this(site.site_path, version, mgr, allProjectsName, au);
|
||||
}
|
||||
|
||||
public SchemaCreator(final @SitePath File site,
|
||||
@Current final SchemaVersion version, final GitRepositoryManager gitMgr,
|
||||
final @GerritPersonIdent PersonIdent au) {
|
||||
public SchemaCreator(@SitePath File site,
|
||||
@Current SchemaVersion version,
|
||||
GitRepositoryManager gitMgr,
|
||||
AllProjectsName ap,
|
||||
@GerritPersonIdent PersonIdent au) {
|
||||
site_path = site;
|
||||
mgr = gitMgr;
|
||||
allProjectsName = ap;
|
||||
serverUser = au;
|
||||
versionNbr = version.getVersionNbr();
|
||||
index_generic = new ScriptRunner("index_generic.sql");
|
||||
@@ -189,18 +194,9 @@ public class SchemaCreator {
|
||||
final SystemConfig s = SystemConfig.create();
|
||||
s.registerEmailPrivateKey = SignedToken.generateRandomKey();
|
||||
|
||||
s.adminGroupId = admin.getId();
|
||||
s.adminGroupUUID = admin.getGroupUUID();
|
||||
|
||||
s.anonymousGroupId = anonymous.getId();
|
||||
|
||||
s.registeredGroupId = registered.getId();
|
||||
|
||||
s.batchUsersGroupId = batchUsers.getId();
|
||||
s.batchUsersGroupUUID = batchUsers.getGroupUUID();
|
||||
|
||||
s.ownerGroupId = owners.getId();
|
||||
s.wildProjectName = DEFAULT_WILD_NAME;
|
||||
try {
|
||||
s.sitePath = site_path.getCanonicalPath();
|
||||
} catch (IOException e) {
|
||||
@@ -213,20 +209,19 @@ public class SchemaCreator {
|
||||
private void initWildCardProject() throws IOException, ConfigInvalidException {
|
||||
Repository git;
|
||||
try {
|
||||
git = mgr.openRepository(DEFAULT_WILD_NAME);
|
||||
git = mgr.openRepository(allProjectsName);
|
||||
} catch (RepositoryNotFoundException notFound) {
|
||||
// A repository may be missing if this project existed only to store
|
||||
// inheritable permissions. For example 'All-Projects'.
|
||||
try {
|
||||
git = mgr.createRepository(DEFAULT_WILD_NAME);
|
||||
git = mgr.createRepository(allProjectsName);
|
||||
} catch (RepositoryNotFoundException err) {
|
||||
final String name = DEFAULT_WILD_NAME.get();
|
||||
final String name = allProjectsName.get();
|
||||
throw new IOException("Cannot create repository " + name, err);
|
||||
}
|
||||
}
|
||||
try {
|
||||
MetaDataUpdate md =
|
||||
new MetaDataUpdate(new NoReplication(), DEFAULT_WILD_NAME, git);
|
||||
MetaDataUpdate md = new MetaDataUpdate(new NoReplication(), allProjectsName, git);
|
||||
md.getCommitBuilder().setAuthor(serverUser);
|
||||
md.getCommitBuilder().setCommitter(serverUser);
|
||||
|
||||
@@ -235,10 +230,14 @@ public class SchemaCreator {
|
||||
p.setDescription("Rights inherited by all other projects");
|
||||
p.setUseContributorAgreements(false);
|
||||
|
||||
AccessSection cap = config.getAccessSection(AccessSection.GLOBAL_CAPABILITIES, true);
|
||||
AccessSection all = config.getAccessSection(AccessSection.ALL, true);
|
||||
AccessSection heads = config.getAccessSection(AccessSection.HEADS, true);
|
||||
AccessSection meta = config.getAccessSection(GitRepositoryManager.REF_CONFIG, true);
|
||||
|
||||
cap.getPermission(GlobalCapability.ADMINISTRATE_SERVER, true)
|
||||
.add(rule(config, admin));
|
||||
|
||||
PermissionRule review = rule(config, registered);
|
||||
review.setRange(-1, 1);
|
||||
heads.getPermission(Permission.LABEL + "Code-Review", true).add(review);
|
||||
@@ -259,7 +258,7 @@ public class SchemaCreator {
|
||||
|
||||
md.setMessage("Initialized Gerrit Code Review " + Version.getVersion());
|
||||
if (!config.commit(md)) {
|
||||
throw new IOException("Cannot create " + DEFAULT_WILD_NAME.get());
|
||||
throw new IOException("Cannot create " + allProjectsName.get());
|
||||
}
|
||||
} finally {
|
||||
git.close();
|
||||
|
||||
@@ -14,9 +14,13 @@
|
||||
|
||||
package com.google.gerrit.server.schema;
|
||||
|
||||
import static com.google.inject.Scopes.SINGLETON;
|
||||
|
||||
import com.google.gerrit.lifecycle.LifecycleModule;
|
||||
import com.google.gerrit.server.GerritPersonIdent;
|
||||
import com.google.gerrit.server.GerritPersonIdentProvider;
|
||||
import com.google.gerrit.server.config.AllProjectsName;
|
||||
import com.google.gerrit.server.config.AllProjectsNameProvider;
|
||||
import com.google.gerrit.server.config.FactoryModule;
|
||||
import com.google.gerrit.server.git.GitRepositoryManager;
|
||||
import com.google.gerrit.server.git.LocalDiskRepositoryManager;
|
||||
@@ -29,8 +33,12 @@ public class SchemaModule extends FactoryModule {
|
||||
protected void configure() {
|
||||
install(new SchemaVersion.Module());
|
||||
|
||||
bind(PersonIdent.class).annotatedWith(GerritPersonIdent.class).toProvider(
|
||||
GerritPersonIdentProvider.class);
|
||||
bind(PersonIdent.class).annotatedWith(GerritPersonIdent.class)
|
||||
.toProvider(GerritPersonIdentProvider.class);
|
||||
|
||||
bind(AllProjectsName.class)
|
||||
.toProvider(AllProjectsNameProvider.class)
|
||||
.in(SINGLETON);
|
||||
|
||||
bind(GitRepositoryManager.class).to(LocalDiskRepositoryManager.class);
|
||||
install(new LifecycleModule() {
|
||||
|
||||
@@ -32,7 +32,7 @@ import java.util.List;
|
||||
/** A version of the database schema. */
|
||||
public abstract class SchemaVersion {
|
||||
/** The current schema version. */
|
||||
private static final Class<? extends SchemaVersion> C = Schema_56.class;
|
||||
private static final Class<? extends SchemaVersion> C = Schema_57.class;
|
||||
|
||||
public static class Module extends AbstractModule {
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,165 @@
|
||||
// Copyright (C) 2011 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.schema;
|
||||
|
||||
import com.google.gerrit.common.data.AccessSection;
|
||||
import com.google.gerrit.common.data.GlobalCapability;
|
||||
import com.google.gerrit.common.data.PermissionRule;
|
||||
import com.google.gerrit.reviewdb.AccountGroup;
|
||||
import com.google.gerrit.reviewdb.AccountGroupName;
|
||||
import com.google.gerrit.reviewdb.Project;
|
||||
import com.google.gerrit.reviewdb.ReviewDb;
|
||||
import com.google.gerrit.reviewdb.SystemConfig;
|
||||
import com.google.gerrit.server.GerritPersonIdent;
|
||||
import com.google.gerrit.server.config.AllProjectsNameProvider;
|
||||
import com.google.gerrit.server.config.SitePaths;
|
||||
import com.google.gerrit.server.git.LocalDiskRepositoryManager;
|
||||
import com.google.gerrit.server.git.MetaDataUpdate;
|
||||
import com.google.gerrit.server.git.NoReplication;
|
||||
import com.google.gerrit.server.git.ProjectConfig;
|
||||
import com.google.gwtorm.client.OrmException;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Provider;
|
||||
|
||||
import org.eclipse.jgit.errors.ConfigInvalidException;
|
||||
import org.eclipse.jgit.lib.PersonIdent;
|
||||
import org.eclipse.jgit.lib.Repository;
|
||||
import org.eclipse.jgit.storage.file.FileBasedConfig;
|
||||
import org.eclipse.jgit.util.FS;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
|
||||
public class Schema_57 extends SchemaVersion {
|
||||
private final SitePaths site;
|
||||
private final LocalDiskRepositoryManager mgr;
|
||||
private final PersonIdent serverUser;
|
||||
|
||||
@Inject
|
||||
Schema_57(Provider<Schema_56> prior, SitePaths site,
|
||||
LocalDiskRepositoryManager mgr, @GerritPersonIdent PersonIdent serverUser) {
|
||||
super(prior);
|
||||
this.site = site;
|
||||
this.mgr = mgr;
|
||||
this.serverUser = serverUser;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void migrateData(ReviewDb db, UpdateUI ui) throws OrmException {
|
||||
SystemConfig sc = db.systemConfig().get(new SystemConfig.Key());
|
||||
Project.NameKey allProjects = sc.wildProjectName;
|
||||
|
||||
FileBasedConfig cfg = new FileBasedConfig(site.gerrit_config, FS.DETECTED);
|
||||
boolean cfgDirty = false;
|
||||
try {
|
||||
cfg.load();
|
||||
} catch (ConfigInvalidException err) {
|
||||
throw new OrmException("Cannot read " + site.gerrit_config, err);
|
||||
} catch (IOException err) {
|
||||
throw new OrmException("Cannot read " + site.gerrit_config, err);
|
||||
}
|
||||
|
||||
if (!allProjects.get().equals(AllProjectsNameProvider.DEFAULT)) {
|
||||
ui.message("Setting gerrit.allProjects = " + allProjects.get());
|
||||
cfg.setString("gerrit", null, "allProjects", allProjects.get());
|
||||
cfgDirty = true;
|
||||
}
|
||||
|
||||
try {
|
||||
Repository git = mgr.openRepository(allProjects);
|
||||
try {
|
||||
MetaDataUpdate md = new MetaDataUpdate(new NoReplication(), allProjects, git);
|
||||
md.getCommitBuilder().setAuthor(serverUser);
|
||||
md.getCommitBuilder().setCommitter(serverUser);
|
||||
|
||||
ProjectConfig config = ProjectConfig.read(md);
|
||||
AccessSection cap = config.getAccessSection(AccessSection.GLOBAL_CAPABILITIES, true);
|
||||
|
||||
// Move the Administrators group reference to All-Projects.
|
||||
cap.getPermission(GlobalCapability.ADMINISTRATE_SERVER, true)
|
||||
.add(new PermissionRule(config.resolve(db.accountGroups().get(sc.adminGroupId))));
|
||||
|
||||
// Move the repository.*.createGroup to Create Project.
|
||||
String[] createGroupList = cfg.getStringList("repository", "*", "createGroup");
|
||||
for (String name : createGroupList) {
|
||||
AccountGroup.NameKey key = new AccountGroup.NameKey(name);
|
||||
AccountGroupName groupName = db.accountGroupNames().get(key);
|
||||
if (groupName == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
AccountGroup group = db.accountGroups().get(groupName.getId());
|
||||
if (group == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
cap.getPermission(GlobalCapability.CREATE_PROJECT, true)
|
||||
.add(new PermissionRule(config.resolve(group)));
|
||||
}
|
||||
if (createGroupList.length != 0) {
|
||||
ui.message("Moved repository.*.createGroup to 'Create Project' capability");
|
||||
cfg.unset("repository", "*", "createGroup");
|
||||
cfgDirty = true;
|
||||
}
|
||||
|
||||
AccountGroup batch = db.accountGroups().get(sc.batchUsersGroupId);
|
||||
if (db.accountGroupMembers().byGroup(sc.batchUsersGroupId).toList().isEmpty() &&
|
||||
db.accountGroupIncludes().byGroup(sc.batchUsersGroupId).toList().isEmpty()) {
|
||||
// If the batch user group is not used, delete it.
|
||||
//
|
||||
if (batch != null) {
|
||||
db.accountGroups().delete(Collections.singleton(batch));
|
||||
|
||||
AccountGroupName name = db.accountGroupNames().get(batch.getNameKey());
|
||||
if (name != null) {
|
||||
db.accountGroupNames().delete(Collections.singleton(name));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// FIXME Assign low priority to this group.
|
||||
}
|
||||
|
||||
md.setMessage("Upgrade to Gerrit Code Review schema 57\n");
|
||||
if (!config.commit(md)) {
|
||||
throw new OrmException("Cannot update " + allProjects);
|
||||
}
|
||||
} finally {
|
||||
git.close();
|
||||
}
|
||||
} catch (ConfigInvalidException err) {
|
||||
throw new OrmException("Cannot read " + allProjects, err);
|
||||
} catch (IOException err) {
|
||||
throw new OrmException("Cannot update " + allProjects, err);
|
||||
}
|
||||
|
||||
if (cfgDirty) {
|
||||
try {
|
||||
cfg.save();
|
||||
} catch (IOException err) {
|
||||
throw new OrmException("Cannot update " + site.gerrit_config, err);
|
||||
}
|
||||
}
|
||||
|
||||
// We cannot set the columns to NULL, so use 0 and a DELETED tag.
|
||||
sc.adminGroupId = new AccountGroup.Id(0);
|
||||
sc.adminGroupUUID = new AccountGroup.UUID("DELETED");
|
||||
sc.anonymousGroupId = new AccountGroup.Id(0);
|
||||
sc.registeredGroupId = new AccountGroup.Id(0);
|
||||
sc.wildProjectName = new Project.NameKey("DELETED");
|
||||
sc.ownerGroupId = new AccountGroup.Id(0);
|
||||
|
||||
db.systemConfig().update(Collections.singleton(sc));
|
||||
}
|
||||
}
|
||||
@@ -29,6 +29,8 @@ import com.google.gerrit.reviewdb.SystemConfig;
|
||||
import com.google.gerrit.rules.PrologEnvironment;
|
||||
import com.google.gerrit.server.AccessPath;
|
||||
import com.google.gerrit.server.CurrentUser;
|
||||
import com.google.gerrit.server.account.CapabilityControl;
|
||||
import com.google.gerrit.server.config.AllProjectsName;
|
||||
import com.google.gerrit.server.config.AuthConfig;
|
||||
import com.google.gerrit.server.config.GerritServerConfig;
|
||||
import com.google.gerrit.server.git.GitRepositoryManager;
|
||||
@@ -36,6 +38,7 @@ import com.google.gerrit.server.git.ProjectConfig;
|
||||
import com.google.inject.AbstractModule;
|
||||
import com.google.inject.Guice;
|
||||
import com.google.inject.Injector;
|
||||
import com.google.inject.assistedinject.FactoryProvider;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
@@ -194,6 +197,10 @@ public class RefControlTest extends TestCase {
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
private final Map<Project.NameKey, ProjectState> all;
|
||||
private final AllProjectsName allProjectsName = new AllProjectsName("parent");
|
||||
private final ProjectCache projectCache;
|
||||
|
||||
private ProjectConfig local;
|
||||
private ProjectConfig parent;
|
||||
private final AccountGroup.UUID admin = new AccountGroup.UUID("test.admin");
|
||||
@@ -205,10 +212,10 @@ public class RefControlTest extends TestCase {
|
||||
|
||||
private final SystemConfig systemConfig;
|
||||
private final AuthConfig authConfig;
|
||||
private final CapabilityControl.Factory capabilityControlFactory;
|
||||
|
||||
public RefControlTest() {
|
||||
systemConfig = SystemConfig.create();
|
||||
systemConfig.adminGroupUUID = admin;
|
||||
systemConfig.batchUsersGroupUUID = anonymous;
|
||||
try {
|
||||
byte[] bin = "abcdefghijklmnopqrstuvwxyz".getBytes("UTF-8");
|
||||
@@ -217,6 +224,37 @@ public class RefControlTest extends TestCase {
|
||||
throw new RuntimeException("Cannot encode key", err);
|
||||
}
|
||||
|
||||
all = new HashMap<Project.NameKey, ProjectState>();
|
||||
projectCache = new ProjectCache() {
|
||||
@Override
|
||||
public ProjectState getAllProjects() {
|
||||
return get(allProjectsName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProjectState get(Project.NameKey projectName) {
|
||||
return all.get(projectName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void evict(Project p) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<Project.NameKey> all() {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<Project.NameKey> byName(String prefix) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateProject(Project.NameKey newProjectName) {
|
||||
}
|
||||
};
|
||||
|
||||
Injector injector = Guice.createInjector(new AbstractModule() {
|
||||
@Override
|
||||
protected void configure() {
|
||||
@@ -224,11 +262,18 @@ public class RefControlTest extends TestCase {
|
||||
.annotatedWith(GerritServerConfig.class) //
|
||||
.toInstance(new Config());
|
||||
|
||||
bind(CapabilityControl.Factory.class)
|
||||
.toProvider(FactoryProvider.newFactory(
|
||||
CapabilityControl.Factory.class,
|
||||
CapabilityControl.class));
|
||||
|
||||
bind(ProjectCache.class).toInstance(projectCache);
|
||||
bind(SystemConfig.class).toInstance(systemConfig);
|
||||
bind(AuthConfig.class);
|
||||
}
|
||||
});
|
||||
authConfig = injector.getInstance(AuthConfig.class);
|
||||
capabilityControlFactory = injector.getInstance(CapabilityControl.Factory.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -287,42 +332,14 @@ public class RefControlTest extends TestCase {
|
||||
}
|
||||
|
||||
private ProjectState newProjectState() {
|
||||
final Map<Project.NameKey, ProjectState> all =
|
||||
new HashMap<Project.NameKey, ProjectState>();
|
||||
final ProjectCache projectCache = new ProjectCache() {
|
||||
@Override
|
||||
public ProjectState get(Project.NameKey projectName) {
|
||||
return all.get(projectName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void evict(Project p) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<Project.NameKey> all() {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<Project.NameKey> byName(String prefix) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateProject(Project.NameKey newProjectName) {
|
||||
}
|
||||
};
|
||||
|
||||
PrologEnvironment.Factory envFactory = null;
|
||||
GitRepositoryManager mgr = null;
|
||||
Project.NameKey wildProject = new Project.NameKey("All-Projects");
|
||||
ProjectControl.AssistedFactory projectControlFactory = null;
|
||||
all.put(local.getProject().getNameKey(), new ProjectState(
|
||||
projectCache, wildProject, projectControlFactory,
|
||||
projectCache, allProjectsName, projectControlFactory,
|
||||
envFactory, mgr, local));
|
||||
all.put(parent.getProject().getNameKey(), new ProjectState(
|
||||
projectCache, wildProject, projectControlFactory,
|
||||
projectCache, allProjectsName, projectControlFactory,
|
||||
envFactory, mgr, parent));
|
||||
return all.get(local.getProject().getNameKey());
|
||||
}
|
||||
@@ -331,7 +348,9 @@ public class RefControlTest extends TestCase {
|
||||
private final Set<AccountGroup.UUID> groups;
|
||||
|
||||
MockUser(AccountGroup.UUID[] groupId) {
|
||||
super(null, AccessPath.UNKNOWN, RefControlTest.this.authConfig);
|
||||
super(RefControlTest.this.capabilityControlFactory,
|
||||
AccessPath.UNKNOWN,
|
||||
RefControlTest.this.authConfig);
|
||||
groups = new HashSet<AccountGroup.UUID>(Arrays.asList(groupId));
|
||||
groups.add(registered);
|
||||
groups.add(anonymous);
|
||||
@@ -351,10 +370,5 @@ public class RefControlTest extends TestCase {
|
||||
public Collection<AccountProjectWatch> getNotificationFilters() {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAdministrator() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
|
||||
package com.google.gerrit.server.schema;
|
||||
|
||||
import com.google.gerrit.reviewdb.AccountGroup;
|
||||
import com.google.gerrit.reviewdb.ApprovalCategory;
|
||||
import com.google.gerrit.reviewdb.ApprovalCategoryValue;
|
||||
import com.google.gerrit.reviewdb.ReviewDb;
|
||||
@@ -71,9 +70,6 @@ public class SchemaCreatorTest extends TestCase {
|
||||
db.assertSchemaVersion();
|
||||
final SystemConfig config = db.getSystemConfig();
|
||||
assertNotNull(config);
|
||||
assertNotNull(config.adminGroupId);
|
||||
assertNotNull(config.anonymousGroupId);
|
||||
assertNotNull(config.registeredGroupId);
|
||||
|
||||
// By default sitePath is set to the current working directory.
|
||||
//
|
||||
@@ -95,58 +91,10 @@ public class SchemaCreatorTest extends TestCase {
|
||||
final SystemConfig act = db.getSystemConfig();
|
||||
|
||||
assertNotSame(exp, act);
|
||||
assertEquals(exp.adminGroupId, act.adminGroupId);
|
||||
assertEquals(exp.anonymousGroupId, act.anonymousGroupId);
|
||||
assertEquals(exp.registeredGroupId, act.registeredGroupId);
|
||||
assertEquals(exp.sitePath, act.sitePath);
|
||||
assertEquals(exp.registerEmailPrivateKey, act.registerEmailPrivateKey);
|
||||
}
|
||||
|
||||
public void testCreateSchema_Group_Administrators() throws OrmException {
|
||||
db.create();
|
||||
final SystemConfig config = db.getSystemConfig();
|
||||
final ReviewDb c = db.open();
|
||||
try {
|
||||
final AccountGroup admin = c.accountGroups().get(config.adminGroupId);
|
||||
assertNotNull(admin);
|
||||
assertEquals(config.adminGroupId, admin.getId());
|
||||
assertEquals("Administrators", admin.getName());
|
||||
assertSame(AccountGroup.Type.INTERNAL, admin.getType());
|
||||
} finally {
|
||||
c.close();
|
||||
}
|
||||
}
|
||||
|
||||
public void testCreateSchema_Group_AnonymousUsers() throws OrmException {
|
||||
db.create();
|
||||
final SystemConfig config = db.getSystemConfig();
|
||||
final ReviewDb c = db.open();
|
||||
try {
|
||||
final AccountGroup anon = c.accountGroups().get(config.anonymousGroupId);
|
||||
assertNotNull(anon);
|
||||
assertEquals(config.anonymousGroupId, anon.getId());
|
||||
assertEquals("Anonymous Users", anon.getName());
|
||||
assertSame(AccountGroup.Type.SYSTEM, anon.getType());
|
||||
} finally {
|
||||
c.close();
|
||||
}
|
||||
}
|
||||
|
||||
public void testCreateSchema_Group_RegisteredUsers() throws OrmException {
|
||||
db.create();
|
||||
final SystemConfig config = db.getSystemConfig();
|
||||
final ReviewDb c = db.open();
|
||||
try {
|
||||
final AccountGroup reg = c.accountGroups().get(config.registeredGroupId);
|
||||
assertNotNull(reg);
|
||||
assertEquals(config.registeredGroupId, reg.getId());
|
||||
assertEquals("Registered Users", reg.getName());
|
||||
assertSame(AccountGroup.Type.SYSTEM, reg.getType());
|
||||
} finally {
|
||||
c.close();
|
||||
}
|
||||
}
|
||||
|
||||
public void testCreateSchema_ApprovalCategory_CodeReview()
|
||||
throws OrmException {
|
||||
final ReviewDb c = db.create().open();
|
||||
|
||||
@@ -18,6 +18,7 @@ import com.google.gerrit.reviewdb.ReviewDb;
|
||||
import com.google.gerrit.reviewdb.SystemConfig;
|
||||
import com.google.gerrit.server.GerritPersonIdent;
|
||||
import com.google.gerrit.server.GerritPersonIdentProvider;
|
||||
import com.google.gerrit.server.config.AllProjectsName;
|
||||
import com.google.gerrit.server.config.GerritServerConfig;
|
||||
import com.google.gerrit.server.config.SitePaths;
|
||||
import com.google.gerrit.server.git.GitRepositoryManager;
|
||||
@@ -80,6 +81,9 @@ public class SchemaUpdaterTest extends TestCase {
|
||||
.annotatedWith(GerritPersonIdent.class) //
|
||||
.toProvider(GerritPersonIdentProvider.class);
|
||||
|
||||
bind(AllProjectsName.class)
|
||||
.toInstance(new AllProjectsName("All-Projects"));
|
||||
|
||||
bind(GitRepositoryManager.class) //
|
||||
.to(LocalDiskRepositoryManager.class);
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ import com.google.gerrit.reviewdb.ReviewDb;
|
||||
import com.google.gerrit.reviewdb.SystemConfig;
|
||||
import com.google.gerrit.server.GerritPersonIdent;
|
||||
import com.google.gerrit.server.GerritPersonIdentProvider;
|
||||
import com.google.gerrit.server.config.AllProjectsName;
|
||||
import com.google.gerrit.server.config.GerritServerConfig;
|
||||
import com.google.gerrit.server.config.SitePath;
|
||||
import com.google.gerrit.server.config.SystemConfigProvider;
|
||||
@@ -144,7 +145,11 @@ public class InMemoryDatabase implements SchemaFactory<ReviewDb> {
|
||||
final ReviewDb c = open();
|
||||
try {
|
||||
try {
|
||||
new SchemaCreator(new File("."), schemaVersion, null,
|
||||
new SchemaCreator(
|
||||
new File("."),
|
||||
schemaVersion,
|
||||
null,
|
||||
new AllProjectsName("Test-Projects"),
|
||||
new PersonIdent("name", "email@site")).create(c);
|
||||
} catch (IOException e) {
|
||||
throw new OrmException("Cannot create in-memory database", e);
|
||||
|
||||
@@ -240,7 +240,8 @@ public abstract class BaseCommand implements Command {
|
||||
protected synchronized void startThread(final CommandRunnable thunk) {
|
||||
final TaskThunk tt = new TaskThunk(thunk);
|
||||
|
||||
if (isAdminCommand()||(isAdminHighPriorityCommand() && userProvider.get().isAdministrator())) {
|
||||
if (isAdminCommand() || (isAdminHighPriorityCommand()
|
||||
&& userProvider.get().getCapabilities().canAdministrateServer())) {
|
||||
// Admin commands should not block the main work threads (there
|
||||
// might be an interactive shell there), nor should they wait
|
||||
// for the main work threads.
|
||||
|
||||
@@ -71,7 +71,8 @@ final class DispatchCommand extends BaseCommand {
|
||||
|
||||
final Command cmd = p.get();
|
||||
|
||||
if (isAdminCommand(cmd) && !currentUser.get().isAdministrator()) {
|
||||
if (isAdminCommand(cmd)
|
||||
&& !currentUser.get().getCapabilities().canAdministrateServer()) {
|
||||
final String msg = "fatal: Not a Gerrit administrator";
|
||||
throw new UnloggedFailure(BaseCommand.STATUS_NOT_ADMIN, msg);
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
package com.google.gerrit.sshd.commands;
|
||||
|
||||
import com.google.gerrit.reviewdb.Project;
|
||||
import com.google.gerrit.server.config.WildProjectName;
|
||||
import com.google.gerrit.server.config.AllProjectsName;
|
||||
import com.google.gerrit.server.git.MetaDataUpdate;
|
||||
import com.google.gerrit.server.git.ProjectConfig;
|
||||
import com.google.gerrit.server.project.ProjectCache;
|
||||
@@ -52,8 +52,7 @@ final class AdminSetParent extends BaseCommand {
|
||||
private MetaDataUpdate.User metaDataUpdateFactory;
|
||||
|
||||
@Inject
|
||||
@WildProjectName
|
||||
private Project.NameKey wildProject;
|
||||
private AllProjectsName allProjectsName;
|
||||
|
||||
@Override
|
||||
public void start(final Environment env) {
|
||||
@@ -71,7 +70,7 @@ final class AdminSetParent extends BaseCommand {
|
||||
final Set<Project.NameKey> grandParents = new HashSet<Project.NameKey>();
|
||||
Project.NameKey newParentKey;
|
||||
|
||||
grandParents.add(wildProject);
|
||||
grandParents.add(allProjectsName);
|
||||
|
||||
if (newParent != null) {
|
||||
newParentKey = newParent.getProject().getNameKey();
|
||||
@@ -98,7 +97,7 @@ final class AdminSetParent extends BaseCommand {
|
||||
final Project.NameKey key = pc.getProject().getNameKey();
|
||||
final String name = pc.getProject().getName();
|
||||
|
||||
if (wildProject.equals(key)) {
|
||||
if (allProjectsName.equals(key)) {
|
||||
// Don't allow the wild card project to have a parent.
|
||||
//
|
||||
err.append("error: Cannot set parent of '" + name + "'\n");
|
||||
@@ -109,7 +108,7 @@ final class AdminSetParent extends BaseCommand {
|
||||
// Try to avoid creating a cycle in the parent pointers.
|
||||
//
|
||||
err.append("error: Cycle exists between '" + name + "' and '"
|
||||
+ (newParentKey != null ? newParentKey.get() : wildProject.get())
|
||||
+ (newParentKey != null ? newParentKey.get() : allProjectsName.get())
|
||||
+ "'\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
|
||||
package com.google.gerrit.sshd.commands;
|
||||
|
||||
import com.google.gerrit.common.CollectionsUtil;
|
||||
import com.google.gerrit.common.data.AccessSection;
|
||||
import com.google.gerrit.common.data.GroupReference;
|
||||
import com.google.gerrit.common.data.Permission;
|
||||
@@ -25,7 +24,6 @@ import com.google.gerrit.reviewdb.Project.SubmitType;
|
||||
import com.google.gerrit.server.GerritPersonIdent;
|
||||
import com.google.gerrit.server.IdentifiedUser;
|
||||
import com.google.gerrit.server.account.GroupCache;
|
||||
import com.google.gerrit.server.config.ProjectCreatorGroups;
|
||||
import com.google.gerrit.server.config.ProjectOwnerGroups;
|
||||
import com.google.gerrit.server.git.GitRepositoryManager;
|
||||
import com.google.gerrit.server.git.MetaDataUpdate;
|
||||
@@ -125,10 +123,6 @@ final class CreateProject extends BaseCommand {
|
||||
@Inject
|
||||
private GroupCache groupCache;
|
||||
|
||||
@Inject
|
||||
@ProjectCreatorGroups
|
||||
private Set<AccountGroup.UUID> projectCreatorGroups;
|
||||
|
||||
@Inject
|
||||
@ProjectOwnerGroups
|
||||
private Set<AccountGroup.UUID> projectOwnerGroups;
|
||||
@@ -153,6 +147,13 @@ final class CreateProject extends BaseCommand {
|
||||
startThread(new CommandRunnable() {
|
||||
@Override
|
||||
public void run() throws Exception {
|
||||
if (!currentUser.getCapabilities().canCreateProject()) {
|
||||
String msg = String.format(
|
||||
"fatal: %s does not have \"Create Project\" capability.",
|
||||
currentUser.getUserName());
|
||||
throw new UnloggedFailure(BaseCommand.STATUS_NOT_ADMIN, msg);
|
||||
}
|
||||
|
||||
parseCommandLine();
|
||||
validateParameters();
|
||||
|
||||
@@ -279,10 +280,6 @@ final class CreateProject extends BaseCommand {
|
||||
projectName.length() - Constants.DOT_GIT_EXT.length());
|
||||
}
|
||||
|
||||
if (!CollectionsUtil.isAnyIncludedIn(currentUser.getEffectiveGroups(), projectCreatorGroups)) {
|
||||
throw new Failure(1, "fatal: Not permitted to create " + projectName);
|
||||
}
|
||||
|
||||
if (ownerIds != null && !ownerIds.isEmpty()) {
|
||||
ownerIds =
|
||||
new ArrayList<AccountGroup.UUID>(new HashSet<AccountGroup.UUID>(ownerIds));
|
||||
|
||||
@@ -65,7 +65,8 @@ final class FlushCaches extends CacheCommand {
|
||||
}
|
||||
|
||||
private void flush() throws Failure {
|
||||
if (caches.contains(WEB_SESSIONS) && !currentUser.isAdministrator()) {
|
||||
if (caches.contains(WEB_SESSIONS)
|
||||
&& !currentUser.getCapabilities().canAdministrateServer()) {
|
||||
String msg = String.format(
|
||||
"fatal: only site administrators can flush %s",
|
||||
WEB_SESSIONS);
|
||||
|
||||
@@ -16,7 +16,7 @@ package com.google.gerrit.sshd.commands;
|
||||
|
||||
import com.google.gerrit.reviewdb.Project;
|
||||
import com.google.gerrit.server.IdentifiedUser;
|
||||
import com.google.gerrit.server.config.WildProjectName;
|
||||
import com.google.gerrit.server.config.AllProjectsName;
|
||||
import com.google.gerrit.server.git.GitRepositoryManager;
|
||||
import com.google.gerrit.server.project.ProjectCache;
|
||||
import com.google.gerrit.server.project.ProjectControl;
|
||||
@@ -84,8 +84,7 @@ final class ListProjects extends BaseCommand {
|
||||
private GitRepositoryManager repoManager;
|
||||
|
||||
@Inject
|
||||
@WildProjectName
|
||||
private Project.NameKey allProjectsName;
|
||||
private AllProjectsName allProjectsName;
|
||||
|
||||
@Option(name = "--show-branch", aliases = {"-b"}, multiValued = true,
|
||||
usage = "displays the sha of each project in the specified branch")
|
||||
|
||||
Reference in New Issue
Block a user