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:
@@ -142,6 +142,25 @@ export class MssqlClient {
|
||||
await this.exec(`ALTER ROLE db_owner ADD MEMBER ${ident(login)}`, database);
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether `login` exists, is enabled, has exactly `password`, and is a db_owner user of
|
||||
* `database`. Read-only: the password is compared with PWDCOMPARE against the stored hash, so
|
||||
* nothing logs in and no failed-login is recorded (novox/hq issue 120).
|
||||
*/
|
||||
async holdsLogin(database: string, login: string, password: string): Promise<boolean> {
|
||||
const server = await this.query(
|
||||
`SELECT CAST(CASE WHEN EXISTS (SELECT 1 FROM sys.sql_logins WHERE name = ${literal(login)} ` +
|
||||
`AND is_disabled = 0 AND PWDCOMPARE(${literal(password)}, password_hash) = 1) ` +
|
||||
`AND DB_ID(${literal(database)}) IS NOT NULL THEN 1 ELSE 0 END AS int) AS ok`,
|
||||
);
|
||||
if (Number(server[0]?.ok) !== 1) return false;
|
||||
const owner = await this.query(
|
||||
`SELECT CAST(IS_ROLEMEMBER('db_owner', ${literal(login)}) AS int) AS ok`,
|
||||
database,
|
||||
);
|
||||
return Number(owner[0]?.ok) === 1;
|
||||
}
|
||||
|
||||
/** Drop a database and its login, idempotently, after evicting live connections. */
|
||||
async dropDatabaseAndLogin(database: string, login: string): Promise<void> {
|
||||
const dbs = await this.query(
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
"type": "module",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@novox/mesh-sdk": "^0.1.0"
|
||||
"@novox/mesh-sdk": "^0.1.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^22.0.0",
|
||||
|
||||
@@ -44,4 +44,9 @@ runProvisioner("mssql-database", {
|
||||
await mssql.dropDatabaseAndLogin(p.as, p.as);
|
||||
await announce("module.mssql.database.deprovisioned", { database: p.as });
|
||||
},
|
||||
// Asked every minute by the harness: whether the backend still holds this consumer exactly as
|
||||
// the mesh gave it, so a login lost behind the provisioner's back is made again (novox/hq issue 120).
|
||||
async holds(p: Provision): Promise<boolean> {
|
||||
return mssql.holdsLogin(p.as, p.as, p.password);
|
||||
},
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user