Permalink
Browse files

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
  • Loading branch information...
1 parent 2d872eb commit ff7eef03990faa02d7ad1ff845f6e9525275fd95 @bklarson bklarson committed May 15, 2012
Showing with 66 additions and 19 deletions.
  1. +3 −2 ...rit-extension-api/src/main/java/com/google/gerrit/extensions/annotations}/RequiresCapability.java
  2. +38 −1 gerrit-httpd/src/main/java/com/google/gerrit/httpd/RestApiServlet.java
  3. +2 −1 gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/account/AccountCapabilitiesServlet.java
  4. +4 −1 gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/change/ListChangesServlet.java
  5. +4 −1 gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/ListProjectsServlet.java
  6. +1 −0 gerrit-sshd/src/main/java/com/google/gerrit/sshd/AliasCommand.java
  7. +1 −0 gerrit-sshd/src/main/java/com/google/gerrit/sshd/DispatchCommand.java
  8. +1 −1 gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/AdminQueryShell.java
  9. +1 −1 gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/AdminSetParent.java
  10. +1 −1 gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/CreateAccountCommand.java
  11. +1 −1 gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/CreateGroupCommand.java
  12. +1 −1 gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/CreateProjectCommand.java
  13. +1 −1 gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/FlushCaches.java
  14. +1 −1 gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/KillCommand.java
  15. +1 −1 gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/PluginInstallCommand.java
  16. +1 −1 gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/PluginLsCommand.java
  17. +1 −1 gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/PluginReloadCommand.java
  18. +1 −1 gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/PluginRemoveCommand.java
  19. +1 −1 gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ShowCaches.java
  20. +1 −1 gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ShowConnections.java
@@ -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.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)
@@ -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,19 +66,45 @@
}
}
+ 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) {
handleError(err, req, res);
}
}
+ 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 @@ protected static void send(HttpServletRequest req, HttpServletResponse res,
return true;
}
}
+
+ @SuppressWarnings("serial") // Never serialized or thrown out of this class.
+ private static class RequireCapabilityException extends Exception {
+ public RequireCapabilityException(String msg) {
+ super(msg);
+ }
+ }
}
@@ -58,8 +58,9 @@
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;
}
@@ -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 @@
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;
}
@@ -16,6 +16,7 @@
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 @@
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;
}
@@ -16,6 +16,7 @@
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;
@@ -16,6 +16,7 @@
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;
@@ -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;
@@ -15,14 +15,14 @@
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;
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;
@@ -16,6 +16,7 @@
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.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;
@@ -17,10 +17,10 @@
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;
@@ -16,14 +16,14 @@
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;
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;
@@ -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;
@@ -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;
@@ -16,9 +16,9 @@
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;
@@ -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;
@@ -17,8 +17,8 @@
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;
@@ -16,8 +16,8 @@
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;
@@ -16,11 +16,11 @@
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;
@@ -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;

0 comments on commit ff7eef0

Please sign in to comment.