diff --git a/syncflow-connectors/src/main/java/com/syncflow/connector/metadata/AbstractJdbcMetadataConnector.java b/syncflow-connectors/src/main/java/com/syncflow/connector/metadata/AbstractJdbcMetadataConnector.java index 6fa5d10..2341620 100644 --- a/syncflow-connectors/src/main/java/com/syncflow/connector/metadata/AbstractJdbcMetadataConnector.java +++ b/syncflow-connectors/src/main/java/com/syncflow/connector/metadata/AbstractJdbcMetadataConnector.java @@ -104,7 +104,7 @@ public List discoverSchemas(ConnectorContext ctx) { @Override public List fetchTables(ConnectorContext ctx, String schema) { - requireIdentifier(schema, "schema"); + schema = requireIdentifier(schema, "schema"); ensureConnected(ctx); var list = new ArrayList(); try { @@ -126,8 +126,8 @@ schema, getStringOrNull(rs, "REMARKS"), @Override public List fetchColumns(ConnectorContext ctx, String schema, String table) { - requireIdentifier(schema, "schema"); - requireIdentifier(table, "table"); + schema = requireIdentifier(schema, "schema"); + table = requireIdentifier(table, "table"); ensureConnected(ctx); var cols = new ArrayList(); try { @@ -158,8 +158,8 @@ public List fetchColumns(ConnectorContext ctx, String schema, St @Override public List fetchIndexes(ConnectorContext ctx, String schema, String table) { - requireIdentifier(schema, "schema"); - requireIdentifier(table, "table"); + schema = requireIdentifier(schema, "schema"); + table = requireIdentifier(table, "table"); ensureConnected(ctx); var map = new LinkedHashMap(); try { @@ -184,8 +184,8 @@ public List fetchIndexes(ConnectorContext ctx, String schema, Str @Override public PrimaryKeyMetadata fetchPrimaryKey(ConnectorContext ctx, String schema, String table) { - requireIdentifier(schema, "schema"); - requireIdentifier(table, "table"); + schema = requireIdentifier(schema, "schema"); + table = requireIdentifier(table, "table"); ensureConnected(ctx); var cols = new ArrayList(); String name = null; @@ -205,8 +205,8 @@ public PrimaryKeyMetadata fetchPrimaryKey(ConnectorContext ctx, String schema, S @Override public List fetchForeignKeys(ConnectorContext ctx, String schema, String table) { - requireIdentifier(schema, "schema"); - requireIdentifier(table, "table"); + schema = requireIdentifier(schema, "schema"); + table = requireIdentifier(table, "table"); ensureConnected(ctx); var map = new LinkedHashMap(); try { @@ -272,16 +272,20 @@ protected Set loadFkColumnNames(ConnectorContext ctx, String schema, Str } /** - * Reject caller-supplied schema/table values that aren't plain SQL - * identifiers. These reach JDBC metadata calls and connector queries, so a - * value like `users; DROP TABLE x` must never be passed through. + * Validate a caller-supplied schema/table value as a plain SQL identifier + * and return it. These reach JDBC metadata calls and connector queries, so + * a value like `users; DROP TABLE x` must never be passed through. + * + * Returning the value keeps the taint flow explicit: the value handed to + * the JDBC call is the validator's output, not the raw user input. */ - protected void requireIdentifier(String value, String label) { + protected String requireIdentifier(String value, String label) { if (value == null || value.isBlank() || !value.matches("[A-Za-z_][A-Za-z0-9_$]*")) { throw new IllegalArgumentException( "Invalid " + label + " identifier: '" + value + "'"); } + return value; } protected String getStringOrNull(ResultSet rs, String col) throws SQLException {