Grant all owned databases when phpMyAdmin SSO has no specific target
The top-nav PHPMYADMIN button intentionally omits adminer_db to request access to every database. determineGrantTargets() and the ticket's new restrict_db field now distinguish that case from a specific per-row database request instead of collapsing both into single-database scope.
This commit is contained in:
@@ -62,6 +62,7 @@ assert_true($mysqlServiceClass->hasConstant('TMP_ROLE_HOST'), 'MySQLService must
|
||||
assert_same('127.0.0.1', $mysqlServiceClass->getConstant('TMP_ROLE_HOST'), 'TMP_ROLE_HOST must scope the temporary SSO role to the phpMyAdmin app host');
|
||||
|
||||
// --- phpMyAdmin SSO must only grant access to the database being logged into, not every database the account owns ---
|
||||
// --- unless no specific database was requested at all (the top-nav PHPMYADMIN button), which must grant everything ---
|
||||
|
||||
$ssoClassForGrants = new ReflectionClass(PhpMyAdminSso::class);
|
||||
assert_true($ssoClassForGrants->hasMethod('determineGrantTargets'), 'PhpMyAdminSso must expose a determineGrantTargets() decision method');
|
||||
@@ -71,12 +72,22 @@ $determineGrantTargets->setAccessible(true);
|
||||
assert_same(
|
||||
['demo_target'],
|
||||
$determineGrantTargets->invoke(null, 'demo_target', ['demo_target', 'demo_other']),
|
||||
'issuing a ticket for one database must only grant that database, not every database the user owns'
|
||||
'requesting one database must only grant that database, not every database the user owns'
|
||||
);
|
||||
assert_same(
|
||||
[],
|
||||
$determineGrantTargets->invoke(null, 'not_owned', ['demo_target', 'demo_other']),
|
||||
'a target database that is not in the owned list must never be granted'
|
||||
'a requested database that is not in the owned list must never be granted'
|
||||
);
|
||||
assert_same(
|
||||
['demo_target', 'demo_other'],
|
||||
$determineGrantTargets->invoke(null, null, ['demo_target', 'demo_other']),
|
||||
'no database requested at all (top-nav PHPMYADMIN button) must grant every owned database'
|
||||
);
|
||||
assert_same(
|
||||
['demo_target', 'demo_other'],
|
||||
$determineGrantTargets->invoke(null, '', ['demo_target', 'demo_other']),
|
||||
'an empty-string requested database must also grant every owned database'
|
||||
);
|
||||
|
||||
// --- phpMyAdmin login ticket files must not be world-readable ---
|
||||
@@ -102,7 +113,7 @@ $auth = [
|
||||
'port' => 33033,
|
||||
'db' => 'demo_db',
|
||||
];
|
||||
$token = $writeTicket->invoke($sso, $auth, 'demo_db');
|
||||
$token = $writeTicket->invoke($sso, $auth, 'demo_db', 'demo_db');
|
||||
|
||||
assert_true(preg_match('/\A[a-f0-9]{64}\z/', $token) === 1, 'ticket token must be a 64 char lowercase hex string');
|
||||
|
||||
@@ -114,9 +125,15 @@ assert_same(0640, $mode, 'ticket files contain a plaintext MySQL password and mu
|
||||
|
||||
$decoded = json_decode((string)file_get_contents($ticketPath), true);
|
||||
assert_true(is_array($decoded), 'ticket file must contain valid JSON');
|
||||
assert_same('demo_db', $decoded['db'] ?? null, 'ticket must record the target database');
|
||||
assert_same('demo_db', $decoded['db'] ?? null, 'ticket must record the target/landing database');
|
||||
assert_same('demo_db', $decoded['restrict_db'] ?? null, 'a single-database login must record that database as the grant restriction');
|
||||
assert_same('da_tmp_phpmyadmin_demo_test', $decoded['auth']['user'] ?? null, 'ticket must record the temporary role name');
|
||||
|
||||
$allDbToken = $writeTicket->invoke($sso, $auth, 'demo_db', '');
|
||||
$allDbTicketPath = $ssoDir . '/tickets/' . $allDbToken . '.json';
|
||||
$allDbDecoded = json_decode((string)file_get_contents($allDbTicketPath), true);
|
||||
assert_same('', $allDbDecoded['restrict_db'] ?? null, 'an all-databases login must record an empty restrict_db (no restriction)');
|
||||
|
||||
// cleanup
|
||||
array_map('unlink', glob($ssoDir . '/tickets/*') ?: []);
|
||||
@rmdir($ssoDir . '/tickets');
|
||||
|
||||
Reference in New Issue
Block a user