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:
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user