From a61d276a83ce33175bb5f8346849d492ed972a56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9A=D1=80=D0=B8=D0=B2=D0=B8=D1=87=20=D0=A1=D0=B5=D1=80?= =?UTF-8?q?=D0=B3=D0=B5=D0=B9?= Date: Thu, 21 Jul 2022 17:39:34 +0300 Subject: [PATCH] Update authenticator && documentation --- Resources/doc/Requests.md | 2 + Resources/doc/Security.md | 27 +++--- ...ticator.php => ApiClientAuthenticator.php} | 5 +- Security/CallbackClientAuthenticator.php | 32 ------- ...est.php => ApiClientAuthenticatorTest.php} | 19 ++--- .../CallbackClientAuthenticatorTest.php | 85 ------------------- 6 files changed, 23 insertions(+), 147 deletions(-) rename Security/{FrontApiClientAuthenticator.php => ApiClientAuthenticator.php} (87%) delete mode 100644 Security/CallbackClientAuthenticator.php rename Tests/Security/{FrontApiClientAuthenticatorTest.php => ApiClientAuthenticatorTest.php} (79%) delete mode 100644 Tests/Security/CallbackClientAuthenticatorTest.php diff --git a/Resources/doc/Requests.md b/Resources/doc/Requests.md index a70866d..9aa1e58 100644 --- a/Resources/doc/Requests.md +++ b/Resources/doc/Requests.md @@ -2,6 +2,8 @@ #### Callbacks (form data) +> For successful deserialization of an entity, there must be setters for the passed parameters + To automatically get the callback request parameter ```php diff --git a/Resources/doc/Security.md b/Resources/doc/Security.md index dbb9932..d0b63ce 100644 --- a/Resources/doc/Security.md +++ b/Resources/doc/Security.md @@ -16,21 +16,10 @@ security: pattern: ^/simple-connection stateless: true security: false - callback: - pattern: ^/callback + front: + pattern: ^/front provider: connection 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: - RetailCrm\ServiceBundle\Security\FrontApiClientAuthenticator main: @@ -38,8 +27,8 @@ security: lazy: true access_control: - - { path: ^/front, roles: IS_AUTHENTICATED_REMEMBERED } - - { path: ^/simple-connection, roles: PUBLIC_ACCESS } + - { path: ^/front, roles: IS_AUTHENTICATED_FULLY } + - { 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: @@ -51,8 +40,8 @@ Login controller will be called after the authenticator successfully authenticat class ApiLoginController extends AbstractController { - #[Route('/auth', name: 'auth')] - public function auth(#[CurrentUser] ?User $user): Response + #[Route('/front', name: 'front')] + public function front(#[CurrentUser] ?User $user): Response { $token = ...; // somehow create an API token for $user @@ -66,3 +55,7 @@ Login controller will be called after the authenticator successfully authenticat ``` The #[CurrentUser] 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 \ No newline at end of file diff --git a/Security/FrontApiClientAuthenticator.php b/Security/ApiClientAuthenticator.php similarity index 87% rename from Security/FrontApiClientAuthenticator.php rename to Security/ApiClientAuthenticator.php index d827f2c..af7dfc1 100644 --- a/Security/FrontApiClientAuthenticator.php +++ b/Security/ApiClientAuthenticator.php @@ -6,12 +6,11 @@ use RetailCrm\ServiceBundle\Response\ErrorJsonResponseFactory; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Security\Core\Exception\AuthenticationException; 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\Passport; use Symfony\Component\Security\Http\Authenticator\Passport\SelfValidatingPassport; -class FrontApiClientAuthenticator extends AbstractClientAuthenticator +class ApiClientAuthenticator extends AbstractClientAuthenticator { public function __construct( ErrorJsonResponseFactory $errorResponseFactory, @@ -40,7 +39,7 @@ class FrontApiClientAuthenticator extends AbstractClientAuthenticator new UserBadge( $identifier ), - [new RememberMeBadge()] + [] ); } } diff --git a/Security/CallbackClientAuthenticator.php b/Security/CallbackClientAuthenticator.php deleted file mode 100644 index 452313c..0000000 --- a/Security/CallbackClientAuthenticator.php +++ /dev/null @@ -1,32 +0,0 @@ -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 - ), - [] - ); - } -} diff --git a/Tests/Security/FrontApiClientAuthenticatorTest.php b/Tests/Security/ApiClientAuthenticatorTest.php similarity index 79% rename from Tests/Security/FrontApiClientAuthenticatorTest.php rename to Tests/Security/ApiClientAuthenticatorTest.php index bfec186..9cfc5eb 100644 --- a/Tests/Security/FrontApiClientAuthenticatorTest.php +++ b/Tests/Security/ApiClientAuthenticatorTest.php @@ -2,10 +2,9 @@ namespace RetailCrm\ServiceBundle\Tests\Security; -use Doctrine\Persistence\ObjectRepository; use PHPUnit\Framework\TestCase; use RetailCrm\ServiceBundle\Response\ErrorJsonResponseFactory; -use RetailCrm\ServiceBundle\Security\FrontApiClientAuthenticator; +use RetailCrm\ServiceBundle\Security\ApiClientAuthenticator; use RetailCrm\ServiceBundle\Tests\DataFixtures\User; use Symfony\Component\HttpFoundation\JsonResponse; 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\Http\Authenticator\Passport\Badge\UserBadge; -class FrontApiClientAuthenticatorTest extends TestCase +class ApiClientAuthenticatorTest extends TestCase { public function testOnAuthenticationFailure(): void { @@ -30,7 +29,7 @@ class FrontApiClientAuthenticatorTest extends TestCase ) ); $security = $this->createMock(Security::class); - $auth = new FrontApiClientAuthenticator($errorResponseFactory, $security); + $auth = new ApiClientAuthenticator($errorResponseFactory, $security); $result = $auth->onAuthenticationFailure(new Request(), new AuthenticationException()); static::assertInstanceOf(JsonResponse::class, $result); @@ -43,7 +42,7 @@ class FrontApiClientAuthenticatorTest extends TestCase $security = $this->createMock(Security::class); $security->method('getUser')->willReturn(new User()); - $auth = new FrontApiClientAuthenticator($errorResponseFactory, $security); + $auth = new ApiClientAuthenticator($errorResponseFactory, $security); $result = $auth->supports(new Request()); static::assertFalse($result); @@ -54,8 +53,8 @@ class FrontApiClientAuthenticatorTest extends TestCase $errorResponseFactory = $this->createMock(ErrorJsonResponseFactory::class); $security = $this->createMock(Security::class); $security->method('getUser')->willReturn(null); - $auth = new FrontApiClientAuthenticator($errorResponseFactory, $security); - $result = $auth->supports(new Request([], [FrontApiClientAuthenticator::AUTH_FIELD => '123'])); + $auth = new ApiClientAuthenticator($errorResponseFactory, $security); + $result = $auth->supports(new Request([], [ApiClientAuthenticator::AUTH_FIELD => '123'])); static::assertTrue($result); } @@ -66,9 +65,9 @@ class FrontApiClientAuthenticatorTest extends TestCase $security = $this->createMock(Security::class); $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::assertEquals( $user->getUserIdentifier(), @@ -86,7 +85,7 @@ class FrontApiClientAuthenticatorTest extends TestCase $request = $this->createMock(Request::class); $token = $this->createMock(TokenInterface::class); - $auth = new FrontApiClientAuthenticator($errorResponseFactory, $security); + $auth = new ApiClientAuthenticator($errorResponseFactory, $security); $result = $auth->onAuthenticationSuccess($request, $token, 'key'); diff --git a/Tests/Security/CallbackClientAuthenticatorTest.php b/Tests/Security/CallbackClientAuthenticatorTest.php deleted file mode 100644 index eff026b..0000000 --- a/Tests/Security/CallbackClientAuthenticatorTest.php +++ /dev/null @@ -1,85 +0,0 @@ -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); - } -}