Introduction
Access Voter (wk-phx-access-voter) is a PHP package for validating privileges and steward within Phoenix Microservices.
Access Voter uses symfony/security package to get security annotations and their parameters within the library.
Requires:
- “php”:”^7.2”
- sensio/framework-extra-bundle: ^5.1
- symfony/security-bundle: ^4.3
- symfony/security: ^4.3
- symfony/expression-language: ^4.3
- symfony/http-foundation: ^4.0
Auth API will pass privilege access and steward access at the header, to retrieve from the header parameter and validate as per resource actions and requested action, using symfony/http-foundation to get the \Request object.
Symfony Docs
The @Security and @IsGranted annotations restrict access on controllers:
/**
* @Security(
* "is_granted('attribute', 'subject') and is_granted('attribute', 'subject') …",
* statusCode='401',
* message='Do not have permission')
*/
Header Parameters
To use Access voter expected header parameters.
- pvg - used to validate privilege level access
- std - used to validate steward level access
Installation
In applications using Symfony Voter, run this command to install the Phx access voter based security annotation before using it:
composer require wk-phx/access-voter
Dependency
While installing phx/access-voter all dependency packages will be installed automatically.
-
symfony/http-foundation
Access voter needs \RequestStack object to get Current Request, with the help of \Request object we can get header and query parameters.Symfony\Component\HttpFoundation\RequestStack; Symfony\Component\HttpFoundation\Request;
-
symfony/security
Access voter needs \Voter to get security annotation’s attributes and subject.Symfony\Component\Security\Core\Authorization\Voter\Voter; Symfony\Component\Security\Core\Authentication\Token\TokenInterface
Privilege Validation
use @Security and @IsGranted library at the top of the controller, after adding security annotation for the privilege as the subject with their attribute.
src/Modules/Asset/AssetController.php
use Sensio\Bundle\FrameworkExtraBundle\Configuration\{
Security,
IsGranted
};
class AssetController extends Controller
{
/**
* @Security(
* "is_granted('cr', 'privilege'))",
* statusCode='401',
* message='Do not have permission'
* )
*/
public function create()
{
// ...
}
}
To use Access Voter and extend the class within microservice, we need to create a class.
To extend the feature of Access Voter library, we have to pass within constructor required parameters
- resourceName (Required)
is the name of the microservice. - \RequestStack (Required)
is allowed access voter to get request object of the method. - \StewardInterface
is required only if we wanted to implement steward validation within microservice.
Path of the class can be src/Security/ .
src/Security/AssetVoter.php
namespace App\Security;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\RequestStack;
use Wk\Phx\Security\AccessVoter;
/**
* Middle ware class to validate Role permissions for Assets
* @package Asset
*/
class AssetVoter extends AccessVoter
{
/**
* Asset voter construct
* @param ContainerInterface $container
* @param RequestStack $requestStack
*/
public function __construct(ContainerInterface $container, RequestStack $requestStack)
{
$resourceName = $container->getParameter('RESOURCE_NAME');
// resourceName => Asset Manager
parent::__construct($resourceName, $requestStack);
}
}
To execute that created class we need to define directory path within config/service.yaml
config/service.yaml
App\Security\:
resource: '../src/Security/*'
public: true
Steward Pre Validate and Steward Filter
To use steward-pre-validate or steward-filter with should implement the first Wk\Phx\Security\Dependency\StewardInterface.
NOTE: without implementing if we are passing steward-pre-validate or steward-filter it will return 401 - Do not have permission
src/Modules/Steward/StewardInterceptor.php
namespace App\Modules\Steward;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\Request;
use Wk\Phx\Security\Dependency\StewardInterface;
/**
* Description of StewardInterceptor
*/
class StewardInterceptor implements StewardInterface
{
/**
* @var string
*/
const ALLOWED_STEWARD_IDS = 'allowedStewardIds';
/**
* Using request object get resource identifier assetId and returns stewardId
* @param Request $reuqest
* @return string
*/
public function getStewardId(Request $reuqest): string
{
$assetId = $reuqest->get('assetId');
// return stewardId by Asset Id
return $this->repository->getStewardByAssetId($assetId);
}
/**
* returns StewardId from Payload using request object
* @param Request $request
* @return string
*/
public function getStewardIdFromPayload(Request $request): string
{
$bodyContentArray = json_decode($request->getContent(), true);
// find if stewardId key is available in $bodyContentPayload
return $bodyContentArray[‘stewardId’];
}
/**
* setting allowed steward ids to query parameter which we can use within DTO to pass SQL Query
* @param Request $request
* @param string $allowedStewardIds
*/
public function setAllowedStewardIds(Request $request, string $allowedStewardIds)
{
$request->query->set(self::ALLOWED_STEWARD_IDS, $allowedStewardIds);
return $request;
}
}
After implementing the StewardInterface we should define the alias to access the class through the interface.
config/service.yaml
Wk\Phx\Security\Dependency\StewardInterface: '@App\Modules\Steward\StewardInterceptor'
use @Security and @IsGranted library at the top of the controller, after adding security annotation for the steward-pre-validate or steward-filter as the subject with their attribute.
src/Modules/Asset/AssetController.php
use Sensio\Bundle\FrameworkExtraBundle\Configuration\{
Security,
IsGranted
};
class AssetController extends Controller
{
// Constant variables to access inside security annotation block
const SECURITY_ANNOTATION_STATUS_CODE = 401;
const SECURITY_ANNOTATION_STATUS_MESSAGE = "Do not have permission";
/**
* @Security(
* "is_granted('cr', 'privilege') and is_granted('cr', 'steward-pre-validate')",
* statusCode=AssetController::SECURITY_ANNOTATION_STATUS_CODE,
* message=AssetController::SECURITY_ANNOTATION_STATUS_MESSAGE
* )
*/
public function create(Request $request)
{
// ...
}
}
src/Security/AssetVoter.php
namespace App\Security;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\RequestStack;
use Wk\Phx\Security\AccessVoter;
use Wk\Phx\Security\Dependency\StewardInterface;
/**
* Middle ware class to validate Role permissions for Assets
* @package Asset
*/
class AssetVoter extends AccessVoter
{
/**
* Asset voter construct
* @param ContainerInterface $container
* @param RequestStack $requestStack
* @param StewardInterface $steward
*/
public function __construct(ContainerInterface $container, RequestStack $requestStack, StewardInterface $steward)
{
$resourceName = $container->getParameter('RESOURCE_NAME');
// Asset Manager
parent::__construct($resourceName, $requestStack, $steward);
}
}
Uninstallation
To remove access-voter, can use below command
composer remove wk-phx/access-voter
Reference
- https://symfony.com/doc/current/bundles/SensioFrameworkExtraBundle/annotations/security.html
- https://symfony.com/doc/current/security/voters.html
- https://symfony.com/doc/current/service_container/request.html
- https://symfony.com/doc/current/components/http_foundation.html
- https://packagist.org/packages/wk-phx/access-voter