From 4026a0136bc5f8fdef05b282fee0f92cb6a10f2b Mon Sep 17 00:00:00 2001 From: Etshy Date: Mon, 29 Jan 2024 02:50:49 +0100 Subject: [PATCH] WIP: rough draft to add doctrine ODM support Update Configuration and Extension to add doctrine_odm options Add an ODM driver (as there are no Builder available for ODM, It's all done manually for now) Update Docs & Managers Move doctrine dependencies in dev Add alias for Doctrine ORM driver --- .gitignore | 2 + composer.json | 7 +- docs/index.md | 3 + src/DependencyInjection/Configuration.php | 14 + .../LeagueOAuth2ServerExtension.php | 38 ++- src/LeagueOAuth2ServerBundle.php | 32 ++- src/Manager/Doctrine/AccessTokenManager.php | 18 +- .../Doctrine/AuthorizationCodeManager.php | 18 +- src/Manager/Doctrine/ClientManager.php | 25 +- src/Manager/Doctrine/RefreshTokenManager.php | 18 +- .../Mapping/Doctrine/ODM/Driver.php | 261 ++++++++++++++++++ .../Mapping/{ => Doctrine/ORM}/Driver.php | 2 +- src/Resources/config/storage/doctrine.php | 5 +- src/Resources/config/storage/doctrine_odm.php | 70 +++++ 14 files changed, 445 insertions(+), 68 deletions(-) create mode 100644 src/Persistence/Mapping/Doctrine/ODM/Driver.php rename src/Persistence/Mapping/{ => Doctrine/ORM}/Driver.php (98%) create mode 100644 src/Resources/config/storage/doctrine_odm.php diff --git a/.gitignore b/.gitignore index 23fcec14..40807e4c 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,5 @@ phpunit.xml # Tests tests/.kernel/ + +.idea/ diff --git a/composer.json b/composer.json index 45c7fcaf..d6b2c960 100644 --- a/composer.json +++ b/composer.json @@ -17,8 +17,6 @@ ], "require": { "php": "^8.1", - "doctrine/doctrine-bundle": "^2.0.8", - "doctrine/orm": "^2.7.1", "league/oauth2-server": "^8.3", "nyholm/psr7": "^1.4", "psr/http-factory": "^1.0", @@ -31,6 +29,11 @@ "require-dev": { "ext-pdo": "*", "ext-pdo_sqlite": "*", + "ext-mongodb": "*", + "doctrine/doctrine-bundle": "^2.0.8", + "doctrine/mongodb-odm": "2.7.x-dev", + "doctrine/mongodb-odm-bundle": "4.7.x-dev", + "doctrine/orm": "^2.7.1", "symfony/browser-kit": "^5.4|^6.2|^7.0", "symfony/phpunit-bridge": "^5.4|^6.2|^7.0" }, diff --git a/docs/index.md b/docs/index.md index 6b293992..1a250e98 100644 --- a/docs/index.md +++ b/docs/index.md @@ -100,6 +100,9 @@ For implementation into Symfony projects, please see [bundle documentation](basi # Table name prefix. table_prefix: oauth2_ + doctrine_odm: + document_manager: default + collection_prefix: oauth2_ in_memory: ~ # Set a custom prefix that replaces the default 'ROLE_OAUTH2_' role prefix diff --git a/src/DependencyInjection/Configuration.php b/src/DependencyInjection/Configuration.php index 11861cfe..c082af3c 100644 --- a/src/DependencyInjection/Configuration.php +++ b/src/DependencyInjection/Configuration.php @@ -188,6 +188,20 @@ private function createPersistenceNode(): NodeDefinition ->end() ->end() ->end() + ->arrayNode('doctrine_odm') + ->children() + ->scalarNode('document_manager') + ->info('Name of the document manager that you wish to use for managing clients and tokens.') + ->cannotBeEmpty() + ->defaultValue('default') + ->end() + ->scalarNode('collection_prefix') + ->info('Collection name prefix.') + ->cannotBeEmpty() + ->defaultValue('oauth2_') + ->end() + ->end() + ->end() // In-memory persistence ->scalarNode('in_memory') ->end() diff --git a/src/DependencyInjection/LeagueOAuth2ServerExtension.php b/src/DependencyInjection/LeagueOAuth2ServerExtension.php index 81922ad0..7d236d4d 100644 --- a/src/DependencyInjection/LeagueOAuth2ServerExtension.php +++ b/src/DependencyInjection/LeagueOAuth2ServerExtension.php @@ -5,6 +5,7 @@ namespace League\Bundle\OAuth2ServerBundle\DependencyInjection; use Doctrine\Bundle\DoctrineBundle\DoctrineBundle; +use Doctrine\Bundle\MongoDBBundle\DoctrineMongoDBBundle; use League\Bundle\OAuth2ServerBundle\AuthorizationServer\GrantTypeInterface; use League\Bundle\OAuth2ServerBundle\Command\CreateClientCommand; use League\Bundle\OAuth2ServerBundle\DBAL\Type\Grant as GrantType; @@ -16,7 +17,8 @@ use League\Bundle\OAuth2ServerBundle\Manager\Doctrine\RefreshTokenManager; use League\Bundle\OAuth2ServerBundle\Manager\InMemory\AccessTokenManager as InMemoryAccessTokenManager; use League\Bundle\OAuth2ServerBundle\Manager\ScopeManagerInterface; -use League\Bundle\OAuth2ServerBundle\Persistence\Mapping\Driver; +use League\Bundle\OAuth2ServerBundle\Persistence\Mapping\Doctrine\ODM\Driver as DoctrineODMDriver; +use League\Bundle\OAuth2ServerBundle\Persistence\Mapping\Doctrine\ORM\Driver as DoctrineORMDrive; use League\Bundle\OAuth2ServerBundle\Security\Authenticator\OAuth2Authenticator; use League\Bundle\OAuth2ServerBundle\Service\CredentialsRevoker\DoctrineCredentialsRevoker; use League\Bundle\OAuth2ServerBundle\ValueObject\Scope as ScopeModel; @@ -105,6 +107,7 @@ private function assertRequiredBundlesAreEnabled(ContainerBuilder $container): v { $requiredBundles = [ 'doctrine' => DoctrineBundle::class, + 'doctrine_mongodb' => DoctrineMongoDBBundle::class, 'security' => SecurityBundle::class, ]; @@ -227,55 +230,62 @@ private function configurePersistence(LoaderInterface $loader, ContainerBuilder break; case 'doctrine': $loader->load('storage/doctrine.php'); - $this->configureDoctrinePersistence($container, $config, $persistenceConfig); + $this->configureDoctrinePersistence($container, $config, $persistenceConfig, 'doctrine'); + break; + case 'doctrine_odm': + $loader->load('storage/doctrine_odm.php'); + $this->configureDoctrinePersistence($container, $config, $persistenceConfig, 'doctrine_odm'); break; } } - private function configureDoctrinePersistence(ContainerBuilder $container, array $config, array $persistenceConfig): void + private function configureDoctrinePersistence(ContainerBuilder $container, array $config, array $persistenceConfig, string $type): void { - $entityManagerName = $persistenceConfig['entity_manager']; + $doctrineManager = $type === 'doctrine_odm' ? 'document_manager' : 'entity_manager'; + $doctrineConfigPrefix = $type === 'doctrine_odm' ? 'doctrine_mongodb.odm' : 'doctrine.orm'; + + $objectManagerName = $persistenceConfig[$doctrineManager]; - $entityManager = new Reference( - sprintf('doctrine.orm.%s_entity_manager', $entityManagerName) + $objectManager = new Reference( + sprintf('%s.%s_%s', $doctrineConfigPrefix, $objectManagerName, $doctrineManager) ); $container ->findDefinition(AccessTokenManager::class) - ->replaceArgument(0, $entityManager) + ->replaceArgument(0, $objectManager) ->replaceArgument(1, $config['authorization_server']['persist_access_token']) ; $container ->findDefinition(ClientManager::class) - ->replaceArgument(0, $entityManager) + ->replaceArgument(0, $objectManager) ->replaceArgument(2, $config['client']['classname']) ; $container ->findDefinition(RefreshTokenManager::class) - ->replaceArgument(0, $entityManager) + ->replaceArgument(0, $objectManager) ; $container ->findDefinition(AuthorizationCodeManager::class) - ->replaceArgument(0, $entityManager) + ->replaceArgument(0, $objectManager) ; $container ->findDefinition(DoctrineCredentialsRevoker::class) - ->replaceArgument(0, $entityManager) + ->replaceArgument(0, $objectManager) ; $container - ->findDefinition(Driver::class) + ->findDefinition($type === 'doctrine_odm'? DoctrineODMDriver::class : DoctrineORMDrive::class) ->replaceArgument(0, $config['client']['classname']) ->replaceArgument(1, $config['authorization_server']['persist_access_token']) ->replaceArgument(2, $persistenceConfig['table_prefix']) ; - $container->setParameter('league.oauth2_server.persistence.doctrine.enabled', true); - $container->setParameter('league.oauth2_server.persistence.doctrine.manager', $entityManagerName); + $container->setParameter("league.oauth2_server.persistence.$type.enabled", true); + $container->setParameter("league.oauth2_server.persistence.$type.manager", $objectManagerName); } private function configureInMemoryPersistence(ContainerBuilder $container, array $config): void diff --git a/src/LeagueOAuth2ServerBundle.php b/src/LeagueOAuth2ServerBundle.php index 1e8baf08..52957352 100644 --- a/src/LeagueOAuth2ServerBundle.php +++ b/src/LeagueOAuth2ServerBundle.php @@ -5,10 +5,12 @@ namespace League\Bundle\OAuth2ServerBundle; use Doctrine\Bundle\DoctrineBundle\DependencyInjection\Compiler\DoctrineOrmMappingsPass; +use Doctrine\Bundle\MongoDBBundle\DependencyInjection\Compiler\DoctrineMongoDBMappingsPass; use League\Bundle\OAuth2ServerBundle\DependencyInjection\CompilerPass\EncryptionKeyPass; use League\Bundle\OAuth2ServerBundle\DependencyInjection\LeagueOAuth2ServerExtension; use League\Bundle\OAuth2ServerBundle\DependencyInjection\Security\OAuth2Factory; -use League\Bundle\OAuth2ServerBundle\Persistence\Mapping\Driver; +use League\Bundle\OAuth2ServerBundle\Persistence\Mapping\Doctrine\ODM\Driver as DoctrineODMDriver; +use League\Bundle\OAuth2ServerBundle\Persistence\Mapping\Doctrine\ORM\Driver as DoctrineORMDriver; use Symfony\Bundle\SecurityBundle\DependencyInjection\SecurityExtension; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Extension\ExtensionInterface; @@ -56,14 +58,26 @@ private function configureSecurityExtension(ContainerBuilder $container): void private function configureDoctrineExtension(ContainerBuilder $container): void { - $container->addCompilerPass( - new DoctrineOrmMappingsPass( - new Reference(Driver::class), - ['League\Bundle\OAuth2ServerBundle\Model'], - ['league.oauth2_server.persistence.doctrine.manager'], - 'league.oauth2_server.persistence.doctrine.enabled' - ) - ); + if (class_exists(DoctrineOrmMappingsPass::class)) { + $container->addCompilerPass( + new DoctrineOrmMappingsPass( + new Reference(DoctrineORMDriver::class), + ['League\Bundle\OAuth2ServerBundle\Model'], + ['league.oauth2_server.persistence.doctrine.manager'], + 'league.oauth2_server.persistence.doctrine.enabled' + ) + ); + } + if (class_exists(DoctrineMongoDBMappingsPass::class)) { + $container->addCompilerPass( + new DoctrineMongoDBMappingsPass( + new Reference(DoctrineODMDriver::class), + ['League\Bundle\OAuth2ServerBundle\Model'], + ['league.oauth2_server.persistence.doctrine_odm.manager'], + 'league.oauth2_server.persistence.doctrine_odm.enabled' + ) + ); + } $container->addCompilerPass(new EncryptionKeyPass()); } diff --git a/src/Manager/Doctrine/AccessTokenManager.php b/src/Manager/Doctrine/AccessTokenManager.php index 607b3312..76287622 100644 --- a/src/Manager/Doctrine/AccessTokenManager.php +++ b/src/Manager/Doctrine/AccessTokenManager.php @@ -4,7 +4,7 @@ namespace League\Bundle\OAuth2ServerBundle\Manager\Doctrine; -use Doctrine\ORM\EntityManagerInterface; +use Doctrine\Persistence\ObjectManager; use League\Bundle\OAuth2ServerBundle\Manager\AccessTokenManagerInterface; use League\Bundle\OAuth2ServerBundle\Model\AccessToken; use League\Bundle\OAuth2ServerBundle\Model\AccessTokenInterface; @@ -12,16 +12,16 @@ final class AccessTokenManager implements AccessTokenManagerInterface { /** - * @var EntityManagerInterface + * @var ObjectManager */ - private $entityManager; + private $objectManager; /** @var bool */ private $persistAccessToken; - public function __construct(EntityManagerInterface $entityManager, bool $persistAccessToken) + public function __construct(ObjectManager $objectManager, bool $persistAccessToken) { - $this->entityManager = $entityManager; + $this->objectManager = $objectManager; $this->persistAccessToken = $persistAccessToken; } @@ -31,7 +31,7 @@ public function find(string $identifier): ?AccessTokenInterface return null; } - return $this->entityManager->find(AccessToken::class, $identifier); + return $this->objectManager->find(AccessToken::class, $identifier); } public function save(AccessTokenInterface $accessToken): void @@ -40,8 +40,8 @@ public function save(AccessTokenInterface $accessToken): void return; } - $this->entityManager->persist($accessToken); - $this->entityManager->flush(); + $this->objectManager->persist($accessToken); + $this->objectManager->flush(); } public function clearExpired(): int @@ -51,7 +51,7 @@ public function clearExpired(): int } /** @var int */ - return $this->entityManager->createQueryBuilder() + return $this->objectManager->createQueryBuilder() ->delete(AccessToken::class, 'at') ->where('at.expiry < :expiry') ->setParameter('expiry', new \DateTimeImmutable(), 'datetime_immutable') diff --git a/src/Manager/Doctrine/AuthorizationCodeManager.php b/src/Manager/Doctrine/AuthorizationCodeManager.php index 3a1ffdee..62c1a4c0 100644 --- a/src/Manager/Doctrine/AuthorizationCodeManager.php +++ b/src/Manager/Doctrine/AuthorizationCodeManager.php @@ -4,7 +4,7 @@ namespace League\Bundle\OAuth2ServerBundle\Manager\Doctrine; -use Doctrine\ORM\EntityManagerInterface; +use Doctrine\Persistence\ObjectManager; use League\Bundle\OAuth2ServerBundle\Manager\AuthorizationCodeManagerInterface; use League\Bundle\OAuth2ServerBundle\Model\AuthorizationCode; use League\Bundle\OAuth2ServerBundle\Model\AuthorizationCodeInterface; @@ -12,30 +12,30 @@ final class AuthorizationCodeManager implements AuthorizationCodeManagerInterface { /** - * @var EntityManagerInterface + * @var ObjectManager */ - private $entityManager; + private $objectManager; - public function __construct(EntityManagerInterface $entityManager) + public function __construct(ObjectManager $objectManager) { - $this->entityManager = $entityManager; + $this->objectManager = $objectManager; } public function find(string $identifier): ?AuthorizationCodeInterface { - return $this->entityManager->find(AuthorizationCode::class, $identifier); + return $this->objectManager->find(AuthorizationCode::class, $identifier); } public function save(AuthorizationCodeInterface $authCode): void { - $this->entityManager->persist($authCode); - $this->entityManager->flush(); + $this->objectManager->persist($authCode); + $this->objectManager->flush(); } public function clearExpired(): int { /** @var int */ - return $this->entityManager->createQueryBuilder() + return $this->objectManager->createQueryBuilder() ->delete(AuthorizationCode::class, 'ac') ->where('ac.expiry < :expiry') ->setParameter('expiry', new \DateTimeImmutable(), 'datetime_immutable') diff --git a/src/Manager/Doctrine/ClientManager.php b/src/Manager/Doctrine/ClientManager.php index 32d2bfd9..dff096d7 100644 --- a/src/Manager/Doctrine/ClientManager.php +++ b/src/Manager/Doctrine/ClientManager.php @@ -4,7 +4,7 @@ namespace League\Bundle\OAuth2ServerBundle\Manager\Doctrine; -use Doctrine\ORM\EntityManagerInterface; +use Doctrine\Persistence\ObjectManager; use League\Bundle\OAuth2ServerBundle\Event\PreSaveClientEvent; use League\Bundle\OAuth2ServerBundle\Manager\ClientFilter; use League\Bundle\OAuth2ServerBundle\Manager\ClientManagerInterface; @@ -19,9 +19,9 @@ final class ClientManager implements ClientManagerInterface { /** - * @var EntityManagerInterface + * @var ObjectManager */ - private $entityManager; + private $objectManager; /** * @var class-string @@ -37,18 +37,19 @@ final class ClientManager implements ClientManagerInterface * @param class-string $clientFqcn */ public function __construct( - EntityManagerInterface $entityManager, + ObjectManager $objectManager, EventDispatcherInterface $dispatcher, string $clientFqcn - ) { - $this->entityManager = $entityManager; + ) + { + $this->objectManager = $objectManager; $this->dispatcher = $dispatcher; $this->clientFqcn = $clientFqcn; } public function find(string $identifier): ?ClientInterface { - $repository = $this->entityManager->getRepository($this->clientFqcn); + $repository = $this->objectManager->getRepository($this->clientFqcn); return $repository->findOneBy(['identifier' => $identifier]); } @@ -58,14 +59,14 @@ public function save(ClientInterface $client): void $event = $this->dispatcher->dispatch(new PreSaveClientEvent($client), OAuth2Events::PRE_SAVE_CLIENT); $client = $event->getClient(); - $this->entityManager->persist($client); - $this->entityManager->flush(); + $this->objectManager->persist($client); + $this->objectManager->flush(); } public function remove(ClientInterface $client): void { - $this->entityManager->remove($client); - $this->entityManager->flush(); + $this->objectManager->remove($client); + $this->objectManager->flush(); } /** @@ -73,7 +74,7 @@ public function remove(ClientInterface $client): void */ public function list(?ClientFilter $clientFilter): array { - $repository = $this->entityManager->getRepository($this->clientFqcn); + $repository = $this->objectManager->getRepository($this->clientFqcn); $criteria = self::filterToCriteria($clientFilter); /** @var list */ diff --git a/src/Manager/Doctrine/RefreshTokenManager.php b/src/Manager/Doctrine/RefreshTokenManager.php index 1bd7ce5e..f8c88952 100644 --- a/src/Manager/Doctrine/RefreshTokenManager.php +++ b/src/Manager/Doctrine/RefreshTokenManager.php @@ -4,7 +4,7 @@ namespace League\Bundle\OAuth2ServerBundle\Manager\Doctrine; -use Doctrine\ORM\EntityManagerInterface; +use Doctrine\Persistence\ObjectManager; use League\Bundle\OAuth2ServerBundle\Manager\RefreshTokenManagerInterface; use League\Bundle\OAuth2ServerBundle\Model\RefreshToken; use League\Bundle\OAuth2ServerBundle\Model\RefreshTokenInterface; @@ -12,30 +12,30 @@ final class RefreshTokenManager implements RefreshTokenManagerInterface { /** - * @var EntityManagerInterface + * @var ObjectManager */ - private $entityManager; + private $objectManager; - public function __construct(EntityManagerInterface $entityManager) + public function __construct(ObjectManager $objectManager) { - $this->entityManager = $entityManager; + $this->objectManager = $objectManager; } public function find(string $identifier): ?RefreshTokenInterface { - return $this->entityManager->find(RefreshToken::class, $identifier); + return $this->objectManager->find(RefreshToken::class, $identifier); } public function save(RefreshTokenInterface $refreshToken): void { - $this->entityManager->persist($refreshToken); - $this->entityManager->flush(); + $this->objectManager->persist($refreshToken); + $this->objectManager->flush(); } public function clearExpired(): int { /** @var int */ - return $this->entityManager->createQueryBuilder() + return $this->objectManager->createQueryBuilder() ->delete(RefreshToken::class, 'rt') ->where('rt.expiry < :expiry') ->setParameter('expiry', new \DateTimeImmutable(), 'datetime_immutable') diff --git a/src/Persistence/Mapping/Doctrine/ODM/Driver.php b/src/Persistence/Mapping/Doctrine/ODM/Driver.php new file mode 100644 index 00000000..ef8bda5f --- /dev/null +++ b/src/Persistence/Mapping/Doctrine/ODM/Driver.php @@ -0,0 +1,261 @@ +clientClass = $clientClass; + $this->persistAccessToken = $persistAccessToken; + $this->collectionPrefix = $collectionPrefix; + } + + public function loadMetadataForClass($className, PersistenceClassMetadata $metadata): void + { + assert($metadata instanceof ClassMetadata); + switch ($className) { + case AbstractClient::class: + $this->buildAbstractClientMetadata($metadata); + + break; + case AccessToken::class: + $this->buildAccessTokenMetadata($metadata); + + break; + case AuthorizationCode::class: + $this->buildAuthorizationCodeMetadata($metadata); + + break; + case Client::class: + $this->buildClientMetadata($metadata); + + break; + case RefreshToken::class: + $this->buildRefreshTokenMetadata($metadata); + + break; + default: + throw new \RuntimeException(sprintf('%s cannot load metadata for class %s', __CLASS__, $className)); + } + } + + public function getAllClassNames() + { + return array_merge( + [ + AbstractClient::class, + AuthorizationCode::class, + RefreshToken::class, + ], + Client::class === $this->clientClass ? [Client::class] : [], + $this->persistAccessToken ? [AccessToken::class] : [] + ); + } + + public function isTransient(string $className) + { + return false; + } + + private function buildAbstractClientMetadata(ClassMetadata $metadata) + { + $metadata->isMappedSuperclass = true; + $mapping = [ + 'name' => 'name', + 'type' => 'string', + ]; + $metadata->mapField($mapping); + $mapping = [ + 'name' => 'secret', + 'type' => 'string', + ]; + $metadata->mapField($mapping); + $mapping = [ + 'name' => 'redirectUris', + 'type' => 'collection', + ]; + $metadata->mapField($mapping); + $mapping = [ + 'name' => 'grants', + 'type' => 'collection', + 'nullable' => true, + ]; + $metadata->mapField($mapping); + $mapping = [ + 'name' => 'scopes', + 'type' => 'collection', + 'nullable' => true, + ]; + $metadata->mapField($mapping); + $mapping = [ + 'name' => 'active', + 'type' => 'boolean', + ]; + $metadata->mapField($mapping); + $mapping = [ + 'name' => 'allowPlainTextPkce', + 'type' => 'boolean', + 'options' => [ + 'default' => 0, + ], + ]; + $metadata->mapField($mapping); + } + + private function buildAccessTokenMetadata(ClassMetadata $metadata): void + { + $metadata->setCollection($this->collectionPrefix . 'access_token'); + $mapping = [ + 'name' => 'identifier', + 'type' => 'string', + 'id' => true, + ]; + $metadata->mapField($mapping); + $mapping = [ + 'name' => 'expiry', + 'type' => 'date_immutable' + ]; + $metadata->mapField($mapping); + $mapping = [ + 'name' => 'userIdentifier', + 'type' => 'string', + 'nullable' => true, + ]; + $metadata->mapField($mapping); + $mapping = [ + 'name' => 'scopes', + 'type' => 'collection', + 'nullable' => true, + ]; + $metadata->mapField($mapping); + $mapping = [ + 'name' => 'revoked', + 'type' => 'bool' + ]; + $metadata->mapField($mapping); + $mapping = [ + 'reference' => true, + 'type' => ClassMetadata::MANY, + 'storeAs' => ClassMetadata::REFERENCE_STORE_AS_DB_REF, + 'orphanRemoval' => false, + 'targetDocument' => $this->clientClass, + 'name' => 'client', + 'strategy' => ClassMetadata::STORAGE_STRATEGY_PUSH_ALL + ]; + $metadata->mapManyReference($mapping); + } + + private function buildAuthorizationCodeMetadata(ClassMetadata $metadata) + { + $metadata->setCollection($this->collectionPrefix . 'authorization_code'); + $mapping = [ + 'name' => 'identifier', + 'type' => 'string', + "id" => true, + ]; + $metadata->mapField($mapping); + $mapping = [ + 'name' => 'expiry', + 'type' => 'datetime_immutable', + ]; + $metadata->mapField($mapping); + $mapping = [ + 'name' => 'userIdentifier', + 'type' => 'string', + 'nullable' => true, + ]; + $metadata->mapField($mapping); + $mapping = [ + 'name' => 'scopes', + 'type' => 'collection', + 'nullable' => true, + ]; + $metadata->mapField($mapping); + $mapping = [ + 'name' => 'revoked', + 'type' => 'bool' + ]; + $metadata->mapField($mapping); + $mapping = [ + 'reference' => true, + 'type' => ClassMetadata::MANY, + 'storeAs' => ClassMetadata::REFERENCE_STORE_AS_DB_REF, + 'orphanRemoval' => false, + 'targetDocument' => $this->clientClass, + 'name' => 'client', + 'strategy' => ClassMetadata::STORAGE_STRATEGY_PUSH_ALL + ]; + $metadata->mapManyReference($mapping); + } + + private function buildClientMetadata(ClassMetadata $metadata): void + { + $metadata->setCollection($this->collectionPrefix . 'client'); + $mapping = [ + 'name' => 'identifier', + 'type' => 'string', + "id" => true, + ]; + $metadata->mapField($mapping); + } + + private function buildRefreshTokenMetadata(ClassMetadata $metadata): void + { + $metadata->setCollection($this->collectionPrefix . 'refresh_token'); + $mapping = [ + 'name' => 'identifier', + 'type' => 'string', + "id" => true, + ]; + $metadata->mapField($mapping); + $mapping = [ + 'name' => 'expiry', + 'type' => 'datetime_immutable', + ]; + $metadata->mapField($mapping); + $mapping = [ + 'name' => 'revoked', + 'type' => 'boolean', + ]; + $metadata->mapField($mapping); + + if ($this->persistAccessToken) { + $mapping = [ + 'reference' => true, + 'type' => ClassMetadata::MANY, + 'storeAs' => ClassMetadata::REFERENCE_STORE_AS_DB_REF, + 'orphanRemoval' => false, + 'targetDocument' => AccessToken::class, + 'name' => 'accessToken', + 'strategy' => ClassMetadata::STORAGE_STRATEGY_PUSH_ALL, + 'nullable' => true, + ]; + $metadata->mapManyReference($mapping); + } + } + +} diff --git a/src/Persistence/Mapping/Driver.php b/src/Persistence/Mapping/Doctrine/ORM/Driver.php similarity index 98% rename from src/Persistence/Mapping/Driver.php rename to src/Persistence/Mapping/Doctrine/ORM/Driver.php index 9e2b8acb..62279d60 100644 --- a/src/Persistence/Mapping/Driver.php +++ b/src/Persistence/Mapping/Doctrine/ORM/Driver.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace League\Bundle\OAuth2ServerBundle\Persistence\Mapping; +namespace League\Bundle\OAuth2ServerBundle\Persistence\Mapping\Doctrine\ORM; use Doctrine\ORM\Mapping\Builder\ClassMetadataBuilder; use Doctrine\Persistence\Mapping\ClassMetadata; diff --git a/src/Resources/config/storage/doctrine.php b/src/Resources/config/storage/doctrine.php index 61c25f9d..4b4b7d2d 100644 --- a/src/Resources/config/storage/doctrine.php +++ b/src/Resources/config/storage/doctrine.php @@ -2,8 +2,6 @@ declare(strict_types=1); -use function Symfony\Component\DependencyInjection\Loader\Configurator\service; - use League\Bundle\OAuth2ServerBundle\Manager\AccessTokenManagerInterface; use League\Bundle\OAuth2ServerBundle\Manager\AuthorizationCodeManagerInterface; use League\Bundle\OAuth2ServerBundle\Manager\ClientManagerInterface; @@ -12,11 +10,12 @@ use League\Bundle\OAuth2ServerBundle\Manager\Doctrine\ClientManager; use League\Bundle\OAuth2ServerBundle\Manager\Doctrine\RefreshTokenManager; use League\Bundle\OAuth2ServerBundle\Manager\RefreshTokenManagerInterface; -use League\Bundle\OAuth2ServerBundle\Persistence\Mapping\Driver; +use League\Bundle\OAuth2ServerBundle\Persistence\Mapping\Doctrine\ORM\Driver; use League\Bundle\OAuth2ServerBundle\Service\CredentialsRevoker\DoctrineCredentialsRevoker; use League\Bundle\OAuth2ServerBundle\Service\CredentialsRevokerInterface; use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator; use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; +use function Symfony\Component\DependencyInjection\Loader\Configurator\service; return static function (ContainerConfigurator $container): void { $container->services() diff --git a/src/Resources/config/storage/doctrine_odm.php b/src/Resources/config/storage/doctrine_odm.php new file mode 100644 index 00000000..92bd34c5 --- /dev/null +++ b/src/Resources/config/storage/doctrine_odm.php @@ -0,0 +1,70 @@ +services() + + ->set('league.oauth2_server.persistence.driver', Driver::class) + ->args([ + null, + null, + null, + ]) + ->alias(Driver::class, 'league.oauth2_server.persistence.driver') + + ->set('league.oauth2_server.manager.doctrine_odm.client', ClientManager::class) + ->args([ + null, + service(EventDispatcherInterface::class), + null, + ]) + ->alias(ClientManagerInterface::class, 'league.oauth2_server.manager.doctrine_odm.client') + ->alias(ClientManager::class, 'league.oauth2_server.manager.doctrine_odm.client') + + ->set('league.oauth2_server.manager.doctrine_odm.access_token', AccessTokenManager::class) + ->args([ + null, + null, + ]) + ->alias(AccessTokenManagerInterface::class, 'league.oauth2_server.manager.doctrine_odm.access_token') + ->alias(AccessTokenManager::class, 'league.oauth2_server.manager.doctrine_odm.access_token') + + ->set('league.oauth2_server.manager.doctrine_odm.refresh_token', RefreshTokenManager::class) + ->args([ + null, + ]) + ->alias(RefreshTokenManagerInterface::class, 'league.oauth2_server.manager.doctrine_odm.refresh_token') + ->alias(RefreshTokenManager::class, 'league.oauth2_server.manager.doctrine_odm.refresh_token') + + ->set('league.oauth2_server.manager.doctrine_odm.authorization_code', AuthorizationCodeManager::class) + ->args([ + null, + ]) + ->alias(AuthorizationCodeManagerInterface::class, 'league.oauth2_server.manager.doctrine_odm.authorization_code') + ->alias(AuthorizationCodeManager::class, 'league.oauth2_server.manager.doctrine_odm.authorization_code') + + ->set('league.oauth2_server.credentials_revoker.doctrine_odm', DoctrineCredentialsRevoker::class) + ->args([ + null, + service(ClientManagerInterface::class), + ]) + ->alias(CredentialsRevokerInterface::class, 'league.oauth2_server.credentials_revoker.doctrine_odm') + ->alias(DoctrineCredentialsRevoker::class, 'league.oauth2_server.credentials_revoker.doctrine_odm') + ; +};