Linux ip-172-31-33-47 5.4.0-1045-aws #47~18.04.1-Ubuntu SMP Tue Apr 13 15:58:14 UTC 2021 x86_64
Apache/2.4.29 (Ubuntu)
: 172.31.33.47 | : 18.220.244.188
Cant Read [ /etc/named.conf ]
7.4.20
www-data
www.github.com/MadExploits
Terminal
AUTO ROOT
Adminer
Backdoor Destroyer
Linux Exploit
Lock Shell
Lock File
Create User
CREATE RDP
PHP Mailer
BACKCONNECT
UNLOCK SHELL
HASH IDENTIFIER
CPANEL RESET
CREATE WP USER
README
+ Create Folder
+ Create File
/
var /
www /
html /
stage /
phpmyadmin /
tests /
unit /
Server /
[ HOME SHELL ]
Name
Size
Permission
Action
Privileges
[ DIR ]
drwxr-xr-x
SysInfo
[ DIR ]
drwxr-xr-x
PluginTest.php
2.49
KB
-rw-r--r--
PluginsTest.php
3.14
KB
-rw-r--r--
PrivilegesTest.php
73.21
KB
-rw-r--r--
SelectTest.php
3.06
KB
-rw-r--r--
Delete
Unzip
Zip
${this.title}
Close
Code Editor : PrivilegesTest.php
<?php declare(strict_types=1); namespace PhpMyAdmin\Tests\Server; use PhpMyAdmin\Config; use PhpMyAdmin\ConfigStorage\Relation; use PhpMyAdmin\ConfigStorage\RelationCleanup; use PhpMyAdmin\ConfigStorage\RelationParameters; use PhpMyAdmin\DatabaseInterface; use PhpMyAdmin\Dbal\ConnectionType; use PhpMyAdmin\Dbal\ResultInterface; use PhpMyAdmin\Dbal\Statement; use PhpMyAdmin\Html\Generator; use PhpMyAdmin\Message; use PhpMyAdmin\Server\Plugins; use PhpMyAdmin\Server\Privileges; use PhpMyAdmin\Template; use PhpMyAdmin\Tests\AbstractTestCase; use PhpMyAdmin\Tests\Stubs\DbiDummy; use PhpMyAdmin\Tests\Stubs\DummyResult; use PhpMyAdmin\Url; use PhpMyAdmin\UserPrivileges; use PhpMyAdmin\Util; use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\Attributes\Group; use ReflectionMethod; use ReflectionProperty; use function __; use function _pgettext; use function htmlspecialchars; use function implode; use function preg_quote; #[CoversClass(Privileges::class)] class PrivilegesTest extends AbstractTestCase { protected DatabaseInterface $dbi; protected DbiDummy $dummyDbi; protected function setUp(): void { parent::setUp(); $this->dummyDbi = $this->createDbiDummy(); $this->dbi = $this->createDatabaseInterface($this->dummyDbi); DatabaseInterface::$instance = $this->dbi; } public function testGetDataForDBInfo(): void { $_REQUEST['username'] = 'PMA_username'; $_REQUEST['hostname'] = 'PMA_hostname'; $_REQUEST['tablename'] = 'PMA_tablename'; $_REQUEST['dbname'] = 'PMA_dbname'; $serverPrivileges = $this->getPrivileges($this->createDatabaseInterface()); [ $username, $hostname, $dbname, $tablename, $routinename, $dbnameIsWildcard, ] = $serverPrivileges->getDataForDBInfo(); self::assertSame('PMA_username', $username); self::assertSame('PMA_hostname', $hostname); self::assertSame('PMA_dbname', $dbname); self::assertSame('PMA_tablename', $tablename); self::assertTrue($dbnameIsWildcard); //pre variable have been defined $_POST['pred_tablename'] = 'PMA_pred__tablename'; $_POST['pred_dbname'] = ['PMA_pred_dbname']; [, , $dbname, $tablename, $routinename, $dbnameIsWildcard] = $serverPrivileges->getDataForDBInfo(); self::assertSame('PMA_pred_dbname', $dbname); self::assertSame('PMA_pred__tablename', $tablename); self::assertTrue($dbnameIsWildcard); // Escaped database $_POST['pred_tablename'] = 'PMA_pred__tablename'; $_POST['pred_dbname'] = ['PMA\_pred\_dbname']; [, , $dbname, $tablename, $routinename, $dbnameIsWildcard] = $serverPrivileges->getDataForDBInfo(); self::assertSame('PMA\_pred\_dbname', $dbname); self::assertSame('PMA_pred__tablename', $tablename); self::assertFalse($dbnameIsWildcard); // Multiselect database - pred unset($_POST['pred_tablename'], $_REQUEST['tablename'], $_REQUEST['dbname']); $_POST['pred_dbname'] = ['PMA\_pred\_dbname', 'PMADbname2']; [, , $dbname, $tablename, , $dbnameIsWildcard] = $serverPrivileges->getDataForDBInfo(); self::assertSame(['PMA\_pred\_dbname', 'PMADbname2'], $dbname); self::assertNull($tablename); self::assertFalse($dbnameIsWildcard); // Multiselect database unset($_POST['pred_tablename'], $_REQUEST['tablename'], $_POST['pred_dbname']); $_REQUEST['dbname'] = ['PMA\_dbname', 'PMADbname2']; [, , $dbname, $tablename, , $dbnameIsWildcard] = $serverPrivileges->getDataForDBInfo(); self::assertSame(['PMA\_dbname', 'PMADbname2'], $dbname); self::assertNull($tablename); self::assertFalse($dbnameIsWildcard); } public function testWildcardEscapeForGrant(): void { $serverPrivileges = $this->getPrivileges($this->createDatabaseInterface()); $dbname = ''; $tablename = ''; $dbAndTable = $serverPrivileges->wildcardEscapeForGrant($dbname, $tablename); self::assertSame('*.*', $dbAndTable); $dbname = 'dbname'; $tablename = ''; $dbAndTable = $serverPrivileges->wildcardEscapeForGrant($dbname, $tablename); self::assertSame('`dbname`.*', $dbAndTable); $dbname = 'dbname'; $tablename = 'tablename'; $dbAndTable = $serverPrivileges->wildcardEscapeForGrant($dbname, $tablename); self::assertSame('`dbname`.`tablename`', $dbAndTable); } public function testRangeOfUsers(): void { $serverPrivileges = $this->getPrivileges($this->createDatabaseInterface()); $ret = $serverPrivileges->rangeOfUsers('INIT'); self::assertSame('WHERE `User` LIKE \'INIT%\' OR `User` LIKE \'init%\'', $ret); $ret = $serverPrivileges->rangeOfUsers('%'); self::assertSame('WHERE `User` LIKE \'\\\\%%\' OR `User` LIKE \'\\\\%%\'', $ret); $ret = $serverPrivileges->rangeOfUsers(''); self::assertSame("WHERE `User` = ''", $ret); $ret = $serverPrivileges->rangeOfUsers(); self::assertSame('', $ret); } public function testGetTableGrantsArray(): void { $serverPrivileges = $this->getPrivileges($this->createDatabaseInterface()); $ret = $serverPrivileges->getTableGrantsArray(); self::assertSame( ['Delete', 'DELETE', __('Allows deleting data.')], $ret[0], ); self::assertSame( ['Create', 'CREATE', __('Allows creating new tables.')], $ret[1], ); } public function testGetGrantsArray(): void { $serverPrivileges = $this->getPrivileges($this->createDatabaseInterface()); $ret = $serverPrivileges->getGrantsArray(); self::assertSame( ['Select_priv', 'SELECT', __('Allows reading data.')], $ret[0], ); self::assertSame( ['Insert_priv', 'INSERT', __('Allows inserting and replacing data.')], $ret[1], ); } public function testGetSqlQueryForDisplayPrivTable(): void { $dbi = $this->createDatabaseInterface(); $serverPrivileges = $this->getPrivileges($dbi); $username = 'pma_username'; $db = '*'; $table = 'pma_table'; $hostname = 'pma_hostname'; //$db == '*' $ret = $serverPrivileges->getSqlQueryForDisplayPrivTable($db, $table, $username, $hostname); $sql = 'SELECT * FROM `mysql`.`user`' . ' WHERE `User` = ' . $dbi->quoteString($username) . ' AND `Host` = ' . $dbi->quoteString($hostname) . ';'; self::assertSame($sql, $ret); //$table == '*' $db = 'pma_db'; $table = '*'; $ret = $serverPrivileges->getSqlQueryForDisplayPrivTable($db, $table, $username, $hostname); $sql = 'SELECT * FROM `mysql`.`db`' . ' WHERE `User` = ' . $dbi->quoteString($username) . ' AND `Host` = ' . $dbi->quoteString($hostname) . ' AND `Db` = \'' . $db . '\''; self::assertSame($sql, $ret); //$table == 'pma_table' $db = 'pma_db'; $table = 'pma_table'; $ret = $serverPrivileges->getSqlQueryForDisplayPrivTable($db, $table, $username, $hostname); $sql = 'SELECT `Table_priv`' . ' FROM `mysql`.`tables_priv`' . ' WHERE `User` = ' . $dbi->quoteString($username) . ' AND `Host` = ' . $dbi->quoteString($hostname) . " AND `Db` = '" . $serverPrivileges->unescapeGrantWildcards($db) . "'" . ' AND `Table_name` = ' . $dbi->quoteString($table) . ';'; self::assertSame($sql, $ret); // SQL escaping $db = "db' AND"; $table = 'pma_table'; $ret = $serverPrivileges->getSqlQueryForDisplayPrivTable($db, $table, $username, $hostname); self::assertSame( 'SELECT `Table_priv` FROM `mysql`.`tables_priv` ' . "WHERE `User` = 'pma_username' AND " . "`Host` = 'pma_hostname' AND `Db` = 'db\' AND' AND " . "`Table_name` = 'pma_table';", $ret, ); } public function testGetDataForChangeOrCopyUser(): void { $GLOBALS['lang'] = 'en'; $dummyDbi = $this->createDbiDummy(); // phpcs:disable Generic.Files.LineLength.TooLong $dummyDbi->addResult( 'SELECT * FROM `mysql`.`user` WHERE `User` = \'PMA_old_username\' AND `Host` = \'PMA_old_hostname\';', [ ['PMA_old_hostname', 'PMA_old_username', 'pma_password', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', '', '', '', '', '0', '0', '0', '0', 'mysql_native_password', 'pma_password', 'N', 'N', '', '0.000000'], ], ['Host', 'User', 'Password', 'Select_priv', 'Insert_priv', 'Update_priv', 'Delete_priv', 'Create_priv', 'Drop_priv', 'Reload_priv', 'Shutdown_priv', 'Process_priv', 'File_priv', 'Grant_priv', 'References_priv', 'Index_priv', 'Alter_priv', 'Show_db_priv', 'Super_priv', 'Create_tmp_table_priv', 'Lock_tables_priv', 'Execute_priv', 'Repl_slave_priv', 'Repl_client_priv', 'Create_view_priv', 'Show_view_priv', 'Create_routine_priv', 'Alter_routine_priv', 'Create_user_priv', 'Event_priv', 'Trigger_priv', 'Create_tablespace_priv', 'Delete_history_priv', 'ssl_type', 'ssl_cipher', 'x509_issuer', 'x509_subject', 'max_questions', 'max_updates', 'max_connections', 'max_user_connections', 'plugin', 'authentication_string', 'password_expired', 'is_role', 'default_role', 'max_statement_time'], ); // phpcs:enable $serverPrivileges = $this->getPrivileges($this->createDatabaseInterface($dummyDbi)); //$_POST['change_copy'] not set $password = $serverPrivileges->getDataForChangeOrCopyUser('', ''); //$_POST['change_copy'] is set $_POST['change_copy'] = true; $password = $serverPrivileges->getDataForChangeOrCopyUser('PMA_old_username', 'PMA_old_hostname'); self::assertSame('pma_password', $password); unset($_POST['change_copy']); } public function testGetExportUserDefinitionTextarea(): void { $dummyDbi = $this->createDbiDummy(); $dummyDbi->addResult( 'SHOW GRANTS FOR \'PMA_username\'@\'PMA_hostname\'', [['grant user2 delete'], ['grant user1 select']], ['Grants for PMA_username@PMA_hostname'], ); $serverPrivileges = $this->getPrivileges($this->createDatabaseInterface($dummyDbi)); $username = 'PMA_username'; $hostname = 'PMA_hostname'; $export = $serverPrivileges->getExportUserDefinitionTextarea($username, $hostname, null); self::assertStringContainsString('grant user2 delete', $export); self::assertStringContainsString('grant user1 select', $export); self::assertStringContainsString('<textarea class="export"', $export); } public function testAddUser(): void { Config::getInstance()->selectedServer['DisableIS'] = false; $GLOBALS['username'] = 'pma_username'; $dummyDbi = $this->createDbiDummy(); $dummyDbi->addResult('SELECT \'1\' FROM `mysql`.`user` WHERE `User` = \'\' AND `Host` = \'localhost\';', []); $dummyDbi->addResult('SET `old_passwords` = 0;', true); $dummyDbi->addResult( 'CREATE USER \'\'@\'localhost\' IDENTIFIED WITH mysql_native_password AS \'pma_dbname\';', true, ); $dummyDbi->addResult('GRANT USAGE ON *.* TO \'\'@\'localhost\' REQUIRE NONE;', true); $dummyDbi->addResult('GRANT ALL PRIVILEGES ON `pma_dbname`.* TO \'\'@\'localhost\';', true); $dbi = $this->createDatabaseInterface($dummyDbi); $dbi->setVersion(['@@version' => '5.7.6', '@@version_comment' => 'MySQL Community Server (GPL)']); $serverPrivileges = $this->getPrivileges($dbi); $dbname = 'pma_dbname'; $username = 'pma_username'; $hostname = 'pma_hostname'; $_POST['adduser_submit'] = true; $_POST['pred_username'] = 'any'; $_POST['pred_hostname'] = 'localhost'; $_POST['pred_password'] = 'keep'; $_POST['createdb-3'] = true; $_POST['userGroup'] = 'username'; $_POST['authentication_plugin'] = 'mysql_native_password'; [ $retMessage,,, $sqlQuery, $addUserError, ] = $serverPrivileges->addUser($dbname, $username, $hostname, $dbname, true); self::assertInstanceOf(Message::class, $retMessage); self::assertSame( 'You have added a new user.', $retMessage->getMessage(), ); self::assertSame( "CREATE USER ''@'localhost' IDENTIFIED WITH mysql_native_password AS '***';" . "GRANT USAGE ON *.* TO ''@'localhost' REQUIRE NONE;" . "GRANT ALL PRIVILEGES ON `pma_dbname`.* TO ''@'localhost';", $sqlQuery, ); self::assertFalse($addUserError); } public function testAddUserOld(): void { Config::getInstance()->selectedServer['DisableIS'] = false; $dummyDbi = $this->createDbiDummy(); $dummyDbi->addResult('SELECT \'1\' FROM `mysql`.`user` WHERE `User` = \'\' AND `Host` = \'localhost\';', []); $dummyDbi->addResult('SET `old_passwords` = 0;', true); $dummyDbi->addResult('CREATE USER \'\'@\'localhost\';', true); $dummyDbi->addResult('SET `old_passwords` = 0;', true); $dummyDbi->addResult('SET PASSWORD FOR \'\'@\'localhost\' = \'pma_dbname\';', true); $dummyDbi->addResult('GRANT USAGE ON *.* TO \'\'@\'localhost\' REQUIRE NONE;', true); $dummyDbi->addResult('GRANT ALL PRIVILEGES ON `pma_dbname`.* TO \'\'@\'localhost\';', true); $dbi = $this->createDatabaseInterface($dummyDbi); $dbi->setVersion(['@@version' => '5.5.6', '@@version_comment' => 'MySQL Community Server (GPL)']); $serverPrivileges = $this->getPrivileges($dbi); $GLOBALS['username'] = 'username'; $dbname = 'pma_dbname'; $username = 'pma_username'; $hostname = 'pma_hostname'; $_POST['adduser_submit'] = true; $_POST['pred_username'] = 'any'; $_POST['pred_hostname'] = 'localhost'; $_POST['pred_password'] = 'keep'; $_POST['createdb-3'] = true; $_POST['userGroup'] = 'username'; $_POST['authentication_plugin'] = 'mysql_native_password'; [ $retMessage,,, $sqlQuery, $addUserError, ] = $serverPrivileges->addUser($dbname, $username, $hostname, $dbname, true); self::assertInstanceOf(Message::class, $retMessage); self::assertSame( 'You have added a new user.', $retMessage->getMessage(), ); self::assertSame( "CREATE USER ''@'localhost';" . "GRANT USAGE ON *.* TO ''@'localhost' REQUIRE NONE;" . "SET PASSWORD FOR ''@'localhost' = '***';" . "GRANT ALL PRIVILEGES ON `pma_dbname`.* TO ''@'localhost';", $sqlQuery, ); self::assertFalse($addUserError); } public function testUpdatePassword(): void { $dummyDbi = $this->createDbiDummy(); $dummyDbi->addResult( 'ALTER USER \'pma_username\'@\'pma_hostname\' IDENTIFIED WITH mysql_native_password BY \'pma_pw\'', true, ); $dummyDbi->addResult('FLUSH PRIVILEGES;', true); $serverPrivileges = $this->getPrivileges($this->createDatabaseInterface($dummyDbi)); $username = 'pma_username'; $hostname = 'pma_hostname'; $errUrl = 'error.php'; $_POST['pma_pw'] = 'pma_pw'; $_POST['authentication_plugin'] = 'mysql_native_password'; $message = $serverPrivileges->updatePassword($errUrl, $username, $hostname); self::assertSame( 'The password for \'pma_username\'@\'pma_hostname\' was changed successfully.', $message->getMessage(), ); } public function testGetMessageAndSqlQueryForPrivilegesRevoke(): void { $dummyDbi = $this->createDbiDummy(); $dummyDbi->addResult( 'REVOKE ALL PRIVILEGES ON `pma_dbname`.`pma_tablename` FROM \'pma_username\'@\'pma_hostname\';', true, ); $dummyDbi->addResult( 'REVOKE GRANT OPTION ON `pma_dbname`.`pma_tablename` FROM \'pma_username\'@\'pma_hostname\';', true, ); $serverPrivileges = $this->getPrivileges($this->createDatabaseInterface($dummyDbi)); $dbname = 'pma_dbname'; $username = 'pma_username'; $hostname = 'pma_hostname'; $tablename = 'pma_tablename'; $_POST['adduser_submit'] = true; $_POST['pred_username'] = 'any'; $_POST['pred_hostname'] = 'localhost'; $_POST['createdb-3'] = true; $_POST['Grant_priv'] = 'Y'; $_POST['max_questions'] = 1000; [$message, $sqlQuery] = $serverPrivileges->getMessageAndSqlQueryForPrivilegesRevoke( $dbname, $tablename, $username, $hostname, '', ); self::assertSame( "You have revoked the privileges for 'pma_username'@'pma_hostname'.", $message->getMessage(), ); self::assertSame( 'REVOKE ALL PRIVILEGES ON `pma_dbname`.`pma_tablename` ' . "FROM 'pma_username'@'pma_hostname'; " . 'REVOKE GRANT OPTION ON `pma_dbname`.`pma_tablename` ' . "FROM 'pma_username'@'pma_hostname';", $sqlQuery, ); } public function testUpdatePrivileges(): void { $dummyDbi = $this->createDbiDummy(); $dummyDbi->addResult( 'REVOKE ALL PRIVILEGES ON `pma_dbname`.`pma_tablename` FROM \'pma_username\'@\'pma_hostname\';', true, ); $serverPrivileges = $this->getPrivileges($this->createDatabaseInterface($dummyDbi)); $dbname = 'pma_dbname'; $username = 'pma_username'; $hostname = 'pma_hostname'; $tablename = 'pma_tablename'; $_POST['adduser_submit'] = true; $_POST['pred_username'] = 'any'; $_POST['pred_hostname'] = 'localhost'; $_POST['createdb-3'] = true; $_POST['Grant_priv'] = 'Y'; $_POST['max_questions'] = 1000; [$sqlQuery, $message] = $serverPrivileges->updatePrivileges($username, $hostname, $tablename, $dbname, ''); self::assertSame( "You have updated the privileges for 'pma_username'@'pma_hostname'.", $message->getMessage(), ); self::assertSame( 'REVOKE ALL PRIVILEGES ON `pma_dbname`.`pma_tablename` FROM \'pma_username\'@\'pma_hostname\'; ', $sqlQuery, ); } public function testUpdatePrivilegesBeforeMySql8Dot11(): void { $dbi = $this->createDatabaseInterface(); $serverPrivileges = $this->getPrivileges($dbi); $dbname = ''; $username = 'pma_username'; $hostname = 'pma_hostname'; $tablename = ''; $_POST['adduser_submit'] = true; $_POST['pred_username'] = 'any'; $_POST['pred_hostname'] = 'localhost'; $_POST['Grant_priv'] = 'Y'; $_POST['max_questions'] = 1000; $_POST['max_connections'] = 20; $_POST['max_updates'] = 30; $_POST['max_user_connections'] = 40; //Mock DBI $dbi = $this->getMockBuilder(DatabaseInterface::class) ->disableOriginalConstructor() ->getMock(); $dbi->expects(self::any())->method('getVersion') ->willReturn(8003); $dbi->expects(self::any()) ->method('quoteString') ->willReturnCallback(static fn (string $string): string => "'" . $string . "'"); $serverPrivileges->dbi = $dbi; [$sqlQuery, $message] = $serverPrivileges->updatePrivileges($username, $hostname, $tablename, $dbname, ''); self::assertSame( "You have updated the privileges for 'pma_username'@'pma_hostname'.", $message->getMessage(), ); self::assertSame( ' GRANT USAGE ON *.* TO \'pma_username\'@\'pma_hostname\' REQUIRE NONE' . ' WITH GRANT OPTION MAX_QUERIES_PER_HOUR 1000 MAX_CONNECTIONS_PER_HOUR 20' . ' MAX_UPDATES_PER_HOUR 30 MAX_USER_CONNECTIONS 40; ', $sqlQuery, ); } public function testUpdatePrivilegesAfterMySql8Dot11(): void { $serverPrivileges = $this->getPrivileges($this->createDatabaseInterface()); $dbname = ''; $username = 'pma_username'; $hostname = 'pma_hostname'; $tablename = ''; $_POST['adduser_submit'] = true; $_POST['pred_username'] = 'any'; $_POST['pred_hostname'] = 'localhost'; $_POST['Grant_priv'] = 'Y'; $_POST['max_questions'] = 1000; $_POST['max_connections'] = 20; $_POST['max_updates'] = 30; $_POST['max_user_connections'] = 40; //Mock DBI $dbi = $this->getMockBuilder(DatabaseInterface::class) ->disableOriginalConstructor() ->getMock(); $dbi->expects(self::any())->method('getVersion') ->willReturn(80011); $dbi->expects(self::any()) ->method('quoteString') ->willReturnCallback(static fn (string $string): string => "'" . $string . "'"); $serverPrivileges->dbi = $dbi; [$sqlQuery, $message] = $serverPrivileges->updatePrivileges($username, $hostname, $tablename, $dbname, ''); self::assertSame( "You have updated the privileges for 'pma_username'@'pma_hostname'.", $message->getMessage(), ); self::assertSame( ' GRANT USAGE ON *.* TO \'pma_username\'@\'pma_hostname\';' . ' ALTER USER \'pma_username\'@\'pma_hostname\' REQUIRE NONE' . ' WITH MAX_QUERIES_PER_HOUR 1000 MAX_CONNECTIONS_PER_HOUR' . ' 20 MAX_UPDATES_PER_HOUR 30 MAX_USER_CONNECTIONS 40;', $sqlQuery, ); } #[Group('medium')] public function testGetHtmlToDisplayPrivilegesTable(): void { $GLOBALS['hostname'] = 'hostname'; $GLOBALS['username'] = 'username'; $dbi = $this->createDatabaseInterface(); $serverPrivileges = $this->getPrivileges($dbi); $html = $serverPrivileges->getHtmlToDisplayPrivilegesTable(); $GLOBALS['username'] = 'username'; //validate 2: button self::assertStringContainsString('Update user privileges', $html); //validate 3: getHtmlForGlobalOrDbSpecificPrivs self::assertStringContainsString('<div class="card">', $html); self::assertStringContainsString( '<div class="card-header js-submenu-label" data-submenu-label="' . __('Global') . '">', $html, ); self::assertStringContainsString( __('Global privileges'), $html, ); self::assertStringContainsString( __('Check all'), $html, ); self::assertStringContainsString( __('Note: MySQL privilege names are expressed in English'), $html, ); //validate 4: getHtmlForGlobalPrivTableWithCheckboxes items //Select_priv self::assertStringContainsString('<input type="checkbox" class="checkall" name="Select_priv"', $html); //Create_user_priv self::assertStringContainsString('<input type="checkbox" class="checkall" name="Create_user_priv"', $html); //Insert_priv self::assertStringContainsString('<input type="checkbox" class="checkall" name="Insert_priv"', $html); //Update_priv self::assertStringContainsString('<input type="checkbox" class="checkall" name="Update_priv"', $html); //Create_priv self::assertStringContainsString('<input type="checkbox" class="checkall" name="Create_priv"', $html); //Create_routine_priv self::assertStringContainsString('<input type="checkbox" class="checkall" name="Create_routine_priv"', $html); //Execute_priv self::assertStringContainsString('<input type="checkbox" class="checkall" name="Execute_priv"', $html); //validate 5: getHtmlForResourceLimits self::assertStringContainsString( '<div class="card-header">' . __('Resource limits') . '</div>', $html, ); self::assertStringContainsString( __('Note: Setting these options to 0 (zero) removes the limit.'), $html, ); self::assertStringContainsString('MAX QUERIES PER HOUR', $html); self::assertStringContainsString('id="text_max_updates" value="0"', $html); self::assertStringContainsString( __('Limits the number of new connections the user may open per hour.'), $html, ); self::assertStringContainsString( __('Limits the number of simultaneous connections the user may have.'), $html, ); self::assertStringContainsString('<div class="card-header">SSL</div>', $html); self::assertStringContainsString('value="NONE"', $html); self::assertStringContainsString('value="ANY"', $html); self::assertStringContainsString('value="X509"', $html); self::assertStringContainsString('value="SPECIFIED"', $html); } public function testGetSqlQueriesForDisplayAndAddUserMySql8011(): void { Config::getInstance()->selectedServer['DisableIS'] = false; $dummyDbi = $this->createDbiDummy(); $dummyDbi->addResult('SET `old_passwords` = 0;', true); $dbi = $this->createDatabaseInterface($dummyDbi); $dbi->setVersion(['@@version' => '8.0.11', '@@version_comment' => 'MySQL Community Server - GPL']); $serverPrivileges = $this->getPrivileges($dbi); $username = 'PMA_username'; $hostname = 'PMA_hostname'; $password = 'pma_password'; $_POST['pred_password'] = 'keep'; $_POST['authentication_plugin'] = 'mysql_native_password'; [ $createUserReal, $createUserShow, ] = $serverPrivileges->getSqlQueriesForDisplayAndAddUser($username, $hostname, $password); //validate 1: $create_user_real self::assertSame( 'CREATE USER \'PMA_username\'@\'PMA_hostname\' IDENTIFIED WITH mysql_native_password BY \'pma_password\';', $createUserReal, ); //validate 2: $create_user_show self::assertSame( 'CREATE USER \'PMA_username\'@\'PMA_hostname\' IDENTIFIED WITH mysql_native_password BY \'***\';', $createUserShow, ); } public function testGetSqlQueriesForDisplayAndAddUserMySql8016(): void { Config::getInstance()->selectedServer['DisableIS'] = false; $dbi = $this->createDatabaseInterface(); $dbi->setVersion(['@@version' => '8.0.16', '@@version_comment' => 'MySQL Community Server - GPL']); $serverPrivileges = $this->getPrivileges($dbi); $username = 'PMA_username'; $hostname = 'PMA_hostname'; $password = 'pma_password'; $_POST['pred_password'] = 'keep'; [ $createUserReal, $createUserShow, ] = $serverPrivileges->getSqlQueriesForDisplayAndAddUser($username, $hostname, $password); //validate 1: $createUserReal self::assertSame( 'CREATE USER \'PMA_username\'@\'PMA_hostname\' IDENTIFIED BY \'pma_password\';', $createUserReal, ); //validate 2: $createUserShow self::assertSame('CREATE USER \'PMA_username\'@\'PMA_hostname\' IDENTIFIED BY \'***\';', $createUserShow); } public function testGetSqlQueriesForDisplayAndAddUserMySql50500AndUserDefinedPassword(): void { $dbiDummy = $this->createDbiDummy(); $dbi = $this->createDatabaseInterface($dbiDummy); $dbi->setVersion(['@@version' => '5.5.0']); $dbiDummy->addResult('SELECT PASSWORD(\'pma_password\');', [['*ABCDEF']], ['PASSWORD(\'pma_password\')']); $serverPrivileges = $this->getPrivileges($dbi); $username = 'PMA_username'; $hostname = 'PMA_hostname'; $password = 'pma_password'; $_POST['pred_password'] = 'userdefined'; $_POST['pma_pw'] = 'pma_password'; [, , , , $passwordSetReal, $passwordSetShow] = $serverPrivileges->getSqlQueriesForDisplayAndAddUser( $username, $hostname, $password, ); self::assertSame('SET PASSWORD FOR \'PMA_username\'@\'PMA_hostname\' = \'*ABCDEF\';', $passwordSetReal); self::assertSame('SET PASSWORD FOR \'PMA_username\'@\'PMA_hostname\' = \'***\';', $passwordSetShow); $dbiDummy->assertAllQueriesConsumed(); } public function testGetSqlQueriesForDisplayAndAddUserWithUserDefinedPassword(): void { $dbi = $this->createDatabaseInterface(); $dbi->setVersion(['@@version' => '10.4.3-MariaDB']); $serverPrivileges = $this->getPrivileges($dbi); $username = 'PMA_username'; $hostname = 'PMA_hostname'; $password = 'pma_password'; $_POST['pred_password'] = 'userdefined'; $_POST['pma_pw'] = 'pma_password'; [$createUserReal, $createUserShow] = $serverPrivileges->getSqlQueriesForDisplayAndAddUser( $username, $hostname, $password, ); self::assertSame( 'CREATE USER \'PMA_username\'@\'PMA_hostname\' IDENTIFIED BY \'pma_password\';', $createUserReal, ); self::assertSame('CREATE USER \'PMA_username\'@\'PMA_hostname\' IDENTIFIED BY \'***\';', $createUserShow); } public function testGetSqlQueriesForDisplayAndAddUser(): void { Config::getInstance()->selectedServer['DisableIS'] = false; $dummyDbi = $this->createDbiDummy(); $dummyDbi->addResult('SET `old_passwords` = 0;', true); $dummyDbi->addResult('GRANT USAGE ON *.* TO \'PMA_username\'@\'PMA_hostname\' REQUIRE NONE;', true); $dbi = $this->createDatabaseInterface($dummyDbi); $dbi->setVersion(['@@version' => '5.7.6', '@@version_comment' => 'MySQL Community Server (GPL)']); $serverPrivileges = $this->getPrivileges($dbi); $username = 'PMA_username'; $hostname = 'PMA_hostname'; $password = 'pma_password'; $_POST['pred_password'] = 'keep'; $_POST['authentication_plugin'] = 'mysql_native_password'; $dbname = 'PMA_db'; [ $createUserReal, $createUserShow, $realSqlQuery, $sqlQuery,,, $alterRealSqlQuery, $alterSqlQuery, ] = $serverPrivileges->getSqlQueriesForDisplayAndAddUser($username, $hostname, $password); //validate 1: $createUserReal self::assertSame( 'CREATE USER \'PMA_username\'@\'PMA_hostname\' IDENTIFIED WITH mysql_native_password AS \'pma_password\';', $createUserReal, ); //validate 2: $createUserShow self::assertSame( 'CREATE USER \'PMA_username\'@\'PMA_hostname\' IDENTIFIED WITH mysql_native_password AS \'***\';', $createUserShow, ); //validate 3:$realSqlQuery self::assertSame('GRANT USAGE ON *.* TO \'PMA_username\'@\'PMA_hostname\' REQUIRE NONE;', $realSqlQuery); //validate 4:$sqlQuery self::assertSame('GRANT USAGE ON *.* TO \'PMA_username\'@\'PMA_hostname\' REQUIRE NONE;', $sqlQuery); self::assertSame('', $alterRealSqlQuery); self::assertSame('', $alterSqlQuery); //Test for addUserAndCreateDatabase [$sqlQuery, $message] = $serverPrivileges->addUserAndCreateDatabase( false, $realSqlQuery, $sqlQuery, $username, $hostname, $dbname, $alterRealSqlQuery, $alterSqlQuery, false, false, false, ); //validate 5: $sqlQuery self::assertSame('GRANT USAGE ON *.* TO \'PMA_username\'@\'PMA_hostname\' REQUIRE NONE;', $sqlQuery); //validate 6: $message self::assertSame( 'You have added a new user.', $message->getMessage(), ); } public function testGetHtmlToDisplayPrivilegesTableWithTableSpecific(): void { $dbi = $this->createDatabaseInterface(); $serverPrivileges = $this->getPrivileges($dbi); $dbi = $this->createDatabaseInterface(); $serverPrivileges->dbi = $dbi; $GLOBALS['username'] = 'PMA_username'; $GLOBALS['hostname'] = 'PMA_hostname'; $html = $serverPrivileges->getHtmlToDisplayPrivilegesTable('PMA_db', 'PMA_table'); self::assertStringContainsString('checkbox_Update_priv_none', $html); self::assertStringContainsString('<dfn title="Allows changing data.">UPDATE</dfn>', $html); self::assertStringContainsString('checkbox_Insert_priv_none', $html); self::assertStringContainsString( __('Allows reading data.'), $html, ); self::assertStringContainsString( __('Allows inserting and replacing data'), $html, ); self::assertStringContainsString( __('Allows changing data.'), $html, ); self::assertStringContainsString( __('Has no effect in this MySQL version.'), $html, ); self::assertStringContainsString('title="Allows performing SHOW CREATE VIEW queries." checked>', $html); self::assertStringContainsString('<dfn title="Allows creating new views.">', $html); self::assertStringContainsString('CREATE VIEW', $html); self::assertStringContainsString('Create_view_priv', $html); self::assertStringContainsString('Show_view_priv', $html); self::assertStringContainsString( _pgettext('None privileges', 'None'), $html, ); } public function testGetHtmlForLoginInformationFields(): void { $dbi = $this->createDatabaseInterface(); $serverPrivileges = $this->getPrivileges($dbi); $GLOBALS['username'] = 'pma_username'; $dbi = $this->getMockBuilder(DatabaseInterface::class) ->disableOriginalConstructor() ->getMock(); $fieldsInfo = [ ['COLUMN_NAME' => 'Host', 'CHARACTER_MAXIMUM_LENGTH' => 80], ['COLUMN_NAME' => 'User', 'CHARACTER_MAXIMUM_LENGTH' => 40], ]; $dbi->expects(self::any())->method('fetchResult') ->willReturn($fieldsInfo); $dbi->expects(self::any()) ->method('quoteString') ->willReturnCallback(static fn (string $string): string => "'" . $string . "'"); $serverPrivileges->dbi = $dbi; $html = $serverPrivileges->getHtmlForLoginInformationFields(); //validate 1: __('Login Information') self::assertStringContainsString( __('Login Information'), $html, ); self::assertStringContainsString( __('User name:'), $html, ); self::assertStringContainsString( __('Any user'), $html, ); self::assertStringContainsString( __('Use text field'), $html, ); $output = Generator::showHint( __( 'When Host table is used, this field is ignored and values stored in Host table are used instead.', ), ); self::assertStringContainsString($output, $html); } public function testGetWithClauseForAddUserAndUpdatePrivs(): void { $serverPrivileges = $this->getPrivileges($this->createDatabaseInterface()); $_POST['Grant_priv'] = 'Y'; $_POST['max_questions'] = 10; $_POST['max_connections'] = 20; $_POST['max_updates'] = 30; $_POST['max_user_connections'] = 40; $sqlQuery = $serverPrivileges->getWithClauseForAddUserAndUpdatePrivs(); $expect = 'WITH GRANT OPTION MAX_QUERIES_PER_HOUR 10 ' . 'MAX_CONNECTIONS_PER_HOUR 20' . ' MAX_UPDATES_PER_HOUR 30 MAX_USER_CONNECTIONS 40'; self::assertStringContainsString($expect, $sqlQuery); } #[Group('medium')] public function testGetHtmlForAddUser(): void { $dbi = $this->createDatabaseInterface(); $serverPrivileges = $this->getPrivileges($dbi); $dbi = $this->getMockBuilder(DatabaseInterface::class) ->disableOriginalConstructor() ->getMock(); $fieldsInfo = [ ['COLUMN_NAME' => 'Host', 'CHARACTER_MAXIMUM_LENGTH' => 80], ['COLUMN_NAME' => 'User', 'CHARACTER_MAXIMUM_LENGTH' => 40], ]; $dbi->expects(self::any())->method('fetchResult') ->willReturn($fieldsInfo); $dbi->expects(self::any()) ->method('quoteString') ->willReturnCallback(static fn (string $string): string => "'" . $string . "'"); $dbi->expects(self::any())->method('isGrantUser') ->willReturn(true); $serverPrivileges->dbi = $dbi; $dbname = 'pma_dbname'; $html = $serverPrivileges->getHtmlForAddUser($dbname); //validate 1: Url::getHiddenInputs self::assertStringContainsString( Url::getHiddenInputs('', ''), $html, ); //validate 2: getHtmlForLoginInformationFields self::assertStringContainsString( $serverPrivileges->getHtmlForLoginInformationFields(), $html, ); //validate 3: Database for user self::assertStringContainsString( __('Database for user'), $html, ); self::assertStringContainsString( __('Grant all privileges on wildcard name (username\\_%).'), $html, ); self::assertStringContainsString('<input type="checkbox" name="createdb-2" id="createdb-2">', $html); //validate 4: getHtmlToDisplayPrivilegesTable self::assertStringContainsString( $serverPrivileges->getHtmlToDisplayPrivilegesTable('*', '*', false), $html, ); //validate 5: button self::assertStringContainsString('Create user', $html); } public function testGetUserLink(): void { $serverPrivileges = $this->getPrivileges($this->createDatabaseInterface()); $username = 'pma_username'; $hostname = 'pma_hostname'; $dbname = 'pma_dbname'; $tablename = 'pma_tablename'; $html = $serverPrivileges->getUserLink('edit', $username, $hostname, $dbname, $tablename, ''); $dbname = 'pma_dbname'; $urlHtml = Url::getCommon([ 'username' => $username, 'hostname' => $hostname, 'dbname' => $dbname, 'tablename' => $tablename, 'routinename' => '', ], ''); self::assertStringContainsString($urlHtml, $html); self::assertStringContainsString( __('Edit privileges'), $html, ); $dbname = 'pma_dbname'; $html = $serverPrivileges->getUserLink('revoke', $username, $hostname, $dbname, $tablename, ''); $dbname = 'pma_dbname'; $urlHtml = Url::getCommon( [ 'username' => $username, 'hostname' => $hostname, 'dbname' => $dbname, 'tablename' => $tablename, 'routinename' => '', 'revokeall' => 1, ], '', ); self::assertStringContainsString($urlHtml, $html); self::assertStringContainsString( __('Revoke'), $html, ); $html = $serverPrivileges->getUserLink('export', $username, $hostname); $urlHtml = Url::getCommon([ 'username' => $username, 'hostname' => $hostname, 'initial' => '', 'export' => 1, ], ''); self::assertStringContainsString($urlHtml, $html); self::assertStringContainsString( __('Export'), $html, ); } public function testGetUserLinkWildcardsEscaped(): void { $serverPrivileges = $this->getPrivileges($this->createDatabaseInterface()); $username = 'pma\_username'; $hostname = 'pma\_hostname'; $dbname = 'pma\_dbname'; $tablename = 'pma\_tablename'; $html = $serverPrivileges->getUserLink('edit', $username, $hostname, $dbname, $tablename, ''); $dbname = 'pma\_dbname'; $urlHtml = Url::getCommon([ 'username' => $username, 'hostname' => $hostname, 'dbname' => $dbname, 'tablename' => $tablename, 'routinename' => '', ], ''); self::assertStringContainsString($urlHtml, $html); self::assertStringContainsString( __('Edit privileges'), $html, ); $dbname = 'pma\_dbname'; $html = $serverPrivileges->getUserLink('revoke', $username, $hostname, $dbname, $tablename, ''); $dbname = 'pma\_dbname'; $urlHtml = Url::getCommon( [ 'username' => $username, 'hostname' => $hostname, 'dbname' => $dbname, 'tablename' => $tablename, 'routinename' => '', 'revokeall' => 1, ], '', ); self::assertStringContainsString($urlHtml, $html); self::assertStringContainsString( __('Revoke'), $html, ); $html = $serverPrivileges->getUserLink('export', $username, $hostname); $urlHtml = Url::getCommon([ 'username' => $username, 'hostname' => $hostname, 'initial' => '', 'export' => 1, ], ''); self::assertStringContainsString($urlHtml, $html); self::assertStringContainsString( __('Export'), $html, ); } public function testGetExtraDataForAjaxBehavior(): void { Config::getInstance()->selectedServer['DisableIS'] = false; $dummyDbi = $this->createDbiDummy(); $dummyDbi->addResult('SELECT * FROM `mysql`.`user` WHERE `User` = \'username\';', []); $serverPrivileges = $this->getPrivileges($this->createDatabaseInterface($dummyDbi)); $password = 'pma_password'; $sqlQuery = 'pma_sql_query'; $username = 'pma_username'; $hostname = 'pma_hostname'; $GLOBALS['dbname'] = 'pma_dbname'; $_POST['adduser_submit'] = 'adduser_submit'; $_POST['username'] = 'username'; $_POST['change_copy'] = 'change_copy'; $_GET['validate_username'] = 'validate_username'; $_GET['username'] = 'username'; $_POST['update_privs'] = 'update_privs'; $extraData = $serverPrivileges->getExtraDataForAjaxBehavior($password, $sqlQuery, $hostname, $username); //user_exists self::assertFalse($extraData['user_exists']); //db_wildcard_privs self::assertTrue($extraData['db_wildcard_privs']); //user_exists self::assertFalse($extraData['db_specific_privs']); //new_user_initial self::assertSame('P', $extraData['new_user_initial']); //sql_query self::assertSame( Generator::getMessage('', $sqlQuery), $extraData['sql_query'], ); //new_user_string self::assertIsString($extraData['new_user_string']); self::assertStringContainsString( htmlspecialchars($hostname), $extraData['new_user_string'], ); self::assertStringContainsString( htmlspecialchars($username), $extraData['new_user_string'], ); //new_privileges self::assertIsString($extraData['new_privileges']); self::assertStringContainsString( implode(', ', $serverPrivileges->extractPrivInfo(null, true)), $extraData['new_privileges'], ); } public function testGetUserGroupForUser(): void { $relationParameters = RelationParameters::fromArray([ 'db' => 'pmadb', 'users' => 'users', 'usergroups' => 'usergroups', 'menuswork' => true, ]); (new ReflectionProperty(Relation::class, 'cache'))->setValue(null, $relationParameters); $dummyDbi = $this->createDbiDummy(); $dummyDbi->addResult( 'SELECT `usergroup` FROM `pmadb`.`users` WHERE `username` = \'pma_username\' LIMIT 1', [['pma_usergroup']], ); $serverPrivileges = $this->getPrivileges($this->createDatabaseInterface($dummyDbi)); self::assertSame('pma_usergroup', $serverPrivileges->getUserGroupForUser('pma_username')); } public function testGetUsersOverview(): void { Config::getInstance()->selectedServer['DisableIS'] = false; $relationParameters = RelationParameters::fromArray([ 'db' => 'pmadb', 'users' => 'users', 'usergroups' => 'usergroups', 'menuswork' => true, 'trackingwork' => true, 'tracking' => 'tracking', ]); (new ReflectionProperty(Relation::class, 'cache'))->setValue(null, $relationParameters); $dummyDbi = $this->createDbiDummy(); $dummyDbi->addResult('SELECT * FROM `pmadb`.`users`', []); $dummyDbi->addResult('SELECT COUNT(*) FROM `pmadb`.`usergroups`', [['0']]); $serverPrivileges = $this->getPrivileges($this->createDatabaseInterface($dummyDbi)); $resultStub = $this->createMock(DummyResult::class); $dbRights = []; $textDir = 'text_dir'; $html = $serverPrivileges->getUsersOverview($resultStub, $dbRights, $textDir); //Url::getHiddenInputs self::assertStringContainsString( Url::getHiddenInputs('', ''), $html, ); //items self::assertStringContainsString( __('User'), $html, ); self::assertStringContainsString( __('Host'), $html, ); self::assertStringContainsString( __('Password'), $html, ); self::assertStringContainsString( __('Global privileges'), $html, ); //Util::showHint self::assertStringContainsString( Generator::showHint( __('Note: MySQL privilege names are expressed in English.'), ), $html, ); //__('User group') self::assertStringContainsString( __('User group'), $html, ); self::assertStringContainsString( __('Grant'), $html, ); self::assertStringContainsString( __('Action'), $html, ); //$text_dir self::assertStringContainsString($textDir, $html); self::assertStringContainsString( Url::getCommon(['adduser' => 1], ''), $html, ); //labels self::assertStringContainsString( __('Add user account'), $html, ); self::assertStringContainsString( __('Remove selected user accounts'), $html, ); self::assertStringContainsString( __('Drop the databases that have the same names as the users.'), $html, ); self::assertStringContainsString( __('Drop the databases that have the same names as the users.'), $html, ); } public function testGetDataForDeleteUsers(): void { $serverPrivileges = $this->getPrivileges($this->createDatabaseInterface()); $_POST['change_copy'] = 'change_copy'; $_POST['old_hostname'] = 'old_hostname'; $_POST['old_username'] = 'old_username'; $relationParameters = RelationParameters::fromArray([]); (new ReflectionProperty(Relation::class, 'cache'))->setValue(null, $relationParameters); $queries = []; $ret = $serverPrivileges->getDataForDeleteUsers($queries); $item = ["# Deleting 'old_username'@'old_hostname' ...", "DROP USER 'old_username'@'old_hostname';"]; self::assertSame($item, $ret); } public function testGetHtmlHeaderForUserProperties(): void { $dummyDbi = $this->createDbiDummy(); $dummyDbi->addResult( 'SELECT \'1\' FROM `mysql`.`user` WHERE `User` = \'username\' AND `Host` = \'hostname\';', [['1']], ); $dummyDbi->addResult('SHOW COLUMNS FROM `tablename`.`tablename`;', []); $serverPrivileges = $this->getPrivileges($this->createDatabaseInterface($dummyDbi)); $dbnameIsWildcard = true; $urlDbname = 'url_dbname'; $dbname = 'dbname'; $username = 'username'; $hostname = 'hostname'; $tablename = 'tablename'; $_REQUEST['tablename'] = 'tablename'; $html = $serverPrivileges->getHtmlForUserProperties( $dbnameIsWildcard, $urlDbname, $username, $hostname, $tablename, $_REQUEST['tablename'], '/server/privileges', ); //title self::assertStringContainsString( __('Edit privileges:'), $html, ); self::assertStringContainsString( __('User account'), $html, ); //Url::getCommon $item = Url::getCommon([ 'username' => $username, 'hostname' => $hostname, 'dbname' => '', 'tablename' => '', ], ''); self::assertStringContainsString($item, $html); //$username & $hostname self::assertStringContainsString( htmlspecialchars($username), $html, ); self::assertStringContainsString( htmlspecialchars($hostname), $html, ); //$dbnameIsWildcard = true self::assertStringContainsString( __('Databases'), $html, ); //$dbnameIsWildcard = true self::assertStringContainsString( __('Databases'), $html, ); //Url::getCommon $item = Url::getCommon([ 'username' => $username, 'hostname' => $hostname, 'dbname' => $urlDbname, 'tablename' => '', ], ''); self::assertStringContainsString($item, $html); self::assertStringContainsString($dbname, $html); } public function testGetHtmlForUserProperties(): void { $this->dummyDbi->addResult( 'SELECT \'1\' FROM `mysql`.`user` WHERE `User` = \'user\' AND `Host` = \'host\';', [['1']], ['1'], ); $this->dummyDbi->addResult( 'SELECT `Table_priv` FROM `mysql`.`tables_priv` WHERE `User` = \'user\' AND `Host` = \'host\'' . ' AND `Db` = \'sakila\' AND `Table_name` = \'actor\';', [], ['Table_priv'], ); $this->dummyDbi->addResult( 'SHOW COLUMNS FROM `sakila`.`actor`;', [ ['actor_id', 'smallint(5) unsigned', 'NO', 'PRI', null, 'auto_increment'], ['first_name', 'varchar(45)', 'NO', '', null, ''], ['last_name', 'varchar(45)', 'NO', 'MUL', null, ''], ['last_update', 'timestamp', 'NO', '', 'current_timestamp()', 'on update current_timestamp()'], ], ['Field', 'Type', 'Null', 'Key', 'Default', 'Extra'], ); $this->dummyDbi->addResult( 'SELECT `Column_name`, `Column_priv` FROM `mysql`.`columns_priv` WHERE `User` = \'user\'' . ' AND `Host` = \'host\' AND `Db` = \'sakila\' AND `Table_name` = \'actor\';', [], ['Column_name', 'Column_priv'], ); $serverPrivileges = $this->getPrivileges($this->dbi); $GLOBALS['username'] = 'user'; $GLOBALS['hostname'] = 'host'; $actual = $serverPrivileges->getHtmlForUserProperties( false, 'sakila', 'user', 'host', 'sakila', 'actor', '/server/privileges', ); self::assertStringContainsString('addUsersForm', $actual); self::assertStringContainsString('SELECT', $actual); self::assertStringContainsString('Allows reading data.', $actual); self::assertStringContainsString('INSERT', $actual); self::assertStringContainsString('Allows inserting and replacing data.', $actual); self::assertStringContainsString('UPDATE', $actual); self::assertStringContainsString('Allows changing data.', $actual); self::assertStringContainsString('DELETE', $actual); self::assertStringContainsString('Allows deleting data.', $actual); self::assertStringContainsString('CREATE', $actual); self::assertStringContainsString('Allows creating new tables.', $actual); self::assertStringContainsString( Url::getHiddenInputs(), $actual, ); //$username & $hostname self::assertStringContainsString('user', $actual); self::assertStringContainsString('host', $actual); //Create a new user with the same privileges self::assertStringContainsString('Create a new user account with the same privileges', $actual); self::assertStringContainsString( __('Database'), $actual, ); $config = Config::getInstance(); self::assertStringContainsString( Util::getScriptNameForOption( $config->settings['DefaultTabDatabase'], 'database', ), $actual, ); $item = Url::getCommon(['db' => 'sakila', 'reload' => 1], ''); self::assertStringContainsString($item, $actual); self::assertStringContainsString('sakila', $actual); //$tablename self::assertStringContainsString( __('Table'), $actual, ); self::assertStringContainsString( Util::getScriptNameForOption( $config->settings['DefaultTabTable'], 'table', ), $actual, ); $item = Url::getCommon(['db' => 'sakila', 'table' => 'actor', 'reload' => 1], ''); self::assertStringContainsString($item, $actual); self::assertStringContainsString('table', $actual); $item = Util::getTitleForTarget($config->settings['DefaultTabTable']); self::assertStringContainsString((string) $item, $actual); } public function testGetHtmlForUserOverview(): void { Config::getInstance()->selectedServer['DisableIS'] = false; $GLOBALS['lang'] = 'en'; $userPrivileges = new UserPrivileges(isReload: true); $dummyDbi = $this->createDbiDummy(); // phpcs:disable Generic.Files.LineLength.TooLong $dummyDbi->addResult( 'SELECT *, IF(`authentication_string` = _latin1 \'\', \'N\', \'Y\') AS `Password` FROM `mysql`.`user` ORDER BY `User` ASC, `Host` ASC', [ ['localhost', 'pma', 'password', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', '', '', '', '', '0', '0', '0', '0', 'mysql_native_password', 'password', 'N', 'N', '', '0.000000', 'Y'], ['localhost', 'root', 'password', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', '', '', '', '', '0', '0', '0', '0', 'mysql_native_password', 'password', 'N', 'N', '', '0.000000', 'Y'], ], ['Host', 'User', 'Password', 'Select_priv', 'Insert_priv', 'Update_priv', 'Delete_priv', 'Create_priv', 'Drop_priv', 'Reload_priv', 'Shutdown_priv', 'Process_priv', 'File_priv', 'Grant_priv', 'References_priv', 'Index_priv', 'Alter_priv', 'Show_db_priv', 'Super_priv', 'Create_tmp_table_priv', 'Lock_tables_priv', 'Execute_priv', 'Repl_slave_priv', 'Repl_client_priv', 'Create_view_priv', 'Show_view_priv', 'Create_routine_priv', 'Alter_routine_priv', 'Create_user_priv', 'Event_priv', 'Trigger_priv', 'Create_tablespace_priv', 'Delete_history_priv', 'ssl_type', 'ssl_cipher', 'x509_issuer', 'x509_subject', 'max_questions', 'max_updates', 'max_connections', 'max_user_connections', 'plugin', 'authentication_string', 'password_expired', 'is_role', 'default_role', 'max_statement_time', 'Password'], ); $dummyDbi->addResult('SELECT COUNT(*) FROM `mysql`.`user`', [[2]]); $dummyDbi->addResult( 'SHOW TABLES FROM `mysql`', [['columns_priv'], ['db'], ['tables_priv'], ['user']], ['Tables_in_mysql'], ); $dummyDbi->addResult( '(SELECT DISTINCT `User`, `Host` FROM `mysql`.`user` ) UNION (SELECT DISTINCT `User`, `Host` FROM `mysql`.`db` ) UNION (SELECT DISTINCT `User`, `Host` FROM `mysql`.`tables_priv` ) UNION (SELECT DISTINCT `User`, `Host` FROM `mysql`.`columns_priv` ) ORDER BY `User` ASC, `Host` ASC', [['pma', 'localhost'], ['root', 'localhost']], ['User', 'Host'], ); // phpcs:enable $serverPrivileges = $this->getPrivileges($this->createDatabaseInterface($dummyDbi)); $_REQUEST = ['ajax_page_request' => '1']; $actual = $serverPrivileges->getHtmlForUserOverview($userPrivileges, 'ltr', null); self::assertStringContainsString('Note: MySQL privilege names are expressed in English.', $actual); self::assertStringContainsString( 'Note: phpMyAdmin gets the users’ privileges directly from MySQL’s privilege tables.', $actual, ); // the user does not have enough privileges $dummyDbi = $this->createDbiDummy(); // phpcs:disable Generic.Files.LineLength.TooLong $dummyDbi->addResult( 'SELECT *, IF(`authentication_string` = _latin1 \'\', \'N\', \'Y\') AS `Password` FROM `mysql`.`user` ORDER BY `User` ASC, `Host` ASC', false, ); $dummyDbi->addResult( 'SELECT *, IF(`authentication_string` = _latin1 \'\', \'N\', \'Y\') AS `Password` FROM `mysql`.`user` ', false, ); $dummyDbi->addResult('SELECT 1 FROM `mysql`.`user`', false); $serverPrivileges = $this->getPrivileges($this->createDatabaseInterface($dummyDbi)); $html = $serverPrivileges->getHtmlForUserOverview($userPrivileges, 'ltr', null); self::assertStringContainsString( Url::getCommon(['adduser' => 1], ''), $html, ); self::assertStringContainsString( Generator::getIcon('b_usradd', 'Add user account'), $html, ); self::assertStringContainsString( __('Add user'), $html, ); // MySQL has older table structure $dummyDbi = $this->createDbiDummy(); // phpcs:disable Generic.Files.LineLength.TooLong $dummyDbi->addResult( 'SELECT *, IF(`authentication_string` = _latin1 \'\', \'N\', \'Y\') AS `Password` FROM `mysql`.`user` ORDER BY `User` ASC, `Host` ASC', false, ); $dummyDbi->addResult( 'SELECT *, IF(`authentication_string` = _latin1 \'\', \'N\', \'Y\') AS `Password` FROM `mysql`.`user` ', false, ); $dummyDbi->addResult('SELECT 1 FROM `mysql`.`user`', [[1]]); $serverPrivileges = $this->getPrivileges($this->createDatabaseInterface($dummyDbi)); $actual = $serverPrivileges->getHtmlForUserOverview($userPrivileges, 'ltr', null); self::assertStringContainsString('Your privilege table structure seems to be older than' . ' this MySQL version!<br>' . 'Please run the <code>mysql_upgrade</code> command' . ' that should be included in your MySQL server distribution' . ' to solve this problem!', $actual); } public function testGetHtmlForAllTableSpecificRights(): void { $dummyDbi = $this->createDbiDummy(); $dummyDbi->addResult( 'SHOW TABLES FROM `mysql`;', [['columns_priv'], ['db'], ['tables_priv'], ['user']], ['Tables_in_mysql'], ); $dummyDbi->addResult( 'SHOW TABLES FROM `mysql`;', [['columns_priv'], ['db'], ['tables_priv'], ['user']], ['Tables_in_mysql'], ); // phpcs:disable Generic.Files.LineLength.TooLong $dummyDbi->addResult( '(SELECT DISTINCT `Table_name` FROM `mysql`.`columns_priv` WHERE `User` = \'pma\' AND `Host` = \'host\' AND `Db` LIKE \'pmadb\') ORDER BY `Table_name` ASC', [], ['Table_name'], ); $dummyDbi->addResult( 'SELECT `Table_name`, `Table_priv`, IF(`Column_priv` = _latin1 \'\', 0, 1) AS \'Column_priv\' FROM `mysql`.`tables_priv` WHERE `User` = \'pma\' AND `Host` = \'host\' AND `Db` LIKE \'pmadb\' ORDER BY `Table_name` ASC;', [], ['Table_name', 'Table_priv', 'Column_priv'], ); $dummyDbi->addResult( '(SELECT DISTINCT `Db` FROM `mysql`.`tables_priv` WHERE `User` = \'pma2\' AND `Host` = \'host2\') UNION (SELECT DISTINCT `Db` FROM `mysql`.`columns_priv` WHERE `User` = \'pma2\' AND `Host` = \'host2\') ORDER BY `Db` ASC', [], ['Db'], ); $dummyDbi->addResult( 'SELECT * FROM `mysql`.`db` WHERE `User` = \'pma2\' AND `Host` = \'host2\' ORDER BY `Db` ASC', [], ['Host', 'Db', 'User', 'Select_priv', 'Insert_priv', 'Update_priv', 'Delete_priv', 'Create_priv', 'Drop_priv', 'Reload_priv', 'Shutdown_priv', 'Process_priv', 'File_priv', 'Grant_priv', 'References_priv', 'Index_priv', 'Alter_priv', 'Show_db_priv', 'Super_priv', 'Create_tmp_table_priv', 'Lock_tables_priv', 'Execute_priv', 'Repl_slave_priv', 'Repl_client_priv', 'Create_view_priv', 'Show_view_priv', 'Create_routine_priv', 'Alter_routine_priv', 'Create_user_priv', 'Event_priv', 'Trigger_priv', 'Create_tablespace_priv', 'Delete_history_priv'], ); // phpcs:enable $dbi = $this->createDatabaseInterface($dummyDbi); DatabaseInterface::$instance = $dbi; $serverPrivileges = $this->getPrivileges($dbi); // Test case 1 $actual = $serverPrivileges->getHtmlForAllTableSpecificRights('pma', 'host', 'table', 'pmadb'); self::assertStringContainsString('<input type="hidden" name="username" value="pma">', $actual); self::assertStringContainsString('<input type="hidden" name="hostname" value="host">', $actual); self::assertStringContainsString( '<div class="card-header js-submenu-label" data-submenu-label="Table">', $actual, ); self::assertStringContainsString('Table-specific privileges', $actual); // Test case 2 $config = Config::getInstance(); $config->selectedServer['DisableIS'] = false; $config->selectedServer['only_db'] = ''; $dummyDbi->addResult( 'SELECT `SCHEMA_NAME` FROM `INFORMATION_SCHEMA`.`SCHEMATA`', [['x'], ['y'], ['z']], ['SCHEMA_NAME'], ); $actual = $serverPrivileges->getHtmlForAllTableSpecificRights('pma2', 'host2', 'database', ''); self::assertStringContainsString( '<div class="card-header js-submenu-label" data-submenu-label="Database">', $actual, ); self::assertStringContainsString('Database-specific privileges', $actual); } public function testGetHtmlForInitials(): void { $GLOBALS['lang'] = 'en'; $dummyDbi = $this->createDbiDummy(); $dummyDbi->addResult('SELECT COUNT(*) FROM `mysql`.`user`', [[21]]); $dummyDbi->addResult( 'SELECT DISTINCT UPPER(LEFT(`User`, 1)) FROM `user`', [['C'], ['-'], ['"'], ['%'], ['\\'], ['']], ); $dbi = $this->createDatabaseInterface($dummyDbi); $serverPrivileges = $this->getPrivileges($dbi); $actual = $serverPrivileges->getHtmlForInitials(); self::assertStringContainsString( '<a class="page-link" href="#" tabindex="-1" aria-disabled="true">A</a>', $actual, ); self::assertMatchesRegularExpression( '/<a class="page-link" href="index.php\?route=\/server\/privileges&initial=C&lang=en">\s*C\s*<\/a>/', $actual, ); self::assertStringContainsString( '<a class="page-link" href="#" tabindex="-1" aria-disabled="true">Z</a>', $actual, ); self::assertMatchesRegularExpression( '/<a class="page-link" href="index.php\?route=\/server\/privileges&initial=-&lang=en">\s*-\s*<\/a>/', $actual, ); self::assertMatchesRegularExpression( '/<a class="page-link" href="index.php\?route=\/server\/privileges&initial=%22&lang=en">\s*"\s*<\/a>/', $actual, ); self::assertMatchesRegularExpression( '/<a class="page-link" href="index.php\?route=\/server\/privileges&initial=%25&lang=en">\s*%\s*<\/a>/', $actual, ); self::assertMatchesRegularExpression( '/<a class="page-link" href="index.php\?route=\/server\/privileges&initial=%5C&lang=en">\s*\\\\\s*<\/a>/', $actual, ); self::assertMatchesRegularExpression( '/<a class="page-link" href="index.php\?route=\/server\/privileges&initial=&lang=en">\s*' . '<span class="text-danger text-nowrap">' . preg_quote(__('Any')) . '<\/span>' . '\s*<\/a>/', $actual, ); self::assertStringContainsString('Show all', $actual); } public function testGetDbRightsForUserOverview(): void { $dbi = $this->createDatabaseInterface(); $serverPrivileges = $this->getPrivileges($dbi); $resultStub = $this->createMock(DummyResult::class); //Mock DBI $dbi = $this->getMockBuilder(DatabaseInterface::class) ->disableOriginalConstructor() ->getMock(); $dbi->expects(self::any()) ->method('query') ->willReturn($resultStub); $dbi->expects(self::any()) ->method('fetchResult') ->willReturn(['db', 'columns_priv']); $resultStub->expects(self::any()) ->method('fetchAssoc') ->willReturn(['User' => 'pmauser', 'Host' => 'local'], []); $dbi->expects(self::any()) ->method('quoteString') ->willReturnCallback(static fn (string $string): string => "'" . $string . "'"); $serverPrivileges->dbi = $dbi; $expected = [ 'pmauser' => [ 'local' => [ 'User' => 'pmauser', 'Host' => 'local', 'Password' => '?', 'Grant_priv' => 'N', 'privs' => ['USAGE'], ], ], ]; $actual = $serverPrivileges->getDbRightsForUserOverview('A'); self::assertSame($expected, $actual); } public function testDeleteUser(): void { $dbi = $this->createDatabaseInterface(); $serverPrivileges = $this->getPrivileges($dbi); $resultStub = $this->createMock(DummyResult::class); //Mock DBI $dbi = $this->getMockBuilder(DatabaseInterface::class) ->disableOriginalConstructor() ->getMock(); $dbi->expects(self::any()) ->method('tryQuery') ->willReturn($resultStub, $resultStub, false); $dbi->expects(self::any()) ->method('getError') ->willReturn('Some error occurred!'); $dbi->expects(self::any()) ->method('quoteString') ->willReturnCallback(static fn (string $string): string => "'" . $string . "'"); $serverPrivileges->dbi = $dbi; // Test case 1 : empty queries $queries = []; $actual = $serverPrivileges->deleteUser($queries); self::assertSame('', $actual[0]); self::assertSame( 'No users selected for deleting!', $actual[1]->getMessage(), ); // Test case 2 : all successful queries $_POST['mode'] = 3; $queries = ['foo']; $actual = $serverPrivileges->deleteUser($queries); self::assertSame("foo\n# Reloading the privileges …\nFLUSH PRIVILEGES;", $actual[0]); self::assertSame( 'The selected users have been deleted successfully.', $actual[1]->getMessage(), ); // Test case 3 : failing queries $_POST['mode'] = 1; $queries = ['bar']; $actual = $serverPrivileges->deleteUser($queries); self::assertSame('bar', $actual[0]); self::assertSame( 'Some error occurred!' . "\n", $actual[1]->getMessage(), ); } public function testGetFormForChangePassword(): void { $serverPrivileges = $this->getPrivileges($this->createDatabaseInterface()); $username = 'pma_username'; $hostname = 'pma_hostname'; $html = $serverPrivileges->getFormForChangePassword($username, $hostname, false, '/server/privileges'); self::assertStringContainsString( Url::getFromRoute('/server/privileges'), $html, ); //Url::getHiddenInputs self::assertStringContainsString( Url::getHiddenInputs(), $html, ); //$username & $hostname self::assertStringContainsString( htmlspecialchars($username), $html, ); self::assertStringContainsString( htmlspecialchars($hostname), $html, ); //labels self::assertStringContainsString('change_password_form', $html); self::assertStringContainsString( __('No Password'), $html, ); self::assertStringContainsString( __('Password:'), $html, ); self::assertStringContainsString( __('Password:'), $html, ); } public function testGetUserPrivileges(): void { $mysqliResultStub = $this->createMock(ResultInterface::class); $mysqliStmtStub = $this->createMock(Statement::class); $mysqliStmtStub->expects(self::exactly(2))->method('execute')->willReturn(true); $mysqliStmtStub->expects(self::exactly(2))->method('getResult')->willReturn($mysqliResultStub); $dbi = $this->createMock(DatabaseInterface::class); $dbi->expects(self::once())->method('isMariaDB')->willReturn(true); $userQuery = 'SELECT * FROM `mysql`.`user` WHERE `User` = ? AND `Host` = ?;'; $globalPrivQuery = 'SELECT * FROM `mysql`.`global_priv` WHERE `User` = ? AND `Host` = ?;'; $dbi->expects(self::exactly(2))->method('prepare')->willReturnMap([ [$userQuery, ConnectionType::User, $mysqliStmtStub], [$globalPrivQuery, ConnectionType::User, $mysqliStmtStub], ]); $mysqliResultStub->expects(self::exactly(2)) ->method('fetchAssoc') ->willReturn( ['Host' => 'test.host', 'User' => 'test.user'], ['Host' => 'test.host', 'User' => 'test.user', 'Priv' => '{"account_locked":true}'], ); $relation = new Relation($this->dbi); $serverPrivileges = new Privileges( new Template(), $dbi, $relation, new RelationCleanup($this->dbi, $relation), new Plugins($this->dbi), ); $method = new ReflectionMethod(Privileges::class, 'getUserPrivileges'); /** @var array|null $actual */ $actual = $method->invokeArgs($serverPrivileges, ['test.user', 'test.host', true]); self::assertSame(['Host' => 'test.host', 'User' => 'test.user', 'account_locked' => 'Y'], $actual); } private function getPrivileges(DatabaseInterface $dbi): Privileges { $relation = new Relation($dbi); return new Privileges(new Template(), $dbi, $relation, new RelationCleanup($dbi, $relation), new Plugins($dbi)); } /** * data provider for testEscapeMysqlWildcards and testUnescapeMysqlWildcards * * @psalm-return list<array{string, string}> */ public static function providerUnEscapeMysqlWildcards(): array { return [ ['\_test', '_test'], ['\_\\', '_\\'], ['\\_\%', '_%'], ['\\\_', '\_'], ['\\\_\\\%', '\_\%'], ['\_\\%\_\_\%', '_%__%'], ['\%\_', '%_'], ['\\\%\\\_', '\%\_'], ]; } /** * @param string $a Expected value * @param string $b String to escape */ #[DataProvider('providerUnEscapeMysqlWildcards')] public function testEscapeMysqlWildcards(string $a, string $b): void { $dbi = $this->createDatabaseInterface(); $serverPrivileges = $this->getPrivileges($dbi); self::assertSame( $a, $serverPrivileges->escapeGrantWildcards($b), ); } /** * @param string $a String to unescape * @param string $b Expected value */ #[DataProvider('providerUnEscapeMysqlWildcards')] public function testUnescapeMysqlWildcards(string $a, string $b): void { $dbi = $this->createDatabaseInterface(); $serverPrivileges = $this->getPrivileges($dbi); self::assertSame( $b, $serverPrivileges->unescapeGrantWildcards($a), ); } }
Close