session = new SessionService(); $this->session->start(); $this->config = new Config(); $this->user_repo = $this->createMock(UserRepository::class); $this->auth = new AuthService($this->config, $this->session, $this->user_repo); } protected function tearDown(): void { $this->session->destroy(); } public function testRegisterAndLoginWithPassword(): void { $user = $this->auth->register('alice', 'alice@example.com', 'secret123'); $this->assertInstanceOf(User::class, $user); $mockUser = new \SiteWeaver\Core\Models\User(1, 'alice', 'alice@example.com', 'secret123'); $mockUser->setHashedPassword(password_hash('secret123', PASSWORD_DEFAULT)); $this->user_repo->method('findByUsername')->willReturn($mockUser); $this->user_repo->method('findById')->willReturn($mockUser); // login should succeed with correct password $result = $this->auth->login('alice', 'secret123'); $this->assertTrue($result); } public function testLoginWithTOTP(): void { // register user and enable TOTP $user = new \SiteWeaver\Core\Models\User(1, 'bob', 'bob@example.com', 'password'); $user->setHashedPassword(password_hash('password', PASSWORD_DEFAULT)); $user->setTotpSecret('dummysecret'); $this->user_repo->method('findByUsername')->willReturn($user); $this->user_repo->method('findById')->willReturn($user); // set dummy TOTP service that always verifies $totp = new DummyTOTPService(); $this->auth->setTOTPService($totp); // login without OTP should fail $this->assertFalse($this->auth->login('bob', 'password')); // login with OTP should succeed $this->assertTrue($this->auth->login('bob', 'password', '123456')); } public function testAuthMiddlewareAccessControl(): void { // register and log in a user $user = new \SiteWeaver\Core\Models\User(1, 'carol', 'carol@example.com', 'pass'); $user->setHashedPassword(password_hash('pass', PASSWORD_DEFAULT)); $this->user_repo->method('findByUsername')->willReturn($user); $this->user_repo->method('findById')->willReturn($user); $this->auth->login('carol', 'pass'); // instantiate middleware $middleware = new \SiteWeaver\Core\Middleware\AuthMiddleware($this->auth); // should not throw exception for authenticated user $this->expectNotToPerformAssertions(); $middleware->handle(); // logout user by removing session key $this->session->remove('user_id'); // handle should now throw RuntimeException $this->expectException(\RuntimeException::class); $this->expectExceptionMessage('Unauthorized'); $middleware->handle(); } public function testLogout(): void { // ensure user is logged in $user = new \SiteWeaver\Core\Models\User(1, 'alice', 'alice@example.com', 'secret123'); $user->setHashedPassword(password_hash('secret123', PASSWORD_DEFAULT)); $this->user_repo->method('findByUsername')->willReturn($user); $this->user_repo->method('findById')->willReturn($user); $this->auth->login('alice', 'secret123'); $this->assertTrue($this->auth->isAuthenticated()); // logout should clear session $this->auth->logout(); $this->assertFalse($this->auth->isAuthenticated()); } }