From fab87c2696b9d6a26310f1bfc024b018ca5184fe Mon Sep 17 00:00:00 2001 From: VirtualTam Date: Fri, 27 Apr 2018 22:12:22 +0200 Subject: Move LoginManager and SessionManager to the Security namespace Signed-off-by: VirtualTam --- tests/security/LoginManagerTest.php | 199 ++++++++++++++++++++++++++++++++++ tests/security/SessionManagerTest.php | 149 +++++++++++++++++++++++++ 2 files changed, 348 insertions(+) create mode 100644 tests/security/LoginManagerTest.php create mode 100644 tests/security/SessionManagerTest.php (limited to 'tests/security') diff --git a/tests/security/LoginManagerTest.php b/tests/security/LoginManagerTest.php new file mode 100644 index 00000000..b957abe3 --- /dev/null +++ b/tests/security/LoginManagerTest.php @@ -0,0 +1,199 @@ +banFile)) { + unlink($this->banFile); + } + + $this->configManager = new \FakeConfigManager([ + 'resource.ban_file' => $this->banFile, + 'resource.log' => $this->logFile, + 'security.ban_after' => 4, + 'security.ban_duration' => 3600, + 'security.trusted_proxies' => [$this->trustedProxy], + ]); + + $this->globals = &$GLOBALS; + unset($this->globals['IPBANS']); + + $this->loginManager = new LoginManager($this->globals, $this->configManager, null); + $this->server['REMOTE_ADDR'] = $this->ipAddr; + } + + /** + * Wipe test resources + */ + public function tearDown() + { + unset($this->globals['IPBANS']); + } + + /** + * Instantiate a LoginManager and load ban records + */ + public function testReadBanFile() + { + file_put_contents( + $this->banFile, + " array('127.0.0.1' => 99));\n?>" + ); + new LoginManager($this->globals, $this->configManager, null); + $this->assertEquals(99, $this->globals['IPBANS']['FAILURES']['127.0.0.1']); + } + + /** + * Record a failed login attempt + */ + public function testHandleFailedLogin() + { + $this->loginManager->handleFailedLogin($this->server); + $this->assertEquals(1, $this->globals['IPBANS']['FAILURES'][$this->ipAddr]); + + $this->loginManager->handleFailedLogin($this->server); + $this->assertEquals(2, $this->globals['IPBANS']['FAILURES'][$this->ipAddr]); + } + + /** + * Record a failed login attempt - IP behind a trusted proxy + */ + public function testHandleFailedLoginBehindTrustedProxy() + { + $server = [ + 'REMOTE_ADDR' => $this->trustedProxy, + 'HTTP_X_FORWARDED_FOR' => $this->ipAddr, + ]; + $this->loginManager->handleFailedLogin($server); + $this->assertEquals(1, $this->globals['IPBANS']['FAILURES'][$this->ipAddr]); + + $this->loginManager->handleFailedLogin($server); + $this->assertEquals(2, $this->globals['IPBANS']['FAILURES'][$this->ipAddr]); + } + + /** + * Record a failed login attempt - IP behind a trusted proxy but not forwarded + */ + public function testHandleFailedLoginBehindTrustedProxyNoIp() + { + $server = [ + 'REMOTE_ADDR' => $this->trustedProxy, + ]; + $this->loginManager->handleFailedLogin($server); + $this->assertFalse(isset($this->globals['IPBANS']['FAILURES'][$this->ipAddr])); + + $this->loginManager->handleFailedLogin($server); + $this->assertFalse(isset($this->globals['IPBANS']['FAILURES'][$this->ipAddr])); + } + + /** + * Record a failed login attempt and ban the IP after too many failures + */ + public function testHandleFailedLoginBanIp() + { + $this->loginManager->handleFailedLogin($this->server); + $this->assertEquals(1, $this->globals['IPBANS']['FAILURES'][$this->ipAddr]); + $this->assertTrue($this->loginManager->canLogin($this->server)); + + $this->loginManager->handleFailedLogin($this->server); + $this->assertEquals(2, $this->globals['IPBANS']['FAILURES'][$this->ipAddr]); + $this->assertTrue($this->loginManager->canLogin($this->server)); + + $this->loginManager->handleFailedLogin($this->server); + $this->assertEquals(3, $this->globals['IPBANS']['FAILURES'][$this->ipAddr]); + $this->assertTrue($this->loginManager->canLogin($this->server)); + + $this->loginManager->handleFailedLogin($this->server); + $this->assertEquals(4, $this->globals['IPBANS']['FAILURES'][$this->ipAddr]); + $this->assertFalse($this->loginManager->canLogin($this->server)); + + // handleFailedLogin is not supposed to be called at this point: + // - no login form should be displayed once an IP has been banned + // - yet this could happen when using custom templates / scripts + $this->loginManager->handleFailedLogin($this->server); + $this->assertEquals(5, $this->globals['IPBANS']['FAILURES'][$this->ipAddr]); + $this->assertFalse($this->loginManager->canLogin($this->server)); + } + + /** + * Nothing to do + */ + public function testHandleSuccessfulLogin() + { + $this->assertTrue($this->loginManager->canLogin($this->server)); + + $this->loginManager->handleSuccessfulLogin($this->server); + $this->assertTrue($this->loginManager->canLogin($this->server)); + } + + /** + * Erase failure records after successfully logging in from this IP + */ + public function testHandleSuccessfulLoginAfterFailure() + { + $this->loginManager->handleFailedLogin($this->server); + $this->loginManager->handleFailedLogin($this->server); + $this->assertEquals(2, $this->globals['IPBANS']['FAILURES'][$this->ipAddr]); + $this->assertTrue($this->loginManager->canLogin($this->server)); + + $this->loginManager->handleSuccessfulLogin($this->server); + $this->assertTrue($this->loginManager->canLogin($this->server)); + $this->assertFalse(isset($this->globals['IPBANS']['FAILURES'][$this->ipAddr])); + $this->assertFalse(isset($this->globals['IPBANS']['BANS'][$this->ipAddr])); + } + + /** + * The IP is not banned + */ + public function testCanLoginIpNotBanned() + { + $this->assertTrue($this->loginManager->canLogin($this->server)); + } + + /** + * The IP is banned + */ + public function testCanLoginIpBanned() + { + // ban the IP for an hour + $this->globals['IPBANS']['FAILURES'][$this->ipAddr] = 10; + $this->globals['IPBANS']['BANS'][$this->ipAddr] = time() + 3600; + + $this->assertFalse($this->loginManager->canLogin($this->server)); + } + + /** + * The IP is banned, and the ban duration is over + */ + public function testCanLoginIpBanExpired() + { + // ban the IP for an hour + $this->globals['IPBANS']['FAILURES'][$this->ipAddr] = 10; + $this->globals['IPBANS']['BANS'][$this->ipAddr] = time() + 3600; + $this->assertFalse($this->loginManager->canLogin($this->server)); + + // lift the ban + $this->globals['IPBANS']['BANS'][$this->ipAddr] = time() - 3600; + $this->assertTrue($this->loginManager->canLogin($this->server)); + } +} diff --git a/tests/security/SessionManagerTest.php b/tests/security/SessionManagerTest.php new file mode 100644 index 00000000..e4e1cfbc --- /dev/null +++ b/tests/security/SessionManagerTest.php @@ -0,0 +1,149 @@ +generateToken(); + + $this->assertEquals(1, $session['tokens'][$token]); + $this->assertEquals(40, strlen($token)); + } + + /** + * Check a session token + */ + public function testCheckToken() + { + $token = '4dccc3a45ad9d03e5542b90c37d8db6d10f2b38b'; + $session = [ + 'tokens' => [ + $token => 1, + ], + ]; + $sessionManager = new SessionManager($session, self::$conf); + + // check and destroy the token + $this->assertTrue($sessionManager->checkToken($token)); + $this->assertFalse(isset($session['tokens'][$token])); + + // ensure the token has been destroyed + $this->assertFalse($sessionManager->checkToken($token)); + } + + /** + * Generate and check a session token + */ + public function testGenerateAndCheckToken() + { + $session = []; + $sessionManager = new SessionManager($session, self::$conf); + + $token = $sessionManager->generateToken(); + + // ensure a token has been generated + $this->assertEquals(1, $session['tokens'][$token]); + $this->assertEquals(40, strlen($token)); + + // check and destroy the token + $this->assertTrue($sessionManager->checkToken($token)); + $this->assertFalse(isset($session['tokens'][$token])); + + // ensure the token has been destroyed + $this->assertFalse($sessionManager->checkToken($token)); + } + + /** + * Check an invalid session token + */ + public function testCheckInvalidToken() + { + $session = []; + $sessionManager = new SessionManager($session, self::$conf); + + $this->assertFalse($sessionManager->checkToken('4dccc3a45ad9d03e5542b90c37d8db6d10f2b38b')); + } + + /** + * Test SessionManager::checkId with a valid ID - TEST ALL THE HASHES! + * + * This tests extensively covers all hash algorithms / bit representations + */ + public function testIsAnyHashSessionIdValid() + { + foreach (self::$sidHashes as $algo => $bpcs) { + foreach ($bpcs as $bpc => $hash) { + $this->assertTrue(SessionManager::checkId($hash)); + } + } + } + + /** + * Test checkId with a valid ID - SHA-1 hashes + */ + public function testIsSha1SessionIdValid() + { + $this->assertTrue(SessionManager::checkId(sha1('shaarli'))); + } + + /** + * Test checkId with a valid ID - SHA-256 hashes + */ + public function testIsSha256SessionIdValid() + { + $this->assertTrue(SessionManager::checkId(hash('sha256', 'shaarli'))); + } + + /** + * Test checkId with a valid ID - SHA-512 hashes + */ + public function testIsSha512SessionIdValid() + { + $this->assertTrue(SessionManager::checkId(hash('sha512', 'shaarli'))); + } + + /** + * Test checkId with invalid IDs. + */ + public function testIsSessionIdInvalid() + { + $this->assertFalse(SessionManager::checkId('')); + $this->assertFalse(SessionManager::checkId([])); + $this->assertFalse( + SessionManager::checkId('c0ZqcWF3VFE2NmJBdm1HMVQ0ZHJ3UmZPbTFsNGhkNHI=') + ); + } +} -- cgit v1.2.3