diff options
Diffstat (limited to 'src/Wallabag/UserBundle')
-rw-r--r-- | src/Wallabag/UserBundle/DependencyInjection/WallabagUserExtension.php | 30 | ||||
-rw-r--r-- | src/Wallabag/UserBundle/Entity/User.php | 49 | ||||
-rw-r--r-- | src/Wallabag/UserBundle/LdapHydrator.php | 103 | ||||
-rw-r--r-- | src/Wallabag/UserBundle/OAuthStorageLdapWrapper.php | 43 | ||||
-rw-r--r-- | src/Wallabag/UserBundle/Resources/config/ldap.yml | 28 | ||||
-rw-r--r-- | src/Wallabag/UserBundle/Resources/config/ldap_services.yml | 22 |
6 files changed, 273 insertions, 2 deletions
diff --git a/src/Wallabag/UserBundle/DependencyInjection/WallabagUserExtension.php b/src/Wallabag/UserBundle/DependencyInjection/WallabagUserExtension.php index 5ca3482e..904a6af1 100644 --- a/src/Wallabag/UserBundle/DependencyInjection/WallabagUserExtension.php +++ b/src/Wallabag/UserBundle/DependencyInjection/WallabagUserExtension.php | |||
@@ -6,9 +6,34 @@ use Symfony\Component\Config\FileLocator; | |||
6 | use Symfony\Component\DependencyInjection\ContainerBuilder; | 6 | use Symfony\Component\DependencyInjection\ContainerBuilder; |
7 | use Symfony\Component\DependencyInjection\Loader; | 7 | use Symfony\Component\DependencyInjection\Loader; |
8 | use Symfony\Component\HttpKernel\DependencyInjection\Extension; | 8 | use Symfony\Component\HttpKernel\DependencyInjection\Extension; |
9 | use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface; | ||
9 | 10 | ||
10 | class WallabagUserExtension extends Extension | 11 | class WallabagUserExtension extends Extension implements PrependExtensionInterface |
11 | { | 12 | { |
13 | public function prepend(ContainerBuilder $container) | ||
14 | { | ||
15 | $ldap = $container->getParameter('ldap_enabled'); | ||
16 | |||
17 | if ($ldap) { | ||
18 | $container->prependExtensionConfig('security', array( | ||
19 | 'providers' => array( | ||
20 | 'chain_provider' => array(), | ||
21 | ), | ||
22 | )); | ||
23 | $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); | ||
24 | $loader->load('ldap.yml'); | ||
25 | } elseif ($container->hasExtension('fr3d_ldap')) { | ||
26 | $container->prependExtensionConfig('fr3_d_ldap', array( | ||
27 | 'driver' => array( | ||
28 | 'host' => 'localhost', | ||
29 | ), | ||
30 | 'user' => array( | ||
31 | 'baseDn' => 'dc=example,dc=com', | ||
32 | ), | ||
33 | )); | ||
34 | } | ||
35 | } | ||
36 | |||
12 | public function load(array $configs, ContainerBuilder $container) | 37 | public function load(array $configs, ContainerBuilder $container) |
13 | { | 38 | { |
14 | $configuration = new Configuration(); | 39 | $configuration = new Configuration(); |
@@ -16,6 +41,9 @@ class WallabagUserExtension extends Extension | |||
16 | 41 | ||
17 | $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config')); | 42 | $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config')); |
18 | $loader->load('services.yml'); | 43 | $loader->load('services.yml'); |
44 | if ($container->getParameter('ldap_enabled')) { | ||
45 | $loader->load('ldap_services.yml'); | ||
46 | } | ||
19 | $container->setParameter('wallabag_user.registration_enabled', $config['registration_enabled']); | 47 | $container->setParameter('wallabag_user.registration_enabled', $config['registration_enabled']); |
20 | } | 48 | } |
21 | 49 | ||
diff --git a/src/Wallabag/UserBundle/Entity/User.php b/src/Wallabag/UserBundle/Entity/User.php index 48446e3c..f93c59c7 100644 --- a/src/Wallabag/UserBundle/Entity/User.php +++ b/src/Wallabag/UserBundle/Entity/User.php | |||
@@ -1,5 +1,15 @@ | |||
1 | <?php | 1 | <?php |
2 | 2 | ||
3 | // This permits to have the LdapUserInterface even when fr3d/ldap-bundle is not | ||
4 | // in the packages | ||
5 | namespace FR3D\LdapBundle\Model; | ||
6 | |||
7 | interface LdapUserInterface | ||
8 | { | ||
9 | public function setDn($dn); | ||
10 | public function getDn(); | ||
11 | } | ||
12 | |||
3 | namespace Wallabag\UserBundle\Entity; | 13 | namespace Wallabag\UserBundle\Entity; |
4 | 14 | ||
5 | use Doctrine\Common\Collections\ArrayCollection; | 15 | use Doctrine\Common\Collections\ArrayCollection; |
@@ -16,6 +26,7 @@ use Wallabag\ApiBundle\Entity\Client; | |||
16 | use Wallabag\CoreBundle\Entity\Config; | 26 | use Wallabag\CoreBundle\Entity\Config; |
17 | use Wallabag\CoreBundle\Entity\Entry; | 27 | use Wallabag\CoreBundle\Entity\Entry; |
18 | use Wallabag\CoreBundle\Helper\EntityTimestampsTrait; | 28 | use Wallabag\CoreBundle\Helper\EntityTimestampsTrait; |
29 | use FR3D\LdapBundle\Model\LdapUserInterface; | ||
19 | 30 | ||
20 | /** | 31 | /** |
21 | * User. | 32 | * User. |
@@ -28,7 +39,7 @@ use Wallabag\CoreBundle\Helper\EntityTimestampsTrait; | |||
28 | * @UniqueEntity("email") | 39 | * @UniqueEntity("email") |
29 | * @UniqueEntity("username") | 40 | * @UniqueEntity("username") |
30 | */ | 41 | */ |
31 | class User extends BaseUser implements TwoFactorInterface, TrustedComputerInterface | 42 | class User extends BaseUser implements TwoFactorInterface, TrustedComputerInterface, LdapUserInterface |
32 | { | 43 | { |
33 | use EntityTimestampsTrait; | 44 | use EntityTimestampsTrait; |
34 | 45 | ||
@@ -68,6 +79,13 @@ class User extends BaseUser implements TwoFactorInterface, TrustedComputerInterf | |||
68 | protected $email; | 79 | protected $email; |
69 | 80 | ||
70 | /** | 81 | /** |
82 | * @var string | ||
83 | * | ||
84 | * @ORM\Column(name="dn", type="text", nullable=true) | ||
85 | */ | ||
86 | protected $dn; | ||
87 | |||
88 | /** | ||
71 | * @var \DateTime | 89 | * @var \DateTime |
72 | * | 90 | * |
73 | * @ORM\Column(name="created_at", type="datetime") | 91 | * @ORM\Column(name="created_at", type="datetime") |
@@ -309,4 +327,33 @@ class User extends BaseUser implements TwoFactorInterface, TrustedComputerInterf | |||
309 | return $this->clients->first(); | 327 | return $this->clients->first(); |
310 | } | 328 | } |
311 | } | 329 | } |
330 | |||
331 | /** | ||
332 | * Set dn. | ||
333 | * | ||
334 | * @param string $dn | ||
335 | * | ||
336 | * @return User | ||
337 | */ | ||
338 | public function setDn($dn) | ||
339 | { | ||
340 | $this->dn = $dn; | ||
341 | |||
342 | return $this; | ||
343 | } | ||
344 | |||
345 | /** | ||
346 | * Get dn. | ||
347 | * | ||
348 | * @return string | ||
349 | */ | ||
350 | public function getDn() | ||
351 | { | ||
352 | return $this->dn; | ||
353 | } | ||
354 | |||
355 | public function isLdapUser() | ||
356 | { | ||
357 | return $this->dn !== null; | ||
358 | } | ||
312 | } | 359 | } |
diff --git a/src/Wallabag/UserBundle/LdapHydrator.php b/src/Wallabag/UserBundle/LdapHydrator.php new file mode 100644 index 00000000..cea2450f --- /dev/null +++ b/src/Wallabag/UserBundle/LdapHydrator.php | |||
@@ -0,0 +1,103 @@ | |||
1 | <?php | ||
2 | |||
3 | namespace Wallabag\UserBundle; | ||
4 | |||
5 | use FR3D\LdapBundle\Hydrator\HydratorInterface; | ||
6 | use FOS\UserBundle\FOSUserEvents; | ||
7 | use FOS\UserBundle\Event\UserEvent; | ||
8 | |||
9 | class LdapHydrator implements HydratorInterface | ||
10 | { | ||
11 | private $userManager; | ||
12 | private $eventDispatcher; | ||
13 | private $attributesMap; | ||
14 | private $enabledAttribute; | ||
15 | private $ldapBaseDn; | ||
16 | private $ldapAdminFilter; | ||
17 | private $ldapDriver; | ||
18 | |||
19 | public function __construct( | ||
20 | $user_manager, | ||
21 | $event_dispatcher, | ||
22 | array $attributes_map, | ||
23 | $ldap_base_dn, | ||
24 | $ldap_admin_filter, | ||
25 | $ldap_driver | ||
26 | ) { | ||
27 | $this->userManager = $user_manager; | ||
28 | $this->eventDispatcher = $event_dispatcher; | ||
29 | |||
30 | $this->attributesMap = array( | ||
31 | 'setUsername' => $attributes_map[0], | ||
32 | 'setEmail' => $attributes_map[1], | ||
33 | 'setName' => $attributes_map[2], | ||
34 | ); | ||
35 | $this->enabledAttribute = $attributes_map[3]; | ||
36 | |||
37 | $this->ldapBaseDn = $ldap_base_dn; | ||
38 | $this->ldapAdminFilter = $ldap_admin_filter; | ||
39 | $this->ldapDriver = $ldap_driver; | ||
40 | } | ||
41 | |||
42 | public function hydrate(array $ldapEntry) | ||
43 | { | ||
44 | $user = $this->userManager->findUserBy(array('dn' => $ldapEntry['dn'])); | ||
45 | |||
46 | if (!$user) { | ||
47 | $user = $this->userManager->createUser(); | ||
48 | $user->setDn($ldapEntry['dn']); | ||
49 | $user->setPassword(''); | ||
50 | $user->setSalt(''); | ||
51 | $this->updateUserFields($user, $ldapEntry); | ||
52 | |||
53 | $event = new UserEvent($user); | ||
54 | $this->eventDispatcher->dispatch(FOSUserEvents::USER_CREATED, $event); | ||
55 | |||
56 | $this->userManager->reloadUser($user); | ||
57 | } else { | ||
58 | $this->updateUserFields($user, $ldapEntry); | ||
59 | } | ||
60 | |||
61 | return $user; | ||
62 | } | ||
63 | |||
64 | private function updateUserFields($user, $ldapEntry) | ||
65 | { | ||
66 | foreach ($this->attributesMap as $key => $value) { | ||
67 | if (is_array($ldapEntry[$value])) { | ||
68 | $ldap_value = $ldapEntry[$value][0]; | ||
69 | } else { | ||
70 | $ldap_value = $ldapEntry[$value]; | ||
71 | } | ||
72 | |||
73 | call_user_func([$user, $key], $ldap_value); | ||
74 | } | ||
75 | |||
76 | if ($this->enabledAttribute !== null) { | ||
77 | $user->setEnabled($ldapEntry[$this->enabledAttribute]); | ||
78 | } else { | ||
79 | $user->setEnabled(true); | ||
80 | } | ||
81 | |||
82 | if ($this->isAdmin($user)) { | ||
83 | $user->addRole('ROLE_SUPER_ADMIN'); | ||
84 | } else { | ||
85 | $user->removeRole('ROLE_SUPER_ADMIN'); | ||
86 | } | ||
87 | |||
88 | $this->userManager->updateUser($user, true); | ||
89 | } | ||
90 | |||
91 | private function isAdmin($user) | ||
92 | { | ||
93 | if ($this->ldapAdminFilter === null) { | ||
94 | return false; | ||
95 | } | ||
96 | |||
97 | $escaped_username = ldap_escape($user->getUsername(), '', LDAP_ESCAPE_FILTER); | ||
98 | $filter = sprintf($this->ldapAdminFilter, $escaped_username); | ||
99 | $entries = $this->ldapDriver->search($this->ldapBaseDn, $filter); | ||
100 | |||
101 | return $entries['count'] == 1; | ||
102 | } | ||
103 | } | ||
diff --git a/src/Wallabag/UserBundle/OAuthStorageLdapWrapper.php b/src/Wallabag/UserBundle/OAuthStorageLdapWrapper.php new file mode 100644 index 00000000..8a851f12 --- /dev/null +++ b/src/Wallabag/UserBundle/OAuthStorageLdapWrapper.php | |||
@@ -0,0 +1,43 @@ | |||
1 | <?php | ||
2 | |||
3 | namespace Wallabag\UserBundle; | ||
4 | |||
5 | use FOS\OAuthServerBundle\Storage\OAuthStorage; | ||
6 | use OAuth2\Model\IOAuth2Client; | ||
7 | use Symfony\Component\Security\Core\Exception\AuthenticationException; | ||
8 | |||
9 | class OAuthStorageLdapWrapper extends OAuthStorage | ||
10 | { | ||
11 | private $ldapManager; | ||
12 | |||
13 | public function setLdapManager($ldap_manager) | ||
14 | { | ||
15 | $this->ldapManager = $ldap_manager; | ||
16 | } | ||
17 | |||
18 | public function checkUserCredentials(IOAuth2Client $client, $username, $password) | ||
19 | { | ||
20 | try { | ||
21 | $user = $this->userProvider->loadUserByUsername($username); | ||
22 | } catch (AuthenticationException $e) { | ||
23 | return false; | ||
24 | } | ||
25 | |||
26 | if ($user->isLdapUser()) { | ||
27 | return $this->checkLdapUserCredentials($user, $password); | ||
28 | } else { | ||
29 | return parent::checkUserCredentials($client, $username, $password); | ||
30 | } | ||
31 | } | ||
32 | |||
33 | private function checkLdapUserCredentials($user, $password) | ||
34 | { | ||
35 | if ($this->ldapManager->bind($user, $password)) { | ||
36 | return array( | ||
37 | 'data' => $user, | ||
38 | ); | ||
39 | } else { | ||
40 | return false; | ||
41 | } | ||
42 | } | ||
43 | } | ||
diff --git a/src/Wallabag/UserBundle/Resources/config/ldap.yml b/src/Wallabag/UserBundle/Resources/config/ldap.yml new file mode 100644 index 00000000..5ec16088 --- /dev/null +++ b/src/Wallabag/UserBundle/Resources/config/ldap.yml | |||
@@ -0,0 +1,28 @@ | |||
1 | fr3d_ldap: | ||
2 | service: | ||
3 | user_hydrator: ldap_user_hydrator | ||
4 | driver: | ||
5 | host: "%ldap_host%" | ||
6 | port: "%ldap_port%" | ||
7 | useSsl: "%ldap_ssl%" | ||
8 | useStartTls: "%ldap_tls%" | ||
9 | bindRequiresDn: "%ldap_bind_requires_dn%" | ||
10 | username: "%ldap_manager_dn%" | ||
11 | password: "%ldap_manager_pw%" | ||
12 | user: | ||
13 | baseDn: "%ldap_base%" | ||
14 | filter: "%ldap_filter%" | ||
15 | usernameAttribute: "%ldap_username_attribute%" | ||
16 | security: | ||
17 | providers: | ||
18 | chain_provider: | ||
19 | chain: | ||
20 | providers: [ fr3d_ldapbundle, fos_userbundle ] | ||
21 | fr3d_ldapbundle: | ||
22 | id: fr3d_ldap.security.user.provider | ||
23 | firewalls: | ||
24 | secured_area: | ||
25 | fr3d_ldap: ~ | ||
26 | form_login: | ||
27 | provider: chain_provider | ||
28 | |||
diff --git a/src/Wallabag/UserBundle/Resources/config/ldap_services.yml b/src/Wallabag/UserBundle/Resources/config/ldap_services.yml new file mode 100644 index 00000000..b3e3fd8a --- /dev/null +++ b/src/Wallabag/UserBundle/Resources/config/ldap_services.yml | |||
@@ -0,0 +1,22 @@ | |||
1 | services: | ||
2 | fos_oauth_server.server: | ||
3 | class: OAuth2\OAuth2 | ||
4 | arguments: | ||
5 | - "@oauth_storage_ldap_wrapper" | ||
6 | - "%fos_oauth_server.server.options%" | ||
7 | oauth_storage_ldap_wrapper: | ||
8 | class: Wallabag\UserBundle\OAuthStorageLdapWrapper | ||
9 | parent: fos_oauth_server.storage | ||
10 | calls: | ||
11 | - [setLdapManager, ["@fr3d_ldap.ldap_manager"]] | ||
12 | |||
13 | ldap_user_hydrator: | ||
14 | class: Wallabag\UserBundle\LdapHydrator | ||
15 | arguments: | ||
16 | - "@fos_user.user_manager" | ||
17 | - "@event_dispatcher" | ||
18 | - [ "%ldap_username_attribute%", "%ldap_email_attribute%", "%ldap_name_attribute%", "%ldap_enabled_attribute%" ] | ||
19 | - "%ldap_base%" | ||
20 | - "%ldap_admin_filter%" | ||
21 | - "@fr3d_ldap.ldap_driver" | ||
22 | |||