-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add user voters and api token authenticator
- Loading branch information
Showing
4 changed files
with
326 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
<?php | ||
|
||
namespace Glavweb\CoreBundle\Security\Authorization; | ||
|
||
use Doctrine\Bundle\DoctrineBundle\Registry; | ||
use Symfony\Component\HttpFoundation\Response; | ||
use Symfony\Component\Security\Core\Authentication\SimplePreAuthenticatorInterface; | ||
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; | ||
use Symfony\Component\Security\Core\Exception\AuthenticationException; | ||
use Symfony\Component\Security\Core\Authentication\Token\PreAuthenticatedToken; | ||
use Symfony\Component\HttpFoundation\Request; | ||
use Symfony\Component\Security\Core\User\UserProviderInterface; | ||
use UserBundle\Entity\User; | ||
|
||
/** | ||
* Class ApiTokenAuthenticator | ||
* @package Glavweb\CoreBundle\Security\Authorization | ||
*/ | ||
class ApiTokenAuthenticator implements SimplePreAuthenticatorInterface | ||
{ | ||
/** | ||
* @var Registry | ||
*/ | ||
private $doctrine; | ||
|
||
/** | ||
* @param Registry $doctrine | ||
*/ | ||
public function __construct(Registry $doctrine) | ||
{ | ||
$this->doctrine = $doctrine; | ||
} | ||
|
||
/** | ||
* @param Request $request | ||
* @param string $providerKey | ||
* @return PreAuthenticatedToken | ||
*/ | ||
public function createToken(Request $request, $providerKey) | ||
{ | ||
$credentials = array( | ||
'token' => $this->getValueByHeaderOrCookie($request, 'Token'), | ||
'username' => $this->getValueByHeaderOrCookie($request, 'Username'), | ||
'expireAt' => $this->getValueByHeaderOrCookie($request, 'ExpireAt'), | ||
); | ||
|
||
return new PreAuthenticatedToken( | ||
'anon.', | ||
$credentials, | ||
$providerKey | ||
); | ||
} | ||
|
||
/** | ||
* @param TokenInterface $token | ||
* @param UserProviderInterface $userProvider | ||
* @param string $providerKey | ||
* @return PreAuthenticatedToken | ||
*/ | ||
public function authenticateToken(TokenInterface $token, UserProviderInterface $userProvider, $providerKey) | ||
{ | ||
$em = $this->doctrine->getManager(); | ||
$userRepository = $em->getRepository('UserBundle:User'); | ||
|
||
$credentials = $token->getCredentials(); | ||
|
||
/** @var User $user */ | ||
|
||
if ($credentials['token']) { | ||
$user = $userRepository->findOneByApiToken($credentials['token']); | ||
|
||
if ($user) { | ||
return new PreAuthenticatedToken( | ||
$user, | ||
$credentials, | ||
$providerKey, | ||
$user->getRoles() | ||
); | ||
} | ||
} | ||
|
||
return new PreAuthenticatedToken( | ||
'anon.', | ||
$credentials, | ||
$providerKey | ||
); | ||
} | ||
|
||
/** | ||
* @param Request $request | ||
* @param AuthenticationException $exception | ||
* @return Response | ||
*/ | ||
public function onAuthenticationFailure(Request $request, AuthenticationException $exception) | ||
{ | ||
return new Response("Authentication Failed.", 403); | ||
} | ||
|
||
/** | ||
* @param TokenInterface $token | ||
* @param string $providerKey | ||
* @return bool | ||
*/ | ||
public function supportsToken(TokenInterface $token, $providerKey) | ||
{ | ||
return $token instanceof PreAuthenticatedToken && $token->getProviderKey() === $providerKey; | ||
} | ||
|
||
/** | ||
* @param Request $request | ||
* @param string $name | ||
* @return array|mixed|string | ||
*/ | ||
private function getValueByHeaderOrCookie(Request $request, $name) | ||
{ | ||
if ($request->headers->has($name)) { | ||
return $request->headers->get($name); | ||
} | ||
|
||
if ($request->cookies->has($name)) { | ||
return $request->cookies->get($name); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
<?php | ||
|
||
namespace Glavweb\CoreBundle\Security\Authorization\Voter; | ||
|
||
use Sonata\UserBundle\Model\HasOwnerInterface; | ||
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; | ||
use Symfony\Component\Security\Core\Authorization\Voter\VoterInterface; | ||
use Symfony\Component\Security\Core\User\UserInterface; | ||
|
||
/** | ||
* Class OwnerVoter | ||
* @package Glavweb\CoreBundle\Security\Authorization\Voter | ||
*/ | ||
class OwnerVoter implements VoterInterface | ||
{ | ||
/** | ||
* Name of owner role | ||
*/ | ||
const ROLE_NAME_OWNER = 'OWNER'; | ||
|
||
/** | ||
* Checks if the voter supports the given attribute. | ||
* | ||
* @param string $attribute An attribute | ||
* | ||
* @return bool true if this Voter supports the attribute, false otherwise | ||
*/ | ||
public function supportsAttribute($attribute) | ||
{ | ||
return true; | ||
} | ||
|
||
/** | ||
* Checks if the voter supports the given class. | ||
* | ||
* @param string $class A class name | ||
* | ||
* @return bool true if this Voter can process the class | ||
*/ | ||
public function supportsClass($class) | ||
{ | ||
$reflectionClass = new \ReflectionClass($class); | ||
return $reflectionClass->implementsInterface('Sonata\UserBundle\Model\HasOwnerInterface'); | ||
} | ||
|
||
/** | ||
* Returns the vote for the given parameters. | ||
* | ||
* This method must return one of the following constants: | ||
* ACCESS_GRANTED, ACCESS_DENIED, or ACCESS_ABSTAIN. | ||
* | ||
* @param TokenInterface $token A TokenInterface instance | ||
* @param object|null $object The object to secure | ||
* @param array $attributes An array of attributes associated with the method being invoked | ||
* | ||
* @return int either ACCESS_GRANTED, ACCESS_ABSTAIN, or ACCESS_DENIED | ||
*/ | ||
public function vote(TokenInterface $token, $object, array $attributes) | ||
{ | ||
if (!$this->supportsClass(get_class($object))) { | ||
return VoterInterface::ACCESS_ABSTAIN; | ||
} | ||
|
||
/** @var UserInterface $user */ | ||
$user = $token->getUser(); | ||
if (!$user instanceof UserInterface) { | ||
return VoterInterface::ACCESS_ABSTAIN; | ||
} | ||
$userRoles = $user->getRoles(); | ||
|
||
foreach ($attributes as $attribute) { | ||
$attribute = $attribute . '_' . self::ROLE_NAME_OWNER; | ||
if (in_array($attribute, $userRoles)) { | ||
$owners = $this->getOwners($object); | ||
|
||
foreach ($owners as $owner) { | ||
if ($owner && $owner->getId() == $user->getId()) { | ||
return VoterInterface::ACCESS_GRANTED; | ||
} | ||
} | ||
} | ||
} | ||
|
||
return VoterInterface::ACCESS_ABSTAIN; | ||
} | ||
|
||
/** | ||
* @param $object | ||
* @return array | ||
*/ | ||
public function getOwners($object) | ||
{ | ||
/** @var HasOwnerInterface $class */ | ||
$class = get_class($object); | ||
$ownerFields = $class::getOwnerFields(); | ||
|
||
$owners = array(); | ||
foreach ($ownerFields as $ownerField) { | ||
if ($ownerField == 'id') { | ||
$owner = $object; | ||
} else { | ||
$method = 'get' . ucfirst($ownerField); | ||
$owner = $object->$method(); | ||
} | ||
|
||
if ($owner instanceof UserInterface) { | ||
$owners[] = $owner; | ||
} | ||
} | ||
|
||
return $owners; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
<?php | ||
|
||
namespace Glavweb\CoreBundle\Security\Authorization\Voter; | ||
|
||
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; | ||
use Symfony\Component\Security\Core\Authorization\Voter\VoterInterface; | ||
use Symfony\Component\Security\Core\User\UserInterface; | ||
|
||
/** | ||
* Class SuperAdminVoter | ||
* @package Glavweb\CoreBundle\Security\Authorization\Voter | ||
*/ | ||
class SuperAdminVoter implements VoterInterface | ||
{ | ||
/** | ||
* Name of super admin role | ||
*/ | ||
const SUPER_ADMIN_ROLE = 'ROLE_SUPER_ADMIN'; | ||
|
||
/** | ||
* Checks if the voter supports the given attribute. | ||
* | ||
* @param string $attribute An attribute | ||
* | ||
* @return bool true if this Voter supports the attribute, false otherwise | ||
*/ | ||
public function supportsAttribute($attribute) | ||
{ | ||
return true; | ||
} | ||
|
||
/** | ||
* Checks if the voter supports the given class. | ||
* | ||
* @param string $class A class name | ||
* | ||
* @return bool true if this Voter can process the class | ||
*/ | ||
public function supportsClass($class) | ||
{ | ||
return true; | ||
} | ||
|
||
/** | ||
* Returns the vote for the given parameters. | ||
* | ||
* This method must return one of the following constants: | ||
* ACCESS_GRANTED, ACCESS_DENIED, or ACCESS_ABSTAIN. | ||
* | ||
* @param TokenInterface $token A TokenInterface instance | ||
* @param object|null $object The object to secure | ||
* @param array $attributes An array of attributes associated with the method being invoked | ||
* | ||
* @return int either ACCESS_GRANTED, ACCESS_ABSTAIN, or ACCESS_DENIED | ||
*/ | ||
public function vote(TokenInterface $token, $object, array $attributes) | ||
{ | ||
/** @var UserInterface $user */ | ||
$user = $token->getUser(); | ||
if (!$user instanceof UserInterface) { | ||
return VoterInterface::ACCESS_ABSTAIN; | ||
} | ||
|
||
$roles = $user->getRoles(); | ||
if (in_array(self::SUPER_ADMIN_ROLE, $roles)) { | ||
return VoterInterface::ACCESS_GRANTED; | ||
} | ||
|
||
return VoterInterface::ACCESS_ABSTAIN; | ||
} | ||
} |