Apply @RequiresCapability to REST API

Move the @RequiresCapability from SSHD to gerrit-extension-api. Modify
the RestApiServlet to check the current user has the required
capabilities. All RestApiServlets must now inject the currentUser
provider in their constructor and pass it to the super class.

Signed-off-by: Brad Larson <bklarson@gmail.com>
Change-Id: Iffc9bc99b8d2fafd07bf624008719b0ec647ce7d
This commit is contained in:
Brad Larson
2012-05-15 16:58:01 -05:00
parent 2d872ebff2
commit ff7eef0399
20 changed files with 66 additions and 19 deletions

View File

@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
package com.google.gerrit.sshd;
package com.google.gerrit.extensions.annotations;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
@@ -21,7 +21,8 @@ import java.lang.annotation.Retention;
import java.lang.annotation.Target;
/**
* Annotation on {@link SshCommand} declaring a capability must be granted.
* Annotation on {@link SshCommand} or {@link RestApiServlet} declaring a
* capability must be granted.
*/
@Target({ElementType.TYPE})
@Retention(RUNTIME)

View File

@@ -15,10 +15,14 @@
package com.google.gerrit.httpd;
import com.google.common.base.Strings;
import com.google.gerrit.extensions.annotations.RequiresCapability;
import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.account.CapabilityControl;
import com.google.gerrit.util.cli.CmdLineParser;
import com.google.gwtjsonrpc.server.RPCServletUtils;
import com.google.gwtjsonrpc.common.JsonConstants;
import com.google.gwtjsonrpc.server.RPCServletUtils;
import com.google.inject.Inject;
import com.google.inject.Provider;
import org.kohsuke.args4j.CmdLineException;
import org.slf4j.Logger;
@@ -62,12 +66,24 @@ public abstract class RestApiServlet extends HttpServlet {
}
}
private final Provider<CurrentUser> currentUser;
@Inject
protected RestApiServlet(final Provider<CurrentUser> currentUser) {
this.currentUser = currentUser;
}
@Override
protected void service(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
noCache(res);
try {
checkRequiresCapability();
super.service(req, res);
} catch (RequireCapabilityException err) {
res.setStatus(HttpServletResponse.SC_FORBIDDEN);
noCache(res);
sendText(req, res, err.getMessage());
} catch (Error err) {
handleError(err, req, res);
} catch (RuntimeException err) {
@@ -75,6 +91,20 @@ public abstract class RestApiServlet extends HttpServlet {
}
}
private void checkRequiresCapability() throws RequireCapabilityException {
RequiresCapability rc = getClass().getAnnotation(RequiresCapability.class);
if (rc != null) {
CurrentUser user = currentUser.get();
CapabilityControl ctl = user.getCapabilities();
if (!ctl.canPerform(rc.value()) && !ctl.canAdministrateServer()) {
String msg = String.format(
"fatal: %s does not have \"%s\" capability.",
user.getUserName(), rc.value());
throw new RequireCapabilityException(msg);
}
}
}
private static void noCache(HttpServletResponse res) {
res.setHeader("Expires", "Fri, 01 Jan 1980 00:00:00 GMT");
res.setHeader("Pragma", "no-cache");
@@ -175,4 +205,11 @@ public abstract class RestApiServlet extends HttpServlet {
return true;
}
}
@SuppressWarnings("serial") // Never serialized or thrown out of this class.
private static class RequireCapabilityException extends Exception {
public RequireCapabilityException(String msg) {
super(msg);
}
}
}

View File

@@ -58,8 +58,9 @@ public class AccountCapabilitiesServlet extends RestApiServlet {
private final Provider<Impl> factory;
@Inject
AccountCapabilitiesServlet(
AccountCapabilitiesServlet(final Provider<CurrentUser> currentUser,
ParameterParser paramParser, Provider<Impl> factory) {
super(currentUser);
this.paramParser = paramParser;
this.factory = factory;
}

View File

@@ -15,6 +15,7 @@
package com.google.gerrit.httpd.rpc.change;
import com.google.gerrit.httpd.RestApiServlet;
import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.OutputFormat;
import com.google.gerrit.server.query.QueryParseException;
import com.google.gerrit.server.query.change.ListChanges;
@@ -43,7 +44,9 @@ public class ListChangesServlet extends RestApiServlet {
private final Provider<ListChanges> factory;
@Inject
ListChangesServlet(ParameterParser paramParser, Provider<ListChanges> ls) {
ListChangesServlet(final Provider<CurrentUser> currentUser,
ParameterParser paramParser, Provider<ListChanges> ls) {
super(currentUser);
this.paramParser = paramParser;
this.factory = ls;
}

View File

@@ -16,6 +16,7 @@ package com.google.gerrit.httpd.rpc.project;
import com.google.common.base.Strings;
import com.google.gerrit.httpd.RestApiServlet;
import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.OutputFormat;
import com.google.gerrit.server.project.ListProjects;
import com.google.inject.Inject;
@@ -36,7 +37,9 @@ public class ListProjectsServlet extends RestApiServlet {
private final Provider<ListProjects> factory;
@Inject
ListProjectsServlet(ParameterParser paramParser, Provider<ListProjects> ls) {
ListProjectsServlet(final Provider<CurrentUser> currentUser,
ParameterParser paramParser, Provider<ListProjects> ls) {
super(currentUser);
this.paramParser = paramParser;
this.factory = ls;
}

View File

@@ -16,6 +16,7 @@ package com.google.gerrit.sshd;
import com.google.common.collect.Lists;
import com.google.common.util.concurrent.Atomics;
import com.google.gerrit.extensions.annotations.RequiresCapability;
import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.account.CapabilityControl;
import com.google.inject.Provider;

View File

@@ -16,6 +16,7 @@ package com.google.gerrit.sshd;
import com.google.common.collect.Sets;
import com.google.common.util.concurrent.Atomics;
import com.google.gerrit.extensions.annotations.RequiresCapability;
import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.account.CapabilityControl;
import com.google.gerrit.sshd.args4j.SubcommandHandler;

View File

@@ -15,8 +15,8 @@
package com.google.gerrit.sshd.commands;
import com.google.gerrit.common.data.GlobalCapability;
import com.google.gerrit.extensions.annotations.RequiresCapability;
import com.google.gerrit.sshd.AdminHighPriorityCommand;
import com.google.gerrit.sshd.RequiresCapability;
import com.google.gerrit.sshd.SshCommand;
import com.google.inject.Inject;

View File

@@ -15,6 +15,7 @@
package com.google.gerrit.sshd.commands;
import com.google.gerrit.common.data.GlobalCapability;
import com.google.gerrit.extensions.annotations.RequiresCapability;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.server.config.AllProjectsName;
import com.google.gerrit.server.git.MetaDataUpdate;
@@ -22,7 +23,6 @@ import com.google.gerrit.server.git.ProjectConfig;
import com.google.gerrit.server.project.ProjectCache;
import com.google.gerrit.server.project.ProjectControl;
import com.google.gerrit.server.project.ProjectState;
import com.google.gerrit.sshd.RequiresCapability;
import com.google.gerrit.sshd.SshCommand;
import com.google.inject.Inject;

View File

@@ -16,6 +16,7 @@ package com.google.gerrit.sshd.commands;
import com.google.gerrit.common.data.GlobalCapability;
import com.google.gerrit.common.errors.InvalidSshKeyException;
import com.google.gerrit.extensions.annotations.RequiresCapability;
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.AccountExternalId;
import com.google.gerrit.reviewdb.client.AccountGroup;
@@ -27,7 +28,6 @@ import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.account.AccountByEmailCache;
import com.google.gerrit.server.account.AccountCache;
import com.google.gerrit.server.ssh.SshKeyCache;
import com.google.gerrit.sshd.RequiresCapability;
import com.google.gerrit.sshd.SshCommand;
import com.google.gwtorm.server.OrmDuplicateKeyException;
import com.google.gwtorm.server.OrmException;

View File

@@ -17,10 +17,10 @@ package com.google.gerrit.sshd.commands;
import com.google.gerrit.common.data.GlobalCapability;
import com.google.gerrit.common.errors.NameAlreadyUsedException;
import com.google.gerrit.common.errors.PermissionDeniedException;
import com.google.gerrit.extensions.annotations.RequiresCapability;
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gerrit.server.account.PerformCreateGroup;
import com.google.gerrit.sshd.RequiresCapability;
import com.google.gerrit.sshd.SshCommand;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;

View File

@@ -16,6 +16,7 @@ package com.google.gerrit.sshd.commands;
import com.google.gerrit.common.data.GlobalCapability;
import com.google.gerrit.common.errors.ProjectCreationFailedException;
import com.google.gerrit.extensions.annotations.RequiresCapability;
import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.reviewdb.client.Project.SubmitType;
@@ -23,7 +24,6 @@ import com.google.gerrit.server.project.CreateProject;
import com.google.gerrit.server.project.CreateProjectArgs;
import com.google.gerrit.server.project.ProjectControl;
import com.google.gerrit.server.project.SuggestParentCandidates;
import com.google.gerrit.sshd.RequiresCapability;
import com.google.gerrit.sshd.SshCommand;
import com.google.inject.Inject;

View File

@@ -15,9 +15,9 @@
package com.google.gerrit.sshd.commands;
import com.google.gerrit.common.data.GlobalCapability;
import com.google.gerrit.extensions.annotations.RequiresCapability;
import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.sshd.BaseCommand;
import com.google.gerrit.sshd.RequiresCapability;
import com.google.inject.Inject;
import net.sf.ehcache.Ehcache;

View File

@@ -15,11 +15,11 @@
package com.google.gerrit.sshd.commands;
import com.google.gerrit.common.data.GlobalCapability;
import com.google.gerrit.extensions.annotations.RequiresCapability;
import com.google.gerrit.server.git.WorkQueue;
import com.google.gerrit.server.git.WorkQueue.Task;
import com.google.gerrit.server.util.IdGenerator;
import com.google.gerrit.sshd.AdminHighPriorityCommand;
import com.google.gerrit.sshd.RequiresCapability;
import com.google.gerrit.sshd.SshCommand;
import com.google.inject.Inject;

View File

@@ -16,9 +16,9 @@ package com.google.gerrit.sshd.commands;
import com.google.common.base.Strings;
import com.google.gerrit.common.data.GlobalCapability;
import com.google.gerrit.extensions.annotations.RequiresCapability;
import com.google.gerrit.server.plugins.PluginInstallException;
import com.google.gerrit.server.plugins.PluginLoader;
import com.google.gerrit.sshd.RequiresCapability;
import com.google.gerrit.sshd.SshCommand;
import com.google.inject.Inject;

View File

@@ -15,9 +15,9 @@
package com.google.gerrit.sshd.commands;
import com.google.gerrit.common.data.GlobalCapability;
import com.google.gerrit.extensions.annotations.RequiresCapability;
import com.google.gerrit.server.plugins.ListPlugins;
import com.google.gerrit.sshd.BaseCommand;
import com.google.gerrit.sshd.RequiresCapability;
import com.google.inject.Inject;
import org.apache.sshd.server.Environment;

View File

@@ -17,8 +17,8 @@ package com.google.gerrit.sshd.commands;
import com.google.gerrit.common.data.GlobalCapability;
import com.google.gerrit.server.plugins.InvalidPluginException;
import com.google.gerrit.server.plugins.PluginInstallException;
import com.google.gerrit.extensions.annotations.RequiresCapability;
import com.google.gerrit.server.plugins.PluginLoader;
import com.google.gerrit.sshd.RequiresCapability;
import com.google.gerrit.sshd.SshCommand;
import com.google.inject.Inject;

View File

@@ -16,8 +16,8 @@ package com.google.gerrit.sshd.commands;
import com.google.common.collect.Sets;
import com.google.gerrit.common.data.GlobalCapability;
import com.google.gerrit.extensions.annotations.RequiresCapability;
import com.google.gerrit.server.plugins.PluginLoader;
import com.google.gerrit.sshd.RequiresCapability;
import com.google.gerrit.sshd.SshCommand;
import com.google.inject.Inject;

View File

@@ -16,11 +16,11 @@ package com.google.gerrit.sshd.commands;
import com.google.gerrit.common.Version;
import com.google.gerrit.common.data.GlobalCapability;
import com.google.gerrit.extensions.annotations.RequiresCapability;
import com.google.gerrit.extensions.events.LifecycleListener;
import com.google.gerrit.server.config.SitePath;
import com.google.gerrit.server.git.WorkQueue;
import com.google.gerrit.server.git.WorkQueue.Task;
import com.google.gerrit.sshd.RequiresCapability;
import com.google.gerrit.sshd.SshDaemon;
import com.google.inject.Inject;

View File

@@ -15,10 +15,10 @@
package com.google.gerrit.sshd.commands;
import com.google.gerrit.common.data.GlobalCapability;
import com.google.gerrit.extensions.annotations.RequiresCapability;
import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.util.IdGenerator;
import com.google.gerrit.sshd.RequiresCapability;
import com.google.gerrit.sshd.SshCommand;
import com.google.gerrit.sshd.SshDaemon;
import com.google.gerrit.sshd.SshSession;