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

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