vendor/knpuniversity/oauth2-client-bundle/src/DependencyInjection/KnpUOAuth2ClientExtension.php line 250

Open in your IDE?
  1. <?php
  2. /*
  3.  * OAuth2 Client Bundle
  4.  * Copyright (c) KnpUniversity <http://knpuniversity.com/>
  5.  *
  6.  * For the full copyright and license information, please view the LICENSE
  7.  * file that was distributed with this source code.
  8.  */
  9. namespace KnpU\OAuth2ClientBundle\DependencyInjection;
  10. use KnpU\OAuth2ClientBundle\DependencyInjection\Providers\AmazonProviderConfigurator;
  11. use KnpU\OAuth2ClientBundle\DependencyInjection\Providers\AppIdProviderConfigurator;
  12. use KnpU\OAuth2ClientBundle\DependencyInjection\Providers\AppleProviderConfigurator;
  13. use KnpU\OAuth2ClientBundle\DependencyInjection\Providers\Auth0ProviderConfigurator;
  14. use KnpU\OAuth2ClientBundle\DependencyInjection\Providers\AzureProviderConfigurator;
  15. use KnpU\OAuth2ClientBundle\DependencyInjection\Providers\BitbucketProviderConfigurator;
  16. use KnpU\OAuth2ClientBundle\DependencyInjection\Providers\BoxProviderConfigurator;
  17. use KnpU\OAuth2ClientBundle\DependencyInjection\Providers\BuddyProviderConfigurator;
  18. use KnpU\OAuth2ClientBundle\DependencyInjection\Providers\BufferProviderConfigurator;
  19. use KnpU\OAuth2ClientBundle\DependencyInjection\Providers\CanvasLMSProviderConfigurator;
  20. use KnpU\OAuth2ClientBundle\DependencyInjection\Providers\CleverProviderConfigurator;
  21. use KnpU\OAuth2ClientBundle\DependencyInjection\Providers\DevianArtProviderConfigurator;
  22. use KnpU\OAuth2ClientBundle\DependencyInjection\Providers\DigitalOceanProviderConfigurator;
  23. use KnpU\OAuth2ClientBundle\DependencyInjection\Providers\DiscordProviderConfigurator;
  24. use KnpU\OAuth2ClientBundle\DependencyInjection\Providers\DribbbleProviderConfigurator;
  25. use KnpU\OAuth2ClientBundle\DependencyInjection\Providers\DropboxProviderConfigurator;
  26. use KnpU\OAuth2ClientBundle\DependencyInjection\Providers\DrupalProviderConfigurator;
  27. use KnpU\OAuth2ClientBundle\DependencyInjection\Providers\ElanceProviderConfigurator;
  28. use KnpU\OAuth2ClientBundle\DependencyInjection\Providers\EventbriteProviderConfigurator;
  29. use KnpU\OAuth2ClientBundle\DependencyInjection\Providers\EveOnlineProviderConfigurator;
  30. use KnpU\OAuth2ClientBundle\DependencyInjection\Providers\FacebookProviderConfigurator;
  31. use KnpU\OAuth2ClientBundle\DependencyInjection\Providers\FitbitProviderConfigurator;
  32. use KnpU\OAuth2ClientBundle\DependencyInjection\Providers\FoursquareProviderConfigurator;
  33. use KnpU\OAuth2ClientBundle\DependencyInjection\Providers\FusionAuthProviderConfigurator;
  34. use KnpU\OAuth2ClientBundle\DependencyInjection\Providers\GenericProviderConfigurator;
  35. use KnpU\OAuth2ClientBundle\DependencyInjection\Providers\GeocachingProviderConfigurator;
  36. use KnpU\OAuth2ClientBundle\DependencyInjection\Providers\GithubProviderConfigurator;
  37. use KnpU\OAuth2ClientBundle\DependencyInjection\Providers\GitlabProviderConfigurator;
  38. use KnpU\OAuth2ClientBundle\DependencyInjection\Providers\GoogleProviderConfigurator;
  39. use KnpU\OAuth2ClientBundle\DependencyInjection\Providers\HeadHunterProviderConfigurator;
  40. use KnpU\OAuth2ClientBundle\DependencyInjection\Providers\HerokuProviderConfigurator;
  41. use KnpU\OAuth2ClientBundle\DependencyInjection\Providers\InstagramProviderConfigurator;
  42. use KnpU\OAuth2ClientBundle\DependencyInjection\Providers\JiraProviderConfigurator;
  43. use KnpU\OAuth2ClientBundle\DependencyInjection\Providers\KeycloakProviderConfigurator;
  44. use KnpU\OAuth2ClientBundle\DependencyInjection\Providers\LinkedInProviderConfigurator;
  45. use KnpU\OAuth2ClientBundle\DependencyInjection\Providers\MailRuProviderConfigurator;
  46. use KnpU\OAuth2ClientBundle\DependencyInjection\Providers\MicrosoftProviderConfigurator;
  47. use KnpU\OAuth2ClientBundle\DependencyInjection\Providers\MollieProviderConfigurator;
  48. use KnpU\OAuth2ClientBundle\DependencyInjection\Providers\OdnoklassnikiProviderConfigurator;
  49. use KnpU\OAuth2ClientBundle\DependencyInjection\Providers\OktaProviderConfigurator;
  50. use KnpU\OAuth2ClientBundle\DependencyInjection\Providers\PaypalProviderConfigurator;
  51. use KnpU\OAuth2ClientBundle\DependencyInjection\Providers\ProviderConfiguratorInterface;
  52. use KnpU\OAuth2ClientBundle\DependencyInjection\Providers\ProviderWithoutClientSecretConfiguratorInterface;
  53. use KnpU\OAuth2ClientBundle\DependencyInjection\Providers\PsnProviderConfigurator;
  54. use KnpU\OAuth2ClientBundle\DependencyInjection\Providers\SalesforceProviderConfigurator;
  55. use KnpU\OAuth2ClientBundle\DependencyInjection\Providers\SlackProviderConfigurator;
  56. use KnpU\OAuth2ClientBundle\DependencyInjection\Providers\SpotifyProviderConfigurator;
  57. use KnpU\OAuth2ClientBundle\DependencyInjection\Providers\StravaProviderConfigurator;
  58. use KnpU\OAuth2ClientBundle\DependencyInjection\Providers\StripeProviderConfigurator;
  59. use KnpU\OAuth2ClientBundle\DependencyInjection\Providers\SymfonyConnectProviderConfigurator;
  60. use KnpU\OAuth2ClientBundle\DependencyInjection\Providers\TwitchHelixProviderConfigurator;
  61. use KnpU\OAuth2ClientBundle\DependencyInjection\Providers\TwitchProviderConfigurator;
  62. use KnpU\OAuth2ClientBundle\DependencyInjection\Providers\UberProviderConfigurator;
  63. use KnpU\OAuth2ClientBundle\DependencyInjection\Providers\UnsplashProviderConfigurator;
  64. use KnpU\OAuth2ClientBundle\DependencyInjection\Providers\VimeoProviderConfigurator;
  65. use KnpU\OAuth2ClientBundle\DependencyInjection\Providers\VKontakteProviderConfigurator;
  66. use KnpU\OAuth2ClientBundle\DependencyInjection\Providers\WaveProviderConfigurator;
  67. use KnpU\OAuth2ClientBundle\DependencyInjection\Providers\YahooProviderConfigurator;
  68. use KnpU\OAuth2ClientBundle\DependencyInjection\Providers\YandexProviderConfigurator;
  69. use KnpU\OAuth2ClientBundle\DependencyInjection\Providers\ZendeskProviderConfigurator;
  70. use Symfony\Component\Config\Definition\Builder\NodeDefinition;
  71. use Symfony\Component\Config\Definition\Builder\TreeBuilder;
  72. use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
  73. use Symfony\Component\Config\Definition\Processor;
  74. use Symfony\Component\Config\FileLocator;
  75. use Symfony\Component\DependencyInjection\Alias;
  76. use Symfony\Component\DependencyInjection\ContainerBuilder;
  77. use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
  78. use Symfony\Component\DependencyInjection\Reference;
  79. use Symfony\Component\HttpKernel\DependencyInjection\Extension;
  80. class KnpUOAuth2ClientExtension extends Extension
  81. {
  82.     /** @var bool */
  83.     private $checkExternalClassExistence;
  84.     private array $configurators = [];
  85.     private array $duplicateProviderTypes = [];
  86.     private static array $supportedProviderTypes = [
  87.         'amazon' => AmazonProviderConfigurator::class,
  88.         'appid' => AppIdProviderConfigurator::class,
  89.         'apple' => AppleProviderConfigurator::class,
  90.         'auth0' => Auth0ProviderConfigurator::class,
  91.         'azure' => AzureProviderConfigurator::class,
  92.         'bitbucket' => BitbucketProviderConfigurator::class,
  93.         'box' => BoxProviderConfigurator::class,
  94.         'buddy' => BuddyProviderConfigurator::class,
  95.         'buffer' => BufferProviderConfigurator::class,
  96.         'canvas_lms' => CanvasLMSProviderConfigurator::class,
  97.         'clever' => CleverProviderConfigurator::class,
  98.         'devian_art' => DevianArtProviderConfigurator::class,
  99.         'digital_ocean' => DigitalOceanProviderConfigurator::class,
  100.         'discord' => DiscordProviderConfigurator::class,
  101.         'dribbble' => DribbbleProviderConfigurator::class,
  102.         'dropbox' => DropboxProviderConfigurator::class,
  103.         'drupal' => DrupalProviderConfigurator::class,
  104.         'elance' => ElanceProviderConfigurator::class,
  105.         'eve_online' => EveOnlineProviderConfigurator::class,
  106.         'eventbrite' => EventbriteProviderConfigurator::class,
  107.         'facebook' => FacebookProviderConfigurator::class,
  108.         'fitbit' => FitbitProviderConfigurator::class,
  109.         'four_square' => FoursquareProviderConfigurator::class,
  110.         'fusion_auth' => FusionAuthProviderConfigurator::class,
  111.         'geocaching' => GeocachingProviderConfigurator::class,
  112.         'github' => GithubProviderConfigurator::class,
  113.         'gitlab' => GitlabProviderConfigurator::class,
  114.         'google' => GoogleProviderConfigurator::class,
  115.         'headhunter' => HeadHunterProviderConfigurator::class,
  116.         'heroku' => HerokuProviderConfigurator::class,
  117.         'instagram' => InstagramProviderConfigurator::class,
  118.         'jira' => JiraProviderConfigurator::class,
  119.         'keycloak' => KeycloakProviderConfigurator::class,
  120.         'linkedin' => LinkedInProviderConfigurator::class,
  121.         'mail_ru' => MailRuProviderConfigurator::class,
  122.         'microsoft' => MicrosoftProviderConfigurator::class,
  123.         'mollie' => MollieProviderConfigurator::class,
  124.         'odnoklassniki' => OdnoklassnikiProviderConfigurator::class,
  125.         'okta' => OktaProviderConfigurator::class,
  126.         'paypal' => PaypalProviderConfigurator::class,
  127.         'psn' => PsnProviderConfigurator::class,
  128.         'salesforce' => SalesforceProviderConfigurator::class,
  129.         'slack' => SlackProviderConfigurator::class,
  130.         'spotify' => SpotifyProviderConfigurator::class,
  131.         'symfony_connect' => SymfonyConnectProviderConfigurator::class,
  132.         'strava' => StravaProviderConfigurator::class,
  133.         'stripe' => StripeProviderConfigurator::class,
  134.         'twitch' => TwitchProviderConfigurator::class,
  135.         'twitch_helix' => TwitchHelixProviderConfigurator::class,
  136.         'uber' => UberProviderConfigurator::class,
  137.         'unsplash' => UnsplashProviderConfigurator::class,
  138.         'vimeo' => VimeoProviderConfigurator::class,
  139.         'vkontakte' => VKontakteProviderConfigurator::class,
  140.         'wave' => WaveProviderConfigurator::class,
  141.         'yahoo' => YahooProviderConfigurator::class,
  142.         'yandex' => YandexProviderConfigurator::class,
  143.         'zendesk' => ZendeskProviderConfigurator::class,
  144.         'generic' => GenericProviderConfigurator::class,
  145.     ];
  146.     /**
  147.      * KnpUOAuth2ClientExtension constructor.
  148.      *
  149.      * @param bool $checkExternalClassExistence
  150.      */
  151.     public function __construct($checkExternalClassExistence true)
  152.     {
  153.         $this->checkExternalClassExistence $checkExternalClassExistence;
  154.     }
  155.     /**
  156.      * Load the bundle configuration.
  157.      */
  158.     public function load(array $configsContainerBuilder $container): void
  159.     {
  160.         $processor = new Processor();
  161.         $configuration = new Configuration();
  162.         $config $processor->processConfiguration($configuration$configs);
  163.         $loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
  164.         $loader->load('services.xml');
  165.         $httpClient $config['http_client'];
  166.         $httpClientOptions $config['http_client_options'];
  167.         $clientConfigurations $config['clients'];
  168.         $clientServiceKeys = [];
  169.         foreach ($clientConfigurations as $key => $clientConfig) {
  170.             // manually make sure "type" is there
  171.             if (!isset($clientConfig['type'])) {
  172.                 throw new InvalidConfigurationException(sprintf('Your "knpu_oauth2_client.clients.%s" config entry is missing the "type" key.'$key));
  173.             }
  174.             $type $clientConfig['type'];
  175.             unset($clientConfig['type']);
  176.             if (!isset(self::$supportedProviderTypes[$type])) {
  177.                 throw new InvalidConfigurationException(sprintf('The "knpu_oauth2_client.clients" config "type" key "%s" is not supported. We support (%s)'$typeimplode(', 'array_keys(self::$supportedProviderTypes))));
  178.             }
  179.             // process the configuration
  180.             $tree = new TreeBuilder('knpu_oauth2_client/clients/'.$key);
  181.             $node method_exists($tree'getRootNode')
  182.                 ? $tree->getRootNode()
  183.                 : $tree->root('knpu_oauth2_client/clients/'.$key);
  184.             $this->buildConfigurationForType($node$type);
  185.             $processor = new Processor();
  186.             $config $processor->process($tree->buildTree(), [$clientConfig]);
  187.             $configurator $this->getConfigurator($type);
  188.             $providerOptions $configurator->getProviderOptions($config);
  189.             $collaborators = [];
  190.             if ($httpClient) {
  191.                 $collaborators['httpClient'] = new Reference($httpClient);
  192.             } else {
  193.                 $providerOptions array_merge($providerOptions$httpClientOptions);
  194.             }
  195.             // hey, we should add the provider/client service!
  196.             $clientServiceKey $this->configureProviderAndClient(
  197.                 $container,
  198.                 $type,
  199.                 $key,
  200.                 $configurator->getProviderClass($config),
  201.                 $configurator->getClientClass($config),
  202.                 $configurator->getPackagistName(),
  203.                 $providerOptions,
  204.                 $config['redirect_route'],
  205.                 $config['redirect_params'],
  206.                 $config['use_state'],
  207.                 $collaborators
  208.             );
  209.             $clientServiceKeys[$key] = $clientServiceKey;
  210.         }
  211.         $container->getDefinition('knpu.oauth2.registry')
  212.             ->replaceArgument(1$clientServiceKeys);
  213.     }
  214.     /**
  215.      * @param string $providerType   The "type" used in the config - e.g. "facebook"
  216.      * @param string $providerKey    The config key used for this - e.g. "facebook_client", "my_facebook"
  217.      * @param string $providerClass  Provider class
  218.      * @param string $clientClass    Class to use for the Client
  219.      * @param string $packageName    Packagist package name required
  220.      * @param array  $options        Options passed to when constructing the provider
  221.      * @param string $redirectRoute  Route name for the redirect URL
  222.      * @param array  $redirectParams Route params for the redirect URL
  223.      * @param bool   $useState
  224.      *
  225.      * @return string The client service id
  226.      */
  227.     private function configureProviderAndClient(ContainerBuilder $container$providerType$providerKey$providerClass$clientClass$packageName, array $options$redirectRoute, array $redirectParams$useState, array $collaborators): string
  228.     {
  229.         if ($this->checkExternalClassExistence && !class_exists($providerClass)) {
  230.             if ('generic' === $providerType) {
  231.                 throw new \LogicException(sprintf('The provider class `%s` must exist in order to use with the "%s" OAuth provider.'$providerClass$providerType));
  232.             }
  233.             throw new \LogicException(sprintf('Run `composer require %s` in order to use the "%s" OAuth provider.'$packageName$providerType));
  234.         }
  235.         $providerServiceKey sprintf('knpu.oauth2.provider.%s'$providerKey);
  236.         $providerDefinition $container->register(
  237.             $providerServiceKey,
  238.             $providerClass
  239.         );
  240.         $providerDefinition->setPublic(false);
  241.         $providerDefinition->setFactory([
  242.             new Reference('knpu.oauth2.provider_factory'),
  243.             'createProvider',
  244.         ]);
  245.         $providerDefinition->setArguments([
  246.             $providerClass,
  247.             $options,
  248.             $redirectRoute,
  249.             $redirectParams,
  250.             $collaborators,
  251.         ]);
  252.         $clientServiceKey sprintf('knpu.oauth2.client.%s'$providerKey);
  253.         $clientDefinition $container->register(
  254.             $clientServiceKey,
  255.             $clientClass
  256.         );
  257.         $clientDefinition->setArguments([
  258.             new Reference($providerServiceKey),
  259.             new Reference('request_stack'),
  260.         ]);
  261.         $clientDefinition->setPublic(true);
  262.         // if stateless, do it!
  263.         if (!$useState) {
  264.             $clientDefinition->addMethodCall('setAsStateless');
  265.         }
  266.         // add an alias, but only if a provider type is used only 1 time
  267.         if (!\in_array($providerType$this->duplicateProviderTypestrue)) {
  268.             // alias already exists? This is a duplicate type, record it
  269.             if ($container->hasAlias($clientClass)) {
  270.                 $this->duplicateProviderTypes[] = $providerType;
  271.             } else {
  272.                 // all good, add the alias
  273.                 $container->setAlias($clientClass, new Alias($clientServiceKeyfalse));
  274.             }
  275.         }
  276.         return $clientServiceKey;
  277.     }
  278.     public static function getAllSupportedTypes(): array
  279.     {
  280.         return array_keys(self::$supportedProviderTypes);
  281.     }
  282.     /**
  283.      * @param string $type
  284.      */
  285.     public function getConfigurator($type): ProviderConfiguratorInterface
  286.     {
  287.         if (!isset($this->configurators[$type])) {
  288.             $class self::$supportedProviderTypes[$type];
  289.             $this->configurators[$type] = new $class();
  290.         }
  291.         return $this->configurators[$type];
  292.     }
  293.     /**
  294.      * Overridden so the alias isn't "knp_uo_auth2_client".
  295.      */
  296.     public function getAlias(): string
  297.     {
  298.         return 'knpu_oauth2_client';
  299.     }
  300.     private function buildConfigurationForType(NodeDefinition $node$type)
  301.     {
  302.         $optionsNode $node->children();
  303.         $optionsNode
  304.             ->scalarNode('client_id')->isRequired()->end()
  305.         ;
  306.         if (self::configuratorNeedsClientSecret($this->getConfigurator($type))) {
  307.             $optionsNode->scalarNode('client_secret')->isRequired()->end();
  308.         }
  309.         $optionsNode
  310.             ->scalarNode('redirect_route')->isRequired()->end()
  311.             ->arrayNode('redirect_params')
  312.                 ->prototype('scalar')->end()
  313.             ->end()
  314.             ->booleanNode('use_state')->defaultValue(true)->end()
  315.         ;
  316.         // allow the specific provider to add more options
  317.         $this->getConfigurator($type)
  318.             ->buildConfiguration($optionsNode);
  319.         $optionsNode->end();
  320.     }
  321.     /**
  322.      * @internal
  323.      */
  324.     public static function configuratorNeedsClientSecret(ProviderConfiguratorInterface $configurator): bool
  325.     {
  326.         if (!$configurator instanceof ProviderWithoutClientSecretConfiguratorInterface) {
  327.             return true;
  328.         }
  329.         return $configurator->needsClientSecret();
  330.     }
  331. }