Skip to content
This repository has been archived by the owner on Jun 29, 2022. It is now read-only.

AutoLoginMiddleware #218 #235

Merged
merged 39 commits into from May 6, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
4092e59
AutoLoginMiddleware #218
mapeveri Apr 1, 2020
08ba4fd
Fix types #218
mapeveri Apr 3, 2020
00c872e
More tests and general adjustments #218
mapeveri Apr 4, 2020
d5f52bf
Adjustments in methods and tests #218
mapeveri Apr 4, 2020
6d2685d
Change name of method and fix description #218
mapeveri Apr 6, 2020
f1654e2
Logger interface for warning in error authentication #218
mapeveri Apr 7, 2020
61632e1
Cookie login #218
mapeveri Apr 8, 2020
a07ecbc
Fix style #218
mapeveri Apr 8, 2020
e7de628
Remove cookie remeber in logout #218
mapeveri Apr 11, 2020
80442d2
Change to DateTimeImmutable and fix tests #218
mapeveri Apr 12, 2020
a1841aa
Improvements tests #218
mapeveri Apr 12, 2020
02558b9
Fix typos in exception messages, remove unused import
samdark Apr 16, 2020
47969ef
Response cookie #218
mapeveri Apr 18, 2020
b6ccd4a
Fix type hinting #218
mapeveri Apr 18, 2020
0447c0b
Merge branch 'master' of https://github.com/yiisoft/yii-web
mapeveri Apr 18, 2020
6a33a34
Fix remove cookie #218
mapeveri Apr 18, 2020
ff1099d
Merge branch 'master' of https://github.com/yiisoft/yii-web
mapeveri Apr 25, 2020
24a3a6f
Remove IdentityInterface from User #218
mapeveri Apr 25, 2020
f46eeb8
Rename AuthenticationKeyInterface -> AutoLoginIdentityInterface
samdark May 5, 2020
be8f65b
Lay out feature structure
samdark May 5, 2020
5f39cab
Merge branch 'master' into master-mapeveri
samdark May 5, 2020
9e111ec
Adjust AutoLogin to use new cookie methods
samdark May 5, 2020
35d2427
Adjust cookie name
samdark May 5, 2020
7a1be2b
Rename variable
samdark May 5, 2020
bba7ab6
Throw exception if repository does not return an interface needed
samdark May 5, 2020
9a82efd
Cleanup, adjust tests
samdark May 5, 2020
9f1dc6a
Use better names
samdark May 6, 2020
d3b128f
Fixes
samdark May 6, 2020
9386ec5
Make duration required argument of AutoLogin
samdark May 6, 2020
ecb4587
Automatically deal with Cookie in AutoLoginMiddleware
samdark May 6, 2020
6dfc980
Fix tests
samdark May 6, 2020
af47ab7
Add AutoLogin tests, fix code
samdark May 6, 2020
53c0d03
Fix code style
samdark May 6, 2020
d70bde1
Add strict types
samdark May 6, 2020
a93c8d6
Finalize AutoLogin, add test stubs
samdark May 6, 2020
ada9831
Remove tests stubs I have no idea on how to implement :(
samdark May 6, 2020
4db5e3a
Merge branch 'master' into master-mapeveri
samdark May 6, 2020
72d71f1
Do not encode cookie manually
samdark May 6, 2020
e89d374
Add strict types
samdark May 6, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
67 changes: 64 additions & 3 deletions src/User/AutoLoginMiddleware.php
Expand Up @@ -2,15 +2,76 @@

namespace Yiisoft\Yii\Web\User;

use Psr\Http\Server\RequestHandlerInterface;
use Psr\Http\Message\ResponseFactoryInterface;
samdark marked this conversation as resolved.
Show resolved Hide resolved
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Yiisoft\Auth\IdentityInterface;
use Yiisoft\Auth\IdentityRepositoryInterface;
use Yiisoft\Yii\Web\User\User;
samdark marked this conversation as resolved.
Show resolved Hide resolved

/**
* AutoLoginMiddleware automatically logs user in based on "remember me" cookie
*/
class AutoLoginMiddleware
class AutoLoginMiddleware implements MiddlewareInterface
roxblnfk marked this conversation as resolved.
Show resolved Hide resolved
{
private User $user;
private IdentityRepositoryInterface $identityRepository;

public function __construct(User $user)
{
public function __construct(
User $user,
IdentityRepositoryInterface $identityRepository
) {
$this->user = $user;
$this->identityRepository = $identityRepository;
}

public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
samdark marked this conversation as resolved.
Show resolved Hide resolved
{
$data = $this->getIdentityAndDurationFromCookie($request);
if ($this->user->login($data['identity'], $data['duration'])) {
samdark marked this conversation as resolved.
Show resolved Hide resolved
try {
$response = $handler->handle($request);
} catch (\Throwable $e) {
samdark marked this conversation as resolved.
Show resolved Hide resolved
throw $e;
}

return $response;
} else {
samdark marked this conversation as resolved.
Show resolved Hide resolved
throw new \Exception("Error authentication");
}
}

/**
* Determines if an identity cookie has a valid format and contains a valid auth key.
* This method is used when [[enableAutoLogin]] is true.
* This method attempts to authenticate a user using the information in the identity cookie.
* @param ServerRequestInterface $request Request to handle
* @return array|null Returns an array of 'identity' and 'duration' if valid, otherwise null.
samdark marked this conversation as resolved.
Show resolved Hide resolved
*/
protected function getIdentityAndDurationFromCookie(ServerRequestInterface $request)
roxblnfk marked this conversation as resolved.
Show resolved Hide resolved
{
$cookies = $request->getCookieParams();
$value = $cookies['remember'] ?? null;
samdark marked this conversation as resolved.
Show resolved Hide resolved

if ($value === null) {
return null;
}

$data = json_decode($value, true);
if (is_array($data) && count($data) == 3) {
roxblnfk marked this conversation as resolved.
Show resolved Hide resolved
samdark marked this conversation as resolved.
Show resolved Hide resolved
list($id, $authKey, $duration) = $data;
samdark marked this conversation as resolved.
Show resolved Hide resolved
$identity = $this->identityRepository->findIdentity($id);
samdark marked this conversation as resolved.
Show resolved Hide resolved
if ($identity !== null) {
if (!$identity instanceof IdentityInterface) {
throw new \Exception("findIdentity() must return an object implementing IdentityInterface.");
samdark marked this conversation as resolved.
Show resolved Hide resolved
} else {
return ['identity' => $identity, 'duration' => $duration];
}
}
}

return null;
}
}
98 changes: 98 additions & 0 deletions tests/User/AutoLoginMiddlewareTest.php
@@ -0,0 +1,98 @@
<?php

roxblnfk marked this conversation as resolved.
Show resolved Hide resolved

namespace Yiisoft\Yii\Web\Tests\User;

use Nyholm\Psr7\Response;
use PHPUnit\Framework\TestCase;
use PHPUnit_Framework_MockObject_MockObject;
use Psr\Http\Message\ResponseInterface;
samdark marked this conversation as resolved.
Show resolved Hide resolved
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\RequestHandlerInterface;
use Yiisoft\Auth\IdentityInterface;
use Yiisoft\Auth\IdentityRepositoryInterface;
use Yiisoft\Yii\Web\User\User;
use Yiisoft\Yii\Web\User\AutoLoginMiddleware;

class AutoLoginMiddlewareTest extends TestCase
samdark marked this conversation as resolved.
Show resolved Hide resolved
{
/**
* @var RequestHandlerInterface|PHPUnit_Framework_MockObject_MockObject
*/
private $requestHandlerMock;

/**
* @var ServerRequestInterface|PHPUnit_Framework_MockObject_MockObject
*/
private $requestMock;

/**
* @var AutoLoginMiddleware
*/
private $autoLoginMiddlewareMock;

/**
* @var IdentityRepositoryInterface
*/
private $identityRepositoryInterfaceMock;

/**
* @var IdentityInterface
*/
private $identityInterfaceMock;
/**
* @var User
*/
private $userMock;

public function setUp(): void
{
parent::setUp();
samdark marked this conversation as resolved.
Show resolved Hide resolved
$this->requestHandlerMock = $this->createMock(RequestHandlerInterface::class);
$this->userMock = $this->createMock(User::class);
$this->identityInterfaceMock = $this->createMock(IdentityInterface::class);
$this->identityRepositoryInterfaceMock = $this->createMock(IdentityRepositoryInterface::class);
$this->autoLoginMiddlewareMock = new AutoLoginMiddleware($this->userMock, $this->identityRepositoryInterfaceMock);
$this->requestMock = $this->createMock(ServerRequestInterface::class);

$this->requestMock
->expects($this->any())
->method('getCookieParams')
->willReturn([
"remember" => json_encode([1, '123456', 60])
]);

$this->identityRepositoryInterfaceMock
->expects($this->any())
->method('findIdentity')
->willReturn($this->identityInterfaceMock);
}

public function testProcessOK(): void
{
$this->userMock
->expects($this->once())
->method('login')
->willReturn(true);

$response = new Response();
$this->requestHandlerMock
->expects($this->once())
->method('handle')
->willReturn($response);


$this->assertEquals($this->autoLoginMiddlewareMock->process($this->requestMock, $this->requestHandlerMock), $response);
}

public function testProcessErrorLogin(): void
{
$this->userMock
->expects($this->once())
->method('login')
->willReturn(false);

$this->expectException(\Exception::class);
$this->autoLoginMiddlewareMock->process($this->requestMock, $this->requestHandlerMock);
}
}