Allow to delegate modify account commands to non administrators
Currently only administrators groups allow to modify accounts. This is impractical on very big installations. Add modify account global capability and allow administrators to optionally delegate this job. Bug: Issue 2786 Change-Id: Icc105c39e76908a075e89ec14921972b91866dd4
This commit is contained in:

committed by
David Pursehouse

parent
e715d2484a
commit
aa49e277a3
@@ -1208,6 +1208,12 @@ kill command ends tasks that currently occupy the Gerrit server, usually
|
||||
a replication task or a user initiated task such as an upload-pack or
|
||||
receive-pack.
|
||||
|
||||
[[capability_modifyAccount]]
|
||||
=== Modify Account
|
||||
|
||||
Allow to link:cmd-set-account.html[modify accounts over the ssh prompt].
|
||||
This capability allows the granted group members to modify any user account
|
||||
setting.
|
||||
|
||||
[[capability_priority]]
|
||||
=== Priority
|
||||
|
@@ -21,7 +21,15 @@ It also allows managing email addresses, which bypasses the
|
||||
verification step we force within the UI.
|
||||
|
||||
== ACCESS
|
||||
Caller must be a member of the privileged 'Administrators' group.
|
||||
Caller must be a member of the privileged 'Administrators' group,
|
||||
or have been granted
|
||||
link:access-control.html#capability_modifyAccount[the 'Modify Account' global capability].
|
||||
|
||||
To set the HTTP password for the user account (option --http-password) the
|
||||
caller must be a member of the privileged 'Administrators' group,
|
||||
or have been granted
|
||||
link:access-control.html#capability_generateHttpPassword[the 'Generate HTTP Password' global capability]
|
||||
in addition to 'Modify Account' global capability.
|
||||
|
||||
== SCRIPTING
|
||||
This command is intended to be used in scripts.
|
||||
|
@@ -38,6 +38,9 @@ public class GlobalCapability {
|
||||
/** Can create any account on the server. */
|
||||
public static final String CREATE_ACCOUNT = "createAccount";
|
||||
|
||||
/** Can modify any account on the server. */
|
||||
public static final String MODIFY_ACCOUNT = "modifyAccount";
|
||||
|
||||
/** Can create any group on the server. */
|
||||
public static final String CREATE_GROUP = "createGroup";
|
||||
|
||||
@@ -108,6 +111,7 @@ public class GlobalCapability {
|
||||
NAMES_ALL.add(FLUSH_CACHES);
|
||||
NAMES_ALL.add(GENERATE_HTTP_PASSWORD);
|
||||
NAMES_ALL.add(KILL_TASK);
|
||||
NAMES_ALL.add(MODIFY_ACCOUNT);
|
||||
NAMES_ALL.add(PRIORITY);
|
||||
NAMES_ALL.add(QUERY_LIMIT);
|
||||
NAMES_ALL.add(RUN_AS);
|
||||
|
@@ -63,7 +63,7 @@ public class AddSshKey implements RestModifyView<AccountResource, Input> {
|
||||
public Response<SshKeyInfo> apply(AccountResource rsrc, Input input)
|
||||
throws AuthException, BadRequestException, OrmException, IOException {
|
||||
if (self.get() != rsrc.getUser()
|
||||
&& !self.get().getCapabilities().canAdministrateServer()) {
|
||||
&& !self.get().getCapabilities().canModifyAccount()) {
|
||||
throw new AuthException("not allowed to add SSH keys");
|
||||
}
|
||||
return apply(rsrc.getUser(), input);
|
||||
|
@@ -110,6 +110,12 @@ public class CapabilityControl {
|
||||
|| canAdministrateServer();
|
||||
}
|
||||
|
||||
/** @return true if the user can modify an account for another user. */
|
||||
public boolean canModifyAccount() {
|
||||
return canPerform(GlobalCapability.MODIFY_ACCOUNT)
|
||||
|| canAdministrateServer();
|
||||
}
|
||||
|
||||
/** @return true if the user can view all accounts. */
|
||||
public boolean canViewAllAccounts() {
|
||||
return canPerform(GlobalCapability.VIEW_ALL_ACCOUNTS)
|
||||
|
@@ -85,7 +85,7 @@ public class CreateEmail implements RestModifyView<AccountResource, Input> {
|
||||
ResourceNotFoundException, OrmException, EmailException,
|
||||
MethodNotAllowedException {
|
||||
if (self.get() != rsrc.getUser()
|
||||
&& !self.get().getCapabilities().canAdministrateServer()) {
|
||||
&& !self.get().getCapabilities().canModifyAccount()) {
|
||||
throw new AuthException("not allowed to add email address");
|
||||
}
|
||||
|
||||
@@ -98,8 +98,8 @@ public class CreateEmail implements RestModifyView<AccountResource, Input> {
|
||||
}
|
||||
|
||||
if (input.noConfirmation
|
||||
&& !self.get().getCapabilities().canAdministrateServer()) {
|
||||
throw new AuthException("must be administrator to use no_confirmation");
|
||||
&& !self.get().getCapabilities().canModifyAccount()) {
|
||||
throw new AuthException("not allowed to use no_confirmation");
|
||||
}
|
||||
|
||||
return apply(rsrc.getUser(), input);
|
||||
|
@@ -29,7 +29,7 @@ import com.google.inject.Singleton;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
@RequiresCapability(GlobalCapability.ADMINISTRATE_SERVER)
|
||||
@RequiresCapability(GlobalCapability.MODIFY_ACCOUNT)
|
||||
@Singleton
|
||||
public class DeleteActive implements RestModifyView<AccountResource, Input> {
|
||||
public static class Input {
|
||||
|
@@ -55,7 +55,7 @@ public class DeleteEmail implements RestModifyView<AccountResource.Email, Input>
|
||||
throws AuthException, ResourceNotFoundException,
|
||||
ResourceConflictException, MethodNotAllowedException, OrmException {
|
||||
if (self.get() != rsrc.getUser()
|
||||
&& !self.get().getCapabilities().canAdministrateServer()) {
|
||||
&& !self.get().getCapabilities().canModifyAccount()) {
|
||||
throw new AuthException("not allowed to delete email address");
|
||||
}
|
||||
return apply(rsrc.getUser(), rsrc.getEmail());
|
||||
|
@@ -22,6 +22,7 @@ import static com.google.gerrit.common.data.GlobalCapability.EMAIL_REVIEWERS;
|
||||
import static com.google.gerrit.common.data.GlobalCapability.FLUSH_CACHES;
|
||||
import static com.google.gerrit.common.data.GlobalCapability.GENERATE_HTTP_PASSWORD;
|
||||
import static com.google.gerrit.common.data.GlobalCapability.KILL_TASK;
|
||||
import static com.google.gerrit.common.data.GlobalCapability.MODIFY_ACCOUNT;
|
||||
import static com.google.gerrit.common.data.GlobalCapability.PRIORITY;
|
||||
import static com.google.gerrit.common.data.GlobalCapability.RUN_GC;
|
||||
import static com.google.gerrit.common.data.GlobalCapability.STREAM_EVENTS;
|
||||
@@ -116,6 +117,7 @@ class GetCapabilities implements RestReadView<AccountResource> {
|
||||
have.put(FLUSH_CACHES, cc.canFlushCaches());
|
||||
have.put(GENERATE_HTTP_PASSWORD, cc.canGenerateHttpPassword());
|
||||
have.put(KILL_TASK, cc.canKillTask());
|
||||
have.put(MODIFY_ACCOUNT, cc.canModifyAccount());
|
||||
have.put(RUN_GC, cc.canRunGC());
|
||||
have.put(STREAM_EVENTS, cc.canStreamEvents());
|
||||
have.put(VIEW_ALL_ACCOUNTS, cc.canViewAllAccounts());
|
||||
|
@@ -40,7 +40,7 @@ public class GetEmails implements RestReadView<AccountResource> {
|
||||
public List<EmailInfo> apply(AccountResource rsrc) throws AuthException,
|
||||
OrmException {
|
||||
if (self.get() != rsrc.getUser()
|
||||
&& !self.get().getCapabilities().canAdministrateServer()) {
|
||||
&& !self.get().getCapabilities().canModifyAccount()) {
|
||||
throw new AuthException("not allowed to list email addresses");
|
||||
}
|
||||
|
||||
|
@@ -45,7 +45,7 @@ public class GetSshKeys implements RestReadView<AccountResource> {
|
||||
public List<SshKeyInfo> apply(AccountResource rsrc) throws AuthException,
|
||||
OrmException {
|
||||
if (self.get() != rsrc.getUser()
|
||||
&& !self.get().getCapabilities().canAdministrateServer()) {
|
||||
&& !self.get().getCapabilities().canModifyAccount()) {
|
||||
throw new AuthException("not allowed to get SSH keys");
|
||||
}
|
||||
return apply(rsrc.getUser());
|
||||
|
@@ -29,7 +29,7 @@ import com.google.inject.Singleton;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
@RequiresCapability(GlobalCapability.ADMINISTRATE_SERVER)
|
||||
@RequiresCapability(GlobalCapability.MODIFY_ACCOUNT)
|
||||
@Singleton
|
||||
public class PutActive implements RestModifyView<AccountResource, Input> {
|
||||
public static class Input {
|
||||
|
@@ -64,7 +64,7 @@ public class PutName implements RestModifyView<AccountResource, Input> {
|
||||
throws AuthException, MethodNotAllowedException,
|
||||
ResourceNotFoundException, OrmException {
|
||||
if (self.get() != rsrc.getUser()
|
||||
&& !self.get().getCapabilities().canAdministrateServer()) {
|
||||
&& !self.get().getCapabilities().canModifyAccount()) {
|
||||
throw new AuthException("not allowed to change name");
|
||||
}
|
||||
return apply(rsrc.getUser(), input);
|
||||
|
@@ -52,7 +52,7 @@ public class PutPreferred implements
|
||||
public Response<String> apply(AccountResource.Email rsrc, Input input)
|
||||
throws AuthException, ResourceNotFoundException, OrmException {
|
||||
if (self.get() != rsrc.getUser()
|
||||
&& !self.get().getCapabilities().canAdministrateServer()) {
|
||||
&& !self.get().getCapabilities().canModifyAccount()) {
|
||||
throw new AuthException("not allowed to set preferred email address");
|
||||
}
|
||||
return apply(rsrc.getUser(), rsrc.getEmail());
|
||||
|
@@ -68,8 +68,8 @@ public class SetDiffPreferences implements RestModifyView<AccountResource, Input
|
||||
public DiffPreferencesInfo apply(AccountResource rsrc, Input input)
|
||||
throws AuthException, OrmException {
|
||||
if (self.get() != rsrc.getUser()
|
||||
&& !self.get().getCapabilities().canAdministrateServer()) {
|
||||
throw new AuthException("restricted to administrator");
|
||||
&& !self.get().getCapabilities().canModifyAccount()) {
|
||||
throw new AuthException("restricted to members of Modify Accounts");
|
||||
}
|
||||
if (input == null) {
|
||||
input = new Input();
|
||||
|
@@ -95,8 +95,8 @@ public class SetPreferences implements RestModifyView<AccountResource, Input> {
|
||||
throws AuthException, ResourceNotFoundException, OrmException,
|
||||
IOException, ConfigInvalidException {
|
||||
if (self.get() != rsrc.getUser()
|
||||
&& !self.get().getCapabilities().canAdministrateServer()) {
|
||||
throw new AuthException("restricted to administrator");
|
||||
&& !self.get().getCapabilities().canModifyAccount()) {
|
||||
throw new AuthException("restricted to members of Modify Accounts");
|
||||
}
|
||||
if (i == null) {
|
||||
i = new Input();
|
||||
|
@@ -55,7 +55,7 @@ public class SshKeys implements
|
||||
public AccountResource.SshKey parse(AccountResource rsrc, IdString id)
|
||||
throws ResourceNotFoundException, OrmException {
|
||||
if (self.get() != rsrc.getUser()
|
||||
&& !self.get().getCapabilities().canAdministrateServer()) {
|
||||
&& !self.get().getCapabilities().canModifyAccount()) {
|
||||
throw new ResourceNotFoundException();
|
||||
}
|
||||
return parse(rsrc.getUser(), id);
|
||||
|
@@ -31,6 +31,7 @@ public class CapabilityConstants extends TranslationBundle {
|
||||
public String flushCaches;
|
||||
public String generateHttpPassword;
|
||||
public String killTask;
|
||||
public String modifyAccount;
|
||||
public String priority;
|
||||
public String queryLimit;
|
||||
public String runAs;
|
||||
|
@@ -7,6 +7,7 @@ emailReviewers = Email Reviewers
|
||||
flushCaches = Flush Caches
|
||||
generateHttpPassword = Generate HTTP Password
|
||||
killTask = Kill Task
|
||||
modifyAccount = Modify Account
|
||||
priority = Priority
|
||||
queryLimit = Query Limit
|
||||
runAs = Run As
|
||||
|
@@ -14,7 +14,9 @@
|
||||
|
||||
package com.google.gerrit.sshd.commands;
|
||||
|
||||
import com.google.gerrit.common.data.GlobalCapability;
|
||||
import com.google.gerrit.common.errors.EmailException;
|
||||
import com.google.gerrit.extensions.annotations.RequiresCapability;
|
||||
import com.google.gerrit.extensions.restapi.RawInput;
|
||||
import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
|
||||
import com.google.gerrit.extensions.restapi.RestApiException;
|
||||
@@ -55,6 +57,7 @@ import java.util.List;
|
||||
|
||||
/** Set a user's account settings. **/
|
||||
@CommandMetaData(name = "set-account", description = "Change an account's settings")
|
||||
@RequiresCapability(GlobalCapability.MODIFY_ACCOUNT)
|
||||
final class SetAccountCommand extends BaseCommand {
|
||||
|
||||
@Argument(index = 0, required = true, metaVar = "USER", usage = "full name, email-address, ssh username or account id")
|
||||
@@ -84,9 +87,6 @@ final class SetAccountCommand extends BaseCommand {
|
||||
@Option(name = "--http-password", metaVar = "PASSWORD", usage = "password for HTTP authentication for the account")
|
||||
private String httpPassword;
|
||||
|
||||
@Inject
|
||||
private IdentifiedUser currentUser;
|
||||
|
||||
@Inject
|
||||
private IdentifiedUser.GenericFactory genericUserFactory;
|
||||
|
||||
@@ -128,13 +128,6 @@ final class SetAccountCommand extends BaseCommand {
|
||||
startThread(new CommandRunnable() {
|
||||
@Override
|
||||
public void run() throws Exception {
|
||||
if (!currentUser.getCapabilities().canAdministrateServer()) {
|
||||
String msg =
|
||||
String.format(
|
||||
"fatal: %s does not have \"Administrator\" capability.",
|
||||
currentUser.getUserName());
|
||||
throw new UnloggedFailure(1, msg);
|
||||
}
|
||||
parseCommandLine();
|
||||
validate();
|
||||
setAccount();
|
||||
|
Reference in New Issue
Block a user