Convert runAs to PermissionBackend

Change-Id: Ia08189d864388b45c7f11b41cc835fda57d7e03d
This commit is contained in:
Shawn Pearce
2017-02-19 20:45:19 -08:00
committed by David Pursehouse
parent f4e84de1ae
commit f49c2a87ab
3 changed files with 35 additions and 11 deletions

View File

@@ -19,11 +19,15 @@ import static javax.servlet.http.HttpServletResponse.SC_FORBIDDEN;
import static javax.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR; import static javax.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
import com.google.gerrit.extensions.registration.DynamicItem; import com.google.gerrit.extensions.registration.DynamicItem;
import com.google.gerrit.extensions.restapi.AuthException;
import com.google.gerrit.reviewdb.client.Account; import com.google.gerrit.reviewdb.client.Account;
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.CurrentUser;
import com.google.gerrit.server.account.AccountResolver; import com.google.gerrit.server.account.AccountResolver;
import com.google.gerrit.server.config.AuthConfig; import com.google.gerrit.server.config.AuthConfig;
import com.google.gerrit.server.permissions.GlobalPermission;
import com.google.gerrit.server.permissions.PermissionBackend;
import com.google.gerrit.server.permissions.PermissionBackendException;
import com.google.gwtorm.server.OrmException; import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject; import com.google.inject.Inject;
import com.google.inject.Provider; import com.google.inject.Provider;
@@ -57,6 +61,7 @@ class RunAsFilter implements Filter {
private final Provider<ReviewDb> db; private final Provider<ReviewDb> db;
private final boolean enabled; private final boolean enabled;
private final DynamicItem<WebSession> session; private final DynamicItem<WebSession> session;
private final PermissionBackend permissionBackend;
private final AccountResolver accountResolver; private final AccountResolver accountResolver;
@Inject @Inject
@@ -64,10 +69,12 @@ class RunAsFilter implements Filter {
Provider<ReviewDb> db, Provider<ReviewDb> db,
AuthConfig config, AuthConfig config,
DynamicItem<WebSession> session, DynamicItem<WebSession> session,
PermissionBackend permissionBackend,
AccountResolver accountResolver) { AccountResolver accountResolver) {
this.db = db; this.db = db;
this.enabled = config.isRunAsEnabled(); this.enabled = config.isRunAsEnabled();
this.session = session; this.session = session;
this.permissionBackend = permissionBackend;
this.accountResolver = accountResolver; this.accountResolver = accountResolver;
} }
@@ -85,12 +92,20 @@ class RunAsFilter implements Filter {
} }
CurrentUser self = session.get().getUser(); CurrentUser self = session.get().getUser();
if (!self.getCapabilities().canRunAs() try {
if (!self.isIdentifiedUser()) {
// Always disallow for anonymous users, even if permitted by the ACL, // Always disallow for anonymous users, even if permitted by the ACL,
// because that would be crazy. // because that would be crazy.
|| !self.isIdentifiedUser()) { throw new AuthException("denied");
}
permissionBackend.user(self).check(GlobalPermission.RUN_AS);
} catch (AuthException e) {
replyError(req, res, SC_FORBIDDEN, "not permitted to use " + RUN_AS, null); replyError(req, res, SC_FORBIDDEN, "not permitted to use " + RUN_AS, null);
return; return;
} catch (PermissionBackendException e) {
log.warn("cannot check runAs", e);
replyError(req, res, SC_INTERNAL_SERVER_ERROR, RUN_AS + " unavailable", null);
return;
} }
Account target; Account target;

View File

@@ -112,11 +112,6 @@ public class CapabilityControl {
return canPerform(GlobalCapability.ACCESS_DATABASE); return canPerform(GlobalCapability.ACCESS_DATABASE);
} }
/** @return true if the user can impersonate another user. */
public boolean canRunAs() {
return canPerform(GlobalCapability.RUN_AS);
}
/** @return which priority queue the user's tasks should be submitted to. */ /** @return which priority queue the user's tasks should be submitted to. */
public QueueProvider.QueueType getQueueType() { public QueueProvider.QueueType getQueueType() {
// If a non-generic group (that is not Anonymous Users or Registered Users) // If a non-generic group (that is not Anonymous Users or Registered Users)
@@ -245,8 +240,6 @@ public class CapabilityControl {
return canMaintainServer(); return canMaintainServer();
case MODIFY_ACCOUNT: case MODIFY_ACCOUNT:
return canModifyAccount(); return canModifyAccount();
case RUN_AS:
return canRunAs();
case VIEW_ALL_ACCOUNTS: case VIEW_ALL_ACCOUNTS:
return canViewAllAccounts(); return canViewAllAccounts();
case VIEW_QUEUE: case VIEW_QUEUE:
@@ -265,6 +258,9 @@ public class CapabilityControl {
case VIEW_CONNECTIONS: case VIEW_CONNECTIONS:
case VIEW_PLUGINS: case VIEW_PLUGINS:
return canPerform(perm.permissionName()) || canAdministrateServer(); return canPerform(perm.permissionName()) || canAdministrateServer();
case RUN_AS:
return canPerform(perm.permissionName());
} }
throw new PermissionBackendException(perm + " unsupported"); throw new PermissionBackendException(perm + " unsupported");
} }

View File

@@ -18,11 +18,15 @@ import static java.nio.charset.StandardCharsets.UTF_8;
import com.google.common.base.Throwables; import com.google.common.base.Throwables;
import com.google.common.util.concurrent.Atomics; import com.google.common.util.concurrent.Atomics;
import com.google.gerrit.extensions.restapi.AuthException;
import com.google.gerrit.reviewdb.client.Account; import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.server.CurrentUser; import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.IdentifiedUser; import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.PeerDaemonUser; import com.google.gerrit.server.PeerDaemonUser;
import com.google.gerrit.server.config.AuthConfig; import com.google.gerrit.server.config.AuthConfig;
import com.google.gerrit.server.permissions.GlobalPermission;
import com.google.gerrit.server.permissions.PermissionBackend;
import com.google.gerrit.server.permissions.PermissionBackendException;
import com.google.gerrit.sshd.SshScope.Context; import com.google.gerrit.sshd.SshScope.Context;
import com.google.inject.Inject; import com.google.inject.Inject;
import java.io.IOException; import java.io.IOException;
@@ -45,6 +49,7 @@ import org.kohsuke.args4j.Option;
public final class SuExec extends BaseCommand { public final class SuExec extends BaseCommand {
private final SshScope sshScope; private final SshScope sshScope;
private final DispatchCommandProvider dispatcher; private final DispatchCommandProvider dispatcher;
private final PermissionBackend permissionBackend;
private boolean enableRunAs; private boolean enableRunAs;
private CurrentUser caller; private CurrentUser caller;
@@ -67,6 +72,7 @@ public final class SuExec extends BaseCommand {
SuExec( SuExec(
final SshScope sshScope, final SshScope sshScope,
@CommandName(Commands.ROOT) final DispatchCommandProvider dispatcher, @CommandName(Commands.ROOT) final DispatchCommandProvider dispatcher,
PermissionBackend permissionBackend,
final CurrentUser caller, final CurrentUser caller,
final SshSession session, final SshSession session,
final IdentifiedUser.GenericFactory userFactory, final IdentifiedUser.GenericFactory userFactory,
@@ -74,6 +80,7 @@ public final class SuExec extends BaseCommand {
AuthConfig config) { AuthConfig config) {
this.sshScope = sshScope; this.sshScope = sshScope;
this.dispatcher = dispatcher; this.dispatcher = dispatcher;
this.permissionBackend = permissionBackend;
this.caller = caller; this.caller = caller;
this.session = session; this.session = session;
this.userFactory = userFactory; this.userFactory = userFactory;
@@ -115,8 +122,14 @@ public final class SuExec extends BaseCommand {
// OK. // OK.
} else if (!enableRunAs) { } else if (!enableRunAs) {
throw die("suexec disabled by auth.enableRunAs = false"); throw die("suexec disabled by auth.enableRunAs = false");
} else if (!caller.getCapabilities().canRunAs()) { } else {
try {
permissionBackend.user(caller).check(GlobalPermission.RUN_AS);
} catch (AuthException e) {
throw die("suexec not permitted"); throw die("suexec not permitted");
} catch (PermissionBackendException e) {
throw die("suexec not available: " + e);
}
} }
} }