diff --git a/.travis.yml b/.travis.yml index e71ec74..a3d6b01 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,9 @@ language: php +services: + - mysql + - postgresql + php: - 5.6 - 7.0 diff --git a/CHANGELOG.md b/CHANGELOG.md index eb3db20..4d07a3c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,9 @@ Changelog Releases -------- - +* 4.0.2 + * Renamed BaseTraitTest to BaseTestTrait with alias from previous name for backwards compatibility + * Deprecated BaseTraitTest you should use BaseTestTrait * 4.0.1 * Add BaseTraitTest for permissions testing * 4.0.0 diff --git a/Docs/Documentation/Testing.md b/Docs/Documentation/Testing.md index 4143a24..47e265e 100644 --- a/Docs/Documentation/Testing.md +++ b/Docs/Documentation/Testing.md @@ -10,7 +10,7 @@ Create a new test class and extends to `IntegrationTestCase` ```php class PermissionsTest extends IntegrationTestCase { - use \CakeDC\Auth\Test\BaseTraitTest; + use \CakeDC\Auth\Test\BaseTestTrait; } ``` diff --git a/composer.json b/composer.json index 9fa8ba0..e35459f 100644 --- a/composer.json +++ b/composer.json @@ -29,7 +29,7 @@ "cakephp/cakephp": "^3.7.0" }, "require-dev": { - "phpunit/phpunit": "^6", + "phpunit/phpunit": "^5.7.14|^6.0", "league/oauth2-facebook": "@stable", "league/oauth2-instagram": "@stable", "league/oauth2-google": "@stable", diff --git a/src/Test/BaseTestTrait.php b/src/Test/BaseTestTrait.php new file mode 100644 index 0000000..8cc5231 --- /dev/null +++ b/src/Test/BaseTestTrait.php @@ -0,0 +1,119 @@ +get(Configure::read('Users.table', 'Users'))->get($id)->toArray(); + $this->session(['Auth' => ['User' => $data]]); + } + + /** + * Login as a username + * + * @param string $username The username to use. + * @return void + */ + public function loginAsUserName($username) + { + $data = TableRegistry::getTableLocator() + ->get(Configure::read('Users.table', 'Users'))->findByUsername($username)->first()->toArray(); + $this->session(['Auth' => ['User' => $data]]); + } + + /** + * @return bool + */ + protected function _isVerboseOrDebug() + { + return !empty(array_intersect(['--debug', '--verbose', '-v'], $_SERVER['argv'])); + } + + /** + * Test permission of one $url when logged as a specific $username + * + * @param string $url The est url. + * @param string $username The test username. + * @param string $method The test request method, 'post' or 'get'. + * @param string $ajax The test request is ajax or not? 'ajax' for yes and 'no-ajax' if not. + * @param string $responseCode The expected response code. + * @param string $responseContains The expected value to contains in response. When expected response code 302 it + * will check for 'Location' header, otherwise will check body response. + * @throws \PHPUnit\Exception + */ + protected function _testPermissions($url, $username, $method, $ajax, $responseCode, $responseContains) + { + if ($this->_isVerboseOrDebug()) { + (new ConsoleIo())->info(__( + "\nUrl: {0} Username: {1} Method: {2} Ajax?: {3} Response Code: {4} Response Contains: {5} ", + $url, + $username, + $method, + $ajax, + $responseCode, + $responseContains + ), 0); + } + $this->loginAsUserName($username); + if ($ajax === 'ajax') { + $_SERVER['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequest'; + } + if ($method === 'post') { + $this->enableCsrfToken(); + $this->enableSecurityToken(); + $this->post($url); + } else { + $this->get($url); + } + if ($responseCode === '200') { + $this->assertResponseOk(); + } else { + $this->assertResponseCode((int)$responseCode); + } + + if ($responseContains) { + $this->assertResponseContains($responseContains); + } else { + $this->assertEmpty((string)$this->_response->getBody()); + } + } + + /** + * Test permissions based on CSV file content, one test for each row. + * + * @param string $csv CSV name + * + * @return array + * @dataProvider provider + * @throws \PHPUnit\Exception + */ + public function testPermissions($csv) + { + $this->assertTrue(file_exists(TESTS . 'Provider' . DS . $csv)); + $rows = array_map('str_getcsv', file(TESTS . 'Provider' . DS . $csv)); + foreach ($rows as $row) { + if ($row[0][0] === '#') { + continue; + } + list($url, $username, $method, $ajax, $responseCode, $responseContains) = array_pad($row, 6, null); + $this->setUp(); + $this->_testPermissions($url, $username, $method, $ajax, $responseCode, $responseContains); + $this->tearDown(); + } + } +} + +// @deprecated 4.0.2 Add backwards compatibility alias. +class_alias('CakeDC\Auth\Test\BaseTestTrait', 'CakeDC\Auth\Test\BaseTraitTest'); diff --git a/src/Test/BaseTraitTest.php b/src/Test/BaseTraitTest.php index 774c74e..4eb71e7 100644 --- a/src/Test/BaseTraitTest.php +++ b/src/Test/BaseTraitTest.php @@ -1,109 +1,4 @@ get(Configure::read('Users.table', 'Users'))->get($id)->toArray(); - $this->session(['Auth' => ['User' => $data]]); - } - - /** - * Login as a username - * - * @param $username - * @return void - */ - public function loginAsUserName($username) - { - $data = TableRegistry::getTableLocator() - ->get(Configure::read('Users.table', 'Users'))->findByUsername($username)->first()->toArray(); - $this->session(['Auth' => ['User' => $data]]); - } - - /** - * @return bool - */ - protected function _isVerboseOrDebug() - { - return !empty(array_intersect(['--debug', '--verbose', '-v'], $_SERVER['argv'])); - } - - /** - * @param $url - * @param $username - * @param $method - * @param $ajax - * @param $responseCode - * @param $responseContains - * @throws \PHPUnit\Exception - */ - protected function _testPermissions($url, $username, $method, $ajax, $responseCode, $responseContains) - { - if ($this->_isVerboseOrDebug()) { - (new ConsoleIo())->info(__( - "\nUrl: {0} Username: {1} Method: {2} Ajax?: {3} Response Code: {4} Response Contains: {5} ", - $url, - $username, - $method, - $ajax, - $responseCode, - $responseContains - ), 0); - } - $this->loginAsUserName($username); - if ($ajax === 'ajax') { - $_SERVER['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequest'; - } - if ($method === 'post') { - $this->enableCsrfToken(); - $this->enableSecurityToken(); - $this->post($url); - } else { - $this->get($url); - } - if ($responseCode === '200') { - $this->assertResponseOk(); - } else { - $this->assertResponseCode((int)$responseCode); - } - - if ($responseContains) { - $this->assertResponseContains($responseContains); - } else { - $this->assertEmpty((string)$this->_response->getBody()); - } - } - - /** - * @param $csv - * @return array - * @dataProvider provider - */ - public function testPermissions($csv) - { - $this->assertTrue(file_exists(TESTS . 'Provider' . DS . $csv)); - $rows = array_map('str_getcsv', file(TESTS . 'Provider' . DS . $csv)); - foreach ($rows as $row) { - if ($row[0][0] === '#') { - continue; - } - list($url, $username, $method, $ajax, $responseCode, $responseContains) = array_pad($row, 6, null); - $this->setUp(); - $this->_testPermissions($url, $username, $method, $ajax, $responseCode, $responseContains); - $this->tearDown(); - } - } -} +// @deprecated 4.0.2 Load new trait and alias +trait_exists('CakeDC\Auth\Test\BaseTestTrait'); +deprecationWarning('Use CakeDC\Auth\Test\BaseTestTrait instead of CakeDC\Auth\Test\BaseTraitTest.'); diff --git a/tests/TestCase/Authenticator/CookieAuthenticatorTest.php b/tests/TestCase/Authenticator/CookieAuthenticatorTest.php index 5095e73..b57fa92 100644 --- a/tests/TestCase/Authenticator/CookieAuthenticatorTest.php +++ b/tests/TestCase/Authenticator/CookieAuthenticatorTest.php @@ -53,9 +53,11 @@ public function testPersistIdentity($setCookie, $field, array $post, array $sess $identifiers = new IdentifierCollection([ 'Authentication.Password' ]); - $request = ServerRequestFactory::fromGlobals( - ['REQUEST_URI' => '/login'] - ); + $request = new \Cake\Http\ServerRequest(); + $uri = new \Zend\Diactoros\Uri('/login'); + $uri->base = null; + $request = $request->withUri($uri); + $request = $request->withParsedBody($post); $request->getSession()->write('CookieAuth', $session); $response = new Response(); diff --git a/tests/TestCase/Authenticator/TwoFactorAuthenticatorTest.php b/tests/TestCase/Authenticator/TwoFactorAuthenticatorTest.php index 3dee4cd..a194e09 100644 --- a/tests/TestCase/Authenticator/TwoFactorAuthenticatorTest.php +++ b/tests/TestCase/Authenticator/TwoFactorAuthenticatorTest.php @@ -26,10 +26,7 @@ class TwoFactorAuthenticatorTest extends TestCase */ public function testAuthenticateFailedNoData() { - $request = ServerRequestFactory::fromGlobals( - ['REQUEST_URI' => '/testpath'], - [] - ); + $request = $this->requestWithTestPath(); $response = new Response(); $identifiers = new IdentifierCollection([ 'Authentication.Password' @@ -50,10 +47,8 @@ public function testAuthenticateFailedNoData() */ public function testAuthenticateFailedInvalidUrl() { - $request = ServerRequestFactory::fromGlobals( - ['REQUEST_URI' => '/testpath'], - [] - ); + $request = $this->requestWithTestPath(); + $request->getSession()->write( TwoFactorAuthenticator::USER_SESSION_KEY, new Entity([ @@ -82,10 +77,7 @@ public function testAuthenticateFailedInvalidUrl() */ public function testAuthenticate() { - $request = ServerRequestFactory::fromGlobals( - ['REQUEST_URI' => '/testpath'], - [] - ); + $request = $this->requestWithTestPath(); $request->getSession()->write( TwoFactorAuthenticator::USER_SESSION_KEY, new Entity([ @@ -106,4 +98,16 @@ public function testAuthenticate() $this->assertInstanceOf(Result::class, $result); $this->assertEquals(Result::SUCCESS, $result->getStatus()); } + + /** + * @return \Cake\Http\ServerRequest + */ + protected function requestWithTestPath() + { + $request = new \Cake\Http\ServerRequest(); + $uri = new \Zend\Diactoros\Uri('/testpath'); + $uri->base = null; + + return $request->withUri($uri); + } } diff --git a/tests/TestCase/Rbac/RbacTest.php b/tests/TestCase/Rbac/RbacTest.php index 1c21fe7..1122814 100644 --- a/tests/TestCase/Rbac/RbacTest.php +++ b/tests/TestCase/Rbac/RbacTest.php @@ -14,8 +14,8 @@ use CakeDC\Auth\Rbac\Rbac; use CakeDC\Auth\Rbac\Rules\Owner; use Cake\Http\ServerRequest; +use Cake\Routing\Router; use Cake\TestSuite\TestCase; -use Cake\Utility\Hash; use Psr\Log\LogLevel; use ReflectionClass; @@ -1122,6 +1122,27 @@ function () { //expected true, ], + 'named-route' => [ + //permissions + [[ + 'plugin' => 'CakeDC/Users', + 'controller' => 'Users', + 'action' => '*', + 'role' => 'admin', + ]], + //user + [ + 'id' => 1, + 'username' => 'luke', + 'role' => 'admin', + ], + //request + [ + '_name' => 'testNamed', + ], + //expected + true, + ], ]; } @@ -1285,14 +1306,10 @@ public function badPermissionProvider() */ protected function _requestFromArray($params) { - $request = new ServerRequest(); + $request = new ServerRequest(Router::url($params)); + $params = Router::parseRequest($request); - return $request - ->withParam('plugin', Hash::get($params, 'plugin')) - ->withParam('controller', Hash::get($params, 'controller')) - ->withParam('action', Hash::get($params, 'action')) - ->withParam('prefix', Hash::get($params, 'prefix')) - ->withParam('_ext', Hash::get($params, '_ext')); + return $request->withAttribute('params', $params); } public function testGetPermissions() diff --git a/tests/config/routes.php b/tests/config/routes.php index bf16b6f..c455986 100644 --- a/tests/config/routes.php +++ b/tests/config/routes.php @@ -1,6 +1,91 @@ 'CakeDC/Users', - 'controller' => 'Users', - 'action' => 'myTest' -]); +use \Cake\Routing\Router; + +Router::defaultRouteClass(\Cake\Routing\Route\DashedRoute::class); + +Router::scope('/', function (\Cake\Routing\RouteBuilder $routes) { + $routes->setExtensions(['other']); + $routes->connect('/my-test', [ + 'plugin' => 'CakeDC/Users', + 'controller' => 'Users', + 'action' => 'myTest' + ]); + $routes->connect('/test-named', [ + 'plugin' => 'CakeDC/Users', + 'controller' => 'Users', + 'action' => 'myTest' + ], [ + '_name' => 'testNamed', + ]); + $routes->connect('/tests/tests/test', [ + 'plugin' => 'Tests', + 'controller' => 'Tests', + 'action' => 'test', + ]); + $routes->connect('/tests/tests/one', [ + 'plugin' => 'Tests', + 'controller' => 'Tests', + 'action' => 'one', + ]); + $routes->connect('/tests/tests/three', [ + 'plugin' => 'Tests', + 'controller' => 'Tests', + 'action' => 'three', + ]); + $routes->connect('/tests/tests/any', [ + 'plugin' => 'Tests', + 'controller' => 'Tests', + 'action' => 'any', + ]); + $routes->connect('/tests/test-tests/test-action', [ + 'plugin' => 'Tests', + 'controller' => 'TestTests', + 'action' => 'testAction', + ]); + $routes->connect('/tests2/test-tests/test-action', [ + 'plugin' => 'tests', + 'controller' => 'test-tests', + 'action' => 'test-action', + ]); + $routes->connect('/any/any/any', [ + 'plugin' => 'Any', + 'controller' => 'Any', + 'action' => 'any', + ]); + $routes->connect('/any/tests/test', [ + 'plugin' => 'Any', + 'controller' => 'Tests', + 'action' => 'test', + ]); + $routes->connect('/something/something/test', [ + 'plugin' => 'Something', + 'controller' => 'Something', + 'action' => 'test', + ]); + $routes->connect('/something/something/something', [ + 'plugin' => 'Something', + 'controller' => 'Something', + 'action' => 'something', + ]); + $routes->connect('/csv/tests/one', [ + 'prefix' => 'csv', + 'controller' => 'Tests', + 'action' => 'one', + ]); + + $routes->fallbacks(\Cake\Routing\Route\DashedRoute::class); + + $routes->setExtensions(['csv']); + $routes->connect('/tests/one', [ + 'controller' => 'Tests', + 'action' => 'one', + ]); +}); + +Router::scope('/admin', ['prefix' => 'admin'], function (\Cake\Routing\RouteBuilder $routes) { + $routes->setExtensions(['other', 'csv']); + $routes->connect('/tests/one', [ + 'controller' => 'Tests', + 'action' => 'one', + ]); +});