mirror of
https://github.com/t8y2/dbx.git
synced 2026-10-19 16:16:45 +00:00
fix(dameng): list all schemas in object browse for normal users
Closes #7699
This commit is contained in:
@@ -461,7 +461,21 @@ public final class DamengAgent extends AbstractJdbcAgent {
|
||||
if (legacyJdbcMetadata) {
|
||||
return unchecked(() -> listJdbcSchemas().stream().map(DatabaseInfo::new).toList());
|
||||
}
|
||||
return unchecked(() -> listVisibleUsers().stream().map(DatabaseInfo::new).toList());
|
||||
// DM8 ALL_USERS is privilege-filtered: a normal user only sees itself, so prefer the
|
||||
// full SYS.SYSOBJECTS catalog (mirroring listSchemas; newer/hardened builds require
|
||||
// the SOI role) and fall back to ALL_USERS when the catalog is not readable.
|
||||
return unchecked(() -> {
|
||||
try {
|
||||
return listVisibleSchemas().stream().map(DatabaseInfo::new).toList();
|
||||
} catch (SQLException catalogError) {
|
||||
try {
|
||||
return listVisibleUsers().stream().map(DatabaseInfo::new).toList();
|
||||
} catch (Exception fallbackError) {
|
||||
catalogError.addSuppressed(fallbackError);
|
||||
throw catalogError;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -52,6 +52,48 @@ class DamengAgentMetadataTest {
|
||||
Assertions.assertTrue(metadataCalls.contains("getTables:DBX\\_TEST"), metadataCalls.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
void listDatabasesPrefersFullSchemaCatalogOverPrivilegeFilteredAllUsers() {
|
||||
DamengAgent agent = new DamengAgent();
|
||||
List<String> sqls = new ArrayList<>();
|
||||
TestSupport.setPrivateConnection(agent, databaseListConnection(sqls, null, null));
|
||||
|
||||
List<DatabaseInfo> databases = agent.listDatabases();
|
||||
|
||||
Assertions.assertEquals(List.of("APP", "E2E_NORMAL", "SYSDBA"), databases.stream().map(DatabaseInfo::getName).toList());
|
||||
Assertions.assertEquals(1, sqls.size(), String.join("\n", sqls));
|
||||
Assertions.assertTrue(sqls.get(0).contains("SYS.SYSOBJECTS"), sqls.get(0));
|
||||
Assertions.assertTrue(sqls.stream().noneMatch(sql -> sql.contains("ALL_USERS")), String.join("\n", sqls));
|
||||
}
|
||||
|
||||
@Test
|
||||
void listDatabasesFallsBackToAllUsersWithoutSysObjectsPrivilege() {
|
||||
DamengAgent agent = new DamengAgent();
|
||||
List<String> sqls = new ArrayList<>();
|
||||
TestSupport.setPrivateConnection(agent, databaseListConnection(sqls, "no SYS.SYSOBJECTS privilege", null));
|
||||
|
||||
List<DatabaseInfo> databases = agent.listDatabases();
|
||||
|
||||
// 无 SOI 角色的普通用户:ALL_USERS 受自主访问控制过滤,只能看到自己,按权限返回属正确行为。
|
||||
Assertions.assertEquals(List.of("E2E_NORMAL"), databases.stream().map(DatabaseInfo::getName).toList());
|
||||
Assertions.assertEquals(2, sqls.size(), String.join("\n", sqls));
|
||||
Assertions.assertTrue(sqls.get(0).contains("SYS.SYSOBJECTS"), sqls.get(0));
|
||||
Assertions.assertTrue(sqls.get(1).contains("ALL_USERS"), sqls.get(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
void listDatabasesPreservesCatalogErrorWhenAllUsersFails() {
|
||||
DamengAgent agent = new DamengAgent();
|
||||
SQLException usersError = new SQLException("ALL_USERS query failed");
|
||||
TestSupport.setPrivateConnection(agent, databaseListConnection(new ArrayList<>(), "no SYS.SYSOBJECTS privilege", usersError));
|
||||
|
||||
RuntimeException error = Assertions.assertThrows(RuntimeException.class, agent::listDatabases);
|
||||
|
||||
Assertions.assertEquals("no SYS.SYSOBJECTS privilege", error.getCause().getMessage());
|
||||
Assertions.assertEquals(1, error.getCause().getSuppressed().length);
|
||||
Assertions.assertSame(usersError, error.getCause().getSuppressed()[0]);
|
||||
}
|
||||
|
||||
@Test
|
||||
void usesColumnCommentsMetadataQuery() {
|
||||
DamengAgent agent = new DamengAgent();
|
||||
@@ -1890,6 +1932,43 @@ class DamengAgentMetadataTest {
|
||||
});
|
||||
}
|
||||
|
||||
private static Connection databaseListConnection(
|
||||
List<String> sqls,
|
||||
String catalogError,
|
||||
SQLException usersError
|
||||
) {
|
||||
return proxy(Connection.class, (method, args) -> {
|
||||
String name = method.getName();
|
||||
if ("prepareStatement".equals(name)) {
|
||||
String sql = (String) args[0];
|
||||
sqls.add(sql);
|
||||
if (sql.contains("SYS.SYSOBJECTS")) {
|
||||
if (catalogError != null) {
|
||||
return failingMetadataStatement(catalogError);
|
||||
}
|
||||
return metadataStatement(List.of(List.of("APP"), List.of("E2E_NORMAL"), List.of("SYSDBA")));
|
||||
}
|
||||
if (sql.contains("ALL_USERS")) {
|
||||
if (usersError != null) {
|
||||
return failingMetadataStatement(usersError);
|
||||
}
|
||||
return metadataStatement(List.of(List.of("E2E_NORMAL")));
|
||||
}
|
||||
throw new AssertionError("Unexpected SQL: " + sql);
|
||||
}
|
||||
if ("getMetaData".equals(name)) {
|
||||
throw new AssertionError("listDatabases must not fall back to JDBC metadata getSchemas");
|
||||
}
|
||||
if ("close".equals(name)) {
|
||||
return null;
|
||||
}
|
||||
if ("isClosed".equals(name)) {
|
||||
return false;
|
||||
}
|
||||
return defaultValue(method.getReturnType());
|
||||
});
|
||||
}
|
||||
|
||||
private static Connection schemaConnection(List<String> params) {
|
||||
return proxy(Connection.class, (method, args) -> {
|
||||
String name = method.getName();
|
||||
|
||||
Reference in New Issue
Block a user