Split off raw SQL access into its own permission

Allowing raw SQL access (via the gsql tool) is potentially
a very risky operation--especially on public servers.

Administrators no longer implicity have this right, and
have to be granted it manually.

Change-Id: I67f3896af24653a92a36538a31a9ce3b1d2f48a1
This commit is contained in:
Chad Horohoe
2013-02-14 16:27:34 -05:00
parent 1c830c11e7
commit abd6d4e1d4
7 changed files with 52 additions and 2 deletions

View File

@@ -25,7 +25,7 @@ import org.kohsuke.args4j.Option;
/** Opens a query processor. */
@AdminHighPriorityCommand
@RequiresCapability(GlobalCapability.ADMINISTRATE_SERVER)
@RequiresCapability(GlobalCapability.ACCESS_DATABASE)
@CommandMetaData(name = "gsql", descr = "Administrative interface to active database")
final class AdminQueryShell extends SshCommand {
@Inject

View File

@@ -15,7 +15,9 @@
package com.google.gerrit.sshd.commands;
import com.google.gerrit.common.Version;
import com.google.gerrit.common.errors.PermissionDeniedException;
import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.IdentifiedUser;
import com.google.gson.JsonObject;
import com.google.gwtorm.jdbc.JdbcSchema;
import com.google.gwtorm.server.OrmException;
@@ -55,6 +57,7 @@ public class QueryShell {
private final BufferedReader in;
private final PrintWriter out;
private final SchemaFactory<ReviewDb> dbFactory;
private final IdentifiedUser currentUser;
private OutputFormat outputFormat = OutputFormat.PRETTY;
private ReviewDb db;
@@ -63,12 +66,14 @@ public class QueryShell {
@Inject
QueryShell(final SchemaFactory<ReviewDb> dbFactory,
final IdentifiedUser currentUser,
@Assisted final InputStream in, @Assisted final OutputStream out)
throws UnsupportedEncodingException {
this.dbFactory = dbFactory;
this.in = new BufferedReader(new InputStreamReader(in, "UTF-8"));
this.out = new PrintWriter(new OutputStreamWriter(out, "UTF-8"));
this.currentUser = currentUser;
}
public void setOutputFormat(OutputFormat fmt) {
@@ -77,6 +82,7 @@ public class QueryShell {
public void run() {
try {
checkPermission();
db = dbFactory.open();
try {
connection = ((JdbcSchema) db).getConnection();
@@ -99,6 +105,8 @@ public class QueryShell {
} catch (SQLException err) {
out.println("fatal: Cannot open connection: " + err.getMessage());
} catch (PermissionDeniedException err) {
out.println("fatal: " + err.getMessage());
} finally {
out.flush();
}
@@ -106,6 +114,7 @@ public class QueryShell {
public void execute(String query) {
try {
checkPermission();
db = dbFactory.open();
try {
connection = ((JdbcSchema) db).getConnection();
@@ -127,11 +136,31 @@ public class QueryShell {
} catch (SQLException err) {
out.println("fatal: Cannot open connection: " + err.getMessage());
} catch (PermissionDeniedException err) {
out.println("fatal: " + err.getMessage());
} finally {
out.flush();
}
}
/**
* Assert that the current user is permitted to perform raw queries.
* <p>
* As the @RequireCapability guards at various entry points of internal
* commands implicitly add administrators (which we want to avoid), we also
* check permissions within QueryShell and grant access only to those who
* canPerformRawQuery, regardless of whether they are administrators or not.
*
* @throws PermissionDeniedException
*/
private void checkPermission() throws PermissionDeniedException {
if (!currentUser.getCapabilities().canAccessDatabase()) {
throw new PermissionDeniedException(String.format(
"%s does not have \"Perform Raw Query\" capability.",
currentUser.getUserName()));
}
}
private void readEvalPrintLoop() {
final StringBuilder buffer = new StringBuilder();
boolean executed = false;