128 lines
4.3 KiB
PHP
128 lines
4.3 KiB
PHP
|
|
<?php
|
||
|
|
/**
|
||
|
|
* File: tests/unit/Core/AuthServiceTest.php
|
||
|
|
*
|
||
|
|
* Author: Funky Waddle
|
||
|
|
* Date: 2026-09-12
|
||
|
|
*
|
||
|
|
* Purpose:
|
||
|
|
* Unit tests for AuthService, SessionService and TOTPService.
|
||
|
|
*/
|
||
|
|
declare(strict_types=1);
|
||
|
|
namespace Tests\unit\Core;
|
||
|
|
|
||
|
|
use SiteWeaver\Core\Config;
|
||
|
|
use SiteWeaver\Core\Repositories\UserRepository;
|
||
|
|
use SiteWeaver\Core\Services\AuthService;
|
||
|
|
use SiteWeaver\Core\Services\SessionService;
|
||
|
|
use SiteWeaver\Core\Services\TOTPService;
|
||
|
|
use SiteWeaver\Core\Models\User;
|
||
|
|
use PHPUnit\Framework\TestCase;
|
||
|
|
|
||
|
|
// Dummy TOTP service for testing
|
||
|
|
class DummyTOTPService extends TOTPService {
|
||
|
|
public function verify(string $secret, string $otp): bool { return true; }
|
||
|
|
}
|
||
|
|
|
||
|
|
final class AuthServiceTest extends TestCase
|
||
|
|
{
|
||
|
|
private Config $config;
|
||
|
|
private SessionService $session;
|
||
|
|
private AuthService $auth;
|
||
|
|
|
||
|
|
protected function setUp(): void
|
||
|
|
{
|
||
|
|
$this->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());
|
||
|
|
}
|
||
|
|
}
|