From 1544c09bdd1c888e77f8a523b1f896b9900e066e Mon Sep 17 00:00:00 2001 From: Lars Vierbergen Date: Sat, 28 Oct 2017 14:54:37 +0200 Subject: [PATCH] Make registration with external account (and prefilled/forced fields) configurable --- .../AuthserverOAuthAccountExtension.php | 10 +- DependencyInjection/Configuration.php | 54 ++++--- EventListener/RegistrationFieldsListener.php | 135 ++++++++++++++++++ EventListener/RegistrationHandlerListener.php | 22 ++- Resources/config/registration_services.xml | 42 ++++++ Resources/config/services.xml | 10 +- Security/Core/User/OAuthUserProvider.php | 12 +- 7 files changed, 244 insertions(+), 41 deletions(-) create mode 100644 EventListener/RegistrationFieldsListener.php create mode 100644 Resources/config/registration_services.xml diff --git a/DependencyInjection/AuthserverOAuthAccountExtension.php b/DependencyInjection/AuthserverOAuthAccountExtension.php index d7b58b7..942c149 100644 --- a/DependencyInjection/AuthserverOAuthAccountExtension.php +++ b/DependencyInjection/AuthserverOAuthAccountExtension.php @@ -17,10 +17,8 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ - namespace vierbergenlars\AuthserverOAuthAccountBundle\DependencyInjection; - use Symfony\Component\Config\Definition\Processor; use Symfony\Component\DependencyInjection\ChildDefinition; use Symfony\Component\DependencyInjection\ContainerBuilder; @@ -89,12 +87,18 @@ class AuthserverOAuthAccountExtension extends Extension implements PrependExtens $config = $processor->processConfiguration(new Configuration(), $configs); $container->getDefinition(self::RESOURCE_OWNER_MAP_SERVICE)->setArgument(0, $config['resource_owners']); - foreach ($config['resource_owners'] as $name => $config) { + foreach ($config['resource_owners'] as $name => $_) { $service = new DefinitionDecorator('vierbergenlars.authserver_oauth_account.external_account_provider.abstract'); $service->replaceArgument(0, $name); $service->addTag(AuthserverExternalAccountBundle::EXTERNAL_ACCOUNT_PROVIDER_TAG); $container->setDefinition('vierbergenlars.authserver_oauth_account.external_account_provider.impl.' . $name, $service); } + + $container->setParameter('vierbergenlars.authserver_oauth_account.registration.enabled', $config['registration']['enabled']); + $container->setParameter('vierbergenlars.authserver_oauth_account.registration.fields', $config['registration']); + if ($config['registration']['enabled']) { + $xmlLoader->load('registration_services.xml'); + } } public function getAlias() diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index eb10739..0b15a98 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -42,33 +42,43 @@ class Configuration implements ConfigurationInterface // @formatter:off $rootNode->children() ->arrayNode('resource_owners') - ->useAttributeAsKey('name') - ->prototype('array') - ->children() - ->arrayNode('config') - ->ignoreExtraKeys(false) - ->end() - ->scalarNode('service_name')->isRequired()->end() - ->scalarNode('icon')->defaultNull()->end() - ->booleanNode('trust_email_verification')->defaultFalse()->end() - ->arrayNode('login_button') - ->addDefaultsIfNotSet() - ->children() - ->scalarNode('label')->defaultNull()->end() - ->scalarNode('style')->defaultValue('default')->end() - ->scalarNode('icon')->defaultNull()->end() + ->useAttributeAsKey('name') + ->prototype('array') + ->children() + ->arrayNode('config') + ->ignoreExtraKeys(false) ->end() - ->end() - ->arrayNode('connect_button') - ->addDefaultsIfNotSet() - ->children() - ->scalarNode('label')->defaultNull()->end() - ->scalarNode('style')->defaultValue('default')->end() - ->scalarNode('icon')->defaultNull()->end() + ->scalarNode('service_name')->isRequired()->end() + ->scalarNode('icon')->defaultNull()->end() + ->booleanNode('trust_email_verification')->defaultFalse()->end() + ->arrayNode('login_button') + ->addDefaultsIfNotSet() + ->children() + ->scalarNode('label')->defaultNull()->end() + ->scalarNode('style')->defaultValue('default')->end() + ->scalarNode('icon')->defaultNull()->end() + ->end() + ->end() + ->arrayNode('connect_button') + ->addDefaultsIfNotSet() + ->children() + ->scalarNode('label')->defaultNull()->end() + ->scalarNode('style')->defaultValue('default')->end() + ->scalarNode('icon')->defaultNull()->end() + ->end() ->end() ->end() ->end() ->end() + ->arrayNode('registration') + ->canBeEnabled() + ->addDefaultsIfNotSet() + ->children() + ->enumNode('display_name')->values(['prefill', 'blank', 'force'])->defaultValue('prefill')->end() + ->enumNode('email')->values(['prefill', 'blank', 'force'])->defaultValue('prefill')->end() + ->enumNode('password')->values(['blank', 'hidden', 'force-disable'])->defaultValue('hidden')->end() + ->end() + ->end() ; // @formatter:on diff --git a/EventListener/RegistrationFieldsListener.php b/EventListener/RegistrationFieldsListener.php new file mode 100644 index 0000000..97b5477 --- /dev/null +++ b/EventListener/RegistrationFieldsListener.php @@ -0,0 +1,135 @@ +. + */ +namespace vierbergenlars\AuthserverOAuthAccountBundle\EventListener; + +use Registration\Event\RegistrationHandleEvent; +use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Registration\RegistrationEvents; +use Registration\Event\RegistrationFormEvent; +use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; +use vierbergenlars\AuthserverOAuthAccountBundle\Entity\TemporaryUser; +use Doctrine\ORM\EntityManagerInterface; +use App\Entity\EmailAddress; +use vierbergenlars\AuthserverOAuthAccountBundle\ResourceOwner\ResourceOwnerMap; +use EmailRulesBundle\EmailHandler\EmailRules; +use Registration\RegistrationHandler\RegistrationRules; + +class RegistrationFieldsListener implements EventSubscriberInterface +{ + + /** + * + * @var TokenStorageInterface + */ + private $tokenStorage; + + /** + * + * @var string[] + */ + private $registrationFields; + + public static function getSubscribedEvents() + { + return [ + RegistrationEvents::BUILD_FORM => [ + 'onBuildForm', + 9 + ] + ]; + } + + public function __construct(TokenStorageInterface $tokenStorage, array $registrationFields) + { + $this->tokenStorage = $tokenStorage; + $this->registrationFields = $registrationFields; + } + + private function getTemporaryUser() + { + $token = $this->tokenStorage->getToken(); + if (!$token) + return null; + $user = $token->getUser(); + if ($user instanceof TemporaryUser) + return $user; + return null; + } + + public function onBuildForm(RegistrationFormEvent $event) + { + if ($this->getTemporaryUser()) { + switch ($this->registrationFields['email']) { + case 'prefill': + break; + case 'blank': + $event->getFormBuilder() + ->getData() + ->getPrimaryEmailAddress() + ->setEmail(''); + break; + case 'force': + $event->getFormBuilder() + ->get('emailAddresses') + ->setDisabled(true); + break; + } + + switch ($this->registrationFields['display_name']) { + case 'prefill': + break; + case 'blank': + $event->getFormBuilder() + ->getData() + ->setDisplayName(''); + break; + case 'force': + $event->getFormBuilder() + ->get('displayName') + ->setDisabled(true); + break; + } + + switch ($this->registrationFields['password']) { + case 'blank': + $event->getFormBuilder() + ->getData() + ->setPasswordEnabled(1); + break; + case 'hidden': + $event->getFormBuilder() + ->getData() + ->setPasswordEnabled(2); + break; + case 'force-disable': + $event->getFormBuilder() + ->getData() + ->setPasswordEnabled(0); + break; + } + + if ($this->registrationFields['password'] === false) { + $event->getFormBuilder() + ->getData() + ->setPasswordEnabled(1); + } + } + } +} diff --git a/EventListener/RegistrationHandlerListener.php b/EventListener/RegistrationHandlerListener.php index 343e2d1..f11cddb 100644 --- a/EventListener/RegistrationHandlerListener.php +++ b/EventListener/RegistrationHandlerListener.php @@ -52,6 +52,12 @@ class RegistrationHandlerListener implements EventSubscriberInterface */ private $resourceOwnerMap; + /** + * + * @var string[] + */ + private $registrationFields; + /** * * @var EmailRules|null @@ -78,11 +84,12 @@ class RegistrationHandlerListener implements EventSubscriberInterface ]; } - public function __construct(EntityManagerInterface $em, TokenStorageInterface $tokenStorage, ResourceOwnerMap $resourceOwnerMap, EmailRules $emailRules = null, RegistrationRules $registrationRules = null) + public function __construct(EntityManagerInterface $em, TokenStorageInterface $tokenStorage, ResourceOwnerMap $resourceOwnerMap, array $registrationFields, EmailRules $emailRules = null, RegistrationRules $registrationRules = null) { $this->em = $em; $this->tokenStorage = $tokenStorage; $this->resourceOwnerMap = $resourceOwnerMap; + $this->registrationFields = $registrationFields; $this->emailRules = $emailRules; $this->registrationRules = $registrationRules; } @@ -100,7 +107,14 @@ class RegistrationHandlerListener implements EventSubscriberInterface public function onBuildForm(RegistrationFormEvent $event) { - if ($tempuser = $this->getTemporaryUser()) { + if (($tempuser = $this->getTemporaryUser()) && $this->registrationFields['email']) { + $user = $event->getFormBuilder()->getData(); + /* @var $user \App\Entity\User */ + if (!$user->getPrimaryEmailAddress()) + $user->addEmailAddress(new EmailAddress()); + if ($this->registrationFields['email'] === 'force') { + $user->getPrimaryEmailAddress()->setEmail($tempuser->getEmail()); + } if ($tempuser->getEmail()) { if ($this->emailRules) { $rule = $this->emailRules->getFirstRuleMatching($tempuser->getEmail()); @@ -116,10 +130,6 @@ class RegistrationHandlerListener implements EventSubscriberInterface return; } } - $user = $event->getFormBuilder()->getData(); - /* @var $user \App\Entity\User */ - if (!$user->getPrimaryEmailAddress()) - $user->addEmailAddress(new EmailAddress()); $user->getPrimaryEmailAddress()->setEmail($tempuser->getEmail()); } } diff --git a/Resources/config/registration_services.xml b/Resources/config/registration_services.xml new file mode 100644 index 0000000..399a0ce --- /dev/null +++ b/Resources/config/registration_services.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + %vierbergenlars.authserver_oauth_account.registration.fields% + + + + + + + + %vierbergenlars.authserver_oauth_account.registration.fields% + + + + diff --git a/Resources/config/services.xml b/Resources/config/services.xml index d127457..ddbf582 100644 --- a/Resources/config/services.xml +++ b/Resources/config/services.xml @@ -25,6 +25,7 @@ + %vierbergenlars.authserver_oauth_account.registration.enabled% @@ -42,14 +43,5 @@ - - - - - - - - - diff --git a/Security/Core/User/OAuthUserProvider.php b/Security/Core/User/OAuthUserProvider.php index 132c489..03fbafb 100644 --- a/Security/Core/User/OAuthUserProvider.php +++ b/Security/Core/User/OAuthUserProvider.php @@ -39,10 +39,17 @@ class OAuthUserProvider extends UserProvider implements OAuthAwareUserProviderIn */ private $registry; - public function __construct(ManagerRegistry $registry) + /** + * + * @var boolean + */ + private $allowRegistrations; + + public function __construct(ManagerRegistry $registry, $allowRegistrations) { parent::__construct($registry); $this->registry = $registry; + $this->allowRegistrations = $allowRegistrations; } /** @@ -59,6 +66,9 @@ class OAuthUserProvider extends UserProvider implements OAuthAwareUserProviderIn try { return $this->getExternalAccount($response)->getUser(); } catch (AccountNotLinkedException $ex) { + if (!$this->allowRegistrations) { + throw $ex; + } $user = new TemporaryUser(); $externalUser = $this->createExternalUser($response); $user->setExternalUser($externalUser);