Every credential provider says whether it still holds a consumer
holds() for postgres, mssql, mongodb, minio, lavinmq, mosquitto, mailu and gitea, so the harness makes again a login the backend lost (hq issue 120). Each checks the mesh's password as the consumer presents it, or compares it read-only, and returns false only when the backend says the credential is absent or wrong; an unreachable backend throws.
This commit is contained in:
@@ -99,6 +99,30 @@ export class PostgresClient {
|
||||
await this.query(`GRANT ALL PRIVILEGES ON DATABASE ${ident(database)} TO ${ident(role)}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether `role` can log in to `database` with exactly `password`: the consumer's own view of its
|
||||
* credential, checked by connecting as it. Read-only. `false` only when the server says so (the
|
||||
* role, the password or the database is wrong or gone); an unreachable server rejects instead,
|
||||
* because being unable to ask is not evidence of loss (novox/hq issue 120).
|
||||
*/
|
||||
async canConnectAs(database: string, role: string, password: string): Promise<boolean> {
|
||||
try {
|
||||
await run(
|
||||
"psql",
|
||||
["-h", this.conn.host, "-p", String(this.conn.port), "-U", role, "-d", database,
|
||||
"-v", "ON_ERROR_STOP=1", "--no-psqlrc", "-tAc", "SELECT 1"],
|
||||
{ env: { ...process.env, PGPASSWORD: password, PGCONNECT_TIMEOUT: "10" }, timeout: 20_000 },
|
||||
);
|
||||
return true;
|
||||
} catch (err) {
|
||||
const text = `${(err as { stderr?: string }).stderr ?? ""}`;
|
||||
if (/password authentication failed|role ".*" does not exist|database ".*" does not exist|not permitted to log in|permission denied for database/i.test(text)) {
|
||||
return false;
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
/** Drop a database and its owning role, idempotently, after evicting live connections. */
|
||||
async dropDatabaseAndRole(database: string, role: string): Promise<void> {
|
||||
await this.query(
|
||||
|
||||
Reference in New Issue
Block a user