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

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