Skip to content

Commit

Permalink
feat: WIP Filter DatabaseMetaData using privileges for the user (#1630)
Browse files Browse the repository at this point in the history
* feat:Filter DatabaseMetaData using privileges for the user
This replaces PR#647 as it required considerable work to merge.
Original work done by Scott Langley @slangley
adds a connection parameter: hideUnprivilegedObjects defaults to false
  • Loading branch information
davecramer committed Dec 5, 2019
1 parent 8106d3d commit ec76bac
Show file tree
Hide file tree
Showing 6 changed files with 624 additions and 1 deletion.
7 changes: 7 additions & 0 deletions pgjdbc/src/main/java/org/postgresql/PGProperty.java
Expand Up @@ -425,6 +425,13 @@ public enum PGProperty {
REWRITE_BATCHED_INSERTS("reWriteBatchedInserts", "false",
"Enable optimization to rewrite and collapse compatible INSERT statements that are batched."),

/**
* Enable mode to filter out the names of database objects for which the current user has no privileges
* granted from appearing in the DatabaseMetaData returned by the driver.
*/
HIDE_UNPRIVILEGED_OBJECTS("hideUnprivilegedObjects", "false",
"Enable hiding of database objects for which the current user has no privileges granted from the DatabaseMetaData"),

/**
* <p>Connection parameter passed in the startup message. This parameter accepts two values; "true"
* and "database". Passing "true" tells the backend to go into walsender mode, wherein a small set
Expand Down
16 changes: 16 additions & 0 deletions pgjdbc/src/main/java/org/postgresql/ds/common/BaseDataSource.java
Expand Up @@ -1495,6 +1495,22 @@ public void setReWriteBatchedInserts(boolean reWrite) {
PGProperty.REWRITE_BATCHED_INSERTS.set(properties, reWrite);
}

/**
* @return boolean indicating property is enabled or not.
* @see PGProperty#HIDE_UNPRIVILEGED_OBJECTS
*/
public boolean getHideUnprivilegedObjects() {
return PGProperty.HIDE_UNPRIVILEGED_OBJECTS.getBoolean(properties);
}

/**
* @param hideUnprivileged boolean value to set the property in the properties collection
* @see PGProperty#HIDE_UNPRIVILEGED_OBJECTS
*/
public void setHideUnprivilegedObjects(boolean hideUnprivileged) {
PGProperty.HIDE_UNPRIVILEGED_OBJECTS.set(properties, hideUnprivileged);
}

//#if mvn.project.property.postgresql.jdbc.spec >= "JDBC4.1"
public java.util.logging.Logger getParentLogger() {
return Logger.getLogger("org.postgresql");
Expand Down
9 changes: 8 additions & 1 deletion pgjdbc/src/main/java/org/postgresql/jdbc/PgConnection.java
Expand Up @@ -134,7 +134,8 @@ private enum ReadOnlyBehavior {
private boolean autoCommit = true;
// Connection's readonly state.
private boolean readOnly = false;

// Filter out database objects for which the current user has no privileges granted from the DatabaseMetaData
private boolean hideUnprivilegedObjects ;
// Bind String to UNSPECIFIED or VARCHAR?
private final boolean bindStringAsVarchar;

Expand Down Expand Up @@ -221,6 +222,8 @@ public PgConnection(HostSpec[] hostSpecs,
setReadOnly(true);
}

this.hideUnprivilegedObjects = PGProperty.HIDE_UNPRIVILEGED_OBJECTS.getBoolean(info);

Set<Integer> binaryOids = getBinaryOids(info);

// split for receive and send for better control
Expand Down Expand Up @@ -948,6 +951,10 @@ public String getCatalog() throws SQLException {
return queryExecutor.getDatabase();
}

public boolean getHideUnprivilegedObjects() {
return hideUnprivilegedObjects;
}

/**
* <p>Overrides finalize(). If called, it closes the connection.</p>
*
Expand Down
23 changes: 23 additions & 0 deletions pgjdbc/src/main/java/org/postgresql/jdbc/PgDatabaseMetaData.java
Expand Up @@ -1045,6 +1045,9 @@ public ResultSet getProcedures(String catalog, String schemaPattern, String proc
if (procedureNamePattern != null && !procedureNamePattern.isEmpty()) {
sql += " AND p.proname LIKE " + escapeQuotes(procedureNamePattern);
}
if (connection.getHideUnprivilegedObjects()) {
sql += " AND has_function_privilege(p.oid,'EXECUTE')";
}
sql += " ORDER BY PROCEDURE_SCHEM, PROCEDURE_NAME, p.oid::text ";

return createMetaDataStatement().executeQuery(sql);
Expand Down Expand Up @@ -1303,6 +1306,10 @@ public ResultSet getTables(String catalog, String schemaPattern, String tableNam
if (schemaPattern != null && !schemaPattern.isEmpty()) {
select += " AND n.nspname LIKE " + escapeQuotes(schemaPattern);
}
if (connection.getHideUnprivilegedObjects()) {
select += " AND has_table_privilege(c.oid, "
+ " 'SELECT, INSERT, UPDATE, DELETE, RULE, REFERENCES, TRIGGER')";
}
orderby = " ORDER BY TABLE_TYPE,TABLE_SCHEM,TABLE_NAME ";

if (tableNamePattern != null && !tableNamePattern.isEmpty()) {
Expand Down Expand Up @@ -1419,6 +1426,9 @@ public ResultSet getSchemas(String catalog, String schemaPattern) throws SQLExce
if (schemaPattern != null && !schemaPattern.isEmpty()) {
sql += " AND nspname LIKE " + escapeQuotes(schemaPattern);
}
if (connection.getHideUnprivilegedObjects()) {
sql += " AND has_schema_privilege(nspname, 'USAGE, CREATE')";
}
sql += " ORDER BY TABLE_SCHEM";

return createMetaDataStatement().executeQuery(sql);
Expand Down Expand Up @@ -2266,6 +2276,10 @@ public ResultSet getTypeInfo() throws SQLException {
+ " AND "
+ " (t.typrelid = 0 OR (SELECT c.relkind = 'c' FROM pg_catalog.pg_class c WHERE c.oid = t.typrelid))";

if (connection.getHideUnprivilegedObjects() && connection.haveMinimumServerVersion(ServerVersion.v9_2)) {
sql += " AND has_type_privilege(t.oid, 'USAGE')";
}

Statement stmt = connection.createStatement();
ResultSet rs = stmt.executeQuery(sql);
// cache some results, this will keep memory usage down, and speed
Expand Down Expand Up @@ -2584,6 +2598,12 @@ public ResultSet getUDTs(String catalog, String schemaPattern, String typeNamePa
toAdd.append(" and n.nspname like ").append(escapeQuotes(schemaPattern));
}
sql += toAdd.toString();

if (connection.getHideUnprivilegedObjects()
&& connection.haveMinimumServerVersion(ServerVersion.v9_2)) {
sql += " AND has_type_privilege(t.oid, 'USAGE')";
}

sql += " order by data_type, type_schem, type_name";
return createMetaDataStatement().executeQuery(sql);
}
Expand Down Expand Up @@ -2695,6 +2715,9 @@ public ResultSet getFunctions(String catalog, String schemaPattern, String funct
if (functionNamePattern != null && !functionNamePattern.isEmpty()) {
sql += " AND p.proname LIKE " + escapeQuotes(functionNamePattern);
}
if (connection.getHideUnprivilegedObjects()) {
sql += " AND has_function_privilege(p.oid,'EXECUTE')";
}
sql += " ORDER BY FUNCTION_SCHEM, FUNCTION_NAME, p.oid::text ";

return createMetaDataStatement().executeQuery(sql);
Expand Down

0 comments on commit ec76bac

Please sign in to comment.