Merge changes If8296539,Id907cc10

* changes:
  Close security hole allowing normal user to become admin
  Remove the generateHttpPassword capability
This commit is contained in:
David Pursehouse 2014-10-22 07:14:10 +00:00 committed by Gerrit Code Review
commit 76623a1a56
12 changed files with 22 additions and 32 deletions

View File

@ -1205,13 +1205,6 @@ This capability doesn't imply permissions to the show-caches command. For that
you need the <<capability_viewCaches,view caches capability>>. you need the <<capability_viewCaches,view caches capability>>.
[[capability_generateHttpPassword]]
=== Generate HTTP Password
Allow the user to generate HTTP passwords for other users. Typically this would
be assigned to a non-interactive users group.
[[capability_kill]] [[capability_kill]]
=== Kill Task === Kill Task

View File

@ -26,12 +26,12 @@ verification step we force within the UI.
Caller must be a member of the privileged 'Administrators' group, Caller must be a member of the privileged 'Administrators' group,
or have been granted or have been granted
link:access-control.html#capability_modifyAccount[the 'Modify Account' global capability]. link:access-control.html#capability_modifyAccount[the 'Modify Account' global capability].
For security reasons only the members of the privileged 'Administrators'
group can add or delete SSH keys for a user.
To set the HTTP password for the user account (option --http-password) or To set the HTTP password for the user account (option --http-password) or
to clear the HTTP password (option --clear-http-password) caller must be to clear the HTTP password (option --clear-http-password) caller must be
a member of the privileged 'Administrators' group, or have been granted a member of the privileged 'Administrators' group.
link:access-control.html#capability_generateHttpPassword[the 'Generate HTTP Password' global capability]
in addition to 'Modify Account' global capability.
== SCRIPTING == SCRIPTING
This command is intended to be used in scripts. This command is intended to be used in scripts.

View File

@ -61,9 +61,6 @@ public class GlobalCapability {
/** Can flush any cache except the active web_sessions cache. */ /** Can flush any cache except the active web_sessions cache. */
public static final String FLUSH_CACHES = "flushCaches"; public static final String FLUSH_CACHES = "flushCaches";
/** Can generate HTTP passwords for user other than self. */
public static final String GENERATE_HTTP_PASSWORD = "generateHttpPassword";
/** Can terminate any task using the kill command. */ /** Can terminate any task using the kill command. */
public static final String KILL_TASK = "killTask"; public static final String KILL_TASK = "killTask";
@ -112,7 +109,6 @@ public class GlobalCapability {
NAMES_ALL.add(CREATE_PROJECT); NAMES_ALL.add(CREATE_PROJECT);
NAMES_ALL.add(EMAIL_REVIEWERS); NAMES_ALL.add(EMAIL_REVIEWERS);
NAMES_ALL.add(FLUSH_CACHES); NAMES_ALL.add(FLUSH_CACHES);
NAMES_ALL.add(GENERATE_HTTP_PASSWORD);
NAMES_ALL.add(KILL_TASK); NAMES_ALL.add(KILL_TASK);
NAMES_ALL.add(MODIFY_ACCOUNT); NAMES_ALL.add(MODIFY_ACCOUNT);
NAMES_ALL.add(PRIORITY); NAMES_ALL.add(PRIORITY);

View File

@ -63,7 +63,7 @@ public class AddSshKey implements RestModifyView<AccountResource, Input> {
public Response<SshKeyInfo> apply(AccountResource rsrc, Input input) public Response<SshKeyInfo> apply(AccountResource rsrc, Input input)
throws AuthException, BadRequestException, OrmException, IOException { throws AuthException, BadRequestException, OrmException, IOException {
if (self.get() != rsrc.getUser() if (self.get() != rsrc.getUser()
&& !self.get().getCapabilities().canModifyAccount()) { && !self.get().getCapabilities().canAdministrateServer()) {
throw new AuthException("not allowed to add SSH keys"); throw new AuthException("not allowed to add SSH keys");
} }
return apply(rsrc.getUser(), input); return apply(rsrc.getUser(), input);

View File

@ -169,12 +169,6 @@ public class CapabilityControl {
|| canAdministrateServer(); || canAdministrateServer();
} }
/** @return true if the user can generate HTTP passwords for users other than self. */
public boolean canGenerateHttpPassword() {
return canPerform(GlobalCapability.GENERATE_HTTP_PASSWORD)
|| canAdministrateServer();
}
/** @return true if the user can impersonate another user. */ /** @return true if the user can impersonate another user. */
public boolean canRunAs() { public boolean canRunAs() {
return canPerform(GlobalCapability.RUN_AS); return canPerform(GlobalCapability.RUN_AS);

View File

@ -14,9 +14,11 @@
package com.google.gerrit.server.account; package com.google.gerrit.server.account;
import com.google.gerrit.extensions.restapi.AuthException;
import com.google.gerrit.extensions.restapi.Response; import com.google.gerrit.extensions.restapi.Response;
import com.google.gerrit.extensions.restapi.RestModifyView; import com.google.gerrit.extensions.restapi.RestModifyView;
import com.google.gerrit.reviewdb.server.ReviewDb; import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.account.DeleteSshKey.Input; import com.google.gerrit.server.account.DeleteSshKey.Input;
import com.google.gerrit.server.ssh.SshKeyCache; import com.google.gerrit.server.ssh.SshKeyCache;
import com.google.gwtorm.server.OrmException; import com.google.gwtorm.server.OrmException;
@ -32,18 +34,26 @@ public class DeleteSshKey implements
public static class Input { public static class Input {
} }
private final Provider<CurrentUser> self;
private final Provider<ReviewDb> dbProvider; private final Provider<ReviewDb> dbProvider;
private final SshKeyCache sshKeyCache; private final SshKeyCache sshKeyCache;
@Inject @Inject
DeleteSshKey(Provider<ReviewDb> dbProvider, SshKeyCache sshKeyCache) { DeleteSshKey(Provider<ReviewDb> dbProvider,
Provider<CurrentUser> self,
SshKeyCache sshKeyCache) {
this.self = self;
this.dbProvider = dbProvider; this.dbProvider = dbProvider;
this.sshKeyCache = sshKeyCache; this.sshKeyCache = sshKeyCache;
} }
@Override @Override
public Response<?> apply(AccountResource.SshKey rsrc, Input input) public Response<?> apply(AccountResource.SshKey rsrc, Input input)
throws OrmException { throws AuthException, OrmException {
if (self.get() != rsrc.getUser()
&& !self.get().getCapabilities().canAdministrateServer()) {
throw new AuthException("not allowed to delete SSH keys");
}
dbProvider.get().accountSshKeys() dbProvider.get().accountSshKeys()
.deleteKeys(Collections.singleton(rsrc.getSshKey().getKey())); .deleteKeys(Collections.singleton(rsrc.getSshKey().getKey()));
sshKeyCache.evict(rsrc.getUser().getUserName()); sshKeyCache.evict(rsrc.getUser().getUserName());

View File

@ -20,7 +20,6 @@ import static com.google.gerrit.common.data.GlobalCapability.CREATE_GROUP;
import static com.google.gerrit.common.data.GlobalCapability.CREATE_PROJECT; import static com.google.gerrit.common.data.GlobalCapability.CREATE_PROJECT;
import static com.google.gerrit.common.data.GlobalCapability.EMAIL_REVIEWERS; 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.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.KILL_TASK;
import static com.google.gerrit.common.data.GlobalCapability.MODIFY_ACCOUNT; 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.PRIORITY;
@ -115,7 +114,6 @@ class GetCapabilities implements RestReadView<AccountResource> {
have.put(CREATE_PROJECT, cc.canCreateProject()); have.put(CREATE_PROJECT, cc.canCreateProject());
have.put(EMAIL_REVIEWERS, cc.canEmailReviewers()); have.put(EMAIL_REVIEWERS, cc.canEmailReviewers());
have.put(FLUSH_CACHES, cc.canFlushCaches()); have.put(FLUSH_CACHES, cc.canFlushCaches());
have.put(GENERATE_HTTP_PASSWORD, cc.canGenerateHttpPassword());
have.put(KILL_TASK, cc.canKillTask()); have.put(KILL_TASK, cc.canKillTask());
have.put(MODIFY_ACCOUNT, cc.canModifyAccount()); have.put(MODIFY_ACCOUNT, cc.canModifyAccount());
have.put(RUN_GC, cc.canRunGC()); have.put(RUN_GC, cc.canRunGC());

View File

@ -36,7 +36,7 @@ public class GetHttpPassword implements RestReadView<AccountResource> {
public String apply(AccountResource rsrc) throws AuthException, public String apply(AccountResource rsrc) throws AuthException,
ResourceNotFoundException { ResourceNotFoundException {
if (self.get() != rsrc.getUser() if (self.get() != rsrc.getUser()
&& !self.get().getCapabilities().canGenerateHttpPassword()) { && !self.get().getCapabilities().canAdministrateServer()) {
throw new AuthException("not allowed to get http password"); throw new AuthException("not allowed to get http password");
} }
AccountState s = rsrc.getUser().state(); AccountState s = rsrc.getUser().state();

View File

@ -79,19 +79,19 @@ public class PutHttpPassword implements RestModifyView<AccountResource, Input> {
String newPassword; String newPassword;
if (input.generate) { if (input.generate) {
if (self.get() != rsrc.getUser() if (self.get() != rsrc.getUser()
&& !self.get().getCapabilities().canGenerateHttpPassword()) { && !self.get().getCapabilities().canAdministrateServer()) {
throw new AuthException("not allowed to generate HTTP password"); throw new AuthException("not allowed to generate HTTP password");
} }
newPassword = generate(); newPassword = generate();
} else if (input.httpPassword == null) { } else if (input.httpPassword == null) {
if (self.get() != rsrc.getUser() if (self.get() != rsrc.getUser()
&& !self.get().getCapabilities().canGenerateHttpPassword()) { && !self.get().getCapabilities().canAdministrateServer()) {
throw new AuthException("not allowed to clear HTTP password"); throw new AuthException("not allowed to clear HTTP password");
} }
newPassword = null; newPassword = null;
} else { } else {
if (!self.get().getCapabilities().canGenerateHttpPassword()) { if (!self.get().getCapabilities().canAdministrateServer()) {
throw new AuthException("not allowed to set HTTP password directly, " throw new AuthException("not allowed to set HTTP password directly, "
+ "requires the Generate HTTP Password permission"); + "requires the Generate HTTP Password permission");
} }

View File

@ -29,7 +29,6 @@ public class CapabilityConstants extends TranslationBundle {
public String createProject; public String createProject;
public String emailReviewers; public String emailReviewers;
public String flushCaches; public String flushCaches;
public String generateHttpPassword;
public String killTask; public String killTask;
public String modifyAccount; public String modifyAccount;
public String priority; public String priority;

View File

@ -5,7 +5,6 @@ createGroup = Create Group
createProject = Create Project createProject = Create Project
emailReviewers = Email Reviewers emailReviewers = Email Reviewers
flushCaches = Flush Caches flushCaches = Flush Caches
generateHttpPassword = Generate HTTP Password
killTask = Kill Task killTask = Kill Task
modifyAccount = Modify Account modifyAccount = Modify Account
priority = Priority priority = Priority

View File

@ -18,6 +18,7 @@ import com.google.common.base.Strings;
import com.google.gerrit.common.data.GlobalCapability; import com.google.gerrit.common.data.GlobalCapability;
import com.google.gerrit.common.errors.EmailException; import com.google.gerrit.common.errors.EmailException;
import com.google.gerrit.extensions.annotations.RequiresCapability; import com.google.gerrit.extensions.annotations.RequiresCapability;
import com.google.gerrit.extensions.restapi.AuthException;
import com.google.gerrit.extensions.restapi.RawInput; import com.google.gerrit.extensions.restapi.RawInput;
import com.google.gerrit.extensions.restapi.ResourceNotFoundException; import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
import com.google.gerrit.extensions.restapi.RestApiException; import com.google.gerrit.extensions.restapi.RestApiException;
@ -260,7 +261,7 @@ final class SetAccountCommand extends SshCommand {
} }
} }
private void deleteSshKey(SshKeyInfo i) throws OrmException { private void deleteSshKey(SshKeyInfo i) throws AuthException, OrmException {
AccountSshKey sshKey = new AccountSshKey( AccountSshKey sshKey = new AccountSshKey(
new AccountSshKey.Id(user.getAccountId(), i.seq), i.sshPublicKey); new AccountSshKey.Id(user.getAccountId(), i.seq), i.sshPublicKey);
deleteSshKey.apply( deleteSshKey.apply(