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

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 method_exists($tree'getRootNode')
  188.                 ? $tree->getRootNode()
  189.                 : $tree->root('knpu_oauth2_client/clients/'.$key);
  190.             $this->buildConfigurationForType($node$type);
  191.             $processor = new Processor();
  192.             $config $processor->process($tree->buildTree(), [$clientConfig]);
  193.             $configurator $this->getConfigurator($type);
  194.             $providerOptions $configurator->getProviderOptions($config);
  195.             $collaborators = [];
  196.             if ($httpClient) {
  197.                 $collaborators['httpClient'] = new Reference($httpClient);
  198.             } else {
  199.                 $providerOptions array_merge($providerOptions$httpClientOptions);
  200.             }
  201.             // hey, we should add the provider/client service!
  202.             $clientServiceKey $this->configureProviderAndClient(
  203.                 $container,
  204.                 $type,
  205.                 $key,
  206.                 $configurator->getProviderClass($config),
  207.                 $configurator->getClientClass($config),
  208.                 $configurator->getPackagistName(),
  209.                 $providerOptions,
  210.                 $config['redirect_route'],
  211.                 $config['redirect_params'],
  212.                 $config['use_state'],
  213.                 $collaborators
  214.             );
  215.             $clientServiceKeys[$key] = $clientServiceKey;
  216.         }
  217.         $container->getDefinition('knpu.oauth2.registry')
  218.             ->replaceArgument(1$clientServiceKeys);
  219.     }
  220.     /**
  221.      * @param string $providerType   The "type" used in the config - e.g. "facebook"
  222.      * @param string $providerKey    The config key used for this - e.g. "facebook_client", "my_facebook"
  223.      * @param string $providerClass  Provider class
  224.      * @param string $clientClass    Class to use for the Client
  225.      * @param string $packageName    Packagist package name required
  226.      * @param array  $options        Options passed to when constructing the provider
  227.      * @param string $redirectRoute  Route name for the redirect URL
  228.      * @param array  $redirectParams Route params for the redirect URL
  229.      * @param bool   $useState
  230.      *
  231.      * @return string The client service id
  232.      */
  233.     private function configureProviderAndClient(ContainerBuilder $container$providerType$providerKey$providerClass$clientClass$packageName, array $options$redirectRoute, array $redirectParams$useState, array $collaborators): string
  234.     {
  235.         if ($this->checkExternalClassExistence && !class_exists($providerClass)) {
  236.             if ('generic' === $providerType) {
  237.                 throw new \LogicException(sprintf('The provider class `%s` must exist in order to use with the "%s" OAuth provider.'$providerClass$providerType));
  238.             }
  239.             throw new \LogicException(sprintf('Run `composer require %s` in order to use the "%s" OAuth provider.'$packageName$providerType));
  240.         }
  241.         $providerServiceKey sprintf('knpu.oauth2.provider.%s'$providerKey);
  242.         $providerDefinition $container->register(
  243.             $providerServiceKey,
  244.             $providerClass
  245.         );
  246.         $providerDefinition->setPublic(false);
  247.         $providerDefinition->setFactory([
  248.             new Reference('knpu.oauth2.provider_factory'),
  249.             'createProvider',
  250.         ]);
  251.         $providerDefinition->setArguments([
  252.             $providerClass,
  253.             $options,
  254.             $redirectRoute,
  255.             $redirectParams,
  256.             $collaborators,
  257.         ]);
  258.         $clientServiceKey sprintf('knpu.oauth2.client.%s'$providerKey);
  259.         $clientDefinition $container->register(
  260.             $clientServiceKey,
  261.             $clientClass
  262.         );
  263.         $clientDefinition->setArguments([
  264.             new Reference($providerServiceKey),
  265.             new Reference('request_stack'),
  266.         ]);
  267.         $clientDefinition->setPublic(true);
  268.         // if stateless, do it!
  269.         if (!$useState) {
  270.             $clientDefinition->addMethodCall('setAsStateless');
  271.         }
  272.         // add an alias, but only if a provider type is used only 1 time
  273.         if (!\in_array($providerType$this->duplicateProviderTypestrue)) {
  274.             // alias already exists? This is a duplicate type, record it
  275.             if ($container->hasAlias($clientClass)) {
  276.                 $this->duplicateProviderTypes[] = $providerType;
  277.             } else {
  278.                 // all good, add the alias
  279.                 $container->setAlias($clientClass, new Alias($clientServiceKeyfalse));
  280.             }
  281.         }
  282.         return $clientServiceKey;
  283.     }
  284.     public static function getAllSupportedTypes(): array
  285.     {
  286.         return array_keys(self::$supportedProviderTypes);
  287.     }
  288.     /**
  289.      * @param string $type
  290.      */
  291.     public function getConfigurator($type): ProviderConfiguratorInterface
  292.     {
  293.         if (!isset($this->configurators[$type])) {
  294.             $class self::$supportedProviderTypes[$type];
  295.             $this->configurators[$type] = new $class();
  296.         }
  297.         return $this->configurators[$type];
  298.     }
  299.     /**
  300.      * Overridden so the alias isn't "knp_uo_auth2_client".
  301.      */
  302.     public function getAlias(): string
  303.     {
  304.         return 'knpu_oauth2_client';
  305.     }
  306.     private function buildConfigurationForType(NodeDefinition $node$type)
  307.     {
  308.         $optionsNode $node->children();
  309.         $optionsNode
  310.             ->scalarNode('client_id')->isRequired()->end()
  311.         ;
  312.         if (self::configuratorNeedsClientSecret($this->getConfigurator($type))) {
  313.             $optionsNode->scalarNode('client_secret')->isRequired()->end();
  314.         }
  315.         $optionsNode
  316.             ->scalarNode('redirect_route')->isRequired()->end()
  317.             ->arrayNode('redirect_params')
  318.                 ->prototype('scalar')->end()
  319.             ->end()
  320.             ->booleanNode('use_state')->defaultValue(true)->end()
  321.         ;
  322.         // allow the specific provider to add more options
  323.         $this->getConfigurator($type)
  324.             ->buildConfiguration($optionsNode);
  325.         $optionsNode->end();
  326.     }
  327.     /**
  328.      * @internal
  329.      */
  330.     public static function configuratorNeedsClientSecret(ProviderConfiguratorInterface $configurator): bool
  331.     {
  332.         if (!$configurator instanceof ProviderWithoutClientSecretConfiguratorInterface) {
  333.             return true;
  334.         }
  335.         return $configurator->needsClientSecret();
  336.     }
  337. }