diff --git a/src/Auth/Adapters/JwtAuthAdapter.php b/src/Auth/Adapters/JwtAuthAdapter.php index daed3a4b..db91f780 100644 --- a/src/Auth/Adapters/JwtAuthAdapter.php +++ b/src/Auth/Adapters/JwtAuthAdapter.php @@ -41,14 +41,16 @@ class JwtAuthAdapter implements AuthenticatableInterface protected JwtToken $jwt; /** + * @param array $config * @throws AuthException */ - public function __construct(AuthServiceInterface $authService, Mailer $mailer, Hasher $hasher, JwtToken $jwt) + public function __construct(AuthServiceInterface $authService, Mailer $mailer, Hasher $hasher, JwtToken $jwt, array $config = []) { $this->authService = $authService; $this->mailer = $mailer; $this->hasher = $hasher; $this->jwt = $jwt; + $this->config = $config; $this->verifySchema($this->authService->userSchema()); } diff --git a/src/Auth/Adapters/SessionAuthAdapter.php b/src/Auth/Adapters/SessionAuthAdapter.php index c095ca52..3e051a15 100644 --- a/src/Auth/Adapters/SessionAuthAdapter.php +++ b/src/Auth/Adapters/SessionAuthAdapter.php @@ -40,16 +40,18 @@ class SessionAuthAdapter implements AuthenticatableInterface { use AuthTrait; - private const REMEMBER_TOKEN_LIFETIME = 2592000; + private const DEFAULT_REMEMBER_LIFETIME = 2592000; /** + * @param array $config * @throws AuthException */ - public function __construct(AuthServiceInterface $authService, Mailer $mailer, Hasher $hasher) + public function __construct(AuthServiceInterface $authService, Mailer $mailer, Hasher $hasher, array $config = []) { $this->authService = $authService; $this->mailer = $mailer; $this->hasher = $hasher; + $this->config = $config; $this->verifySchema($this->authService->userSchema()); } @@ -203,10 +205,12 @@ private function setRememberToken(User $user): void [$this->keyFields[AuthKeys::REMEMBER_TOKEN] => $rememberToken] ); + $rememberLifetime = $this->config['session']['remember_lifetime'] ?? self::DEFAULT_REMEMBER_LIFETIME; + cookie()->set( $this->keyFields[AuthKeys::REMEMBER_TOKEN], $rememberToken, - self::REMEMBER_TOKEN_LIFETIME, + $rememberLifetime, '/', '', true, diff --git a/src/Auth/Factories/AuthFactory.php b/src/Auth/Factories/AuthFactory.php index 985b4f2a..bf2c9b12 100644 --- a/src/Auth/Factories/AuthFactory.php +++ b/src/Auth/Factories/AuthFactory.php @@ -89,10 +89,11 @@ public static function get(?string $adapter = null): Auth private static function createInstance(string $adapterClass, string $adapter): Auth { $authService = self::createAuthService($adapter); + $authConfig = (array) config()->get('auth'); $adapterInstance = $adapter === AuthType::JWT - ? new $adapterClass($authService, mailer(), new Hasher(), self::createJwtInstance()) - : new $adapterClass($authService, mailer(), new Hasher()); + ? new $adapterClass($authService, mailer(), new Hasher(), self::createJwtInstance(), $authConfig) + : new $adapterClass($authService, mailer(), new Hasher(), $authConfig); if (!$adapterInstance instanceof AuthenticatableInterface) { throw AuthException::adapterNotSupported($adapter); diff --git a/src/Auth/Traits/AuthTrait.php b/src/Auth/Traits/AuthTrait.php index 5a4c7505..faaff53e 100644 --- a/src/Auth/Traits/AuthTrait.php +++ b/src/Auth/Traits/AuthTrait.php @@ -46,6 +46,11 @@ trait AuthTrait protected int $otpLength = 6; + /** + * @var array + */ + protected array $config = []; + /** * @var array */ @@ -219,7 +224,7 @@ protected function twoStepVerification(User $user): string $time = new DateTime(); - $time->add(new DateInterval('PT' . config()->get('auth.otp_expires') . 'M')); + $time->add(new DateInterval('PT' . ($this->config['otp_expires'] ?? 2) . 'M')); $this->authService->update( $this->keyFields[AuthKeys::USERNAME], @@ -354,6 +359,6 @@ protected function verifySchema(array $schema): void protected function isTwoFactorEnabled(): bool { - return filter_var(config()->get('auth.two_fa'), FILTER_VALIDATE_BOOLEAN); + return filter_var($this->config['two_fa'] ?? false, FILTER_VALIDATE_BOOLEAN); } } diff --git a/src/Module/Templates/DemoApi/src/config/auth.php.tpl b/src/Module/Templates/DemoApi/src/config/auth.php.tpl index 9bdb0f86..a36feb64 100644 --- a/src/Module/Templates/DemoApi/src/config/auth.php.tpl +++ b/src/Module/Templates/DemoApi/src/config/auth.php.tpl @@ -10,6 +10,7 @@ return [ 'session' => [ 'service' => {{MODULE_NAMESPACE}}\Services\AuthService::class, + 'remember_lifetime' => env('REMEMBER_LIFETIME', 2592000), ], 'jwt' => [ diff --git a/src/Module/Templates/DemoWeb/src/config/auth.php.tpl b/src/Module/Templates/DemoWeb/src/config/auth.php.tpl index 29446681..3ad8fd67 100644 --- a/src/Module/Templates/DemoWeb/src/config/auth.php.tpl +++ b/src/Module/Templates/DemoWeb/src/config/auth.php.tpl @@ -10,6 +10,7 @@ return [ 'session' => [ 'service' => {{MODULE_NAMESPACE}}\Services\AuthService::class, + 'remember_lifetime' => env('REMEMBER_LIFETIME', 2592000), ], 'jwt' => [ diff --git a/tests/Unit/Auth/Adapters/JwtAuthAdapterTest.php b/tests/Unit/Auth/Adapters/JwtAuthAdapterTest.php index f75cd661..a7d8d54e 100644 --- a/tests/Unit/Auth/Adapters/JwtAuthAdapterTest.php +++ b/tests/Unit/Auth/Adapters/JwtAuthAdapterTest.php @@ -16,9 +16,17 @@ class JwtAuthAdapterTest extends AuthTestCase public function setUp(): void { - parent::setUp(); + $this->jwtAuth = $this->createJwtAuth(); + + $admin = $this->jwtAuth->signup($this->adminUser); + + $this->jwtAuth->activate($admin->getFieldValue('activation_token')); + } + + private function createJwtAuth(): JwtAuthAdapter + { $jwt = (new JwtToken()) ->setLeeway(1) ->setClaims([ @@ -30,11 +38,13 @@ public function setUp(): void 'exp' => time() + 60, ]); - $this->jwtAuth = new JwtAuthAdapter($this->authService, $this->mailer, (new Hasher())->setCost(4), $jwt); - - $admin = $this->jwtAuth->signup($this->adminUser); - - $this->jwtAuth->activate($admin->getFieldValue('activation_token')); + return new JwtAuthAdapter( + $this->authService, + $this->mailer, + (new Hasher())->setCost(4), + $jwt, + (array) config()->get('auth') + ); } public function tearDown(): void @@ -60,7 +70,8 @@ public function testApiSigninIncorrectCredentials(): void public function testApiSigninCorrectCredentials(): void { - config()->set('TWO_FA', false); + config()->set('auth.two_fa', false); + $this->jwtAuth = $this->createJwtAuth(); $this->assertIsArray($this->jwtAuth->signin('admin@qt.com', 'qwerty')); @@ -148,8 +159,8 @@ public function testApiForgetReset(): void public function testApiVerifyOtp(): void { config()->set('auth.two_fa', true); - config()->set('auth.otp_expires', 2); + $this->jwtAuth = $this->createJwtAuth(); $otp_token = $this->jwtAuth->signin('admin@qt.com', 'qwerty'); @@ -163,8 +174,8 @@ public function testApiVerifyOtp(): void public function testApiSigninWithoutVerification(): void { config()->set('auth.two_fa', false); - config()->set('auth.otp_expires', 2); + $this->jwtAuth = $this->createJwtAuth(); $this->assertArrayHasKey('access_token', $this->jwtAuth->signin('admin@qt.com', 'qwerty')); @@ -174,8 +185,8 @@ public function testApiSigninWithoutVerification(): void public function testApiSigninWithVerification(): void { config()->set('auth.two_fa', true); - config()->set('auth.otp_expires', 2); + $this->jwtAuth = $this->createJwtAuth(); $this->assertIsString($this->jwtAuth->signin('admin@qt.com', 'qwerty')); } @@ -183,8 +194,8 @@ public function testApiSigninWithVerification(): void public function testApiResendOtp(): void { config()->set('auth.two_fa', true); - config()->set('auth.otp_expires', 2); + $this->jwtAuth = $this->createJwtAuth(); $otp_token = $this->jwtAuth->signin('admin@qt.com', 'qwerty'); diff --git a/tests/Unit/Auth/Adapters/SessionAuthAdapterTest.php b/tests/Unit/Auth/Adapters/SessionAuthAdapterTest.php index a3f2c401..48e707e3 100644 --- a/tests/Unit/Auth/Adapters/SessionAuthAdapterTest.php +++ b/tests/Unit/Auth/Adapters/SessionAuthAdapterTest.php @@ -19,13 +19,23 @@ public function setUp(): void config()->set('auth.two_fa', false); - $this->sessionAuth = new SessionAuthAdapter($this->authService, $this->mailer, (new Hasher())->setCost(4)); + $this->sessionAuth = $this->createSessionAuth(); $admin = $this->sessionAuth->signup($this->adminUser); $this->sessionAuth->activate($admin->getFieldValue('activation_token')); } + private function createSessionAuth(): SessionAuthAdapter + { + return new SessionAuthAdapter( + $this->authService, + $this->mailer, + (new Hasher())->setCost(4), + (array) config()->get('auth') + ); + } + public function tearDown(): void { self::$users = []; @@ -157,8 +167,8 @@ public function testWebForgetReset(): void public function testWebVerifyOtp(): void { config()->set('auth.two_fa', true); - config()->set('auth.otp_expires', 2); + $this->sessionAuth = $this->createSessionAuth(); $otp_token = $this->sessionAuth->signin('admin@qt.com', 'qwerty'); @@ -168,8 +178,8 @@ public function testWebVerifyOtp(): void public function testWebSigninWithoutVerification(): void { config()->set('auth.two_fa', false); - config()->set('auth.otp_expires', 2); + $this->sessionAuth = $this->createSessionAuth(); $this->assertTrue($this->sessionAuth->signin('admin@qt.com', 'qwerty')); } @@ -177,8 +187,8 @@ public function testWebSigninWithoutVerification(): void public function testWebSigninWithVerification(): void { config()->set('auth.two_fa', true); - config()->set('auth.otp_expires', 2); + $this->sessionAuth = $this->createSessionAuth(); $this->assertIsString($this->sessionAuth->signin('admin@qt.com', 'qwerty')); } @@ -186,8 +196,8 @@ public function testWebSigninWithVerification(): void public function testWebResendOtp(): void { config()->set('auth.two_fa', true); - config()->set('auth.otp_expires', 2); + $this->sessionAuth = $this->createSessionAuth(); $otp_token = $this->sessionAuth->signin('admin@qt.com', 'qwerty'); @@ -219,4 +229,14 @@ public function testWebRefreshUser(): void $this->assertEquals('Human', $refreshedUser->lastname); } + + public function testWebRememberTokenLifetimeIsConfigurable(): void + { + config()->set('auth.session.remember_lifetime', 86400); + $this->sessionAuth = $this->createSessionAuth(); + + $this->sessionAuth->signin('admin@qt.com', 'qwerty', true); + + $this->assertTrue(cookie()->has('remember_token')); + } } diff --git a/tests/Unit/Auth/AuthTest.php b/tests/Unit/Auth/AuthTest.php index 6bfa7a88..a76d3d6e 100644 --- a/tests/Unit/Auth/AuthTest.php +++ b/tests/Unit/Auth/AuthTest.php @@ -35,18 +35,20 @@ public function setUp(): void public function testAuthGetAdapter(): void { - $auth = new Auth(new SessionAuthAdapter($this->authService, $this->mailer, $this->hasher)); + $authConfig = (array) config()->get('auth'); + + $auth = new Auth(new SessionAuthAdapter($this->authService, $this->mailer, $this->hasher, $authConfig)); $this->assertInstanceOf(AuthenticatableInterface::class, $auth->getAdapter()); - $auth = new Auth(new JwtAuthAdapter($this->authService, $this->mailer, $this->hasher, $this->jwt)); + $auth = new Auth(new JwtAuthAdapter($this->authService, $this->mailer, $this->hasher, $this->jwt, $authConfig)); $this->assertInstanceOf(AuthenticatableInterface::class, $auth->getAdapter()); } public function testAuthCallingValidMethod(): void { - $auth = new Auth(new JwtAuthAdapter($this->authService, $this->mailer, $this->hasher, $this->jwt)); + $auth = new Auth(new JwtAuthAdapter($this->authService, $this->mailer, $this->hasher, $this->jwt, (array) config()->get('auth'))); $user = $auth->getAdapter()->signup($this->adminUser); @@ -61,7 +63,7 @@ public function testAuthCallingValidMethod(): void public function testAuthCallingInvalidMethod(): void { - $auth = new Auth(new JwtAuthAdapter($this->authService, $this->mailer, $this->hasher, $this->jwt)); + $auth = new Auth(new JwtAuthAdapter($this->authService, $this->mailer, $this->hasher, $this->jwt, (array) config()->get('auth'))); $this->expectException(AuthException::class); diff --git a/tests/_root/shared/config/auth.php b/tests/_root/shared/config/auth.php index 53a5c8db..a842a160 100644 --- a/tests/_root/shared/config/auth.php +++ b/tests/_root/shared/config/auth.php @@ -5,6 +5,7 @@ 'session' => [ 'service' => Quantum\Tests\_root\modules\Test\Services\AuthService::class, + 'remember_lifetime' => env('REMEMBER_LIFETIME', 2592000), ], 'jwt' => [