From e6e4548a22a18c86295d4ecb99b6b8cca8bdeab2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20=C5=A0tancl?= Date: Wed, 20 May 2020 14:33:24 +0200 Subject: [PATCH] Use % for CREATE % GRANT queries --- assets/TenancyServiceProvider.stub.php | 1 - docker-compose.yml | 9 ++++ ...rmissionControlledMySQLDatabaseManager.php | 6 +-- tests/DatabaseUsersTest.php | 4 +- tests/TenantDatabaseManagerTest.php | 47 +++++++++++++++++++ 5 files changed, 61 insertions(+), 6 deletions(-) diff --git a/assets/TenancyServiceProvider.stub.php b/assets/TenancyServiceProvider.stub.php index 586d9ad6..cb68ed94 100644 --- a/assets/TenancyServiceProvider.stub.php +++ b/assets/TenancyServiceProvider.stub.php @@ -16,7 +16,6 @@ class TenancyServiceProvider extends ServiceProvider public function events() { return [ - // Tenant events Events\CreatingTenant::class => [], Events\TenantCreated::class => [ diff --git a/docker-compose.yml b/docker-compose.yml index d5315fb9..81cba898 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -30,6 +30,15 @@ services: MYSQL_PASSWORD: password networks: - testnet + mysql2: + image: mysql:5.7 + environment: + MYSQL_ROOT_PASSWORD: password + MYSQL_DATABASE: main + MYSQL_USER: user # redundant + MYSQL_PASSWORD: password + networks: + - testnet postgres: image: postgres:11 environment: diff --git a/src/TenantDatabaseManagers/PermissionControlledMySQLDatabaseManager.php b/src/TenantDatabaseManagers/PermissionControlledMySQLDatabaseManager.php index 7a247c6c..0855cb74 100644 --- a/src/TenantDatabaseManagers/PermissionControlledMySQLDatabaseManager.php +++ b/src/TenantDatabaseManagers/PermissionControlledMySQLDatabaseManager.php @@ -30,14 +30,14 @@ class PermissionControlledMySQLDatabaseManager extends MySQLDatabaseManager impl throw new TenantDatabaseUserAlreadyExistsException($username); } - $this->database()->statement("CREATE USER `{$username}`@`{$hostname}` IDENTIFIED BY '{$password}'"); + $this->database()->statement("CREATE USER `{$username}`@`%` IDENTIFIED BY '{$password}'"); $grants = implode(', ', static::$grants); if ($this->isVersion8()) { // MySQL 8+ - $grantQuery = "GRANT $grants ON `$database`.* TO `$username`@`$hostname`"; + $grantQuery = "GRANT $grants ON `$database`.* TO `$username`@`%`"; } else { // MySQL 5.7 - $grantQuery = "GRANT $grants ON `$database`.* TO `$username`@`$hostname` IDENTIFIED BY '$password'"; + $grantQuery = "GRANT $grants ON `$database`.* TO `$username`@`%` IDENTIFIED BY '$password'"; } return $this->database()->statement($grantQuery); diff --git a/tests/DatabaseUsersTest.php b/tests/DatabaseUsersTest.php index 01b33157..7d440572 100644 --- a/tests/DatabaseUsersTest.php +++ b/tests/DatabaseUsersTest.php @@ -89,8 +89,8 @@ class DatabaseUsersTest extends TestCase 'tenancy_db_username' => $user = 'user' . Str::random(8), ]); - $query = DB::connection('mysql')->select("SHOW GRANTS FOR `{$tenant->database()->getUsername()}`@`{$tenant->database()->connection()['host']}`")[1]; - $this->assertStringStartsWith('GRANT CREATE, ALTER, ALTER ROUTINE ON', $query->{"Grants for {$user}@mysql"}); // @mysql because that's the hostname within the docker network + $query = DB::connection('mysql')->select("SHOW GRANTS FOR `{$tenant->database()->getUsername()}`@`%`")[1]; + $this->assertStringStartsWith('GRANT CREATE, ALTER, ALTER ROUTINE ON', $query->{"Grants for {$user}@%"}); // @mysql because that's the hostname within the docker network } /** @test */ diff --git a/tests/TenantDatabaseManagerTest.php b/tests/TenantDatabaseManagerTest.php index ba579ba1..513cf603 100644 --- a/tests/TenantDatabaseManagerTest.php +++ b/tests/TenantDatabaseManagerTest.php @@ -4,6 +4,7 @@ declare(strict_types=1); namespace Stancl\Tenancy\Tests; +use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Event; use Stancl\Tenancy\Tests\Etc\Tenant; use Stancl\Tenancy\DatabaseManager; @@ -21,6 +22,7 @@ use Stancl\Tenancy\TenantDatabaseManagers\PostgreSQLSchemaManager; use Stancl\Tenancy\TenantDatabaseManagers\SQLiteDatabaseManager; use Stancl\Tenancy\Tests\TestCase; use Illuminate\Support\Str; +use PDO; class TenantDatabaseManagerTest extends TestCase { @@ -163,4 +165,49 @@ class TenantDatabaseManagerTest extends TestCase 'tenancy_db_name' => $name, ]); } + + /** @test */ + public function tenant_database_can_be_created_on_a_foreign_server() + { + config([ + 'tenancy.database_managers.mysql' => PermissionControlledMySQLDatabaseManager::class, + 'database.connections.mysql2' => [ + 'driver' => 'mysql', + 'host' => 'mysql2', // important line + 'port' => 3306, + 'database' => 'main', + 'username' => 'root', + 'password' => 'password', + 'unix_socket' => env('DB_SOCKET', ''), + 'charset' => 'utf8mb4', + 'collation' => 'utf8mb4_unicode_ci', + 'prefix' => '', + 'prefix_indexes' => true, + 'strict' => true, + 'engine' => null, + 'options' => extension_loaded('pdo_mysql') ? array_filter([ + PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'), + ]) : [], + ], + ]); + + Event::listen(TenantCreated::class, JobPipeline::make([CreateDatabase::class])->send(function (TenantCreated $event) { + return $event->tenant; + })->toListener()); + + $name = 'foo' . Str::random(8); + $tenant = Tenant::create([ + 'tenancy_db_name' => $name, + 'tenancy_db_connection' => 'mysql2', + ]); + + /** @var PermissionControlledMySQLDatabaseManager $manager */ + $manager = $tenant->database()->manager(); + + $manager->setConnection('mysql'); + $this->assertFalse($manager->databaseExists($name)); + + $manager->setConnection('mysql2'); + $this->assertTrue($manager->databaseExists($name)); + } }