Created
November 1, 2020 17:21
-
-
Save yceruto/f1500b350065481568a3b2971fde8d0f to your computer and use it in GitHub Desktop.
Guard Authenticator for OAuth2Bundle (https://github.com/trikoder/oauth2-bundle)
This file contains hidden or 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
<?php | |
namespace App\Security\Authentication\Token; | |
use Symfony\Component\Security\Guard\Token\GuardTokenInterface; | |
use Trikoder\Bundle\OAuth2Bundle\Security\Authentication\Token\OAuth2Token; | |
class OAuth2GuardToken implements GuardTokenInterface | |
{ | |
private $token; | |
public function __construct(OAuth2Token $token) | |
{ | |
$this->token = $token; | |
} | |
// ... | |
} |
This file contains hidden or 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
<?php | |
namespace App\Security\Guard; | |
use App\Security\Authentication\Token\OAuth2GuardToken; | |
use League\OAuth2\Server\Exception\OAuthServerException; | |
use League\OAuth2\Server\ResourceServer; | |
use Symfony\Bridge\PsrHttpMessage\HttpMessageFactoryInterface; | |
use Symfony\Component\HttpFoundation\JsonResponse; | |
use Symfony\Component\HttpFoundation\Request; | |
use Symfony\Component\HttpFoundation\Response; | |
use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException; | |
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; | |
use Trikoder\Bundle\OAuth2Bundle\Security\Authentication\Token\OAuth2Token; | |
use Trikoder\Bundle\OAuth2Bundle\Security\Authentication\Token\OAuth2TokenFactory; | |
use Trikoder\Bundle\OAuth2Bundle\Security\Exception\InsufficientScopesException; | |
use Trikoder\Bundle\OAuth2Bundle\Security\Exception\Oauth2AuthenticationFailedException; | |
class OAuth2TokenAuthenticator extends AbstractGuardAuthenticator | |
{ | |
private $httpMessageFactory; | |
private $resourceServer; | |
private $oauth2TokenFactory; | |
private $psr7Request; | |
public function __construct(HttpMessageFactoryInterface $httpMessageFactory, ResourceServer $resourceServer, OAuth2TokenFactory $oauth2TokenFactory) | |
{ | |
$this->httpMessageFactory = $httpMessageFactory; | |
$this->resourceServer = $resourceServer; | |
$this->oauth2TokenFactory = $oauth2TokenFactory; | |
} | |
public function start(Request $request, AuthenticationException $authException = null): Response | |
{ | |
$exception = new UnauthorizedHttpException('Bearer'); | |
return new JsonResponse(['code' => $exception->getCode(), 'message' => ''], $exception->getCode(), $exception->getHeaders()); | |
} | |
public function supports(Request $request): bool | |
{ | |
return 0 === strpos($request->headers->get('Authorization'), 'Bearer '); | |
} | |
public function getCredentials(Request $request) | |
{ | |
$psr7Request = $this->httpMessageFactory->createRequest($request); | |
try { | |
$this->psr7Request = $this->resourceServer->validateAuthenticatedRequest($psr7Request); | |
} catch (OAuthServerException $e) { | |
throw new AuthenticationException('The resource server rejected the request.', 0, $e); | |
} | |
return $this->psr7Request->getAttribute('oauth_user_id'); | |
} | |
public function getUser($userIdentifier, UserProviderInterface $userProvider): ?UserInterface | |
{ | |
if ('' === $userIdentifier) { | |
/* | |
* If the identifier is an empty string, that means that the | |
* access token isn't bound to a user defined in the system. | |
*/ | |
return null; | |
} | |
return $userProvider->loadUserByUsername($userIdentifier); | |
} | |
public function checkCredentials($token, UserInterface $user): bool | |
{ | |
return true; | |
} | |
public function createAuthenticatedToken(UserInterface $user, $providerKey): OAuth2GuardToken | |
{ | |
$oauth2Token = $this->oauth2TokenFactory->createOAuth2Token($this->psr7Request, $user, $providerKey); | |
if (!$this->isAccessToRouteGranted($oauth2Token)) { | |
throw InsufficientScopesException::create($oauth2Token); | |
} | |
$oauth2Token->setAuthenticated(true); | |
return new OAuth2GuardToken($oauth2Token); | |
} | |
public function onAuthenticationFailure(Request $request, AuthenticationException $exception): ?Response | |
{ | |
if ($exception instanceof InsufficientScopesException || $exception instanceof Oauth2AuthenticationFailedException) { | |
return new JsonResponse([ | |
'code' => $exception->getCode(), | |
'message' => $exception->getMessage(), | |
], $exception->getCode()); | |
} | |
$previous = $exception->getPrevious(); | |
if ($previous instanceof OAuthServerException) { | |
return new JsonResponse([ | |
'code' => $previous->getHttpStatusCode(), | |
'message' => $exception->getMessage(), | |
], $previous->getHttpStatusCode(), $previous->getHttpHeaders()); | |
} | |
return $this->start($request, $exception); | |
} | |
public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey): ?Response | |
{ | |
return $this->psr7Request = null; | |
} | |
public function supportsRememberMe(): bool | |
{ | |
return false; | |
} | |
private function isAccessToRouteGranted(OAuth2Token $token): bool | |
{ | |
$routeScopes = $this->psr7Request->getAttribute('oauth2_scopes', []); | |
if ([] === $routeScopes) { | |
return true; | |
} | |
$tokenScopes = $token | |
->getAttribute('server_request') | |
->getAttribute('oauth_scopes'); | |
/* | |
* If the end result is empty that means that all route | |
* scopes are available inside the issued token scopes. | |
*/ | |
return [] === array_diff($routeScopes, $tokenScopes); | |
} | |
} |
This file contains hidden or 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
security: | |
# ... | |
firewalls: | |
api: | |
# ... | |
guard: | |
entry_point: App\Security\Guard\OAuth2TokenAuthenticator | |
authenticators: | |
- App\Security\Guard\OAuth2TokenAuthenticator |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment