Skip to content

Commit

Permalink
Firewall->getExpirationTime() + more tests
Browse files Browse the repository at this point in the history
  • Loading branch information
mabar committed Jul 23, 2021
1 parent c020556 commit 56e4bbb
Show file tree
Hide file tree
Showing 7 changed files with 174 additions and 3 deletions.
1 change: 1 addition & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,7 @@ $firewall->login($identity);
$firewall->isLoggedIn(); // true
$firewall->getIdentity(); // $identity
$firewall->getAuthenticationTime(); // Instant
$firewall->getExpirationTime(); // Instant|null
$firewall->hasRole($role); // bool
$firewall->isAllowed($privilege); // bool
```
Expand Down
15 changes: 15 additions & 0 deletions src/Authentication/BaseFirewall.php
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,21 @@ public function getAuthenticationTime(): Instant
return $login->getAuthenticationTime();
}

public function getExpirationTime(): ?Instant
{
$login = $this->fetchCurrentLogin();

if ($login === null) {
throw NotLoggedIn::create(static::class, __FUNCTION__);
}

$expiration = $login->getExpiration();

return $expiration === null
? null
: $expiration->getTime();
}

public function hasRole(string $role): bool
{
$identity = $this->fetchIdentity();
Expand Down
5 changes: 5 additions & 0 deletions src/Authentication/Firewall.php
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,11 @@ public function hasPrivilege(string $privilege): bool;
*/
public function getAuthenticationTime(): Instant;

/**
* @throws NotLoggedIn
*/
public function getExpirationTime(): ?Instant;

/**
* @throws NotLoggedIn
*/
Expand Down
40 changes: 40 additions & 0 deletions tests/Doubles/TestingArrayLoginStorage.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?php declare(strict_types = 1);

namespace Tests\Orisai\Auth\Doubles;

use Orisai\Auth\Authentication\Data\Logins;
use Orisai\Auth\Authentication\LoginStorage;
use function random_int;

final class TestingArrayLoginStorage implements LoginStorage
{

/** @var array<Logins> */
private array $logins = [];

/** @var array<int> */
private array $tokens = [];

public function getLogins(string $namespace): Logins
{
return $this->logins[$namespace]
?? ($this->logins[$namespace] = new Logins());
}

public function regenerateSecurityToken(string $namespace): void
{
$this->tokens[$namespace] = random_int(0, 1_000_000);
}

public function alreadyExists(string $namespace): bool
{
return isset($this->logins[$namespace]);
}

public function getToken(string $namespace): int
{
return $this->tokens[$namespace]
?? ($this->tokens[$namespace] = random_int(0, 1_000_000));
}

}
2 changes: 1 addition & 1 deletion tests/Doubles/TestingFirewall.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public function __construct(
$this->namespace = $namespace;
}

protected function getNamespace(): string
public function getNamespace(): string
{
return $this->namespace;
}
Expand Down
104 changes: 104 additions & 0 deletions tests/Unit/Authentication/BaseFirewallTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
use Tests\Orisai\Auth\Doubles\AlwaysPassIdentityRenewer;
use Tests\Orisai\Auth\Doubles\NeverPassIdentityRenewer;
use Tests\Orisai\Auth\Doubles\NewIdentityIdentityRenewer;
use Tests\Orisai\Auth\Doubles\TestingArrayLoginStorage;
use Tests\Orisai\Auth\Doubles\TestingFirewall;
use Throwable;
use function array_keys;
Expand Down Expand Up @@ -289,6 +290,44 @@ public function testRenewerRemovedIdentity(): void
self::assertSame($firewall::REASON_INVALID_IDENTITY, $expired->getLogoutReason());
}

public function testSecurityTokenRegenerates(): void
{
$storage = new TestingArrayLoginStorage();
$renewer = new NeverPassIdentityRenewer();
$firewall = new TestingFirewall(
$storage,
$renewer,
$this->authorizer(),
);
$namespace = $firewall->getNamespace();
$identity = new IntIdentity(123, []);

$token1 = $storage->getToken($namespace);
$token2 = $storage->getToken($namespace);
self::assertSame($token1, $token2);

$firewall->login($identity);
$token3 = $storage->getToken($namespace);
self::assertNotSame($token2, $token3);

$firewall->login($identity);
$token4 = $storage->getToken($namespace);
self::assertNotSame($token3, $token4);

$firewall->logout();
$token5 = $storage->getToken($namespace);
self::assertNotSame($token4, $token5);

$firewall->login($identity);
$token6 = $storage->getToken($namespace);

$firewall->resetLoginsChecks();
self::assertFalse($firewall->isLoggedIn());

$token7 = $storage->getToken($namespace);
self::assertNotSame($token6, $token7);
}

public function testTimeExpiredIdentity(): void
{
$clock = new FixedClock(Instant::now());
Expand Down Expand Up @@ -367,6 +406,30 @@ public function testExpirationTimeInThePast(): void
$firewall->setExpiration(Instant::now()->minusSeconds(10));
}

public function testExpirationTimeIsRightNow(): void
{
$storage = new ArrayLoginStorage();
$clock = new FixedClock(Instant::of(1));
$firewall = new TestingFirewall(
$storage,
$this->renewer(),
$this->authorizer(),
$clock,
);
$identity = new IntIdentity(123, []);

$firewall->login($identity);

$this->expectException(InvalidArgument::class);
$this->expectExceptionMessage(<<<'MSG'
Context: Trying to set login expiration time.
Problem: Expiration time is lower than current time.
Solution: Choose expiration time which is in future.
MSG);

$firewall->setExpiration($clock->getTime());
}

public function testExpirationCannotBeSet(): void
{
$storage = new ArrayLoginStorage();
Expand All @@ -383,6 +446,47 @@ public function testExpirationCannotBeSet(): void
$firewall->setExpiration(Instant::now()->minusSeconds(10));
}

public function testGetExpirationTime(): void
{
$storage = new ArrayLoginStorage();
$clock = new FixedClock(Instant::of(1));
$firewall = new TestingFirewall(
$storage,
$this->renewer(),
$this->authorizer(),
$clock,
);

$identity = new IntIdentity(123, []);

$firewall->login($identity);
self::assertNull($firewall->getExpirationTime());

$expiration = Instant::of(5);
$firewall->setExpiration($expiration);
self::assertSame(5, $firewall->getExpirationTime()->getEpochSecond());

$firewall->resetLoginsChecks();
$clock->move(1);
self::assertSame(6, $firewall->getExpirationTime()->getEpochSecond());
}

public function testNotLoggedInGetExpirationTime(): void
{
$storage = new ArrayLoginStorage();
$firewall = new TestingFirewall($storage, $this->renewer(), $this->authorizer());

$this->expectException(NotLoggedIn::class);
$this->expectExceptionMessage(<<<'MSG'
Context: Calling Tests\Orisai\Auth\Doubles\TestingFirewall->getExpirationTime().
Problem: User is not logged in firewall.
Solution: Login with TestingFirewall->login($identity) or check with
TestingFirewall->isLoggedIn().
MSG);

$firewall->getExpirationTime();
}

public function testNotLoggedInGetIdentity(): void
{
$storage = new ArrayLoginStorage();
Expand Down
10 changes: 8 additions & 2 deletions tests/Unit/Authorization/PrivilegeAuthorizerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -663,15 +663,21 @@ public function testOverrideAllowThenDenyFromMostSpecific(): void
self::assertFalse($authorizer->isAllowed($identity, 'article'));
}

public function testAuthorizerDontDefineAllIdentityRoles(): void
public function testSkipUnknownRoles(): void
{
$authorizer = new PrivilegeAuthorizer($this->policies());
$identity = new IntIdentity(1, ['not-defined-by-authorizer']);
$identity = new IntIdentity(1, ['unknown']);

$authorizer->addRole('known');
$authorizer->addPrivilege('something');
$authorizer->allow('known', 'something');

self::assertFalse($authorizer->hasPrivilege($identity, 'something'));
self::assertFalse($authorizer->isAllowed($identity, 'something'));

$identity = new IntIdentity(1, ['unknown', 'known']);
self::assertTrue($authorizer->hasPrivilege($identity, 'something'));
self::assertTrue($authorizer->isAllowed($identity, 'something'));
}

public function testAllowChecksRole(): void
Expand Down

0 comments on commit 56e4bbb

Please sign in to comment.