Skip to content

Commit

Permalink
Merge branch 'v3.x'
Browse files Browse the repository at this point in the history
  • Loading branch information
HypeMC committed Feb 16, 2021
2 parents 97ef0bc + 74a8782 commit ca5f14d
Show file tree
Hide file tree
Showing 12 changed files with 416 additions and 18 deletions.
18 changes: 18 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,24 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project [adheres to Semantic Versioning, but only for the public API](README.md#versioning).

## [3.2.0] - 2020-10-26

### Added
- Jobs with the `prefer-lowest` composer flag to CI ([#204](https://github.com/trikoder/oauth2-bundle/pull/204))
- On delete `CASCADE` on authorization code entity client association ([#216](https://github.com/trikoder/oauth2-bundle/pull/216))
- `Trikoder\Bundle\OAuth2Bundle\Event\AbstractUserResolveEvent` abstract class for user resolve events ([#221](https://github.com/trikoder/oauth2-bundle/pull/221))
- Add per grant type configuration options ([#199](https://github.com/trikoder/oauth2-bundle/pull/199))
- CI testing - Symfony 5.1 ([#230](https://github.com/trikoder/oauth2-bundle/pull/230))
- Cleanup command (`trikoder:oauth2:clear-revoked-tokens`) for revoked tokens ([#234](https://github.com/trikoder/oauth2-bundle/pull/234))
- Setter for the `secret` property of the `Client` Doctrine entity ([#239](https://github.com/trikoder/oauth2-bundle/pull/239))

### Changed
- Pass previous exception to`Oauth2AuthenticationFailedException` exception ([#223](https://github.com/trikoder/oauth2-bundle/pull/223))
- Allow PHPUnit 9 ([#238](https://github.com/trikoder/oauth2-bundle/pull/238))

### Deprecated
- Legacy service aliases ([#203](https://github.com/trikoder/oauth2-bundle/pull/203))

## [3.1.1] - 2020-04-10
### Removed
- `userIdentifier` index from `oauth2_access_token` and `oauth2_authorization_code` tables ([6108915](https://github.com/trikoder/oauth2-bundle/commit/6108915ee83c5597160d2be9669966b20d0e461f))
Expand Down
4 changes: 2 additions & 2 deletions DependencyInjection/TrikoderOAuth2Extension.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace Trikoder\Bundle\OAuth2Bundle\DependencyInjection;

use Ajgarlag\Bundle\PsrHttpMessageBundle\AjgarlagPsrHttpMessageBundle;
use DateInterval;
use Defuse\Crypto\Key;
use Doctrine\Bundle\DoctrineBundle\DoctrineBundle;
Expand All @@ -18,7 +19,6 @@
use League\OAuth2\Server\ResourceServer;
use LogicException;
use RuntimeException;
use Sensio\Bundle\FrameworkExtraBundle\SensioFrameworkExtraBundle;
use Symfony\Bundle\SecurityBundle\SecurityBundle;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\Config\Loader\LoaderInterface;
Expand Down Expand Up @@ -115,7 +115,7 @@ private function assertRequiredBundlesAreEnabled(ContainerBuilder $container): v
$requiredBundles = [
'doctrine' => DoctrineBundle::class,
'security' => SecurityBundle::class,
'sensio_framework_extra' => SensioFrameworkExtraBundle::class,
'ajgarlag_psr_http_message' => AjgarlagPsrHttpMessageBundle::class,
];

foreach ($requiredBundles as $bundleAlias => $requiredBundle) {
Expand Down
9 changes: 8 additions & 1 deletion Resources/config/services.xml
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@
<service id="Trikoder\Bundle\OAuth2Bundle\Security\Firewall\OAuth2Listener">
<argument type="service" id="security.token_storage" />
<argument type="service" id="security.authentication.manager" />
<argument type="service" id="sensio_framework_extra.psr7.http_message_factory" />
<argument type="service" id="Symfony\Bridge\PsrHttpMessage\HttpMessageFactoryInterface" />
<argument key="$oauth2TokenFactory" type="service" id="Trikoder\Bundle\OAuth2Bundle\Security\Authentication\Token\OAuth2TokenFactory" />
</service>
<service id="trikoder.oauth2.security.firewall.oauth2_listener" alias="Trikoder\Bundle\OAuth2Bundle\Security\Firewall\OAuth2Listener">
Expand All @@ -94,6 +94,13 @@
<argument key="$grants" type="tagged_iterator" tag="trikoder.oauth2.authorization_server.grant" />
</service>

<!-- Guard Security Layer-->
<service id="Trikoder\Bundle\OAuth2Bundle\Security\Guard\Authenticator\OAuth2Authenticator">
<argument type="service" id="Symfony\Bridge\PsrHttpMessage\HttpMessageFactoryInterface" />
<argument type="service" id="League\OAuth2\Server\ResourceServer" />
<argument type="service" id="Trikoder\Bundle\OAuth2Bundle\Security\Authentication\Token\OAuth2TokenFactory" />
</service>

<!-- The league authorization server -->
<service id="League\OAuth2\Server\AuthorizationServer">
<argument key="$clientRepository" type="service" id="League\OAuth2\Server\Repositories\ClientRepositoryInterface" />
Expand Down
3 changes: 2 additions & 1 deletion Security/Authentication/Token/OAuth2Token.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@
use Psr\Http\Message\ServerRequestInterface;
use Symfony\Component\Security\Core\Authentication\Token\AbstractToken;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Guard\Token\GuardTokenInterface;

final class OAuth2Token extends AbstractToken
final class OAuth2Token extends AbstractToken implements GuardTokenInterface
{
/**
* @var string
Expand Down
126 changes: 126 additions & 0 deletions Security/Guard/Authenticator/OAuth2Authenticator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
<?php

declare(strict_types=1);

namespace Trikoder\Bundle\OAuth2Bundle\Security\Guard\Authenticator;

use League\OAuth2\Server\Exception\OAuthServerException;
use League\OAuth2\Server\ResourceServer;
use Symfony\Bridge\PsrHttpMessage\HttpMessageFactoryInterface;
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\AuthenticatorInterface;
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\User\NullUser;

/**
* @author Yonel Ceruto <yonelceruto@gmail.com>
* @author Antonio J. García Lagar <aj@garcialagar.es>
*/
final class OAuth2Authenticator implements AuthenticatorInterface
{
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 Response('', $exception->getStatusCode(), $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
{
return '' === $userIdentifier ? new NullUser() : $userProvider->loadUserByUsername($userIdentifier);
}

public function checkCredentials($token, UserInterface $user): bool
{
return true;
}

public function createAuthenticatedToken(UserInterface $user, $providerKey): OAuth2Token
{
$tokenUser = $user instanceof NullUser ? null : $user;

$oauth2Token = $this->oauth2TokenFactory->createOAuth2Token($this->psr7Request, $tokenUser, $providerKey);

if (!$this->isAccessToRouteGranted($oauth2Token)) {
throw InsufficientScopesException::create($oauth2Token);
}

$oauth2Token->setAuthenticated(true);

return $oauth2Token;
}

public function onAuthenticationFailure(Request $request, AuthenticationException $exception): ?Response
{
$this->psr7Request = null;

throw $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);
}
}
38 changes: 38 additions & 0 deletions Security/User/NullUser.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<?php

declare(strict_types=1);

namespace Trikoder\Bundle\OAuth2Bundle\Security\User;

use Symfony\Component\Security\Core\User\UserInterface;

/**
* @author Antonio J. García Lagar <aj@garcialagar.es>
*/
final class NullUser implements UserInterface
{
public function getUsername(): string
{
return '';
}

public function getPassword(): string
{
return '';
}

public function getSalt(): ?string
{
return null;
}

public function getRoles(): array
{
return [];
}

public function eraseCredentials(): void
{
return;
}
}
18 changes: 12 additions & 6 deletions Service/CredentialsRevoker/DoctrineCredentialsRevoker.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ public function revokeCredentialsForUser(UserInterface $user): void

$this->entityManager->createQueryBuilder()
->update(AccessToken::class, 'at')
->set('at.revoked', true)
->set('at.revoked', ':revoked')
->setParameter('revoked', true)
->where('at.userIdentifier = :userIdentifier')
->setParameter('userIdentifier', $userIdentifier)
->getQuery()
Expand All @@ -39,7 +40,8 @@ public function revokeCredentialsForUser(UserInterface $user): void
$queryBuilder = $this->entityManager->createQueryBuilder();
$queryBuilder
->update(RefreshToken::class, 'rt')
->set('rt.revoked', true)
->set('rt.revoked', ':revoked')
->setParameter('revoked', true)
->where($queryBuilder->expr()->in(
'rt.accessToken',
$this->entityManager->createQueryBuilder()
Expand All @@ -54,7 +56,8 @@ public function revokeCredentialsForUser(UserInterface $user): void

$this->entityManager->createQueryBuilder()
->update(AuthorizationCode::class, 'ac')
->set('ac.revoked', true)
->set('ac.revoked', ':revoked')
->setParameter('revoked', true)
->where('ac.userIdentifier = :userIdentifier')
->setParameter('userIdentifier', $userIdentifier)
->getQuery()
Expand All @@ -69,15 +72,17 @@ public function revokeCredentialsForClient(Client $client): void

$this->entityManager->createQueryBuilder()
->update(AccessToken::class, 'at')
->set('at.revoked', true)
->set('at.revoked', ':revoked')
->setParameter('revoked', true)
->where('at.client = :client')
->setParameter('client', $doctrineClient)
->getQuery()
->execute();

$queryBuilder = $this->entityManager->createQueryBuilder();
$queryBuilder->update(RefreshToken::class, 'rt')
->set('rt.revoked', true)
->set('rt.revoked', ':revoked')
->setParameter('revoked', true)
->where($queryBuilder->expr()->in(
'rt.accessToken',
$this->entityManager->createQueryBuilder()
Expand All @@ -92,7 +97,8 @@ public function revokeCredentialsForClient(Client $client): void

$this->entityManager->createQueryBuilder()
->update(AuthorizationCode::class, 'ac')
->set('ac.revoked', true)
->set('ac.revoked', ':revoked')
->setParameter('revoked', true)
->where('ac.client = :client')
->setParameter('client', $doctrineClient)
->getQuery()
Expand Down
Loading

0 comments on commit ca5f14d

Please sign in to comment.