Skip to content

Merge v3.x into master #195

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Apr 10, 2020
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,14 @@ 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](http://semver.org/spec/v2.0.0.html).

## [3.1.0] - 2020-04-09
### Added
- Ability to revoke credentials (access tokens, authorization codes and refresh tokens) programmatically ([fee109d](https://github.com/trikoder/oauth2-bundle/commit/fee109da2d52d73dfc81501d0af3d66216f09de6))
- Support for registering custom grant types ([6b37588](https://github.com/trikoder/oauth2-bundle/commit/6b3758807b7cca6835c00504f1632ea78de563a5))

### Fixed
- Console command `trikoder:oauth2:list-clients` not being able to list clients without a secret ([da38b7a](https://github.com/trikoder/oauth2-bundle/commit/da38b7ab77060b4d43aca405559d5ffbd7a34d8d))

## [3.0.0] - 2020-02-26
### Added
- Ability to restrict clients from using the `plain` challenge method during PKCE ([4562a1f](https://github.com/trikoder/oauth2-bundle/commit/4562a1ff306375fd651aa91c85d0d4fd6f4c1b13))
Expand Down
2 changes: 1 addition & 1 deletion Command/ListClientsCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ private function getRows(array $clients, array $columns): array
];

return array_map(static function (string $column) use ($values): string {
return $values[$column];
return $values[$column] ?? '';
}, $columns);
}, $clients);
}
Expand Down
10 changes: 10 additions & 0 deletions DependencyInjection/TrikoderOAuth2Extension.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,15 @@
use Trikoder\Bundle\OAuth2Bundle\DBAL\Type\RedirectUri as RedirectUriType;
use Trikoder\Bundle\OAuth2Bundle\DBAL\Type\Scope as ScopeType;
use Trikoder\Bundle\OAuth2Bundle\EventListener\ConvertExceptionToResponseListener;
use Trikoder\Bundle\OAuth2Bundle\League\AuthorizationServer\GrantTypeInterface;
use Trikoder\Bundle\OAuth2Bundle\Manager\Doctrine\AccessTokenManager;
use Trikoder\Bundle\OAuth2Bundle\Manager\Doctrine\AuthorizationCodeManager;
use Trikoder\Bundle\OAuth2Bundle\Manager\Doctrine\ClientManager;
use Trikoder\Bundle\OAuth2Bundle\Manager\Doctrine\RefreshTokenManager;
use Trikoder\Bundle\OAuth2Bundle\Manager\ScopeManagerInterface;
use Trikoder\Bundle\OAuth2Bundle\Model\Scope as ScopeModel;
use Trikoder\Bundle\OAuth2Bundle\Security\Authentication\Token\OAuth2TokenFactory;
use Trikoder\Bundle\OAuth2Bundle\Service\CredentialsRevoker\DoctrineCredentialsRevoker;

final class TrikoderOAuth2Extension extends Extension implements PrependExtensionInterface, CompilerPassInterface
{
Expand Down Expand Up @@ -70,6 +72,9 @@ public function load(array $configs, ContainerBuilder $container)
'method' => 'onKernelException',
'priority' => $config['exception_event_listener_priority'],
]);

$container->registerForAutoconfiguration(GrantTypeInterface::class)
->addTag('trikoder.oauth2.authorization_server.grant');
}

/**
Expand Down Expand Up @@ -268,6 +273,11 @@ private function configureDoctrinePersistence(ContainerBuilder $container, array
->replaceArgument('$entityManager', $entityManager)
;

$container
->getDefinition(DoctrineCredentialsRevoker::class)
->replaceArgument('$entityManager', $entityManager)
;

$container->setParameter('trikoder.oauth2.persistence.doctrine.enabled', true);
$container->setParameter('trikoder.oauth2.persistence.doctrine.manager', $entityManagerName);
}
Expand Down
27 changes: 27 additions & 0 deletions League/AuthorizationServer/GrantConfigurator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php

declare(strict_types=1);

namespace Trikoder\Bundle\OAuth2Bundle\League\AuthorizationServer;

use League\OAuth2\Server\AuthorizationServer;

final class GrantConfigurator
{
/**
* @var iterable|GrantTypeInterface[]
*/
private $grants;

public function __construct(iterable $grants)
{
$this->grants = $grants;
}

public function __invoke(AuthorizationServer $authorizationServer): void
{
foreach ($this->grants as $grant) {
$authorizationServer->enableGrantType($grant, $grant->getAccessTokenTTL());
}
}
}
13 changes: 13 additions & 0 deletions League/AuthorizationServer/GrantTypeInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

declare(strict_types=1);

namespace Trikoder\Bundle\OAuth2Bundle\League\AuthorizationServer;

use DateInterval;
use League\OAuth2\Server\Grant\GrantTypeInterface as LeagueGrantTypeInterface;

interface GrantTypeInterface extends LeagueGrantTypeInterface
{
public function getAccessTokenTTL(): ?DateInterval;
}
5 changes: 2 additions & 3 deletions Manager/ClientManagerInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,10 @@
namespace Trikoder\Bundle\OAuth2Bundle\Manager;

use Trikoder\Bundle\OAuth2Bundle\Model\Client;
use Trikoder\Bundle\OAuth2Bundle\Service\ClientFinderInterface;

interface ClientManagerInterface
interface ClientManagerInterface extends ClientFinderInterface
{
public function find(string $identifier): ?Client;

public function save(Client $client): void;

public function remove(Client $client): void;
Expand Down
7 changes: 0 additions & 7 deletions Model/Grant.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,6 @@

namespace Trikoder\Bundle\OAuth2Bundle\Model;

use RuntimeException;
use Trikoder\Bundle\OAuth2Bundle\OAuth2Grants;

class Grant
{
/**
Expand All @@ -16,10 +13,6 @@ class Grant

public function __construct(string $grant)
{
if (!OAuth2Grants::has($grant)) {
throw new RuntimeException(sprintf('The \'%s\' grant is not supported.', $grant));
}

$this->grant = $grant;
}

Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ security:
* [Basic setup](docs/basic-setup.md)
* [Controlling token scopes](docs/controlling-token-scopes.md)
* [Password grant handling](docs/password-grant-handling.md)
* [Implementing custom grant type](docs/implementing-custom-grant-type.md)

## Development

Expand Down
3 changes: 3 additions & 0 deletions Resources/config/doctrine/model/AccessToken.orm.xml
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,8 @@
<many-to-one field="client" target-entity="Trikoder\Bundle\OAuth2Bundle\Model\Client">
<join-column name="client" referenced-column-name="identifier" nullable="false" on-delete="CASCADE" />
</many-to-one>
<indexes>
<index columns="userIdentifier" />
</indexes>
</entity>
</doctrine-mapping>
3 changes: 3 additions & 0 deletions Resources/config/doctrine/model/AuthorizationCode.orm.xml
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,8 @@
<many-to-one field="client" target-entity="Trikoder\Bundle\OAuth2Bundle\Model\Client">
<join-column name="client" referenced-column-name="identifier" nullable="false" />
</many-to-one>
<indexes>
<index columns="userIdentifier" />
</indexes>
</entity>
</doctrine-mapping>
7 changes: 7 additions & 0 deletions Resources/config/services.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<services>
<service id="Trikoder\Bundle\OAuth2Bundle\Service\ClientFinderInterface" alias="Trikoder\Bundle\OAuth2Bundle\Manager\ClientManagerInterface" />

<!-- The league repositories -->
<service id="Trikoder\Bundle\OAuth2Bundle\League\Repository\ClientRepository">
<argument type="service" id="Trikoder\Bundle\OAuth2Bundle\Manager\ClientManagerInterface" />
Expand Down Expand Up @@ -70,13 +72,18 @@
</service>
<service id="trikoder.oauth2.security.firewall.oauth2_listener" alias="Trikoder\Bundle\OAuth2Bundle\Security\Firewall\OAuth2Listener" />

<service id="Trikoder\Bundle\OAuth2Bundle\League\AuthorizationServer\GrantConfigurator">
<argument key="$grants" type="tagged_iterator" tag="trikoder.oauth2.authorization_server.grant" />
</service>

<!-- The league authorization server -->
<service id="League\OAuth2\Server\AuthorizationServer">
<argument key="$clientRepository" type="service" id="League\OAuth2\Server\Repositories\ClientRepositoryInterface" />
<argument key="$accessTokenRepository" type="service" id="League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface" />
<argument key="$scopeRepository" type="service" id="League\OAuth2\Server\Repositories\ScopeRepositoryInterface" />
<argument key="$privateKey" />
<argument key="$encryptionKey" />
<configurator service="Trikoder\Bundle\OAuth2Bundle\League\AuthorizationServer\GrantConfigurator"/>
</service>
<service id="league.oauth2.server.authorization_server" alias="League\OAuth2\Server\AuthorizationServer" />

Expand Down
5 changes: 5 additions & 0 deletions Resources/config/storage/doctrine.xml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@
<service id="Trikoder\Bundle\OAuth2Bundle\Manager\AuthorizationCodeManagerInterface" alias="Trikoder\Bundle\OAuth2Bundle\Manager\Doctrine\AuthorizationCodeManager" />

<!-- Services -->
<service id="Trikoder\Bundle\OAuth2Bundle\Service\CredentialsRevokerInterface" alias="Trikoder\Bundle\OAuth2Bundle\Service\CredentialsRevoker\DoctrineCredentialsRevoker" />
<service id="Trikoder\Bundle\OAuth2Bundle\Service\CredentialsRevoker\DoctrineCredentialsRevoker">
<argument key="$entityManager" />
</service>

<service id="Trikoder\Bundle\OAuth2Bundle\Manager\Doctrine\ClientManager">
<argument key="$entityManager" />
</service>
Expand Down
15 changes: 15 additions & 0 deletions Service/ClientFinderInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

declare(strict_types=1);

namespace Trikoder\Bundle\OAuth2Bundle\Service;

use Trikoder\Bundle\OAuth2Bundle\Model\Client;

/**
* @api
*/
interface ClientFinderInterface
{
public function find(string $identifier): ?Client;
}
101 changes: 101 additions & 0 deletions Service/CredentialsRevoker/DoctrineCredentialsRevoker.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
<?php

declare(strict_types=1);

namespace Trikoder\Bundle\OAuth2Bundle\Service\CredentialsRevoker;

use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Security\Core\User\UserInterface;
use Trikoder\Bundle\OAuth2Bundle\Model\AccessToken;
use Trikoder\Bundle\OAuth2Bundle\Model\AuthorizationCode;
use Trikoder\Bundle\OAuth2Bundle\Model\Client;
use Trikoder\Bundle\OAuth2Bundle\Model\RefreshToken;
use Trikoder\Bundle\OAuth2Bundle\Service\CredentialsRevokerInterface;

final class DoctrineCredentialsRevoker implements CredentialsRevokerInterface
{
/**
* @var EntityManagerInterface
*/
private $entityManager;

public function __construct(EntityManagerInterface $entityManager)
{
$this->entityManager = $entityManager;
}

public function revokeCredentialsForUser(UserInterface $user): void
{
$userIdentifier = $user->getUsername();

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

$queryBuilder = $this->entityManager->createQueryBuilder();
$queryBuilder
->update(RefreshToken::class, 'rt')
->set('rt.revoked', true)
->where($queryBuilder->expr()->in(
'rt.accessToken',
$this->entityManager->createQueryBuilder()
->select('at.identifier')
->from(AccessToken::class, 'at')
->where('at.userIdentifier = :userIdentifier')
->getDQL()
))
->setParameter('userIdentifier', $userIdentifier)
->getQuery()
->execute();

$this->entityManager->createQueryBuilder()
->update(AuthorizationCode::class, 'ac')
->set('ac.revoked', true)
->where('ac.userIdentifier = :userIdentifier')
->setParameter('userIdentifier', $userIdentifier)
->getQuery()
->execute();
}

public function revokeCredentialsForClient(Client $client): void
{
$doctrineClient = $this->entityManager
->getRepository(Client::class)
->findOneBy(['identifier' => $client->getIdentifier()]);

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

$queryBuilder = $this->entityManager->createQueryBuilder();
$queryBuilder->update(RefreshToken::class, 'rt')
->set('rt.revoked', true)
->where($queryBuilder->expr()->in(
'rt.accessToken',
$this->entityManager->createQueryBuilder()
->select('at.identifier')
->from(AccessToken::class, 'at')
->where('at.client = :client')
->getDQL()
))
->setParameter('client', $doctrineClient)
->getQuery()
->execute();

$this->entityManager->createQueryBuilder()
->update(AuthorizationCode::class, 'ac')
->set('ac.revoked', true)
->where('ac.client = :client')
->setParameter('client', $doctrineClient)
->getQuery()
->execute();
}
}
21 changes: 21 additions & 0 deletions Service/CredentialsRevokerInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php

declare(strict_types=1);

namespace Trikoder\Bundle\OAuth2Bundle\Service;

use Symfony\Component\Security\Core\User\UserInterface;
use Trikoder\Bundle\OAuth2Bundle\Model\Client;

/**
* Service responsible for revoking credentials on client-level and user-level.
* Credentials = access tokens, refresh tokens and authorization codes.
*
* @api
*/
interface CredentialsRevokerInterface
{
public function revokeCredentialsForUser(UserInterface $user): void;

public function revokeCredentialsForClient(Client $client): void;
}
Loading