Initial service bundle (#1)
This commit is contained in:
parent
9309a2d122
commit
d44da0d531
34
.github/workflows/ci.yml
vendored
Normal file
34
.github/workflows/ci.yml
vendored
Normal file
@ -0,0 +1,34 @@
|
||||
name: ci
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- '**'
|
||||
tags-ignore:
|
||||
- '*.*'
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
php-version: ['7.3', '7.4', '8.0']
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Setup PHP ${{ matrix.php-version }}
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: ${{ matrix.php-version }}
|
||||
coverage: pcov
|
||||
- name: Composer cache
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ${{ env.HOME }}/.composer/cache
|
||||
key: ${{ runner.os }}-php-${{ hashFiles('**/composer.lock') }}
|
||||
- name: Install dependencies
|
||||
run: composer install -o
|
||||
- name: Run tests
|
||||
run: composer run tests
|
||||
- name: Coverage
|
||||
run: bash <(curl -s https://codecov.io/bash)
|
6
.gitignore
vendored
6
.gitignore
vendored
@ -30,6 +30,7 @@
|
||||
!bin/console
|
||||
!bin/symfony_requirements
|
||||
/vendor/
|
||||
composer.lock
|
||||
|
||||
# Assets and user uploads
|
||||
/web/bundles/
|
||||
@ -38,6 +39,8 @@
|
||||
# PHPUnit
|
||||
/app/phpunit.xml
|
||||
/phpunit.xml
|
||||
.phpunit.result.cache
|
||||
test-report.xml
|
||||
|
||||
# Build data
|
||||
/build/
|
||||
@ -50,3 +53,6 @@
|
||||
|
||||
# Embedded web-server pid file
|
||||
/.web-server-pid
|
||||
|
||||
.idea
|
||||
coverage.xml
|
||||
|
43
ArgumentResolver/AbstractValueResolver.php
Normal file
43
ArgumentResolver/AbstractValueResolver.php
Normal file
@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
namespace RetailCrm\ServiceBundle\ArgumentResolver;
|
||||
|
||||
use RetailCrm\ServiceBundle\Exceptions\InvalidRequestArgumentException;
|
||||
use Symfony\Component\Validator\Validator\ValidatorInterface;
|
||||
|
||||
/**
|
||||
* Class AbstractValueResolver
|
||||
*
|
||||
* @package RetailCrm\ServiceBundle\ArgumentResolver
|
||||
*/
|
||||
abstract class AbstractValueResolver
|
||||
{
|
||||
protected $validator;
|
||||
|
||||
/**
|
||||
* AbstractValueResolver constructor.
|
||||
*
|
||||
* @param ValidatorInterface $validator
|
||||
*/
|
||||
public function __construct(ValidatorInterface $validator)
|
||||
{
|
||||
$this->validator = $validator;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param object $data
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function validate(object $data): void
|
||||
{
|
||||
$errors = $this->validator->validate($data);
|
||||
if (0 !== count($errors)) {
|
||||
throw new InvalidRequestArgumentException(
|
||||
sprintf("Invalid request parameter %s", \get_class($data)),
|
||||
400,
|
||||
$errors
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
86
ArgumentResolver/CallbackValueResolver.php
Normal file
86
ArgumentResolver/CallbackValueResolver.php
Normal file
@ -0,0 +1,86 @@
|
||||
<?php
|
||||
|
||||
namespace RetailCrm\ServiceBundle\ArgumentResolver;
|
||||
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface;
|
||||
use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata;
|
||||
use Symfony\Component\Serializer\SerializerInterface;
|
||||
use Generator;
|
||||
use Symfony\Component\Validator\Validator\ValidatorInterface;
|
||||
|
||||
/**
|
||||
* Class CallbackValueResolver
|
||||
*
|
||||
* @package RetailCrm\ServiceBundle\ArgumentResolver
|
||||
*/
|
||||
class CallbackValueResolver extends AbstractValueResolver implements ArgumentValueResolverInterface
|
||||
{
|
||||
private $serializer;
|
||||
private $requestSchema;
|
||||
|
||||
/**
|
||||
* CallbackValueResolver constructor.
|
||||
*
|
||||
* @param SerializerInterface $serializer
|
||||
* @param ValidatorInterface $validator
|
||||
* @param array $requestSchema
|
||||
*/
|
||||
public function __construct(
|
||||
SerializerInterface $serializer,
|
||||
ValidatorInterface $validator,
|
||||
array $requestSchema
|
||||
) {
|
||||
parent::__construct($validator);
|
||||
|
||||
$this->serializer = $serializer;
|
||||
$this->requestSchema = $requestSchema;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc }
|
||||
*/
|
||||
public function supports(Request $request, ArgumentMetadata $argument): bool
|
||||
{
|
||||
if (empty($this->requestSchema) || $request->getMethod() !== Request::METHOD_POST) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return null !== $this->search($request, $argument);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc }
|
||||
*/
|
||||
public function resolve(Request $request, ArgumentMetadata $argument): Generator
|
||||
{
|
||||
$parameter = $this->search($request, $argument);
|
||||
$data = $this->serializer->deserialize($request->request->get($parameter), $argument->getType(), 'json');
|
||||
$this->validate($data);
|
||||
|
||||
yield $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @param ArgumentMetadata $argument
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
private function search(Request $request, ArgumentMetadata $argument): ?string
|
||||
{
|
||||
foreach ($this->requestSchema as $callback) {
|
||||
if ($argument->getType() !== $callback['type']) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($callback['params'] as $param) {
|
||||
if ($request->request->has($param)) {
|
||||
return $param;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
93
ArgumentResolver/ClientValueResolver.php
Normal file
93
ArgumentResolver/ClientValueResolver.php
Normal file
@ -0,0 +1,93 @@
|
||||
<?php
|
||||
|
||||
namespace RetailCrm\ServiceBundle\ArgumentResolver;
|
||||
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface;
|
||||
use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata;
|
||||
use Symfony\Component\Serializer\Exception\ExceptionInterface;
|
||||
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
|
||||
use Symfony\Component\Serializer\SerializerInterface;
|
||||
use Symfony\Component\Validator\Validator\ValidatorInterface;
|
||||
use Generator;
|
||||
|
||||
/**
|
||||
* Class ClientValueResolver
|
||||
*
|
||||
* @package RetailCrm\ServiceBundle\ArgumentResolver
|
||||
*/
|
||||
class ClientValueResolver extends AbstractValueResolver implements ArgumentValueResolverInterface
|
||||
{
|
||||
private $serializer;
|
||||
private $denormalizer;
|
||||
private $requestSchema;
|
||||
|
||||
/**
|
||||
* ClientValueResolver constructor.
|
||||
*
|
||||
* @param ValidatorInterface $validator
|
||||
* @param SerializerInterface $serializer
|
||||
* @param DenormalizerInterface $denormalizer
|
||||
* @param array $requestSchema
|
||||
*/
|
||||
public function __construct(
|
||||
ValidatorInterface $validator,
|
||||
SerializerInterface $serializer,
|
||||
DenormalizerInterface $denormalizer,
|
||||
array $requestSchema
|
||||
) {
|
||||
parent::__construct($validator);
|
||||
|
||||
$this->serializer = $serializer;
|
||||
$this->denormalizer = $denormalizer;
|
||||
$this->requestSchema = $requestSchema;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function supports(Request $request, ArgumentMetadata $argument): bool
|
||||
{
|
||||
return in_array($argument->getType(), $this->requestSchema, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function resolve(Request $request, ArgumentMetadata $argument): Generator
|
||||
{
|
||||
if (Request::METHOD_GET === $request->getMethod()) {
|
||||
$dto = $this->handleGetData($request->query->all(), $argument->getType());
|
||||
} else {
|
||||
$dto = $this->handlePostData($request->getContent(), $argument->getType());
|
||||
}
|
||||
|
||||
$this->validate($dto);
|
||||
|
||||
yield $dto;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* @param string $type
|
||||
*
|
||||
* @return object
|
||||
*
|
||||
* @throws ExceptionInterface
|
||||
*/
|
||||
private function handleGetData(array $data, string $type): object
|
||||
{
|
||||
return $this->denormalizer->denormalize($data, $type);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $data
|
||||
* @param string $type
|
||||
*
|
||||
* @return object
|
||||
*/
|
||||
private function handlePostData(string $data, string $type): object
|
||||
{
|
||||
return $this->serializer->deserialize($data, $type, 'json');
|
||||
}
|
||||
}
|
46
DependencyInjection/Configuration.php
Normal file
46
DependencyInjection/Configuration.php
Normal file
@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
namespace RetailCrm\ServiceBundle\DependencyInjection;
|
||||
|
||||
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
|
||||
use Symfony\Component\Config\Definition\ConfigurationInterface;
|
||||
|
||||
/**
|
||||
* Class Configuration
|
||||
*
|
||||
* @package RetailCrm\ServiceBundle\DependencyInjection
|
||||
*/
|
||||
class Configuration implements ConfigurationInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc }
|
||||
*/
|
||||
public function getConfigTreeBuilder(): TreeBuilder
|
||||
{
|
||||
$treeBuilder = new TreeBuilder('retail_crm_service');
|
||||
$rootNode = $treeBuilder->getRootNode();
|
||||
|
||||
$rootNode
|
||||
->children()
|
||||
->arrayNode('request_schema')
|
||||
->children()
|
||||
->arrayNode('callback')
|
||||
->arrayPrototype()
|
||||
->children()
|
||||
->scalarNode('type')->isRequired()->end()
|
||||
->arrayNode('params')
|
||||
->isRequired()->scalarPrototype()->end()
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
->arrayNode('client')
|
||||
->scalarPrototype()->end()
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
->end();
|
||||
|
||||
return $treeBuilder;
|
||||
}
|
||||
}
|
63
DependencyInjection/RetailCrmServiceExtension.php
Normal file
63
DependencyInjection/RetailCrmServiceExtension.php
Normal file
@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
namespace RetailCrm\ServiceBundle\DependencyInjection;
|
||||
|
||||
use RetailCrm\ServiceBundle\ArgumentResolver\CallbackValueResolver;
|
||||
use RetailCrm\ServiceBundle\ArgumentResolver\ClientValueResolver;
|
||||
use RetailCrm\ServiceBundle\Response\ErrorJsonResponseFactory;
|
||||
use RetailCrm\ServiceBundle\Security\CallbackClientAuthenticator;
|
||||
use RetailCrm\ServiceBundle\Security\FrontApiClientAuthenticator;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Extension\Extension;
|
||||
|
||||
/**
|
||||
* Class RetailCrmServiceExtension
|
||||
*
|
||||
* @package RetailCrm\ServiceBundle\DependencyInjection
|
||||
*/
|
||||
class RetailCrmServiceExtension extends Extension
|
||||
{
|
||||
/**
|
||||
* @param array $configs
|
||||
* @param ContainerBuilder $container
|
||||
*/
|
||||
public function load(array $configs, ContainerBuilder $container): void
|
||||
{
|
||||
$configuration = $this->getConfiguration($configs, $container);
|
||||
$config = $this->processConfiguration($configuration, $configs);
|
||||
|
||||
$container->setParameter(
|
||||
'retail_crm_service.request_schema.callback',
|
||||
$config['request_schema']['callback']
|
||||
);
|
||||
|
||||
$container->setParameter(
|
||||
'retail_crm_service.request_schema.client',
|
||||
$config['request_schema']['client']
|
||||
);
|
||||
|
||||
$container
|
||||
->register(CallbackValueResolver::class)
|
||||
->setArgument('$requestSchema', '%retail_crm_service.request_schema.callback%')
|
||||
->addTag('controller.argument_value_resolver', ['priority' => 50])
|
||||
->setAutowired(true);
|
||||
|
||||
$container
|
||||
->register(ClientValueResolver::class)
|
||||
->setArgument('$requestSchema', '%retail_crm_service.request_schema.client%')
|
||||
->addTag('controller.argument_value_resolver', ['priority' => 50])
|
||||
->setAutowired(true);
|
||||
|
||||
$container
|
||||
->register(ErrorJsonResponseFactory::class)
|
||||
->setAutowired(true);
|
||||
|
||||
$container
|
||||
->register(CallbackClientAuthenticator::class)
|
||||
->setAutowired(true);
|
||||
|
||||
$container
|
||||
->register(FrontApiClientAuthenticator::class)
|
||||
->setAutowired(true);
|
||||
}
|
||||
}
|
38
Exceptions/InvalidRequestArgumentException.php
Normal file
38
Exceptions/InvalidRequestArgumentException.php
Normal file
@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
namespace RetailCrm\ServiceBundle\Exceptions;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use Throwable;
|
||||
|
||||
/**
|
||||
* Class InvalidRequestArgumentException
|
||||
*
|
||||
* @package RetailCrm\ServiceBundle\Exceptions
|
||||
*/
|
||||
class InvalidRequestArgumentException extends InvalidArgumentException
|
||||
{
|
||||
private $validateErrors;
|
||||
|
||||
/**
|
||||
* InvalidRequestArgumentException constructor.
|
||||
* @param string $message
|
||||
* @param int $code
|
||||
* @param array $errors
|
||||
* @param Throwable|null $previous
|
||||
*/
|
||||
public function __construct($message = "", $code = 0, iterable $errors = [], Throwable $previous = null)
|
||||
{
|
||||
parent::__construct($message, $code, $previous);
|
||||
|
||||
$this->validateErrors = $errors;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return iterable
|
||||
*/
|
||||
public function getValidateErrors(): iterable
|
||||
{
|
||||
return $this->validateErrors;
|
||||
}
|
||||
}
|
26
Models/Error.php
Normal file
26
Models/Error.php
Normal file
@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace RetailCrm\ServiceBundle\Models;
|
||||
|
||||
/**
|
||||
* Class Error
|
||||
*
|
||||
* @package RetailCrm\ServiceBundle\Models
|
||||
*/
|
||||
class Error
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $code;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $message;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
public $details;
|
||||
}
|
148
Resources/doc/index.md
Normal file
148
Resources/doc/index.md
Normal file
@ -0,0 +1,148 @@
|
||||
## Installation
|
||||
|
||||
`composer require retailcrm/service-bundle`
|
||||
|
||||
## Usage
|
||||
|
||||
Enable bundle in `config/bundles.php`:
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
return [
|
||||
// other bundles
|
||||
RetailCrm\ServiceBundle\RetailCrmServiceBundle::class => ['all' => true]
|
||||
];
|
||||
|
||||
```
|
||||
|
||||
Create bundle config file in `config/packages/retail_crm_service.yaml`:
|
||||
|
||||
```yaml
|
||||
retail_crm_service:
|
||||
request_schema: ~
|
||||
```
|
||||
|
||||
### Deserializing incoming requests
|
||||
|
||||
#### Callbacks (form data)
|
||||
|
||||
To automatically get the callback request parameter
|
||||
|
||||
```php
|
||||
|
||||
class AppController extends AbstractController
|
||||
{
|
||||
public function activityAction(\App\Dto\Callback\Activity $activity): Response
|
||||
{
|
||||
// handle activity
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
add to the config:
|
||||
|
||||
```yaml
|
||||
retail_crm_service:
|
||||
request_schema:
|
||||
callback:
|
||||
- type: App\Dto\Callback\Activity
|
||||
params: ["activity"]
|
||||
```
|
||||
|
||||
request automatically will be deserialization to $activity.
|
||||
|
||||
#### Body json content
|
||||
|
||||
```php
|
||||
|
||||
class AppController extends AbstractController
|
||||
{
|
||||
public function someAction(\App\Dto\Body $activity): Response
|
||||
{
|
||||
// handle activity
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
add to the config:
|
||||
|
||||
```yaml
|
||||
retail_crm_service:
|
||||
request_schema:
|
||||
client:
|
||||
- App\Dto\Body
|
||||
```
|
||||
|
||||
### Authentication
|
||||
|
||||
Example security configuration:
|
||||
|
||||
```yaml
|
||||
security:
|
||||
providers:
|
||||
client:
|
||||
entity:
|
||||
class: 'App\Entity\Connection' # must implements UserInterface
|
||||
property: 'clientId'
|
||||
firewalls:
|
||||
api:
|
||||
pattern: ^/api
|
||||
provider: client
|
||||
anonymous: ~
|
||||
lazy: true
|
||||
stateless: false
|
||||
guard:
|
||||
authenticators:
|
||||
- RetailCrm\ServiceBundle\Security\FrontApiClientAuthenticator
|
||||
callback:
|
||||
pattern: ^/callback
|
||||
provider: client
|
||||
anonymous: ~
|
||||
lazy: true
|
||||
stateless: true
|
||||
guard:
|
||||
authenticators:
|
||||
- RetailCrm\ServiceBundle\Security\CallbackClientAuthenticator
|
||||
main:
|
||||
anonymous: true
|
||||
lazy: true
|
||||
|
||||
access_control:
|
||||
- { path: ^/api/login, roles: IS_AUTHENTICATED_ANONYMOUSLY } # login for programmatically authentication user
|
||||
- { path: ^/api, roles: ROLE_USER }
|
||||
- { path: ^/callback, roles: ROLE_USER }
|
||||
```
|
||||
|
||||
To authenticate the user after creating it, you can use the following code
|
||||
|
||||
```php
|
||||
|
||||
use Symfony\Component\Security\Guard\GuardAuthenticatorHandler;
|
||||
use RetailCrm\ServiceBundle\Security\FrontApiClientAuthenticator;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
class AppController extends AbstractController
|
||||
{
|
||||
public function someAction(
|
||||
Request $request,
|
||||
GuardAuthenticatorHandler $guardAuthenticatorHandler,
|
||||
FrontApiClientAuthenticator $frontApiClientAuthenticator,
|
||||
ConnectionManager $manager
|
||||
): Response {
|
||||
$user = $manager->getUser(); // getting user
|
||||
|
||||
$guardAuthenticatorHandler->authenticateUserAndHandleSuccess(
|
||||
$user,
|
||||
$request,
|
||||
$frontApiClientAuthenticator,
|
||||
'api'
|
||||
);
|
||||
// ...
|
||||
}
|
||||
}
|
||||
|
||||
```
|
44
Response/ErrorJsonResponseFactory.php
Normal file
44
Response/ErrorJsonResponseFactory.php
Normal file
@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
namespace RetailCrm\ServiceBundle\Response;
|
||||
|
||||
use RetailCrm\ServiceBundle\Models\Error;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Serializer\SerializerInterface;
|
||||
|
||||
/**
|
||||
* Class ErrorJsonResponseFactory
|
||||
*
|
||||
* @package RetailCrm\ServiceBundle\Response
|
||||
*/
|
||||
class ErrorJsonResponseFactory
|
||||
{
|
||||
private $serializer;
|
||||
|
||||
/**
|
||||
* ErrorJsonResponseFactory constructor.
|
||||
*
|
||||
* @param SerializerInterface $serializer
|
||||
*/
|
||||
public function __construct(SerializerInterface $serializer)
|
||||
{
|
||||
$this->serializer = $serializer;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Error $error
|
||||
* @param int $statusCode
|
||||
* @param array $headers
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function create(Error $error, int $statusCode = Response::HTTP_BAD_REQUEST, array $headers = []): Response
|
||||
{
|
||||
return JsonResponse::fromJsonString(
|
||||
$this->serializer->serialize($error, 'json'),
|
||||
$statusCode,
|
||||
$headers
|
||||
);
|
||||
}
|
||||
}
|
9
RetailCrmServiceBundle.php
Normal file
9
RetailCrmServiceBundle.php
Normal file
@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
namespace RetailCrm\ServiceBundle;
|
||||
|
||||
use Symfony\Component\HttpKernel\Bundle\Bundle;
|
||||
|
||||
class RetailCrmServiceBundle extends Bundle
|
||||
{
|
||||
}
|
89
Security/AbstractClientAuthenticator.php
Normal file
89
Security/AbstractClientAuthenticator.php
Normal file
@ -0,0 +1,89 @@
|
||||
<?php
|
||||
|
||||
namespace RetailCrm\ServiceBundle\Security;
|
||||
|
||||
use RetailCrm\ServiceBundle\Models\Error;
|
||||
use RetailCrm\ServiceBundle\Response\ErrorJsonResponseFactory;
|
||||
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\Core\User\UserInterface;
|
||||
use Symfony\Component\Security\Core\User\UserProviderInterface;
|
||||
use Symfony\Component\Security\Guard\AbstractGuardAuthenticator;
|
||||
|
||||
/**
|
||||
* Class AbstractClientAuthenticator
|
||||
*
|
||||
* @package RetailCrm\ServiceBundle\Security
|
||||
*/
|
||||
abstract class AbstractClientAuthenticator extends AbstractGuardAuthenticator
|
||||
{
|
||||
public const AUTH_FIELD = 'clientId';
|
||||
|
||||
private $errorResponseFactory;
|
||||
|
||||
/**
|
||||
* AbstractClientAuthenticator constructor.
|
||||
*
|
||||
* @param ErrorJsonResponseFactory $errorResponseFactory
|
||||
*/
|
||||
public function __construct(ErrorJsonResponseFactory $errorResponseFactory)
|
||||
{
|
||||
$this->errorResponseFactory = $errorResponseFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc }
|
||||
*/
|
||||
public function start(Request $request, AuthenticationException $authException = null): Response
|
||||
{
|
||||
$error = new Error();
|
||||
$error->message = 'Authentication required';
|
||||
|
||||
return $this->errorResponseFactory->create($error,Response::HTTP_UNAUTHORIZED);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc }
|
||||
*/
|
||||
public function getCredentials(Request $request): string
|
||||
{
|
||||
return $request->get(static::AUTH_FIELD);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc }
|
||||
*/
|
||||
public function getUser($credentials, UserProviderInterface $userProvider): ?UserInterface
|
||||
{
|
||||
return $userProvider->loadUserByUsername($credentials);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc }
|
||||
*/
|
||||
public function checkCredentials($credentials, UserInterface $user): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc }
|
||||
*/
|
||||
public function onAuthenticationFailure(Request $request, AuthenticationException $exception): ?Response
|
||||
{
|
||||
$error = new Error();
|
||||
$error->message = $exception->getMessageKey();
|
||||
|
||||
return $this->errorResponseFactory->create($error,Response::HTTP_FORBIDDEN);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc }
|
||||
*/
|
||||
public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $providerKey): ?Response
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
29
Security/CallbackClientAuthenticator.php
Normal file
29
Security/CallbackClientAuthenticator.php
Normal file
@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace RetailCrm\ServiceBundle\Security;
|
||||
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
/**
|
||||
* Class CallbackClientAuthenticator
|
||||
*
|
||||
* @package RetailCrm\ServiceBundle\Security
|
||||
*/
|
||||
class CallbackClientAuthenticator extends AbstractClientAuthenticator
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc }
|
||||
*/
|
||||
public function supports(Request $request): bool
|
||||
{
|
||||
return $request->request->has(static::AUTH_FIELD) || $request->query->has(static::AUTH_FIELD);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc }
|
||||
*/
|
||||
public function supportsRememberMe(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
52
Security/FrontApiClientAuthenticator.php
Normal file
52
Security/FrontApiClientAuthenticator.php
Normal file
@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
namespace RetailCrm\ServiceBundle\Security;
|
||||
|
||||
use RetailCrm\ServiceBundle\Response\ErrorJsonResponseFactory;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\Security\Core\Security;
|
||||
|
||||
/**
|
||||
* Class FrontApiClientAuthenticator
|
||||
*
|
||||
* @package RetailCrm\ServiceBundle\Security
|
||||
*/
|
||||
class FrontApiClientAuthenticator extends AbstractClientAuthenticator
|
||||
{
|
||||
private $security;
|
||||
|
||||
/**
|
||||
* FrontApiClientAuthenticator constructor.
|
||||
*
|
||||
* @param ErrorJsonResponseFactory $errorResponseFactory
|
||||
* @param Security $security
|
||||
*/
|
||||
public function __construct(
|
||||
ErrorJsonResponseFactory $errorResponseFactory,
|
||||
Security $security
|
||||
) {
|
||||
parent::__construct($errorResponseFactory);
|
||||
|
||||
$this->security = $security;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc }
|
||||
*/
|
||||
public function supports(Request $request): bool
|
||||
{
|
||||
if ($this->security->getUser()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $request->request->has(static::AUTH_FIELD);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc }
|
||||
*/
|
||||
public function supportsRememberMe(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
113
Tests/ArgumentResolver/CallbackValueResolverTest.php
Normal file
113
Tests/ArgumentResolver/CallbackValueResolverTest.php
Normal file
@ -0,0 +1,113 @@
|
||||
<?php
|
||||
|
||||
namespace RetailCrm\ServiceBundle\Tests\ArgumentResolver;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use RetailCrm\ServiceBundle\ArgumentResolver\CallbackValueResolver;
|
||||
use RetailCrm\ServiceBundle\Exceptions\InvalidRequestArgumentException;
|
||||
use RetailCrm\ServiceBundle\Tests\DataFixtures\RequestDto;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata;
|
||||
use Symfony\Component\Serializer\Encoder\JsonEncoder;
|
||||
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
|
||||
use Symfony\Component\Serializer\Serializer;
|
||||
use Symfony\Component\Validator\Validation;
|
||||
use Generator;
|
||||
|
||||
/**
|
||||
* Class CallbackValueResolverTest
|
||||
*
|
||||
* @package RetailCrm\ServiceBundle\Tests\ArgumentResolver
|
||||
*/
|
||||
class CallbackValueResolverTest extends TestCase
|
||||
{
|
||||
private $resolver;
|
||||
|
||||
public function setUp(): void
|
||||
{
|
||||
$serializer = new Serializer([new ObjectNormalizer()], [new JsonEncoder()]);
|
||||
$this->resolver = new CallbackValueResolver(
|
||||
$serializer,
|
||||
Validation::createValidatorBuilder()
|
||||
->enableAnnotationMapping()
|
||||
->getValidator(),
|
||||
[
|
||||
[
|
||||
'type' => RequestDto::class,
|
||||
'params' => ['request_parameter']
|
||||
]
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
public function testSupports(): void
|
||||
{
|
||||
$argument = new ArgumentMetadata('RequestDto', RequestDto::class, false, false, null);
|
||||
$request = new Request(
|
||||
[],
|
||||
['request_parameter' => json_encode(['param' => 'parameter'], JSON_THROW_ON_ERROR)],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
['REQUEST_METHOD' => Request::METHOD_POST]
|
||||
);
|
||||
|
||||
$result = $this->resolver->supports($request, $argument);
|
||||
|
||||
static::assertTrue($result);
|
||||
}
|
||||
|
||||
public function testNotSupports(): void
|
||||
{
|
||||
$argument = new ArgumentMetadata('RequestDto', 'NotFoundRequestDto', false, false, null);
|
||||
$request = new Request(
|
||||
[],
|
||||
['request_parameter' => json_encode(['param' => 'parameter'], JSON_THROW_ON_ERROR)],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
['REQUEST_METHOD' => Request::METHOD_POST]
|
||||
);
|
||||
|
||||
$result = $this->resolver->supports($request, $argument);
|
||||
|
||||
static::assertFalse($result);
|
||||
}
|
||||
|
||||
public function testResolve(): void
|
||||
{
|
||||
$argument = new ArgumentMetadata('RequestDto', RequestDto::class, false, false, null);
|
||||
$request = new Request(
|
||||
[],
|
||||
['request_parameter' => json_encode(['param' => 'parameter'], JSON_THROW_ON_ERROR)],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
['REQUEST_METHOD' => Request::METHOD_POST]
|
||||
);
|
||||
|
||||
$result = $this->resolver->resolve($request, $argument);
|
||||
|
||||
static::assertInstanceOf(Generator::class, $result);
|
||||
static::assertInstanceOf(RequestDto::class, $result->current());
|
||||
static::assertEquals('parameter', $result->current()->param);
|
||||
}
|
||||
|
||||
public function testResolveFailure(): void
|
||||
{
|
||||
$argument = new ArgumentMetadata('RequestDto', RequestDto::class, false, false, null);
|
||||
$request = new Request(
|
||||
[],
|
||||
['request_parameter' => json_encode(['param' => null], JSON_THROW_ON_ERROR)],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
['REQUEST_METHOD' => Request::METHOD_POST]
|
||||
);
|
||||
|
||||
$this->expectException(InvalidRequestArgumentException::class);
|
||||
|
||||
$result = $this->resolver->resolve($request, $argument);
|
||||
$result->current();
|
||||
}
|
||||
}
|
136
Tests/ArgumentResolver/ClientValueResolverTest.php
Normal file
136
Tests/ArgumentResolver/ClientValueResolverTest.php
Normal file
@ -0,0 +1,136 @@
|
||||
<?php
|
||||
|
||||
namespace RetailCrm\ServiceBundle\Tests\ArgumentResolver;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use RetailCrm\ServiceBundle\ArgumentResolver\ClientValueResolver;
|
||||
use RetailCrm\ServiceBundle\Exceptions\InvalidRequestArgumentException;
|
||||
use RetailCrm\ServiceBundle\Tests\DataFixtures\RequestDto;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata;
|
||||
use Symfony\Component\Serializer\Encoder\JsonEncoder;
|
||||
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
|
||||
use Symfony\Component\Serializer\Serializer;
|
||||
use Symfony\Component\Validator\Validation;
|
||||
use Generator;
|
||||
|
||||
/**
|
||||
* Class ClientValueResolverTest
|
||||
*
|
||||
* @package RetailCrm\ServiceBundle\Tests\ArgumentResolver
|
||||
*/
|
||||
class ClientValueResolverTest extends TestCase
|
||||
{
|
||||
private $resolver;
|
||||
|
||||
public function setUp(): void
|
||||
{
|
||||
$serializer = new Serializer([new ObjectNormalizer()], [new JsonEncoder()]);
|
||||
$this->resolver = new ClientValueResolver(
|
||||
Validation::createValidatorBuilder()
|
||||
->enableAnnotationMapping()
|
||||
->getValidator(),
|
||||
$serializer,
|
||||
$serializer,
|
||||
[
|
||||
RequestDto::class
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
public function testSupports(): void
|
||||
{
|
||||
$argument = new ArgumentMetadata('RequestDto', RequestDto::class, false, false, null);
|
||||
$request = new Request();
|
||||
|
||||
$result = $this->resolver->supports($request, $argument);
|
||||
|
||||
static::assertTrue($result);
|
||||
}
|
||||
|
||||
public function testNotSupports(): void
|
||||
{
|
||||
$argument = new ArgumentMetadata('RequestDto', 'NotFoundRequestDto', false, false, null);
|
||||
$request = new Request();
|
||||
|
||||
$result = $this->resolver->supports($request, $argument);
|
||||
|
||||
static::assertFalse($result);
|
||||
}
|
||||
|
||||
public function testResolvePost(): void
|
||||
{
|
||||
$argument = new ArgumentMetadata('RequestDto', RequestDto::class, false, false, null);
|
||||
$request = new Request(
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
['REQUEST_METHOD' => Request::METHOD_POST],
|
||||
json_encode(['param' => 'parameter'], JSON_THROW_ON_ERROR)
|
||||
);
|
||||
|
||||
$result = $this->resolver->resolve($request, $argument);
|
||||
|
||||
static::assertInstanceOf(Generator::class, $result);
|
||||
static::assertInstanceOf(RequestDto::class, $result->current());
|
||||
static::assertEquals('parameter', $result->current()->param);
|
||||
}
|
||||
|
||||
public function testResolvePostFailure(): void
|
||||
{
|
||||
$argument = new ArgumentMetadata('RequestDto', RequestDto::class, false, false, null);
|
||||
$request = new Request(
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
['REQUEST_METHOD' => Request::METHOD_POST],
|
||||
json_encode(['param' => null], JSON_THROW_ON_ERROR)
|
||||
);
|
||||
|
||||
$this->expectException(InvalidRequestArgumentException::class);
|
||||
|
||||
$result = $this->resolver->resolve($request, $argument);
|
||||
$result->current();
|
||||
}
|
||||
|
||||
public function testResolveGet(): void
|
||||
{
|
||||
$argument = new ArgumentMetadata('RequestDto', RequestDto::class, false, false, null);
|
||||
$request = new Request(
|
||||
['param' => 'parameter'],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[]
|
||||
);
|
||||
|
||||
$result = $this->resolver->resolve($request, $argument);
|
||||
|
||||
static::assertInstanceOf(Generator::class, $result);
|
||||
static::assertInstanceOf(RequestDto::class, $result->current());
|
||||
static::assertEquals('parameter', $result->current()->param);
|
||||
}
|
||||
|
||||
public function testResolveGetFailure(): void
|
||||
{
|
||||
$argument = new ArgumentMetadata('RequestDto', RequestDto::class, false, false, null);
|
||||
$request = new Request(
|
||||
['param' => null],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[]
|
||||
);
|
||||
|
||||
$this->expectException(InvalidRequestArgumentException::class);
|
||||
|
||||
$result = $this->resolver->resolve($request, $argument);
|
||||
$result->current();
|
||||
}
|
||||
}
|
19
Tests/DataFixtures/RequestDto.php
Normal file
19
Tests/DataFixtures/RequestDto.php
Normal file
@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace RetailCrm\ServiceBundle\Tests\DataFixtures;
|
||||
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
/**
|
||||
* Class RequestDto
|
||||
*
|
||||
* @package RetailCrm\ServiceBundle\Tests\DataFixtures
|
||||
*/
|
||||
class RequestDto
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
* @Assert\NotNull()
|
||||
*/
|
||||
public $param;
|
||||
}
|
37
Tests/DataFixtures/User.php
Normal file
37
Tests/DataFixtures/User.php
Normal file
@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
namespace RetailCrm\ServiceBundle\Tests\DataFixtures;
|
||||
|
||||
use Symfony\Component\Security\Core\User\UserInterface;
|
||||
|
||||
/**
|
||||
* Class User
|
||||
*
|
||||
* @package RetailCrm\ServiceBundle\Tests\DataFixtures
|
||||
*/
|
||||
class User implements UserInterface
|
||||
{
|
||||
public function getRoles(): array
|
||||
{
|
||||
return ["USER"];
|
||||
}
|
||||
|
||||
public function getPassword(): string
|
||||
{
|
||||
return "123";
|
||||
}
|
||||
|
||||
public function getSalt(): string
|
||||
{
|
||||
return "salt";
|
||||
}
|
||||
|
||||
public function getUsername(): string
|
||||
{
|
||||
return "user";
|
||||
}
|
||||
|
||||
public function eraseCredentials(): void
|
||||
{
|
||||
}
|
||||
}
|
77
Tests/DependencyInjection/ConfigurationTest.php
Normal file
77
Tests/DependencyInjection/ConfigurationTest.php
Normal file
@ -0,0 +1,77 @@
|
||||
<?php
|
||||
|
||||
namespace RetailCrm\ServiceBundle\Tests\DependencyInjection;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use RetailCrm\ServiceBundle\DependencyInjection\Configuration;
|
||||
use Symfony\Component\Config\Definition\Processor;
|
||||
|
||||
/**
|
||||
* Class ConfigurationTest
|
||||
*
|
||||
* @package RetailCrm\ServiceBundle\Tests\DependencyInjection
|
||||
*/
|
||||
class ConfigurationTest extends TestCase
|
||||
{
|
||||
public function testConfig(): void
|
||||
{
|
||||
$processor = new Processor();
|
||||
|
||||
$configs = [
|
||||
[
|
||||
'request_schema' => [
|
||||
'callback' => [
|
||||
[
|
||||
'type' => 'type',
|
||||
'params' => ['param']
|
||||
]
|
||||
],
|
||||
'client' => [
|
||||
'type1',
|
||||
'type2'
|
||||
]
|
||||
]
|
||||
]
|
||||
];
|
||||
|
||||
$config = $processor->processConfiguration(new Configuration(), $configs);
|
||||
|
||||
static::assertArrayHasKey('request_schema', $config);
|
||||
static::assertArrayHasKey('callback', $config['request_schema']);
|
||||
static::assertArrayHasKey('client', $config['request_schema']);
|
||||
static::assertEquals(
|
||||
[
|
||||
'type' => 'type',
|
||||
'params' => ['param']
|
||||
],
|
||||
$config['request_schema']['callback'][0]
|
||||
);
|
||||
static::assertEquals(
|
||||
[
|
||||
'type1',
|
||||
'type2'
|
||||
],
|
||||
$config['request_schema']['client']
|
||||
);
|
||||
}
|
||||
|
||||
public function testPartConfig(): void
|
||||
{
|
||||
$processor = new Processor();
|
||||
|
||||
$configs = [
|
||||
[
|
||||
'request_schema' => [
|
||||
'client' => [
|
||||
'type',
|
||||
]
|
||||
]
|
||||
]
|
||||
];
|
||||
|
||||
$config = $processor->processConfiguration(new Configuration(), $configs);
|
||||
|
||||
static::assertArrayHasKey('client', $config['request_schema']);
|
||||
static::assertEquals(['type'], $config['request_schema']['client']);
|
||||
}
|
||||
}
|
55
Tests/DependencyInjection/RetailCrmServiceExtensionTest.php
Normal file
55
Tests/DependencyInjection/RetailCrmServiceExtensionTest.php
Normal file
@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
namespace RetailCrm\ServiceBundle\Tests\DependencyInjection;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use RetailCrm\ServiceBundle\ArgumentResolver\CallbackValueResolver;
|
||||
use RetailCrm\ServiceBundle\ArgumentResolver\ClientValueResolver;
|
||||
use RetailCrm\ServiceBundle\DependencyInjection\RetailCrmServiceExtension;
|
||||
use RetailCrm\ServiceBundle\Response\ErrorJsonResponseFactory;
|
||||
use RetailCrm\ServiceBundle\Security\CallbackClientAuthenticator;
|
||||
use RetailCrm\ServiceBundle\Security\FrontApiClientAuthenticator;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\ParameterBag\EnvPlaceholderParameterBag;
|
||||
|
||||
/**
|
||||
* Class RetailCrmServiceExtensionTest
|
||||
*
|
||||
* @package RetailCrm\ServiceBundle\Tests\DependencyInjection
|
||||
*/
|
||||
class RetailCrmServiceExtensionTest extends TestCase
|
||||
{
|
||||
private $container;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$container = new ContainerBuilder(new EnvPlaceholderParameterBag());
|
||||
$container->getCompilerPassConfig()->setOptimizationPasses([]);
|
||||
$container->getCompilerPassConfig()->setRemovingPasses([]);
|
||||
|
||||
$extension = new RetailCrmServiceExtension();
|
||||
$extension->load(
|
||||
[
|
||||
[
|
||||
'request_schema' => []
|
||||
]
|
||||
],
|
||||
$container
|
||||
);
|
||||
|
||||
$container->compile();
|
||||
|
||||
$this->container = $container;
|
||||
}
|
||||
|
||||
public function testLoad(): void
|
||||
{
|
||||
static::assertTrue($this->container->hasParameter('retail_crm_service.request_schema.callback'));
|
||||
static::assertTrue($this->container->hasParameter('retail_crm_service.request_schema.client'));
|
||||
static::assertTrue($this->container->hasDefinition(CallbackValueResolver::class));
|
||||
static::assertTrue($this->container->hasDefinition(ClientValueResolver::class));
|
||||
static::assertTrue($this->container->hasDefinition(ErrorJsonResponseFactory::class));
|
||||
static::assertTrue($this->container->hasDefinition(CallbackClientAuthenticator::class));
|
||||
static::assertTrue($this->container->hasDefinition(FrontApiClientAuthenticator::class));
|
||||
}
|
||||
}
|
35
Tests/Response/ErrorJsonResponseFactoryTest.php
Normal file
35
Tests/Response/ErrorJsonResponseFactoryTest.php
Normal file
@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
namespace RetailCrm\ServiceBundle\Tests\Response;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use RetailCrm\ServiceBundle\Models\Error;
|
||||
use RetailCrm\ServiceBundle\Response\ErrorJsonResponseFactory;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Serializer\Encoder\JsonEncoder;
|
||||
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
|
||||
use Symfony\Component\Serializer\Serializer;
|
||||
|
||||
class ErrorJsonResponseFactoryTest extends TestCase
|
||||
{
|
||||
private $serializer;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->serializer = new Serializer([new ObjectNormalizer()], [new JsonEncoder()]);
|
||||
}
|
||||
|
||||
public function testCreate(): void
|
||||
{
|
||||
$factory = new ErrorJsonResponseFactory($this->serializer);
|
||||
$error = new Error();
|
||||
$error->message = 'Test error message';
|
||||
|
||||
$result = $factory->create($error);
|
||||
|
||||
static::assertInstanceOf(JsonResponse::class, $result);
|
||||
static::assertEquals(Response::HTTP_BAD_REQUEST, $result->getStatusCode());
|
||||
static::assertEquals('{"code":null,"message":"Test error message","details":null}', $result->getContent());
|
||||
}
|
||||
}
|
135
Tests/Security/CallbackClientAuthenticatorTest.php
Normal file
135
Tests/Security/CallbackClientAuthenticatorTest.php
Normal file
@ -0,0 +1,135 @@
|
||||
<?php
|
||||
|
||||
namespace RetailCrm\ServiceBundle\Tests\Security;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use RetailCrm\ServiceBundle\Response\ErrorJsonResponseFactory;
|
||||
use RetailCrm\ServiceBundle\Security\CallbackClientAuthenticator;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Security\Core\Exception\AuthenticationException;
|
||||
use Symfony\Component\Security\Core\User\UserInterface;
|
||||
|
||||
/**
|
||||
* Class CallbackClientAuthenticatorTest
|
||||
*
|
||||
* @package RetailCrm\ServiceBundle\Tests\Security
|
||||
*/
|
||||
class CallbackClientAuthenticatorTest extends TestCase
|
||||
{
|
||||
public function testStart(): void
|
||||
{
|
||||
$errorResponseFactory = $this->createMock(ErrorJsonResponseFactory::class);
|
||||
$errorResponseFactory
|
||||
->expects(static::once())
|
||||
->method('create')
|
||||
->willReturn(
|
||||
new JsonResponse(['message' => 'Authentication required'], Response::HTTP_UNAUTHORIZED)
|
||||
);
|
||||
|
||||
$auth = new CallbackClientAuthenticator($errorResponseFactory);
|
||||
$result = $auth->start(new Request(), new AuthenticationException());
|
||||
|
||||
static::assertInstanceOf(JsonResponse::class, $result);
|
||||
static::assertEquals(Response::HTTP_UNAUTHORIZED, $result->getStatusCode());
|
||||
}
|
||||
|
||||
public function testGetCredentials(): void
|
||||
{
|
||||
$errorResponseFactory = $this->createMock(ErrorJsonResponseFactory::class);
|
||||
|
||||
$auth = new CallbackClientAuthenticator($errorResponseFactory);
|
||||
$result = $auth->getCredentials(new Request([], [CallbackClientAuthenticator::AUTH_FIELD => '123']));
|
||||
|
||||
static::assertEquals('123', $result);
|
||||
|
||||
$result = $auth->getCredentials(new Request([CallbackClientAuthenticator::AUTH_FIELD => '123']));
|
||||
|
||||
static::assertEquals('123', $result);
|
||||
}
|
||||
|
||||
public function testCheckCredentials(): void
|
||||
{
|
||||
$errorResponseFactory = $this->createMock(ErrorJsonResponseFactory::class);
|
||||
|
||||
$user = new class implements UserInterface {
|
||||
public function getRoles(): array
|
||||
{
|
||||
return ["USER"];
|
||||
}
|
||||
|
||||
public function getPassword(): string
|
||||
{
|
||||
return "123";
|
||||
}
|
||||
|
||||
public function getSalt(): string
|
||||
{
|
||||
return "salt";
|
||||
}
|
||||
|
||||
public function getUsername(): string
|
||||
{
|
||||
return "user";
|
||||
}
|
||||
|
||||
public function eraseCredentials(): void
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
$auth = new CallbackClientAuthenticator($errorResponseFactory);
|
||||
$result = $auth->checkCredentials(new Request(), $user);
|
||||
|
||||
static::assertTrue($result);
|
||||
}
|
||||
|
||||
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->start(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 testSupportsRememberMe(): void
|
||||
{
|
||||
$errorResponseFactory = $this->createMock(ErrorJsonResponseFactory::class);
|
||||
|
||||
$auth = new CallbackClientAuthenticator($errorResponseFactory);
|
||||
$result = $auth->supportsRememberMe();
|
||||
|
||||
static::assertFalse($result);
|
||||
}
|
||||
}
|
123
Tests/Security/FrontApiClientAuthenticatorTest.php
Normal file
123
Tests/Security/FrontApiClientAuthenticatorTest.php
Normal file
@ -0,0 +1,123 @@
|
||||
<?php
|
||||
|
||||
namespace RetailCrm\ServiceBundle\Tests\Security;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use RetailCrm\ServiceBundle\Response\ErrorJsonResponseFactory;
|
||||
use RetailCrm\ServiceBundle\Security\CallbackClientAuthenticator;
|
||||
use RetailCrm\ServiceBundle\Security\FrontApiClientAuthenticator;
|
||||
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\Exception\AuthenticationException;
|
||||
use Symfony\Component\Security\Core\Security;
|
||||
use Symfony\Component\Security\Core\User\UserInterface;
|
||||
|
||||
/**
|
||||
* Class FrontApiClientAuthenticatorTest
|
||||
*
|
||||
* @package RetailCrm\ServiceBundle\Tests\Security
|
||||
*/
|
||||
class FrontApiClientAuthenticatorTest extends TestCase
|
||||
{
|
||||
public function testStart(): void
|
||||
{
|
||||
$errorResponseFactory = $this->createMock(ErrorJsonResponseFactory::class);
|
||||
$errorResponseFactory
|
||||
->expects(static::once())
|
||||
->method('create')
|
||||
->willReturn(
|
||||
new JsonResponse(['message' => 'Authentication required'], Response::HTTP_UNAUTHORIZED)
|
||||
);
|
||||
$security = $this->createMock(Security::class);
|
||||
|
||||
$auth = new FrontApiClientAuthenticator($errorResponseFactory, $security);
|
||||
$result = $auth->start(new Request(), new AuthenticationException());
|
||||
|
||||
static::assertInstanceOf(JsonResponse::class, $result);
|
||||
static::assertEquals(Response::HTTP_UNAUTHORIZED, $result->getStatusCode());
|
||||
}
|
||||
|
||||
public function testGetCredentials(): void
|
||||
{
|
||||
$errorResponseFactory = $this->createMock(ErrorJsonResponseFactory::class);
|
||||
$security = $this->createMock(Security::class);
|
||||
|
||||
$auth = new FrontApiClientAuthenticator($errorResponseFactory, $security);
|
||||
$result = $auth->getCredentials(new Request([], [CallbackClientAuthenticator::AUTH_FIELD => '123']));
|
||||
|
||||
static::assertEquals('123', $result);
|
||||
|
||||
$result = $auth->getCredentials(new Request([CallbackClientAuthenticator::AUTH_FIELD => '123']));
|
||||
|
||||
static::assertEquals('123', $result);
|
||||
}
|
||||
|
||||
public function testCheckCredentials(): void
|
||||
{
|
||||
$errorResponseFactory = $this->createMock(ErrorJsonResponseFactory::class);
|
||||
$security = $this->createMock(Security::class);
|
||||
|
||||
$auth = new FrontApiClientAuthenticator($errorResponseFactory, $security);
|
||||
$result = $auth->checkCredentials(new Request(), new User());
|
||||
|
||||
static::assertTrue($result);
|
||||
}
|
||||
|
||||
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
|
||||
)
|
||||
);
|
||||
$security = $this->createMock(Security::class);
|
||||
|
||||
$auth = new FrontApiClientAuthenticator($errorResponseFactory, $security);
|
||||
$result = $auth->start(new Request(), new AuthenticationException());
|
||||
|
||||
static::assertInstanceOf(JsonResponse::class, $result);
|
||||
static::assertEquals(Response::HTTP_FORBIDDEN, $result->getStatusCode());
|
||||
}
|
||||
|
||||
public function testSupportsFalse(): void
|
||||
{
|
||||
$errorResponseFactory = $this->createMock(ErrorJsonResponseFactory::class);
|
||||
$security = $this->createMock(Security::class);
|
||||
$security->method('getUser')->willReturn(new User());
|
||||
|
||||
$auth = new FrontApiClientAuthenticator($errorResponseFactory, $security);
|
||||
$result = $auth->supports(new Request());
|
||||
|
||||
static::assertFalse($result);
|
||||
}
|
||||
|
||||
public function testSupportsTrue(): void
|
||||
{
|
||||
$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']));
|
||||
|
||||
static::assertTrue($result);
|
||||
}
|
||||
|
||||
public function testSupportsRememberMe(): void
|
||||
{
|
||||
$errorResponseFactory = $this->createMock(ErrorJsonResponseFactory::class);
|
||||
$security = $this->createMock(Security::class);
|
||||
|
||||
$auth = new FrontApiClientAuthenticator($errorResponseFactory, $security);
|
||||
$result = $auth->supportsRememberMe();
|
||||
|
||||
static::assertTrue($result);
|
||||
}
|
||||
}
|
43
composer.json
Normal file
43
composer.json
Normal file
@ -0,0 +1,43 @@
|
||||
{
|
||||
"name": "retailcrm/service-bundle",
|
||||
"description": "Core bundle for RetailCRM integration services",
|
||||
"type": "symfony-bundle",
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
{
|
||||
"name": "RetailCRM",
|
||||
"email": "support@retailcrm.pro"
|
||||
}
|
||||
],
|
||||
"minimum-stability": "stable",
|
||||
"require": {
|
||||
"php": ">=7.3",
|
||||
"symfony/framework-bundle": "^4.0|^5.0",
|
||||
"symfony/serializer": "^5.2",
|
||||
"symfony/http-kernel": "^4.0|^5.0",
|
||||
"symfony/validator": "^4.0|^5.0",
|
||||
"symfony/security-guard": "^4.0|^5.0"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"RetailCrm\\ServiceBundle\\": ""
|
||||
},
|
||||
"exclude-from-classmap": [
|
||||
"Tests/"
|
||||
]
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"RetailCrm\\ServiceBundle\\Tests\\": "Tests/"
|
||||
}
|
||||
},
|
||||
"require-dev": {
|
||||
"ext-json": "*",
|
||||
"phpunit/phpunit": "^8.0 || ^9.0",
|
||||
"doctrine/annotations": "^1.11",
|
||||
"doctrine/cache": "^1.10"
|
||||
},
|
||||
"scripts": {
|
||||
"tests": "./vendor/bin/phpunit -c phpunit.xml.dist"
|
||||
}
|
||||
}
|
33
phpunit.xml.dist
Normal file
33
phpunit.xml.dist
Normal file
@ -0,0 +1,33 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<phpunit backupGlobals="false"
|
||||
backupStaticAttributes="false"
|
||||
colors="true"
|
||||
convertErrorsToExceptions="true"
|
||||
convertNoticesToExceptions="true"
|
||||
convertWarningsToExceptions="true"
|
||||
processIsolation="false"
|
||||
stopOnFailure="false"
|
||||
bootstrap="vendor/autoload.php"
|
||||
>
|
||||
<coverage>
|
||||
<include>
|
||||
<directory>./</directory>
|
||||
</include>
|
||||
<exclude>
|
||||
<directory>./Tests</directory>
|
||||
<directory>./vendor</directory>
|
||||
</exclude>
|
||||
<report>
|
||||
<clover outputFile="coverage.xml"/>
|
||||
</report>
|
||||
</coverage>
|
||||
<testsuites>
|
||||
<testsuite name="RetailCRM Service Bundle Tests">
|
||||
<directory>./Tests</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
<logging>
|
||||
<junit outputFile="test-report.xml"/>
|
||||
</logging>
|
||||
</phpunit>
|
Loading…
Reference in New Issue
Block a user