1
0
mirror of synced 2024-11-28 15:46:04 +03:00

Update authenticator && documentation

This commit is contained in:
Кривич Сергей 2022-07-21 17:39:34 +03:00
parent 180ccab466
commit a61d276a83
6 changed files with 23 additions and 147 deletions

View File

@ -2,6 +2,8 @@
#### Callbacks (form data) #### Callbacks (form data)
> For successful deserialization of an entity, there must be setters for the passed parameters
To automatically get the callback request parameter To automatically get the callback request parameter
```php ```php

View File

@ -16,21 +16,10 @@ security:
pattern: ^/simple-connection pattern: ^/simple-connection
stateless: true stateless: true
security: false security: false
callback: front:
pattern: ^/callback pattern: ^/front
provider: connection provider: connection
stateless: true stateless: true
custom_authenticators:
- RetailCrm\ServiceBundle\Security\CallbackClientAuthenticator
front:
pattern: ^/auth
provider: connection
stateless: false
remember_me:
secret: '%kernel.secret%'
lifetime: 604800 # 1 week in seconds
signature_properties: ['clientId']
always_remember_me: true
custom_authenticators: custom_authenticators:
- RetailCrm\ServiceBundle\Security\FrontApiClientAuthenticator - RetailCrm\ServiceBundle\Security\FrontApiClientAuthenticator
main: main:
@ -38,8 +27,8 @@ security:
lazy: true lazy: true
access_control: access_control:
- { path: ^/front, roles: IS_AUTHENTICATED_REMEMBERED } - { path: ^/front, roles: IS_AUTHENTICATED_FULLY }
- { path: ^/simple-connection, roles: PUBLIC_ACCESS } - { path: ^/(simple-connection), roles: PUBLIC_ACCESS }
``` ```
Login controller will be called after the authenticator successfully authenticates the user. You can get the authenticated user, generate a token (or whatever you need to return) and return response: Login controller will be called after the authenticator successfully authenticates the user. You can get the authenticated user, generate a token (or whatever you need to return) and return response:
@ -51,8 +40,8 @@ Login controller will be called after the authenticator successfully authenticat
class ApiLoginController extends AbstractController class ApiLoginController extends AbstractController
{ {
#[Route('/auth', name: 'auth')] #[Route('/front', name: 'front')]
public function auth(#[CurrentUser] ?User $user): Response public function front(#[CurrentUser] ?User $user): Response
{ {
$token = ...; // somehow create an API token for $user $token = ...; // somehow create an API token for $user
@ -66,3 +55,7 @@ Login controller will be called after the authenticator successfully authenticat
``` ```
The <code>#[CurrentUser]</code> can only be used in controller arguments to retrieve the authenticated user. In services, you would use getUser(). The <code>#[CurrentUser]</code> can only be used in controller arguments to retrieve the authenticated user. In services, you would use getUser().
See the [manual](https://symfony.com/doc/6.0/security.html) for more information.
> If you set the parameter stateless: false, then during an active session the login will be made on the basis of the data deserialized from the session storage

View File

@ -6,12 +6,11 @@ use RetailCrm\ServiceBundle\Response\ErrorJsonResponseFactory;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\Exception\AuthenticationException; use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Core\Security; use Symfony\Component\Security\Core\Security;
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\RememberMeBadge;
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge; use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
use Symfony\Component\Security\Http\Authenticator\Passport\Passport; use Symfony\Component\Security\Http\Authenticator\Passport\Passport;
use Symfony\Component\Security\Http\Authenticator\Passport\SelfValidatingPassport; use Symfony\Component\Security\Http\Authenticator\Passport\SelfValidatingPassport;
class FrontApiClientAuthenticator extends AbstractClientAuthenticator class ApiClientAuthenticator extends AbstractClientAuthenticator
{ {
public function __construct( public function __construct(
ErrorJsonResponseFactory $errorResponseFactory, ErrorJsonResponseFactory $errorResponseFactory,
@ -40,7 +39,7 @@ class FrontApiClientAuthenticator extends AbstractClientAuthenticator
new UserBadge( new UserBadge(
$identifier $identifier
), ),
[new RememberMeBadge()] []
); );
} }
} }

View File

@ -1,32 +0,0 @@
<?php
namespace RetailCrm\ServiceBundle\Security;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
use Symfony\Component\Security\Http\Authenticator\Passport\Passport;
use Symfony\Component\Security\Http\Authenticator\Passport\SelfValidatingPassport;
class CallbackClientAuthenticator extends AbstractClientAuthenticator
{
public function supports(Request $request): bool
{
return $request->request->has(static::AUTH_FIELD) || $request->query->has(static::AUTH_FIELD);
}
public function authenticate(Request $request): Passport
{
$identifier = $request->request->get(static::AUTH_FIELD);
if (null === $identifier) {
throw new AuthenticationException('Request does not contain authentication data');
}
return new SelfValidatingPassport(
new UserBadge(
$identifier
),
[]
);
}
}

View File

@ -2,10 +2,9 @@
namespace RetailCrm\ServiceBundle\Tests\Security; namespace RetailCrm\ServiceBundle\Tests\Security;
use Doctrine\Persistence\ObjectRepository;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use RetailCrm\ServiceBundle\Response\ErrorJsonResponseFactory; use RetailCrm\ServiceBundle\Response\ErrorJsonResponseFactory;
use RetailCrm\ServiceBundle\Security\FrontApiClientAuthenticator; use RetailCrm\ServiceBundle\Security\ApiClientAuthenticator;
use RetailCrm\ServiceBundle\Tests\DataFixtures\User; use RetailCrm\ServiceBundle\Tests\DataFixtures\User;
use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
@ -15,7 +14,7 @@ use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Core\Security; use Symfony\Component\Security\Core\Security;
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge; use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
class FrontApiClientAuthenticatorTest extends TestCase class ApiClientAuthenticatorTest extends TestCase
{ {
public function testOnAuthenticationFailure(): void public function testOnAuthenticationFailure(): void
{ {
@ -30,7 +29,7 @@ class FrontApiClientAuthenticatorTest extends TestCase
) )
); );
$security = $this->createMock(Security::class); $security = $this->createMock(Security::class);
$auth = new FrontApiClientAuthenticator($errorResponseFactory, $security); $auth = new ApiClientAuthenticator($errorResponseFactory, $security);
$result = $auth->onAuthenticationFailure(new Request(), new AuthenticationException()); $result = $auth->onAuthenticationFailure(new Request(), new AuthenticationException());
static::assertInstanceOf(JsonResponse::class, $result); static::assertInstanceOf(JsonResponse::class, $result);
@ -43,7 +42,7 @@ class FrontApiClientAuthenticatorTest extends TestCase
$security = $this->createMock(Security::class); $security = $this->createMock(Security::class);
$security->method('getUser')->willReturn(new User()); $security->method('getUser')->willReturn(new User());
$auth = new FrontApiClientAuthenticator($errorResponseFactory, $security); $auth = new ApiClientAuthenticator($errorResponseFactory, $security);
$result = $auth->supports(new Request()); $result = $auth->supports(new Request());
static::assertFalse($result); static::assertFalse($result);
@ -54,8 +53,8 @@ class FrontApiClientAuthenticatorTest extends TestCase
$errorResponseFactory = $this->createMock(ErrorJsonResponseFactory::class); $errorResponseFactory = $this->createMock(ErrorJsonResponseFactory::class);
$security = $this->createMock(Security::class); $security = $this->createMock(Security::class);
$security->method('getUser')->willReturn(null); $security->method('getUser')->willReturn(null);
$auth = new FrontApiClientAuthenticator($errorResponseFactory, $security); $auth = new ApiClientAuthenticator($errorResponseFactory, $security);
$result = $auth->supports(new Request([], [FrontApiClientAuthenticator::AUTH_FIELD => '123'])); $result = $auth->supports(new Request([], [ApiClientAuthenticator::AUTH_FIELD => '123']));
static::assertTrue($result); static::assertTrue($result);
} }
@ -66,9 +65,9 @@ class FrontApiClientAuthenticatorTest extends TestCase
$security = $this->createMock(Security::class); $security = $this->createMock(Security::class);
$user = new User(); $user = new User();
$auth = new FrontApiClientAuthenticator($errorResponseFactory, $security); $auth = new ApiClientAuthenticator($errorResponseFactory, $security);
$passport = $auth->authenticate(new Request([], [FrontApiClientAuthenticator::AUTH_FIELD => '123'])); $passport = $auth->authenticate(new Request([], [ApiClientAuthenticator::AUTH_FIELD => '123']));
static::assertTrue($passport->hasBadge(UserBadge::class)); static::assertTrue($passport->hasBadge(UserBadge::class));
static::assertEquals( static::assertEquals(
$user->getUserIdentifier(), $user->getUserIdentifier(),
@ -86,7 +85,7 @@ class FrontApiClientAuthenticatorTest extends TestCase
$request = $this->createMock(Request::class); $request = $this->createMock(Request::class);
$token = $this->createMock(TokenInterface::class); $token = $this->createMock(TokenInterface::class);
$auth = new FrontApiClientAuthenticator($errorResponseFactory, $security); $auth = new ApiClientAuthenticator($errorResponseFactory, $security);
$result = $auth->onAuthenticationSuccess($request, $token, 'key'); $result = $auth->onAuthenticationSuccess($request, $token, 'key');

View File

@ -1,85 +0,0 @@
<?php
namespace RetailCrm\ServiceBundle\Tests\Security;
use Doctrine\Persistence\ObjectRepository;
use PHPUnit\Framework\TestCase;
use RetailCrm\ServiceBundle\Response\ErrorJsonResponseFactory;
use RetailCrm\ServiceBundle\Security\CallbackClientAuthenticator;
use RetailCrm\ServiceBundle\Tests\DataFixtures\User;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
class CallbackClientAuthenticatorTest extends TestCase
{
public function testOnAuthenticationFailure(): void
{
$errorResponseFactory = $this->createMock(ErrorJsonResponseFactory::class);
$errorResponseFactory
->expects(static::once())
->method('create')
->willReturn(
new JsonResponse(
['message' => 'An authentication exception occurred.'],
Response::HTTP_FORBIDDEN
)
);
$auth = new CallbackClientAuthenticator($errorResponseFactory);
$result = $auth->onAuthenticationFailure(new Request(), new AuthenticationException());
static::assertInstanceOf(JsonResponse::class, $result);
static::assertEquals(Response::HTTP_FORBIDDEN, $result->getStatusCode());
}
public function testSupports(): void
{
$errorResponseFactory = $this->createMock(ErrorJsonResponseFactory::class);
$auth = new CallbackClientAuthenticator($errorResponseFactory);
$result = $auth->supports(new Request([], [CallbackClientAuthenticator::AUTH_FIELD => '123']));
static::assertTrue($result);
$result = $auth->supports(new Request([CallbackClientAuthenticator::AUTH_FIELD => '123']));
static::assertTrue($result);
$result = $auth->supports(new Request());
static::assertFalse($result);
}
public function testAuthenticate(): void
{
$errorResponseFactory = $this->createMock(ErrorJsonResponseFactory::class);
$user = new User();
$auth = new CallbackClientAuthenticator($errorResponseFactory);
$passport = $auth->authenticate(new Request([], [CallbackClientAuthenticator::AUTH_FIELD => '123']));
static::assertTrue($passport->hasBadge(UserBadge::class));
static::assertEquals(
$user->getUserIdentifier(),
$passport->getBadge(UserBadge::class)->getUserIdentifier()
);
$this->expectException(AuthenticationException::class);
$auth->authenticate(new Request());
}
public function testOnAuthenticationSuccess(): void
{
$errorResponseFactory = $this->createMock(ErrorJsonResponseFactory::class);
$request = $this->createMock(Request::class);
$token = $this->createMock(TokenInterface::class);
$auth = new CallbackClientAuthenticator($errorResponseFactory);
$result = $auth->onAuthenticationSuccess($request, $token, 'key');
static::assertNull($result);
}
}