commit
ac227fd8f7
@ -0,0 +1 @@ |
||||
/vendor/ |
@ -0,0 +1,67 @@ |
||||
<?php |
||||
/** |
||||
* Authserver, an OAuth2-based single-signon authentication provider written in PHP. |
||||
* |
||||
* Copyright (C) $today.date Lars Vierbergen |
||||
* |
||||
* his program is free software: you can redistribute it and/or modify |
||||
* it under the terms of the GNU Affero General Public License as |
||||
* published by the Free Software Foundation, either version 3 of the |
||||
* License, or (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU Affero General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU Affero General Public License |
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
*/ |
||||
|
||||
namespace vierbergenlars\AuthserverOAuthAccountBundle; |
||||
|
||||
|
||||
use App\Plugin\Event\ContainerConfigEvent; |
||||
use App\Plugin\Event\GetBundlesEvent; |
||||
use App\Plugin\PluginEvents; |
||||
use HWI\Bundle\OAuthBundle\HWIOAuthBundle; |
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface; |
||||
use Symfony\Component\HttpKernel\Bundle\Bundle; |
||||
use vierbergenlars\AuthserverExternalAccountBundle\AuthserverExternalAccountBundle; |
||||
use vierbergenlars\AuthserverOAuthAccountBundle\DependencyInjection\AuthserverOAuthAccountExtension; |
||||
|
||||
class AuthserverOAuthAccountBundle extends Bundle implements EventSubscriberInterface |
||||
{ |
||||
public static function getSubscribedEvents() |
||||
{ |
||||
return [ |
||||
PluginEvents::INITIALIZE_BUNDLES => 'onInitializeBundles', |
||||
PluginEvents::CONTAINER_CONFIG => ['onContainerConfig', -20], |
||||
]; |
||||
} |
||||
|
||||
public function onContainerConfig(ContainerConfigEvent $event) |
||||
{ |
||||
$event->getConfigManipulator('[security][firewalls][public]') |
||||
->prependConfig(['oauth' => []]); |
||||
|
||||
} |
||||
|
||||
public function onInitializeBundles(GetBundlesEvent $event) |
||||
{ |
||||
$event->addBundle(new AuthserverExternalAccountBundle()); |
||||
$event->addBundle(new HWIOAuthBundle()); |
||||
} |
||||
|
||||
public function getContainerExtension() |
||||
{ |
||||
return new AuthserverOAuthAccountExtension(); |
||||
} |
||||
|
||||
public function getParent() |
||||
{ |
||||
return 'HWIOAuthBundle'; |
||||
} |
||||
|
||||
|
||||
} |
@ -0,0 +1,63 @@ |
||||
<?php |
||||
|
||||
/** |
||||
* Authserver, an OAuth2-based single-signon authentication provider written in PHP. |
||||
* |
||||
* Copyright (C) $today.date Lars Vierbergen |
||||
* |
||||
* his program is free software: you can redistribute it and/or modify |
||||
* it under the terms of the GNU Affero General Public License as |
||||
* published by the Free Software Foundation, either version 3 of the |
||||
* License, or (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU Affero General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU Affero General Public License |
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
*/ |
||||
|
||||
namespace vierbergenlars\AuthserverOAuthAccountBundle\Controller; |
||||
|
||||
use HWI\Bundle\OAuthBundle\Controller\ConnectController as BaseConnectController; |
||||
use Symfony\Component\Form\Extension\Core\Type\FormType; |
||||
use Symfony\Component\HttpFoundation\Request; |
||||
use Symfony\Component\HttpFoundation\Response; |
||||
use vierbergenlars\AuthserverExternalAccountBundle\Entity\ExternalUser; |
||||
use vierbergenlars\AuthserverOAuthAccountBundle\DependencyInjection\AuthserverOAuthAccountExtension; |
||||
|
||||
class ConnectController extends BaseConnectController |
||||
{ |
||||
protected function render($view, array $parameters = [], Response $response = null) |
||||
{ |
||||
if($view === 'HWIOAuthBundle:Connect:connect_success.html.twig') |
||||
return $this->redirectToRoute('user_profile'); |
||||
|
||||
$resourceOwnerConfig = $this->container->get(AuthserverOAuthAccountExtension::RESOURCE_OWNER_MAP_SERVICE); |
||||
|
||||
return parent::render($view, $parameters + ['resourceOwnerConfig' => $resourceOwnerConfig], $response); |
||||
} |
||||
|
||||
public function disconnectServiceAction(Request $request, ExternalUser $externalUser) |
||||
{ |
||||
if($externalUser->getUser() !== $this->getUser()) |
||||
throw $this->createAccessDeniedException(); |
||||
|
||||
$form = $this->createForm(FormType::class); |
||||
$form->handleRequest($request); |
||||
|
||||
if($form->isSubmitted() && $form->isValid()) { |
||||
$this->container->get('hwi_oauth.account.connector')->disconnect($externalUser); |
||||
|
||||
return $this->redirectToRoute('user_profile'); |
||||
} |
||||
|
||||
return $this->render('AuthserverOAuthAccountBundle:Connect:disconnect_service.html.twig', [ |
||||
'externalUser' => $externalUser, |
||||
'form' => $form->createView(), |
||||
]); |
||||
|
||||
} |
||||
} |
@ -0,0 +1,92 @@ |
||||
<?php |
||||
/** |
||||
* Authserver, an OAuth2-based single-signon authentication provider written in PHP. |
||||
* |
||||
* Copyright (C) $today.date Lars Vierbergen |
||||
* |
||||
* his program is free software: you can redistribute it and/or modify |
||||
* it under the terms of the GNU Affero General Public License as |
||||
* published by the Free Software Foundation, either version 3 of the |
||||
* License, or (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU Affero General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU Affero General Public License |
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
*/ |
||||
|
||||
namespace vierbergenlars\AuthserverOAuthAccountBundle\DependencyInjection; |
||||
|
||||
|
||||
use Symfony\Component\Config\Definition\Processor; |
||||
use Symfony\Component\DependencyInjection\ContainerBuilder; |
||||
use Symfony\Component\Config\FileLocator; |
||||
use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface; |
||||
use Symfony\Component\HttpKernel\DependencyInjection\Extension; |
||||
use Symfony\Component\DependencyInjection\Loader; |
||||
use vierbergenlars\AuthserverOAuthAccountBundle\ResourceOwner\ResourceOwnerConfig; |
||||
|
||||
class AuthserverOAuthAccountExtension extends Extension implements PrependExtensionInterface |
||||
{ |
||||
const RESOURCE_OWNER_MAP_SERVICE = 'vierbergenlars.authserver_oauth_account.resource_owner_map'; |
||||
const USER_PROVIDER_SERVICE = 'vierbergenlars.authserver_oauth_account.user_provider'; |
||||
|
||||
public function prepend(ContainerBuilder $container) |
||||
{ |
||||
$container->prependExtensionConfig('hwi_oauth', [ |
||||
'firewall_names' => ['public'], |
||||
'connect' => [ |
||||
'account_connector' => self::USER_PROVIDER_SERVICE, |
||||
] |
||||
]); |
||||
|
||||
$configs = $container->getExtensionConfig($this->getAlias()); |
||||
|
||||
$processor = new Processor(); |
||||
$config = $processor->processConfiguration(new Configuration(), $configs); |
||||
$container->prependExtensionConfig('hwi_oauth', [ |
||||
'resource_owners' => array_map(function($resource_owner) { |
||||
return (new ResourceOwnerConfig($resource_owner))->getHwiConfig(); |
||||
}, $config['resource_owners']), |
||||
]); |
||||
|
||||
$container->loadFromExtension('security', [ |
||||
'firewalls' => [ |
||||
'public' => [ |
||||
'oauth' => [ |
||||
'resource_owners' => array_combine(array_keys($config['resource_owners']), array_map(function($roName) { |
||||
return '/login/oauth/'.$roName; |
||||
}, array_keys($config['resource_owners']))), |
||||
'login_path' => 'app_login', |
||||
'failure_path' => 'app_login', |
||||
'oauth_user_provider' => [ |
||||
'service' => self::USER_PROVIDER_SERVICE, |
||||
], |
||||
], |
||||
] |
||||
], |
||||
]); |
||||
} |
||||
|
||||
public function load(array $configs, ContainerBuilder $container) |
||||
{ |
||||
$servicesDirectory = __DIR__.'/../Resources/config'; |
||||
$fileLocator = new FileLocator($servicesDirectory); |
||||
$xmlLoader = new Loader\XmlFileLoader($container, $fileLocator); |
||||
$xmlLoader->load('services.xml'); |
||||
|
||||
$processor = new Processor(); |
||||
$config = $processor->processConfiguration(new Configuration(), $configs); |
||||
|
||||
$container->getDefinition(self::RESOURCE_OWNER_MAP_SERVICE) |
||||
->setArgument(0, $config['resource_owners']); |
||||
} |
||||
|
||||
public function getAlias() |
||||
{ |
||||
return 'oauth'; |
||||
} |
||||
} |
@ -0,0 +1,78 @@ |
||||
<?php |
||||
/** |
||||
* Authserver, an OAuth2-based single-signon authentication provider written in PHP. |
||||
* |
||||
* Copyright (C) $today.date Lars Vierbergen |
||||
* |
||||
* his program is free software: you can redistribute it and/or modify |
||||
* it under the terms of the GNU Affero General Public License as |
||||
* published by the Free Software Foundation, either version 3 of the |
||||
* License, or (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU Affero General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU Affero General Public License |
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
*/ |
||||
|
||||
namespace vierbergenlars\AuthserverOAuthAccountBundle\DependencyInjection; |
||||
|
||||
use Symfony\Component\Config\Definition\Builder\TreeBuilder; |
||||
use Symfony\Component\Config\Definition\ConfigurationInterface; |
||||
|
||||
/** |
||||
* This is the class that validates and merges configuration from your app/config files |
||||
* |
||||
* To learn more see {@link http://symfony.com/doc/current/cookbook/bundles/extension.html#cookbook-bundles-extension-config-class} |
||||
*/ |
||||
class Configuration implements ConfigurationInterface |
||||
{ |
||||
/** |
||||
* {@inheritDoc} |
||||
*/ |
||||
public function getConfigTreeBuilder() |
||||
{ |
||||
$treeBuilder = new TreeBuilder(); |
||||
$rootNode = $treeBuilder->root('oauth'); |
||||
|
||||
|
||||
$rootNode->children() |
||||
->arrayNode('resource_owners') |
||||
->useAttributeAsKey('name') |
||||
->prototype('array') |
||||
->children() |
||||
->arrayNode('config') |
||||
->ignoreExtraKeys(false) |
||||
->end() |
||||
->scalarNode('service_name')->isRequired()->end() |
||||
->scalarNode('icon')->defaultNull()->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() |
||||
; |
||||
|
||||
|
||||
// Here you should define the parameters that are allowed to |
||||
// configure your bundle. See the documentation linked above for |
||||
// more information on that topic. |
||||
return $treeBuilder; |
||||
} |
||||
} |
@ -0,0 +1,66 @@ |
||||
<?php |
||||
/** |
||||
* Authserver, an OAuth2-based single-signon authentication provider written in PHP. |
||||
* |
||||
* Copyright (C) $today.date Lars Vierbergen |
||||
* |
||||
* his program is free software: you can redistribute it and/or modify |
||||
* it under the terms of the GNU Affero General Public License as |
||||
* published by the Free Software Foundation, either version 3 of the |
||||
* License, or (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU Affero General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU Affero General Public License |
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
*/ |
||||
|
||||
namespace vierbergenlars\AuthserverOAuthAccountBundle\EventListener; |
||||
|
||||
|
||||
use HWI\Bundle\OAuthBundle\Security\OAuthUtils; |
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface; |
||||
use Symfony\Component\HttpFoundation\Request; |
||||
use vierbergenlars\AuthserverExternalAccountBundle\Event\LoginButtonEvent; |
||||
use vierbergenlars\AuthserverExternalAccountBundle\ExternalAccountEvents; |
||||
use vierbergenlars\AuthserverOAuthAccountBundle\ResourceOwner\ResourceOwnerMap; |
||||
|
||||
class LoginButtonListener implements EventSubscriberInterface |
||||
{ |
||||
/** |
||||
* @var OAuthUtils |
||||
*/ |
||||
private $oauthUtils; |
||||
|
||||
/** |
||||
* @var ResourceOwnerMap |
||||
*/ |
||||
private $resourceOwnerConfig; |
||||
|
||||
public function __construct(OAuthUtils $oauthUtils, ResourceOwnerMap $resourceOwnerConfig) |
||||
{ |
||||
|
||||
$this->oauthUtils = $oauthUtils; |
||||
$this->resourceOwnerConfig = $resourceOwnerConfig; |
||||
} |
||||
|
||||
public static function getSubscribedEvents() |
||||
{ |
||||
return [ |
||||
ExternalAccountEvents::LOGIN_BUTTON => 'onLoginButton' |
||||
]; |
||||
} |
||||
|
||||
public function onLoginButton(LoginButtonEvent $event) |
||||
{ |
||||
foreach($this->oauthUtils->getResourceOwners() as $owner) |
||||
{ |
||||
$event->addButton($this->resourceOwnerConfig[$owner]->getLoginButton() + [ |
||||
'url' => $this->oauthUtils->getLoginUrl(new Request(), $owner), |
||||
]); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,100 @@ |
||||
<?php |
||||
/** |
||||
* Authserver, an OAuth2-based single-signon authentication provider written in PHP. |
||||
* |
||||
* Copyright (C) $today.date Lars Vierbergen |
||||
* |
||||
* his program is free software: you can redistribute it and/or modify |
||||
* it under the terms of the GNU Affero General Public License as |
||||
* published by the Free Software Foundation, either version 3 of the |
||||
* License, or (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU Affero General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU Affero General Public License |
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
*/ |
||||
|
||||
namespace vierbergenlars\AuthserverOAuthAccountBundle\EventListener; |
||||
|
||||
|
||||
use App\Event\TemplateEvent; |
||||
use HWI\Bundle\OAuthBundle\Security\OAuthUtils; |
||||
use Symfony\Bridge\Doctrine\ManagerRegistry; |
||||
use Symfony\Bundle\FrameworkBundle\Templating\TemplateReference; |
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface; |
||||
use User\UserEvents; |
||||
use vierbergenlars\AuthserverExternalAccountBundle\Entity\ExternalUser; |
||||
use vierbergenlars\AuthserverOAuthAccountBundle\ResourceOwner\ResourceOwnerMap; |
||||
|
||||
class ProfileTemplateListener implements EventSubscriberInterface |
||||
{ |
||||
/** |
||||
* @var ManagerRegistry |
||||
*/ |
||||
private $registry; |
||||
|
||||
/** |
||||
* @var ResourceOwnerMap |
||||
*/ |
||||
private $resourceOwnerConfig; |
||||
|
||||
/** |
||||
* @var OAuthUtils |
||||
*/ |
||||
private $oAuthUtils; |
||||
|
||||
public function __construct(ManagerRegistry $registry, ResourceOwnerMap $resourceOwnerConfig, OAuthUtils $oAuthUtils) |
||||
{ |
||||
$this->registry = $registry; |
||||
$this->resourceOwnerConfig = $resourceOwnerConfig; |
||||
$this->oAuthUtils = $oAuthUtils; |
||||
} |
||||
|
||||
public static function getSubscribedEvents() |
||||
{ |
||||
return [ |
||||
UserEvents::USER_PROFILE_VIEW => [ |
||||
['addOAuthAccountsTop', -50], |
||||
['addOAuthAccounts', -60], |
||||
['addOAuthAccountsBottom', -70], |
||||
], |
||||
]; |
||||
} |
||||
|
||||
public function addOAuthAccountsTop(TemplateEvent $event) |
||||
{ |
||||
$event->addTemplate(new TemplateReference('AuthserverOAuthAccountBundle', 'Profile', 'oauth_accounts_top', 'html', 'twig')); |
||||
} |
||||
|
||||
|
||||
public function addOAuthAccounts(TemplateEvent $event) |
||||
{ |
||||
$externalUsers = $this->registry->getManagerForClass(ExternalUser::class) |
||||
->getRepository(ExternalUser::class) |
||||
->findBy([ |
||||
'user' => $event->getSubject(), |
||||
]); |
||||
|
||||
foreach($this->oAuthUtils->getResourceOwners() as $resourceOwner) { |
||||
/* @var $resourceOwner string */ |
||||
$roExternalUsers = array_filter($externalUsers, function(ExternalUser $externalUser) use($resourceOwner) { |
||||
return $externalUser->getProvider() === $resourceOwner; |
||||
}); |
||||
$event->addTemplate(new TemplateReference('AuthserverOAuthAccountBundle', 'Profile', 'oauth_account', 'html', 'twig'), [ |
||||
'externalUsers' => $roExternalUsers, |
||||
'resourceOwnerConfig' => $this->resourceOwnerConfig[$resourceOwner], |
||||
'resourceOwner' => $resourceOwner, |
||||
]); |
||||
} |
||||
} |
||||
|
||||
public function addOAuthAccountsBottom(TemplateEvent $event) |
||||
{ |
||||
$event->addTemplate(new TemplateReference('AuthserverOAuthAccountBundle', 'Profile', 'oauth_accounts_bottom', 'html', 'twig')); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,76 @@ |
||||
<?php |
||||
/** |
||||
* Authserver, an OAuth2-based single-signon authentication provider written in PHP. |
||||
* |
||||
* Copyright (C) $today.date Lars Vierbergen |
||||
* |
||||
* his program is free software: you can redistribute it and/or modify |
||||
* it under the terms of the GNU Affero General Public License as |
||||
* published by the Free Software Foundation, either version 3 of the |
||||
* License, or (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU Affero General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU Affero General Public License |
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
*/ |
||||
|
||||
namespace vierbergenlars\AuthserverOAuthAccountBundle\ResourceOwner; |
||||
|
||||
|
||||
class ResourceOwnerConfig |
||||
{ |
||||
/** |
||||
* @var array |
||||
*/ |
||||
private $config; |
||||
|
||||
public function __construct(array $config) |
||||
{ |
||||
|
||||
$this->config = $config; |
||||
} |
||||
|
||||
public function getHwiConfig() |
||||
{ |
||||
return $this->config['config']; |
||||
} |
||||
|
||||
public function getServiceName() |
||||
{ |
||||
return $this->config['service_name']; |
||||
} |
||||
|
||||
public function getIcon() |
||||
{ |
||||
return $this->config['icon']; |
||||
} |
||||
|
||||
public function getLoginButton() |
||||
{ |
||||
$config = $this->config['login_button']; |
||||
foreach([ |
||||
'icon' => $this->getIcon(), |
||||
'label' => $this->getServiceName().' Login', |
||||
] as $k=>$v) |
||||
$config[$k] = $config[$k]?:$v; |
||||
|
||||
return $config; |
||||
} |
||||
|
||||
public function getConnectButton() |
||||
{ |
||||
$config = $this->config['connect_button']; |
||||
foreach([ |
||||
'icon' => $this->getIcon(), |
||||
'label' => 'Connect with '.$this->getServiceName(), |
||||
] as $k=>$v) |
||||
$config[$k] = $config[$k]?:$v; |
||||
|
||||
return $config; |
||||
} |
||||
|
||||
} |
@ -0,0 +1,58 @@ |
||||
<?php |
||||
/** |
||||
* Authserver, an OAuth2-based single-signon authentication provider written in PHP. |
||||
* |
||||
* Copyright (C) $today.date Lars Vierbergen |
||||
* |
||||
* his program is free software: you can redistribute it and/or modify |
||||
* it under the terms of the GNU Affero General Public License as |
||||
* published by the Free Software Foundation, either version 3 of the |
||||
* License, or (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU Affero General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU Affero General Public License |
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
*/ |
||||
|
||||
namespace vierbergenlars\AuthserverOAuthAccountBundle\ResourceOwner; |
||||
|
||||
class ResourceOwnerMap implements \ArrayAccess, \IteratorAggregate |
||||
{ |
||||
private $config; |
||||
|
||||
public function __construct(array $config) |
||||
{ |
||||
$this->config = $config; |
||||
} |
||||
|
||||
public function offsetExists($offset) |
||||
{ |
||||
return isset($this->config[$offset]); |
||||
} |
||||
|
||||
public function offsetGet($offset) |
||||
{ |
||||
if(!$this->config[$offset] instanceof ResourceOwnerConfig) |
||||
$this->config[$offset] = new ResourceOwnerConfig($this->config[$offset]); |
||||
return $this->config[$offset]; |
||||
} |
||||
|
||||
public function offsetSet($offset, $value) |
||||
{ |
||||
throw new \LogicException(sprintf('%s is frozen.', self::class)); |
||||
} |
||||
|
||||
public function offsetUnset($offset) |
||||
{ |
||||
throw new \LogicException(sprintf('%s is frozen.', self::class)); |
||||
} |
||||
|
||||
public function getIterator() |
||||
{ |
||||
return new ResourceOwnerMapIterator($this, array_keys($this->config)); |
||||
} |
||||
} |
@ -0,0 +1,77 @@ |
||||
<?php |
||||
/** |
||||
* Authserver, an OAuth2-based single-signon authentication provider written in PHP. |
||||
* |
||||
* Copyright (C) $today.date Lars Vierbergen |
||||
* |
||||
* his program is free software: you can redistribute it and/or modify |
||||
* it under the terms of the GNU Affero General Public License as |
||||
* published by the Free Software Foundation, either version 3 of the |
||||
* License, or (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU Affero General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU Affero General Public License |
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
*/ |
||||
|
||||
namespace vierbergenlars\AuthserverOAuthAccountBundle\ResourceOwner; |
||||
|
||||
class ResourceOwnerMapIterator implements \Iterator |
||||
{ |
||||
/** |
||||
* @var ResourceOwnerMap |
||||
*/ |
||||
private $resourceOwnerMap; |
||||
|
||||
/** |
||||
* @var string[] |
||||
*/ |
||||
private $keySet; |
||||
|
||||
/** |
||||
* @var int |
||||
*/ |
||||
private $index = 0; |
||||
|
||||
/** |
||||
* ResourceOwnerMapIterator constructor. |
||||
* |
||||
* @param ResourceOwnerMap $resourceOwnerMap |
||||
* @param \string[] $keySet |
||||
*/ |
||||
public function __construct(ResourceOwnerMap $resourceOwnerMap, array $keySet) |
||||
{ |
||||
$this->resourceOwnerMap = $resourceOwnerMap; |
||||
$this->keySet = $keySet; |
||||
} |
||||
|
||||
public function current() |
||||
{ |
||||
return $this->resourceOwnerMap->offsetGet($this->keySet[$this->index]); |
||||
} |
||||
|
||||
public function next() |
||||
{ |
||||
$this->index++; |
||||
} |
||||
|
||||
public function key() |
||||
{ |
||||
return $this->keySet[$this->index]; |
||||
} |
||||
|
||||
public function valid() |
||||
{ |
||||
return isset($this->keySet[$this->index]); |
||||
} |
||||
|
||||
public function rewind() |
||||
{ |
||||
$this->index = 0; |
||||
} |
||||
|
||||
} |
@ -0,0 +1,16 @@ |
||||
hwi_oauth_redirect: |
||||
resource: "@HWIOAuthBundle/Resources/config/routing/redirect.xml" |
||||
prefix: /login/oauth-connect |
||||
|
||||
hwi_oauth_connect: |
||||
resource: "@HWIOAuthBundle/Resources/config/routing/connect.xml" |
||||
prefix: /usr/oauth/connect |
||||
|
||||
vierbergenlars_oauth_account_disconnect: |
||||
path: /usr/oauth/disconnect/{externalUser} |
||||
defaults: |
||||
_controller: AuthserverOAuthAccountBundle:Connect:disconnectService |
||||
|
||||
oauth_login_paths: |
||||
resource: vierbergenlars.authserver_oauth_account.route_provider:getOAuthLoginPaths |
||||
type: service |
@ -0,0 +1,51 @@ |
||||
<?xml version="1.0" ?> |
||||
|
||||
<!-- |
||||
~ Authserver, an OAuth2-based single-signon authentication provider written in PHP. |
||||
~ |
||||
~ Copyright (C) $today.date Lars Vierbergen |
||||
~ |
||||
~ his program is free software: you can redistribute it and/or modify |
||||
~ it under the terms of the GNU Affero General Public License as |
||||
~ published by the Free Software Foundation, either version 3 of the |
||||
~ License, or (at your option) any later version. |
||||
~ |
||||
~ This program is distributed in the hope that it will be useful, |
||||
~ but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
~ GNU Affero General Public License for more details. |
||||
~ |
||||
~ You should have received a copy of the GNU Affero General Public License |
||||
~ along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
--> |
||||
|
||||
<container xmlns="http://symfony.com/schema/dic/services" |
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
||||
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd"> |
||||
<services> |
||||
<service id="vierbergenlars.authserver_oauth_account.user_provider" class="vierbergenlars\AuthserverOAuthAccountBundle\Security\Core\User\OAuthUserProvider"> |
||||
<argument type="service" id="doctrine" /> |
||||
</service> |
||||
<service id="vierbergenlars.authserver_oauth_account.route_provider" class="vierbergenlars\AuthserverOAuthAccountBundle\Routing\RouteProvider"> |
||||
<argument type="service" id="hwi_oauth.resource_ownermap.public" /> |
||||
</service> |
||||
|
||||
<service id="vierbergenlars.authserver_oauth_account.resource_owner_map" class="vierbergenlars\AuthserverOAuthAccountBundle\ResourceOwner\ResourceOwnerMap"> |
||||
<argument /> |
||||
</service> |
||||
|
||||
<!-- Event listeners --> |
||||
<service class="vierbergenlars\AuthserverOAuthAccountBundle\EventListener\LoginButtonListener"> |
||||
<argument type="service" id="hwi_oauth.security.oauth_utils" /> |
||||
<argument type="service" id="vierbergenlars.authserver_oauth_account.resource_owner_map" /> |
||||
<tag name="kernel.event_subscriber" /> |
||||
</service> |
||||
|
||||
<service class="vierbergenlars\AuthserverOAuthAccountBundle\EventListener\ProfileTemplateListener"> |
||||
<argument type="service" id="doctrine" /> |
||||
<argument type="service" id="vierbergenlars.authserver_oauth_account.resource_owner_map" /> |
||||
<argument type="service" id="hwi_oauth.security.oauth_utils"/> |
||||
<tag name="kernel.event_subscriber" /> |
||||
</service> |
||||
</services> |
||||
</container> |
@ -0,0 +1,32 @@ |
||||
{% extends '::base.html.twig' %} |
||||
{% block title %}{{ parent() }} - Connect Account{% endblock %} |
||||
{% block body %} |
||||
<div class="container"> |
||||
<div class="row"> |
||||
<div class="col-xs-12 col-sm-6 col-sm-offset-3 col-md-4 col-md-offset-4"> |
||||
<div class="panel panel-primary"> |
||||
<div class="panel-heading"> |
||||
<h3 class="panel-title">{{ 'header.connecting' | trans({}, 'HWIOAuthBundle')}}</h3> |
||||
</div> |
||||
<div class="panel-body"> |
||||
<p>{{ 'connect.confirm.text' | trans({'%service%': resourceOwnerConfig[service].serviceName | trans({}, 'HWIOAuthBundle'), '%name%': userInformation.realName}, 'HWIOAuthBundle') }}</p> |
||||
<p> |
||||
{{ form_start(form, {'action': path('hwi_oauth_connect_service', {'service': service, 'key': key})}) }} |
||||
{{ form_widget(form) }} |
||||
<div> |
||||
<button type="submit" class="btn btn-primary">{{ 'connect.confirm.submit' | trans({}, 'HWIOAuthBundle') }}</button> |
||||
<a href="{{ path('user_profile') }}" class="btn btn-link">{{ 'connect.confirm.cancel' | trans({}, 'HWIOAuthBundle') }}</a> |
||||
</div> |
||||
{{ form_end(form) }} |
||||
</p> |
||||
</div> |
||||
{% if userInformation.profilePicture is defined and userInformation.profilePicture is not empty %} |
||||
<div class="panel-body"> |
||||
<img src="{{ userInformation.profilePicture }}" style="width: 100%" /> |
||||
</div> |
||||
{% endif %} |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
{% endblock %} |
@ -0,0 +1,5 @@ |
||||
{% extends 'HWIOAuthBundle::layout.html.twig' %} |
||||
|
||||
{% block hwi_oauth_content %} |
||||
<h3>{{ 'header.success' | trans({'%name%': userInformation.realName}, 'HWIOAuthBundle') }}</h3> |
||||
{% endblock hwi_oauth_content %} |
@ -0,0 +1,27 @@ |
||||
{% extends '::base.html.twig' %} |
||||
{% block title %}{{ parent() }} - Disconnect Account{% endblock %} |
||||
{% block body %} |
||||
<div class="container"> |
||||
<div class="row"> |
||||
<div class="col-xs-12 col-sm-6 col-sm-offset-3 col-md-4 col-md-offset-4"> |
||||
<div class="panel panel-primary"> |
||||
<div class="panel-heading"> |
||||
<h3 class="panel-title">Disconnecting</h3> |
||||
</div> |
||||
<div class="panel-body"> |
||||
<p>Are you sure you want to disconnect your {{ resourceOwnerConfig[externalUser.provider].serviceName }} account "{{ externalUser.providerFriendlyName }}"?</p> |
||||
<p> |
||||
{{ form_start(form) }} |
||||
{{ form_widget(form) }} |
||||
<div> |
||||
<button type="submit" class="btn btn-primary">Disconnect account</button> |
||||
<a href="{{ path('user_profile') }}" class="btn btn-link">Cancel</a> |
||||
</div> |
||||
{{ form_end(form) }} |
||||
</p> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
{% endblock %} |
@ -0,0 +1,24 @@ |
||||
{# @var resourceOwnerConfig \vierbergenlars\AuthserverOAuthAccountBundle\ResourceOwner\ResourceOwnerConfig #} |
||||
{# @var externalUsers \vierbergenlars\AuthserverExternalAccountBundle\Entity\ExternalUser[] #} |
||||
<h4> |
||||
{% if resourceOwnerConfig.icon %} |
||||
{{ icon(resourceOwnerConfig.icon) }} |
||||
{% endif %} |
||||
{{ resourceOwnerConfig.serviceName }} |
||||
</h4> |
||||
|
||||
{% for externalUser in externalUsers %} |
||||
Connected to {{ externalUser.providerFriendlyName }} |
||||
<a href="{{ url('vierbergenlars_oauth_account_disconnect', {externalUser: externalUser.id}) }}" class="btn btn-link btn-sm">{{ icon('chain-broken') }} Disconnect account</a> |
||||
<br> |
||||
{% endfor %} |
||||
|
||||
{% set buttonConfig = resourceOwnerConfig.connectButton %} |
||||
|
||||
<a href="{{ hwi_oauth_login_url(resourceOwner) }}" |
||||
class="btn btn-{{ buttonConfig.style }}"> |
||||
{% if buttonConfig.icon %} |
||||
{{ icon(buttonConfig.icon) }} |
||||
{% endif %} |
||||
{{ buttonConfig.label }} |
||||
</a> |
@ -0,0 +1,2 @@ |
||||
</div> |
||||
</div> |
@ -0,0 +1,5 @@ |
||||
<div class="panel panel-default"> |
||||
<div class="panel-heading"> |
||||
<h2 class="panel-title">External authentication sources</h2> |
||||
</div> |
||||
<div class="panel-body"> |
@ -0,0 +1,60 @@ |
||||
<?php |
||||
/** |
||||
* Authserver, an OAuth2-based single-signon authentication provider written in PHP. |
||||
* |
||||
* Copyright (C) $today.date Lars Vierbergen |
||||
* |
||||
* his program is free software: you can redistribute it and/or modify |
||||
* it under the terms of the GNU Affero General Public License as |
||||
* published by the Free Software Foundation, either version 3 of the |
||||
* License, or (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU Affero General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU Affero General Public License |
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
*/ |
||||
|
||||
/** |
||||
* Created by PhpStorm. |
||||
* User: lars |
||||
* Date: 27/08/17 |
||||
* Time: 20:38 |
||||
*/ |
||||
|
||||
namespace vierbergenlars\AuthserverOAuthAccountBundle\Routing; |
||||
|
||||
|
||||
use HWI\Bundle\OAuthBundle\Security\Http\ResourceOwnerMap; |
||||
use Symfony\Component\Routing\Route; |
||||
use Symfony\Component\Routing\RouteCollection; |
||||
|
||||
class RouteProvider |
||||
{ |
||||
/** |
||||
* @var ResourceOwnerMap |
||||
*/ |
||||
private $resourceOwnerMap; |
||||
|
||||
public function __construct(ResourceOwnerMap $resourceOwnerMap) |
||||
{ |
||||
$this->resourceOwnerMap = $resourceOwnerMap; |
||||
} |
||||
|
||||
public function getOAuthLoginPaths() |
||||
{ |
||||
$routeCollection = new RouteCollection(); |
||||
|
||||
foreach($this->resourceOwnerMap->getResourceOwners() as $key =>$resourceOwner) { |
||||
/* @var $resourceOwner \HWI\Bundle\OAuthBundle\OAuth\ResourceOwnerInterface */ |
||||
$route = new Route('/login/oauth/'.$key); |
||||
$routeCollection->add('vl_authserver_oauth_account_'.$key, $route); |
||||
} |
||||
|
||||
return $routeCollection; |
||||
} |
||||
|
||||
} |
@ -0,0 +1,124 @@ |
||||
<?php |
||||
/** |
||||
* Authserver, an OAuth2-based single-signon authentication provider written in PHP. |
||||
* |
||||
* Copyright (C) $today.date Lars Vierbergen |
||||
* |
||||
* his program is free software: you can redistribute it and/or modify |
||||
* it under the terms of the GNU Affero General Public License as |
||||
* published by the Free Software Foundation, either version 3 of the |
||||
* License, or (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU Affero General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU Affero General Public License |
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
*/ |
||||
|
||||
|
||||
namespace vierbergenlars\AuthserverOAuthAccountBundle\Security\Core\User; |
||||
|
||||
|
||||
use App\Entity\User; |
||||
use App\Security\User\UserProvider; |
||||
use Doctrine\Common\Persistence\ManagerRegistry; |
||||
use HWI\Bundle\OAuthBundle\Connect\AccountConnectorInterface; |
||||
use HWI\Bundle\OAuthBundle\OAuth\Response\UserResponseInterface; |
||||
use HWI\Bundle\OAuthBundle\Security\Core\Exception\AccountNotLinkedException; |
||||
use HWI\Bundle\OAuthBundle\Security\Core\User\OAuthAwareUserProviderInterface; |
||||
use Symfony\Component\Security\Core\User\UserInterface; |
||||
use vierbergenlars\AuthserverExternalAccountBundle\Entity\ExternalUser; |
||||
|
||||
class OAuthUserProvider extends UserProvider implements OAuthAwareUserProviderInterface, AccountConnectorInterface |
||||
{ |
||||
/** |
||||
* @var ManagerRegistry |
||||
*/ |
||||
private $registry; |
||||
|
||||
public function __construct(ManagerRegistry $registry) |
||||
{ |
||||
parent::__construct($registry); |
||||
$this->registry = $registry; |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Loads the user by a given UserResponseInterface object. |
||||
* |
||||
* @param UserResponseInterface $response |
||||
* |
||||
* @return UserInterface |
||||
* |
||||
* @throws AccountNotLinkedException if the provider is not linked to an account |
||||
*/ |
||||
public function loadUserByOAuthUserResponse(UserResponseInterface $response) |
||||
{ |
||||
return $this->getExternalAccount($response)->getUser(); |
||||
} |
||||
|
||||
public function connect(UserInterface $user, UserResponseInterface $response) |
||||
{ |
||||
if(!$user instanceof User) |
||||
throw new \UnexpectedValueException('User must be instance of '.User::class.', got '.get_class($username)); |
||||
try { |
||||
$externalUser = $this->getExternalAccount($response); |
||||
$this->disconnect($externalUser); |
||||
} catch(AccountNotLinkedException $ex) { |
||||
// do nothing |
||||
} |
||||
$externalUser = new ExternalUser(); |
||||
$externalUser->setUser($user); |
||||
$externalUser->setProvider($response->getResourceOwner()->getName()); |
||||
$externalUser->setProviderRef($response->getUsername()); |
||||
$externalUser->setProviderFriendlyName($response->getRealName()); |
||||
$this->getManager()->persist($externalUser); |
||||
$this->getManager()->flush(); |
||||
} |
||||
|
||||
public function disconnect(ExternalUser $externalUser) |
||||
{ |
||||
$this->getManager()->remove($externalUser); |
||||
$this->getManager()->flush(); |
||||
} |
||||
|
||||
/** |
||||
* @return \Doctrine\Common\Persistence\ObjectRepository |
||||
*/ |
||||
private function getRepo() |
||||
{ |
||||
return $this->getManager()->getRepository('AuthserverExternalAccountBundle:ExternalUser'); |
||||
} |
||||
|
||||
/** |
||||
* @return \Doctrine\Common\Persistence\ObjectManager|null |
||||
*/ |
||||
private function getManager() |
||||
{ |
||||
return $this->registry->getManagerForClass('AuthserverExternalAccountBundle:ExternalUser'); |
||||
} |
||||
|
||||
/** |
||||
* @param UserResponseInterface $response |
||||
* @return ExternalUser |
||||
*/ |
||||
private function getExternalAccount(UserResponseInterface $response) |
||||
{ |
||||
$repo = $this->getRepo(); |
||||
|
||||
$externalAccount = $repo->findOneBy([ |
||||
'provider' => $response->getResourceOwner()->getName(), |
||||
'provider_ref' => $response->getUsername() |
||||
]); |
||||
|
||||
if(!$externalAccount) { |
||||
throw new AccountNotLinkedException(sprintf('No external account registered for provider "%s", ref: "%s"', $response->getResourceOwner()->getName(), $response->getUsername())); |
||||
} |
||||
|
||||
return $externalAccount; |
||||
} |
||||
|
||||
} |
@ -0,0 +1,18 @@ |
||||
{ |
||||
"name": "vierbergenlars/authserver-oauth-account-bundle", |
||||
"require": { |
||||
"hwi/oauth-bundle": "^0.5.3" |
||||
}, |
||||
"autoload": { |
||||
"psr-4": { |
||||
"vierbergenlars\\AuthserverOAuthAccountBundle\\": "." |
||||
} |
||||
}, |
||||
"license": "AGPL", |
||||
"authors": [ |
||||
{ |
||||
"name": "Lars Vierbergen", |
||||
"email": "vierbergenlars@gmail.com" |
||||
} |
||||
] |
||||
} |
File diff suppressed because it is too large
Load Diff
Reference in new issue