]>
Commit | Line | Data |
---|---|---|
24fd1fe6 IB |
1 | diff --git a/.travis.yml b/.travis.yml |
2 | index 04cea258..56b1f576 100644 | |
3 | --- a/.travis.yml | |
4 | +++ b/.travis.yml | |
5 | @@ -58,6 +58,7 @@ install: | |
6 | ||
7 | before_script: | |
8 | - PHP=$TRAVIS_PHP_VERSION | |
9 | + - echo "extension=ldap.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/travis.ini | |
10 | - if [[ ! $PHP = hhvm* ]]; then echo "memory_limit=-1" >> ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/travis.ini; fi; | |
11 | # xdebug isn't enable for PHP 7.1 | |
12 | - if [[ ! $PHP = hhvm* ]]; then phpenv config-rm xdebug.ini || echo "xdebug not available"; fi | |
13 | diff --git a/app/AppKernel.php b/app/AppKernel.php | |
14 | index 40726f05..c4f465dc 100644 | |
15 | --- a/app/AppKernel.php | |
16 | +++ b/app/AppKernel.php | |
17 | @@ -42,6 +42,10 @@ class AppKernel extends Kernel | |
18 | new OldSound\RabbitMqBundle\OldSoundRabbitMqBundle(), | |
19 | ]; | |
20 | ||
21 | + if (class_exists('FR3D\\LdapBundle\\FR3DLdapBundle')) { | |
22 | + $bundles[] = new FR3D\LdapBundle\FR3DLdapBundle(); | |
23 | + } | |
24 | + | |
25 | if (in_array($this->getEnvironment(), ['dev', 'test'], true)) { | |
26 | $bundles[] = new Symfony\Bundle\DebugBundle\DebugBundle(); | |
27 | $bundles[] = new Symfony\Bundle\WebProfilerBundle\WebProfilerBundle(); | |
28 | diff --git a/app/DoctrineMigrations/Version20170710113900.php b/app/DoctrineMigrations/Version20170710113900.php | |
29 | new file mode 100644 | |
30 | index 00000000..7be83110 | |
31 | --- /dev/null | |
32 | +++ b/app/DoctrineMigrations/Version20170710113900.php | |
33 | @@ -0,0 +1,54 @@ | |
34 | +<?php | |
35 | + | |
36 | +namespace Application\Migrations; | |
37 | + | |
38 | +use Doctrine\DBAL\Migrations\AbstractMigration; | |
39 | +use Doctrine\DBAL\Schema\Schema; | |
40 | +use Symfony\Component\DependencyInjection\ContainerAwareInterface; | |
41 | +use Symfony\Component\DependencyInjection\ContainerInterface; | |
42 | + | |
43 | +/** | |
44 | + * Added dn field on wallabag_users | |
45 | + */ | |
46 | +class Version20170710113900 extends AbstractMigration implements ContainerAwareInterface | |
47 | +{ | |
48 | + /** | |
49 | + * @var ContainerInterface | |
50 | + */ | |
51 | + private $container; | |
52 | + | |
53 | + public function setContainer(ContainerInterface $container = null) | |
54 | + { | |
55 | + $this->container = $container; | |
56 | + } | |
57 | + | |
58 | + private function getTable($tableName) | |
59 | + { | |
60 | + return $this->container->getParameter('database_table_prefix').$tableName; | |
61 | + } | |
62 | + | |
63 | + /** | |
64 | + * @param Schema $schema | |
65 | + */ | |
66 | + public function up(Schema $schema) | |
67 | + { | |
68 | + $usersTable = $schema->getTable($this->getTable('user')); | |
69 | + | |
70 | + $this->skipIf($usersTable->hasColumn('dn'), 'It seems that you already played this migration.'); | |
71 | + | |
72 | + $usersTable->addColumn('dn', 'text', [ | |
73 | + 'default' => null, | |
74 | + 'notnull' => false, | |
75 | + ]); | |
76 | + } | |
77 | + | |
78 | + /** | |
79 | + * @param Schema $schema | |
80 | + */ | |
81 | + public function down(Schema $schema) | |
82 | + { | |
83 | + $usersTable = $schema->getTable($this->getTable('user')); | |
84 | + $usersTable->dropColumn('dn'); | |
85 | + } | |
86 | +} | |
87 | + | |
88 | diff --git a/app/config/parameters.yml.dist b/app/config/parameters.yml.dist | |
89 | index 6b0cb8e8..cfd41b69 100644 | |
90 | --- a/app/config/parameters.yml.dist | |
91 | +++ b/app/config/parameters.yml.dist | |
92 | @@ -62,3 +62,23 @@ parameters: | |
93 | redis_port: 6379 | |
94 | redis_path: null | |
95 | redis_password: null | |
96 | + | |
97 | + # ldap configuration | |
98 | + # To enable, you need to require fr3d/ldap-bundle | |
99 | + ldap_enabled: false | |
100 | + ldap_host: localhost | |
101 | + ldap_port: 389 | |
102 | + ldap_tls: false | |
103 | + ldap_ssl: false | |
104 | + ldap_bind_requires_dn: true | |
105 | + ldap_base: dc=example,dc=com | |
106 | + ldap_manager_dn: ou=Manager,dc=example,dc=com | |
107 | + ldap_manager_pw: password | |
108 | + ldap_filter: (&(ObjectClass=Person)) | |
109 | + # optional (if null: no ldap user is admin) | |
110 | + ldap_admin_filter: (&(memberOf=ou=admins,dc=example,dc=com)(uid=%s)) | |
111 | + ldap_username_attribute: uid | |
112 | + ldap_email_attribute: mail | |
113 | + ldap_name_attribute: cn | |
114 | + # optional (default sets user as enabled unconditionally) | |
115 | + ldap_enabled_attribute: ~ | |
116 | diff --git a/app/config/security.yml b/app/config/security.yml | |
117 | index 02afc9ea..48fbb553 100644 | |
118 | --- a/app/config/security.yml | |
119 | +++ b/app/config/security.yml | |
120 | @@ -6,6 +6,7 @@ security: | |
121 | ROLE_ADMIN: ROLE_USER | |
122 | ROLE_SUPER_ADMIN: [ ROLE_USER, ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH ] | |
123 | ||
124 | + # /!\ This list is modified in WallabagUserBundle when LDAP is enabled | |
125 | providers: | |
126 | administrators: | |
127 | entity: | |
128 | @@ -36,6 +37,7 @@ security: | |
129 | pattern: ^/login$ | |
130 | anonymous: ~ | |
131 | ||
132 | + # /!\ This section is modified in WallabagUserBundle when LDAP is enabled | |
133 | secured_area: | |
134 | pattern: ^/ | |
135 | form_login: | |
136 | diff --git a/composer.json b/composer.json | |
137 | index 68cfad05..32a3d1a4 100644 | |
138 | --- a/composer.json | |
139 | +++ b/composer.json | |
140 | @@ -85,7 +85,11 @@ | |
141 | "friendsofsymfony/jsrouting-bundle": "^1.6.3", | |
142 | "bdunogier/guzzle-site-authenticator": "^1.0.0", | |
143 | "defuse/php-encryption": "^2.1", | |
144 | - "html2text/html2text": "^4.1" | |
145 | + "html2text/html2text": "^4.1", | |
146 | + "fr3d/ldap-bundle": "^3.0" | |
147 | + }, | |
148 | + "suggest": { | |
149 | + "fr3d/ldap-bundle": "If you want to authenticate via LDAP" | |
150 | }, | |
151 | "require-dev": { | |
152 | "doctrine/doctrine-fixtures-bundle": "~2.2", | |
153 | diff --git a/composer.lock b/composer.lock | |
154 | index 251ee081..37795e0b 100644 | |
155 | --- a/composer.lock | |
156 | +++ b/composer.lock | |
157 | @@ -4,7 +4,7 @@ | |
158 | "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", | |
159 | "This file is @generated automatically" | |
160 | ], | |
161 | - "content-hash": "d2a0bd8408dccdeb7a7455996519829b", | |
162 | + "content-hash": "4699d166d03a8e5f70d802d0bc3e6a20", | |
163 | "packages": [ | |
164 | { | |
165 | "name": "bdunogier/guzzle-site-authenticator", | |
166 | @@ -1346,6 +1346,65 @@ | |
167 | ], | |
168 | "time": "2018-12-14T19:44:53+00:00" | |
169 | }, | |
170 | + { | |
171 | + "name": "fr3d/ldap-bundle", | |
172 | + "version": "v3.0.0", | |
173 | + "source": { | |
174 | + "type": "git", | |
175 | + "url": "https://github.com/Maks3w/FR3DLdapBundle.git", | |
176 | + "reference": "5a8927c11af45fa06331b97221c6da1a4a237475" | |
177 | + }, | |
178 | + "dist": { | |
179 | + "type": "zip", | |
180 | + "url": "https://api.github.com/repos/Maks3w/FR3DLdapBundle/zipball/5a8927c11af45fa06331b97221c6da1a4a237475", | |
181 | + "reference": "5a8927c11af45fa06331b97221c6da1a4a237475", | |
182 | + "shasum": "" | |
183 | + }, | |
184 | + "require": { | |
185 | + "php": ">=5.5", | |
186 | + "psr/log": "~1.0", | |
187 | + "symfony/config": "2.3 - 3", | |
188 | + "symfony/dependency-injection": "2.3 - 3", | |
189 | + "symfony/polyfill-php56": "^1.1", | |
190 | + "symfony/security": "2.3 - 3", | |
191 | + "symfony/security-bundle": "2.3 - 3", | |
192 | + "zendframework/zend-ldap": "2.5 - 3" | |
193 | + }, | |
194 | + "require-dev": { | |
195 | + "fabpot/php-cs-fixer": "1.11.*", | |
196 | + "fr3d/psr3-message-assertions": "0.1.*", | |
197 | + "friendsofsymfony/user-bundle": "~1.3", | |
198 | + "maks3w/phpunit-methods-trait": "^4.6", | |
199 | + "phpunit/phpunit": "^4.6", | |
200 | + "symfony/validator": "2.3 - 3" | |
201 | + }, | |
202 | + "suggest": { | |
203 | + "friendsofsymfony/user-bundle": "Integrate authentication and management for DB users, useful for unmanned LDAP servers", | |
204 | + "symfony/validator": "Allow pre-validate for existing users before register new ones" | |
205 | + }, | |
206 | + "type": "symfony-bundle", | |
207 | + "autoload": { | |
208 | + "psr-4": { | |
209 | + "FR3D\\LdapBundle\\": "" | |
210 | + } | |
211 | + }, | |
212 | + "notification-url": "https://packagist.org/downloads/", | |
213 | + "license": [ | |
214 | + "MIT" | |
215 | + ], | |
216 | + "authors": [ | |
217 | + { | |
218 | + "name": "Maks3w" | |
219 | + } | |
220 | + ], | |
221 | + "description": "This package provide users and authentication services based on LDAP directories for Symfony2 framework", | |
222 | + "homepage": "https://github.com/Maks3w/FR3DLdapBundle", | |
223 | + "keywords": [ | |
224 | + "Authentication", | |
225 | + "ldap" | |
226 | + ], | |
227 | + "time": "2016-02-12T17:45:14+00:00" | |
228 | + }, | |
229 | { | |
230 | "name": "friendsofsymfony/jsrouting-bundle", | |
231 | "version": "1.6.3", | |
232 | @@ -7027,6 +7086,59 @@ | |
233 | "zf2" | |
234 | ], | |
235 | "time": "2018-04-25T15:33:34+00:00" | |
236 | + }, | |
237 | + { | |
238 | + "name": "zendframework/zend-ldap", | |
239 | + "version": "2.10.0", | |
240 | + "source": { | |
241 | + "type": "git", | |
242 | + "url": "https://github.com/zendframework/zend-ldap.git", | |
243 | + "reference": "b63c7884a08d3a6bda60ebcf7d6238cf8ad89f49" | |
244 | + }, | |
245 | + "dist": { | |
246 | + "type": "zip", | |
247 | + "url": "https://api.github.com/repos/zendframework/zend-ldap/zipball/b63c7884a08d3a6bda60ebcf7d6238cf8ad89f49", | |
248 | + "reference": "b63c7884a08d3a6bda60ebcf7d6238cf8ad89f49", | |
249 | + "shasum": "" | |
250 | + }, | |
251 | + "require": { | |
252 | + "ext-ldap": "*", | |
253 | + "php": "^5.6 || ^7.0" | |
254 | + }, | |
255 | + "require-dev": { | |
256 | + "php-mock/php-mock-phpunit": "^1.1.2 || ^2.1.1", | |
257 | + "phpunit/phpunit": "^5.7.27 || ^6.5.8 || ^7.1.2", | |
258 | + "zendframework/zend-coding-standard": "~1.0.0", | |
259 | + "zendframework/zend-config": "^2.5", | |
260 | + "zendframework/zend-eventmanager": "^2.6.3 || ^3.0.1", | |
261 | + "zendframework/zend-stdlib": "^2.7 || ^3.0" | |
262 | + }, | |
263 | + "suggest": { | |
264 | + "zendframework/zend-eventmanager": "Zend\\EventManager component" | |
265 | + }, | |
266 | + "type": "library", | |
267 | + "extra": { | |
268 | + "branch-alias": { | |
269 | + "dev-master": "2.10.x-dev", | |
270 | + "dev-develop": "2.11.x-dev" | |
271 | + } | |
272 | + }, | |
273 | + "autoload": { | |
274 | + "psr-4": { | |
275 | + "Zend\\Ldap\\": "src/" | |
276 | + } | |
277 | + }, | |
278 | + "notification-url": "https://packagist.org/downloads/", | |
279 | + "license": [ | |
280 | + "BSD-3-Clause" | |
281 | + ], | |
282 | + "description": "Provides support for LDAP operations including but not limited to binding, searching and modifying entries in an LDAP directory", | |
283 | + "keywords": [ | |
284 | + "ZendFramework", | |
285 | + "ldap", | |
286 | + "zf" | |
287 | + ], | |
288 | + "time": "2018-07-05T05:05:12+00:00" | |
289 | } | |
290 | ], | |
291 | "packages-dev": [ | |
292 | @@ -7561,12 +7673,12 @@ | |
293 | "source": { | |
294 | "type": "git", | |
295 | "url": "https://github.com/symfony/phpunit-bridge.git", | |
296 | - "reference": "5dab0d4b2ac99ab22b447b615fdfdc10ec4af3d5" | |
297 | + "reference": "d61ec438634e0f234c6bda1c6ee97016bbb0e7a1" | |
298 | }, | |
299 | "dist": { | |
300 | "type": "zip", | |
301 | - "url": "https://api.github.com/repos/symfony/phpunit-bridge/zipball/5dab0d4b2ac99ab22b447b615fdfdc10ec4af3d5", | |
302 | - "reference": "5dab0d4b2ac99ab22b447b615fdfdc10ec4af3d5", | |
303 | + "url": "https://api.github.com/repos/symfony/phpunit-bridge/zipball/d61ec438634e0f234c6bda1c6ee97016bbb0e7a1", | |
304 | + "reference": "d61ec438634e0f234c6bda1c6ee97016bbb0e7a1", | |
305 | "shasum": "" | |
306 | }, | |
307 | "require": { | |
308 | @@ -7619,7 +7731,7 @@ | |
309 | ], | |
310 | "description": "Symfony PHPUnit Bridge", | |
311 | "homepage": "https://symfony.com", | |
312 | - "time": "2019-01-01T13:45:19+00:00" | |
313 | + "time": "2019-01-16T13:27:11+00:00" | |
314 | }, | |
315 | { | |
316 | "name": "symfony/polyfill-php72", | |
317 | diff --git a/scripts/install.sh b/scripts/install.sh | |
318 | index 8b7ea03f..3a4a33ab 100755 | |
319 | --- a/scripts/install.sh | |
320 | +++ b/scripts/install.sh | |
321 | @@ -26,5 +26,8 @@ ENV=$1 | |
322 | TAG=$(git describe --tags $(git rev-list --tags --max-count=1)) | |
323 | ||
324 | git checkout $TAG | |
325 | +if [ -n "$LDAP_ENABLED" ]; then | |
326 | + SYMFONY_ENV=$ENV $COMPOSER_COMMAND require --no-update fr3d/ldap-bundle | |
327 | +fi | |
328 | SYMFONY_ENV=$ENV $COMPOSER_COMMAND install --no-dev -o --prefer-dist | |
329 | php bin/console wallabag:install --env=$ENV | |
330 | diff --git a/scripts/update.sh b/scripts/update.sh | |
331 | index c62d104a..6259a431 100755 | |
332 | --- a/scripts/update.sh | |
333 | +++ b/scripts/update.sh | |
334 | @@ -32,6 +32,9 @@ git fetch origin | |
335 | git fetch --tags | |
336 | TAG=$(git describe --tags $(git rev-list --tags --max-count=1)) | |
337 | git checkout $TAG --force | |
338 | +if [ -n "$LDAP_ENABLED" ]; then | |
339 | + SYMFONY_ENV=$ENV $COMPOSER_COMMAND require --no-update fr3d/ldap-bundle | |
340 | +fi | |
341 | SYMFONY_ENV=$ENV $COMPOSER_COMMAND install --no-dev -o --prefer-dist | |
342 | php bin/console doctrine:migrations:migrate --no-interaction --env=$ENV | |
343 | php bin/console cache:clear --env=$ENV | |
344 | diff --git a/src/Wallabag/UserBundle/DependencyInjection/WallabagUserExtension.php b/src/Wallabag/UserBundle/DependencyInjection/WallabagUserExtension.php | |
345 | index 5ca3482e..904a6af1 100644 | |
346 | --- a/src/Wallabag/UserBundle/DependencyInjection/WallabagUserExtension.php | |
347 | +++ b/src/Wallabag/UserBundle/DependencyInjection/WallabagUserExtension.php | |
348 | @@ -6,9 +6,34 @@ use Symfony\Component\Config\FileLocator; | |
349 | use Symfony\Component\DependencyInjection\ContainerBuilder; | |
350 | use Symfony\Component\DependencyInjection\Loader; | |
351 | use Symfony\Component\HttpKernel\DependencyInjection\Extension; | |
352 | +use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface; | |
353 | ||
354 | -class WallabagUserExtension extends Extension | |
355 | +class WallabagUserExtension extends Extension implements PrependExtensionInterface | |
356 | { | |
357 | + public function prepend(ContainerBuilder $container) | |
358 | + { | |
359 | + $ldap = $container->getParameter('ldap_enabled'); | |
360 | + | |
361 | + if ($ldap) { | |
362 | + $container->prependExtensionConfig('security', array( | |
363 | + 'providers' => array( | |
364 | + 'chain_provider' => array(), | |
365 | + ), | |
366 | + )); | |
367 | + $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); | |
368 | + $loader->load('ldap.yml'); | |
369 | + } elseif ($container->hasExtension('fr3d_ldap')) { | |
370 | + $container->prependExtensionConfig('fr3_d_ldap', array( | |
371 | + 'driver' => array( | |
372 | + 'host' => 'localhost', | |
373 | + ), | |
374 | + 'user' => array( | |
375 | + 'baseDn' => 'dc=example,dc=com', | |
376 | + ), | |
377 | + )); | |
378 | + } | |
379 | + } | |
380 | + | |
381 | public function load(array $configs, ContainerBuilder $container) | |
382 | { | |
383 | $configuration = new Configuration(); | |
384 | @@ -16,6 +41,9 @@ class WallabagUserExtension extends Extension | |
385 | ||
386 | $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config')); | |
387 | $loader->load('services.yml'); | |
388 | + if ($container->getParameter('ldap_enabled')) { | |
389 | + $loader->load('ldap_services.yml'); | |
390 | + } | |
391 | $container->setParameter('wallabag_user.registration_enabled', $config['registration_enabled']); | |
392 | } | |
393 | ||
394 | diff --git a/src/Wallabag/UserBundle/Entity/User.php b/src/Wallabag/UserBundle/Entity/User.php | |
395 | index 48446e3c..f93c59c7 100644 | |
396 | --- a/src/Wallabag/UserBundle/Entity/User.php | |
397 | +++ b/src/Wallabag/UserBundle/Entity/User.php | |
398 | @@ -1,5 +1,15 @@ | |
399 | <?php | |
400 | ||
401 | +// This permits to have the LdapUserInterface even when fr3d/ldap-bundle is not | |
402 | +// in the packages | |
403 | +namespace FR3D\LdapBundle\Model; | |
404 | + | |
405 | +interface LdapUserInterface | |
406 | +{ | |
407 | + public function setDn($dn); | |
408 | + public function getDn(); | |
409 | +} | |
410 | + | |
411 | namespace Wallabag\UserBundle\Entity; | |
412 | ||
413 | use Doctrine\Common\Collections\ArrayCollection; | |
414 | @@ -16,6 +26,7 @@ use Wallabag\ApiBundle\Entity\Client; | |
415 | use Wallabag\CoreBundle\Entity\Config; | |
416 | use Wallabag\CoreBundle\Entity\Entry; | |
417 | use Wallabag\CoreBundle\Helper\EntityTimestampsTrait; | |
418 | +use FR3D\LdapBundle\Model\LdapUserInterface; | |
419 | ||
420 | /** | |
421 | * User. | |
422 | @@ -28,7 +39,7 @@ use Wallabag\CoreBundle\Helper\EntityTimestampsTrait; | |
423 | * @UniqueEntity("email") | |
424 | * @UniqueEntity("username") | |
425 | */ | |
426 | -class User extends BaseUser implements TwoFactorInterface, TrustedComputerInterface | |
427 | +class User extends BaseUser implements TwoFactorInterface, TrustedComputerInterface, LdapUserInterface | |
428 | { | |
429 | use EntityTimestampsTrait; | |
430 | ||
431 | @@ -67,6 +78,13 @@ class User extends BaseUser implements TwoFactorInterface, TrustedComputerInterf | |
432 | */ | |
433 | protected $email; | |
434 | ||
435 | + /** | |
436 | + * @var string | |
437 | + * | |
438 | + * @ORM\Column(name="dn", type="text", nullable=true) | |
439 | + */ | |
440 | + protected $dn; | |
441 | + | |
442 | /** | |
443 | * @var \DateTime | |
444 | * | |
445 | @@ -309,4 +327,33 @@ class User extends BaseUser implements TwoFactorInterface, TrustedComputerInterf | |
446 | return $this->clients->first(); | |
447 | } | |
448 | } | |
449 | + | |
450 | + /** | |
451 | + * Set dn. | |
452 | + * | |
453 | + * @param string $dn | |
454 | + * | |
455 | + * @return User | |
456 | + */ | |
457 | + public function setDn($dn) | |
458 | + { | |
459 | + $this->dn = $dn; | |
460 | + | |
461 | + return $this; | |
462 | + } | |
463 | + | |
464 | + /** | |
465 | + * Get dn. | |
466 | + * | |
467 | + * @return string | |
468 | + */ | |
469 | + public function getDn() | |
470 | + { | |
471 | + return $this->dn; | |
472 | + } | |
473 | + | |
474 | + public function isLdapUser() | |
475 | + { | |
476 | + return $this->dn !== null; | |
477 | + } | |
478 | } | |
479 | diff --git a/src/Wallabag/UserBundle/LdapHydrator.php b/src/Wallabag/UserBundle/LdapHydrator.php | |
480 | new file mode 100644 | |
481 | index 00000000..cea2450f | |
482 | --- /dev/null | |
483 | +++ b/src/Wallabag/UserBundle/LdapHydrator.php | |
484 | @@ -0,0 +1,103 @@ | |
485 | +<?php | |
486 | + | |
487 | +namespace Wallabag\UserBundle; | |
488 | + | |
489 | +use FR3D\LdapBundle\Hydrator\HydratorInterface; | |
490 | +use FOS\UserBundle\FOSUserEvents; | |
491 | +use FOS\UserBundle\Event\UserEvent; | |
492 | + | |
493 | +class LdapHydrator implements HydratorInterface | |
494 | +{ | |
495 | + private $userManager; | |
496 | + private $eventDispatcher; | |
497 | + private $attributesMap; | |
498 | + private $enabledAttribute; | |
499 | + private $ldapBaseDn; | |
500 | + private $ldapAdminFilter; | |
501 | + private $ldapDriver; | |
502 | + | |
503 | + public function __construct( | |
504 | + $user_manager, | |
505 | + $event_dispatcher, | |
506 | + array $attributes_map, | |
507 | + $ldap_base_dn, | |
508 | + $ldap_admin_filter, | |
509 | + $ldap_driver | |
510 | + ) { | |
511 | + $this->userManager = $user_manager; | |
512 | + $this->eventDispatcher = $event_dispatcher; | |
513 | + | |
514 | + $this->attributesMap = array( | |
515 | + 'setUsername' => $attributes_map[0], | |
516 | + 'setEmail' => $attributes_map[1], | |
517 | + 'setName' => $attributes_map[2], | |
518 | + ); | |
519 | + $this->enabledAttribute = $attributes_map[3]; | |
520 | + | |
521 | + $this->ldapBaseDn = $ldap_base_dn; | |
522 | + $this->ldapAdminFilter = $ldap_admin_filter; | |
523 | + $this->ldapDriver = $ldap_driver; | |
524 | + } | |
525 | + | |
526 | + public function hydrate(array $ldapEntry) | |
527 | + { | |
528 | + $user = $this->userManager->findUserBy(array('dn' => $ldapEntry['dn'])); | |
529 | + | |
530 | + if (!$user) { | |
531 | + $user = $this->userManager->createUser(); | |
532 | + $user->setDn($ldapEntry['dn']); | |
533 | + $user->setPassword(''); | |
534 | + $user->setSalt(''); | |
535 | + $this->updateUserFields($user, $ldapEntry); | |
536 | + | |
537 | + $event = new UserEvent($user); | |
538 | + $this->eventDispatcher->dispatch(FOSUserEvents::USER_CREATED, $event); | |
539 | + | |
540 | + $this->userManager->reloadUser($user); | |
541 | + } else { | |
542 | + $this->updateUserFields($user, $ldapEntry); | |
543 | + } | |
544 | + | |
545 | + return $user; | |
546 | + } | |
547 | + | |
548 | + private function updateUserFields($user, $ldapEntry) | |
549 | + { | |
550 | + foreach ($this->attributesMap as $key => $value) { | |
551 | + if (is_array($ldapEntry[$value])) { | |
552 | + $ldap_value = $ldapEntry[$value][0]; | |
553 | + } else { | |
554 | + $ldap_value = $ldapEntry[$value]; | |
555 | + } | |
556 | + | |
557 | + call_user_func([$user, $key], $ldap_value); | |
558 | + } | |
559 | + | |
560 | + if ($this->enabledAttribute !== null) { | |
561 | + $user->setEnabled($ldapEntry[$this->enabledAttribute]); | |
562 | + } else { | |
563 | + $user->setEnabled(true); | |
564 | + } | |
565 | + | |
566 | + if ($this->isAdmin($user)) { | |
567 | + $user->addRole('ROLE_SUPER_ADMIN'); | |
568 | + } else { | |
569 | + $user->removeRole('ROLE_SUPER_ADMIN'); | |
570 | + } | |
571 | + | |
572 | + $this->userManager->updateUser($user, true); | |
573 | + } | |
574 | + | |
575 | + private function isAdmin($user) | |
576 | + { | |
577 | + if ($this->ldapAdminFilter === null) { | |
578 | + return false; | |
579 | + } | |
580 | + | |
581 | + $escaped_username = ldap_escape($user->getUsername(), '', LDAP_ESCAPE_FILTER); | |
582 | + $filter = sprintf($this->ldapAdminFilter, $escaped_username); | |
583 | + $entries = $this->ldapDriver->search($this->ldapBaseDn, $filter); | |
584 | + | |
585 | + return $entries['count'] == 1; | |
586 | + } | |
587 | +} | |
588 | diff --git a/src/Wallabag/UserBundle/OAuthStorageLdapWrapper.php b/src/Wallabag/UserBundle/OAuthStorageLdapWrapper.php | |
589 | new file mode 100644 | |
590 | index 00000000..8a851f12 | |
591 | --- /dev/null | |
592 | +++ b/src/Wallabag/UserBundle/OAuthStorageLdapWrapper.php | |
593 | @@ -0,0 +1,43 @@ | |
594 | +<?php | |
595 | + | |
596 | +namespace Wallabag\UserBundle; | |
597 | + | |
598 | +use FOS\OAuthServerBundle\Storage\OAuthStorage; | |
599 | +use OAuth2\Model\IOAuth2Client; | |
600 | +use Symfony\Component\Security\Core\Exception\AuthenticationException; | |
601 | + | |
602 | +class OAuthStorageLdapWrapper extends OAuthStorage | |
603 | +{ | |
604 | + private $ldapManager; | |
605 | + | |
606 | + public function setLdapManager($ldap_manager) | |
607 | + { | |
608 | + $this->ldapManager = $ldap_manager; | |
609 | + } | |
610 | + | |
611 | + public function checkUserCredentials(IOAuth2Client $client, $username, $password) | |
612 | + { | |
613 | + try { | |
614 | + $user = $this->userProvider->loadUserByUsername($username); | |
615 | + } catch (AuthenticationException $e) { | |
616 | + return false; | |
617 | + } | |
618 | + | |
619 | + if ($user->isLdapUser()) { | |
620 | + return $this->checkLdapUserCredentials($user, $password); | |
621 | + } else { | |
622 | + return parent::checkUserCredentials($client, $username, $password); | |
623 | + } | |
624 | + } | |
625 | + | |
626 | + private function checkLdapUserCredentials($user, $password) | |
627 | + { | |
628 | + if ($this->ldapManager->bind($user, $password)) { | |
629 | + return array( | |
630 | + 'data' => $user, | |
631 | + ); | |
632 | + } else { | |
633 | + return false; | |
634 | + } | |
635 | + } | |
636 | +} | |
637 | diff --git a/src/Wallabag/UserBundle/Resources/config/ldap.yml b/src/Wallabag/UserBundle/Resources/config/ldap.yml | |
638 | new file mode 100644 | |
639 | index 00000000..5ec16088 | |
640 | --- /dev/null | |
641 | +++ b/src/Wallabag/UserBundle/Resources/config/ldap.yml | |
642 | @@ -0,0 +1,28 @@ | |
643 | +fr3d_ldap: | |
644 | + service: | |
645 | + user_hydrator: ldap_user_hydrator | |
646 | + driver: | |
647 | + host: "%ldap_host%" | |
648 | + port: "%ldap_port%" | |
649 | + useSsl: "%ldap_ssl%" | |
650 | + useStartTls: "%ldap_tls%" | |
651 | + bindRequiresDn: "%ldap_bind_requires_dn%" | |
652 | + username: "%ldap_manager_dn%" | |
653 | + password: "%ldap_manager_pw%" | |
654 | + user: | |
655 | + baseDn: "%ldap_base%" | |
656 | + filter: "%ldap_filter%" | |
657 | + usernameAttribute: "%ldap_username_attribute%" | |
658 | +security: | |
659 | + providers: | |
660 | + chain_provider: | |
661 | + chain: | |
662 | + providers: [ fr3d_ldapbundle, fos_userbundle ] | |
663 | + fr3d_ldapbundle: | |
664 | + id: fr3d_ldap.security.user.provider | |
665 | + firewalls: | |
666 | + secured_area: | |
667 | + fr3d_ldap: ~ | |
668 | + form_login: | |
669 | + provider: chain_provider | |
670 | + | |
671 | diff --git a/src/Wallabag/UserBundle/Resources/config/ldap_services.yml b/src/Wallabag/UserBundle/Resources/config/ldap_services.yml | |
672 | new file mode 100644 | |
673 | index 00000000..b3e3fd8a | |
674 | --- /dev/null | |
675 | +++ b/src/Wallabag/UserBundle/Resources/config/ldap_services.yml | |
676 | @@ -0,0 +1,22 @@ | |
677 | +services: | |
678 | + fos_oauth_server.server: | |
679 | + class: OAuth2\OAuth2 | |
680 | + arguments: | |
681 | + - "@oauth_storage_ldap_wrapper" | |
682 | + - "%fos_oauth_server.server.options%" | |
683 | + oauth_storage_ldap_wrapper: | |
684 | + class: Wallabag\UserBundle\OAuthStorageLdapWrapper | |
685 | + parent: fos_oauth_server.storage | |
686 | + calls: | |
687 | + - [setLdapManager, ["@fr3d_ldap.ldap_manager"]] | |
688 | + | |
689 | + ldap_user_hydrator: | |
690 | + class: Wallabag\UserBundle\LdapHydrator | |
691 | + arguments: | |
692 | + - "@fos_user.user_manager" | |
693 | + - "@event_dispatcher" | |
694 | + - [ "%ldap_username_attribute%", "%ldap_email_attribute%", "%ldap_name_attribute%", "%ldap_enabled_attribute%" ] | |
695 | + - "%ldap_base%" | |
696 | + - "%ldap_admin_filter%" | |
697 | + - "@fr3d_ldap.ldap_driver" | |
698 | + |