diff options
Diffstat (limited to 'virtual')
-rw-r--r-- | virtual/modules/databases/default.nix | 1 | ||||
-rw-r--r-- | virtual/modules/websites/tools/tools/default.nix | 7 | ||||
-rw-r--r-- | virtual/modules/websites/tools/tools/wallabag.nix | 160 | ||||
-rw-r--r-- | virtual/modules/websites/tools/tools/wallabag_ldap.patch | 537 |
4 files changed, 704 insertions, 1 deletions
diff --git a/virtual/modules/databases/default.nix b/virtual/modules/databases/default.nix index 0e21837..b896428 100644 --- a/virtual/modules/databases/default.nix +++ b/virtual/modules/databases/default.nix | |||
@@ -166,6 +166,7 @@ in { | |||
166 | # Nextcloud: 14 | 166 | # Nextcloud: 14 |
167 | # Mastodon: 13 | 167 | # Mastodon: 13 |
168 | # Mediagoblin: 12 | 168 | # Mediagoblin: 12 |
169 | # wallabag: 0 ? | ||
169 | services.redis = rec { | 170 | services.redis = rec { |
170 | enable = config.services.myDatabases.redis.enable; | 171 | enable = config.services.myDatabases.redis.enable; |
171 | bind = "127.0.0.1"; | 172 | bind = "127.0.0.1"; |
diff --git a/virtual/modules/websites/tools/tools/default.nix b/virtual/modules/websites/tools/tools/default.nix index f29ac11..d69ccc9 100644 --- a/virtual/modules/websites/tools/tools/default.nix +++ b/virtual/modules/websites/tools/tools/default.nix | |||
@@ -4,6 +4,7 @@ let | |||
4 | ympd = pkgs.callPackage ./ympd.nix {}; | 4 | ympd = pkgs.callPackage ./ympd.nix {}; |
5 | ttrss = pkgs.callPackage ./ttrss.nix { inherit (mylibs) checkEnv fetchedGithub fetchedGit; }; | 5 | ttrss = pkgs.callPackage ./ttrss.nix { inherit (mylibs) checkEnv fetchedGithub fetchedGit; }; |
6 | roundcubemail = pkgs.callPackage ./roundcubemail.nix { inherit (mylibs) checkEnv; }; | 6 | roundcubemail = pkgs.callPackage ./roundcubemail.nix { inherit (mylibs) checkEnv; }; |
7 | wallabag = pkgs.callPackage ./wallabag.nix { inherit (mylibs) checkEnv; }; | ||
7 | 8 | ||
8 | cfg = config.services.myWebsites.tools.tools; | 9 | cfg = config.services.myWebsites.tools.tools; |
9 | in { | 10 | in { |
@@ -18,7 +19,8 @@ in { | |||
18 | adminer.apache.modules | 19 | adminer.apache.modules |
19 | ++ ympd.apache.modules | 20 | ++ ympd.apache.modules |
20 | ++ ttrss.apache.modules | 21 | ++ ttrss.apache.modules |
21 | ++ roundcubemail.apache.modules; | 22 | ++ roundcubemail.apache.modules |
23 | ++ wallabag.apache.modules; | ||
22 | 24 | ||
23 | services.ympd = ympd.config // { enable = false; }; | 25 | services.ympd = ympd.config // { enable = false; }; |
24 | 26 | ||
@@ -31,6 +33,7 @@ in { | |||
31 | ympd.apache.vhostConf | 33 | ympd.apache.vhostConf |
32 | ttrss.apache.vhostConf | 34 | ttrss.apache.vhostConf |
33 | roundcubemail.apache.vhostConf | 35 | roundcubemail.apache.vhostConf |
36 | wallabag.apache.vhostConf | ||
34 | ]; | 37 | ]; |
35 | }; | 38 | }; |
36 | 39 | ||
@@ -38,11 +41,13 @@ in { | |||
38 | adminer = adminer.phpFpm.pool; | 41 | adminer = adminer.phpFpm.pool; |
39 | ttrss = ttrss.phpFpm.pool; | 42 | ttrss = ttrss.phpFpm.pool; |
40 | roundcubemail = roundcubemail.phpFpm.pool; | 43 | roundcubemail = roundcubemail.phpFpm.pool; |
44 | wallabag = wallabag.phpFpm.pool; | ||
41 | }; | 45 | }; |
42 | 46 | ||
43 | system.activationScripts = { | 47 | system.activationScripts = { |
44 | ttrss = ttrss.activationScript; | 48 | ttrss = ttrss.activationScript; |
45 | roundcubemail = roundcubemail.activationScript; | 49 | roundcubemail = roundcubemail.activationScript; |
50 | wallabag = wallabag.activationScript; | ||
46 | }; | 51 | }; |
47 | 52 | ||
48 | systemd.services.tt-rss = { | 53 | systemd.services.tt-rss = { |
diff --git a/virtual/modules/websites/tools/tools/wallabag.nix b/virtual/modules/websites/tools/tools/wallabag.nix new file mode 100644 index 0000000..92787b8 --- /dev/null +++ b/virtual/modules/websites/tools/tools/wallabag.nix | |||
@@ -0,0 +1,160 @@ | |||
1 | { stdenv, fetchurl, writeText, checkEnv, phpPackages, php, which }: | ||
2 | let | ||
3 | wallabag = rec { | ||
4 | varDir = "/var/lib/wallabag"; | ||
5 | parameters = | ||
6 | assert checkEnv "NIXOPS_WALLABAG_SQL_PASSWORD"; | ||
7 | assert checkEnv "NIXOPS_WALLABAG_SECRET"; | ||
8 | assert checkEnv "NIXOPS_WALLABAG_LDAP_PASSWORD"; | ||
9 | writeText "parameters.yml" '' | ||
10 | # This file is auto-generated during the composer install | ||
11 | parameters: | ||
12 | database_driver: pdo_pgsql | ||
13 | database_driver_class: Wallabag\CoreBundle\Doctrine\DBAL\Driver\CustomPostgreSQLDriver | ||
14 | database_host: db-1.immae.eu | ||
15 | database_port: null | ||
16 | database_name: webapps | ||
17 | database_user: wallabag | ||
18 | database_password: ${builtins.getEnv "NIXOPS_WALLABAG_SQL_PASSWORD"} | ||
19 | database_path: null | ||
20 | database_table_prefix: wallabag_ | ||
21 | database_socket: null | ||
22 | database_charset: utf8 | ||
23 | domain_name: https://tools.immae.eu/wallabag | ||
24 | mailer_transport: smtp | ||
25 | mailer_host: mail.immae.eu | ||
26 | mailer_user: null | ||
27 | mailer_password: null | ||
28 | locale: fr | ||
29 | secret: ${builtins.getEnv "NIXOPS_WALLABAG_SECRET"} | ||
30 | twofactor_auth: true | ||
31 | twofactor_sender: wallabag@immae.eu | ||
32 | fosuser_registration: false | ||
33 | fosuser_confirmation: true | ||
34 | from_email: wallabag@immae.eu | ||
35 | rss_limit: 50 | ||
36 | rabbitmq_host: localhost | ||
37 | rabbitmq_port: 5672 | ||
38 | rabbitmq_user: guest | ||
39 | rabbitmq_password: guest | ||
40 | rabbitmq_prefetch_count: 10 | ||
41 | redis_scheme: tcp | ||
42 | redis_host: localhost | ||
43 | redis_port: 6379 | ||
44 | redis_path: null | ||
45 | redis_password: null | ||
46 | sites_credentials: { } | ||
47 | ldap_enabled: true | ||
48 | ldap_host: ldap.immae.eu | ||
49 | ldap_port: 636 | ||
50 | ldap_tls: false | ||
51 | ldap_ssl: true | ||
52 | ldap_bind_requires_dn: true | ||
53 | ldap_base: 'dc=immae,dc=eu' | ||
54 | ldap_manager_dn: 'cn=wallabag,ou=services,dc=immae,dc=eu' | ||
55 | ldap_manager_pw: ${builtins.getEnv "NIXOPS_WALLABAG_LDAP_PASSWORD"} | ||
56 | ldap_filter: '(&(memberOf=cn=users,cn=wallabag,ou=services,dc=immae,dc=eu))' | ||
57 | ldap_admin_filter: '(&(memberOf=cn=admins,cn=wallabag,ou=services,dc=immae,dc=eu)(uid=%s))' | ||
58 | ldap_username_attribute: uid | ||
59 | ldap_email_attribute: mail | ||
60 | ldap_name_attribute: cn | ||
61 | ldap_enabled_attribute: null | ||
62 | ''; | ||
63 | webappDir = stdenv.mkDerivation rec { | ||
64 | # Beware when upgrading, I probably messed up with the migrations table | ||
65 | # (due to a psql bug in wallabag) | ||
66 | version = "2.3.2"; | ||
67 | name = "wallabag-${version}"; | ||
68 | src = fetchurl { | ||
69 | url = "https://static.wallabag.org/releases/wallabag-release-${version}.tar.gz"; | ||
70 | sha256 = "17yczdvgl43j6wa7hksxi2b51afvyd56vdya6hbbv68iiba4jyh4"; | ||
71 | }; | ||
72 | patches = [ ./wallabag_ldap.patch ]; | ||
73 | dontBuild = "true"; | ||
74 | installPhase = '' | ||
75 | cp -a . $out | ||
76 | cd $out | ||
77 | export SYMFONY_ENV=prod | ||
78 | php -d memory_limit=-1 ${phpPackages.composer}/libexec/composer/composer.phar require --update-no-dev -o --prefer-dist fr3d/ldap-bundle | ||
79 | rm -rf web/assets var/cache app/config/parameters.yml data | ||
80 | mv var var_old | ||
81 | ln -sf ${parameters} app/config/parameters.yml | ||
82 | ln -sf ../../../../../${varDir}/var var | ||
83 | ln -sf ../../../../../${varDir}/data data | ||
84 | ln -sf ../../../../../../${varDir}/assets web/assets | ||
85 | ''; | ||
86 | buildInputs = [ php phpPackages.composer ]; | ||
87 | }; | ||
88 | activationScript = '' | ||
89 | install -m 0755 -o ${apache.user} -g ${apache.group} -d ${varDir} \ | ||
90 | ${varDir}/var ${varDir}/data/db ${varDir}/assets/images | ||
91 | if [ ! -f "${varDir}/currentWebappDir" -o \ | ||
92 | "${webappDir}" != "$(cat ${varDir}/currentWebappDir 2>/dev/null)" ]; then | ||
93 | pushd ${webappDir} > /dev/null | ||
94 | $wrapperDir/sudo -u wwwrun ./bin/console --env=prod doctrine:migrations:migrate --no-interaction | ||
95 | $wrapperDir/sudo -u wwwrun ./bin/console --env=prod cache:clear | ||
96 | popd > /dev/null | ||
97 | echo -n "${webappDir}" > ${varDir}/currentWebappDir | ||
98 | fi | ||
99 | ''; | ||
100 | webRoot = "${webappDir}/web"; | ||
101 | apache = { | ||
102 | user = "wwwrun"; | ||
103 | group = "wwwrun"; | ||
104 | modules = [ "proxy_fcgi" ]; | ||
105 | vhostConf = '' | ||
106 | # FIXME | ||
107 | Alias /assets "${varDir}/assets" | ||
108 | Alias /wallabag "${webRoot}" | ||
109 | <Directory "${webRoot}"> | ||
110 | AllowOverride None | ||
111 | Require all granted | ||
112 | # For OAuth (apps) | ||
113 | CGIPassAuth On | ||
114 | |||
115 | <FilesMatch "\.php$"> | ||
116 | SetHandler "proxy:unix:${phpFpm.socket}|fcgi://localhost" | ||
117 | </FilesMatch> | ||
118 | |||
119 | <IfModule mod_rewrite.c> | ||
120 | Options -MultiViews | ||
121 | RewriteEngine On | ||
122 | RewriteCond %{REQUEST_FILENAME} !-f | ||
123 | RewriteRule ^(.*)$ app.php [QSA,L] | ||
124 | </IfModule> | ||
125 | </Directory> | ||
126 | <Directory "${webRoot}/bundles"> | ||
127 | <IfModule mod_rewrite.c> | ||
128 | RewriteEngine Off | ||
129 | </IfModule> | ||
130 | </Directory> | ||
131 | <Directory "${varDir}/assets"> | ||
132 | AllowOverride None | ||
133 | Require all granted | ||
134 | </Directory> | ||
135 | ''; | ||
136 | }; | ||
137 | phpFpm = rec { | ||
138 | basedir = builtins.concatStringsSep ":" [ webappDir parameters varDir ]; | ||
139 | socket = "/var/run/phpfpm/wallabag.sock"; | ||
140 | pool = '' | ||
141 | listen = ${socket} | ||
142 | user = ${apache.user} | ||
143 | group = ${apache.group} | ||
144 | listen.owner = ${apache.user} | ||
145 | listen.group = ${apache.group} | ||
146 | pm = dynamic | ||
147 | pm.max_children = 60 | ||
148 | pm.start_servers = 2 | ||
149 | pm.min_spare_servers = 1 | ||
150 | pm.max_spare_servers = 10 | ||
151 | |||
152 | ; Needed to avoid clashes in browser cookies (same domain) | ||
153 | php_value[session.name] = WallabagPHPSESSID | ||
154 | php_admin_value[open_basedir] = "${basedir}:/tmp" | ||
155 | php_value[max_execution_time] = 300 | ||
156 | ''; | ||
157 | }; | ||
158 | }; | ||
159 | in | ||
160 | wallabag | ||
diff --git a/virtual/modules/websites/tools/tools/wallabag_ldap.patch b/virtual/modules/websites/tools/tools/wallabag_ldap.patch new file mode 100644 index 0000000..1b93b57 --- /dev/null +++ b/virtual/modules/websites/tools/tools/wallabag_ldap.patch | |||
@@ -0,0 +1,537 @@ | |||
1 | commit 4cd6e7f3bbcff7e2a1c5a39917176d28fa02911f | ||
2 | Author: Ismaël Bouya <ismael.bouya@normalesup.org> | ||
3 | Date: Sat Jun 16 11:40:00 2018 +0200 | ||
4 | |||
5 | Add ldap | ||
6 | |||
7 | diff --git a/.travis.yml b/.travis.yml | ||
8 | index 57b3aa53..3b7638eb 100644 | ||
9 | --- a/.travis.yml | ||
10 | +++ b/.travis.yml | ||
11 | @@ -54,6 +54,7 @@ branches: | ||
12 | |||
13 | before_script: | ||
14 | - PHP=$TRAVIS_PHP_VERSION | ||
15 | + - echo "extension=ldap.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/travis.ini | ||
16 | - if [[ ! $PHP = hhvm* ]]; then echo "memory_limit=-1" >> ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/travis.ini; fi; | ||
17 | # xdebug isn't enable for PHP 7.1 | ||
18 | - if [[ ! $PHP = hhvm* ]]; then phpenv config-rm xdebug.ini || echo "xdebug not available"; fi | ||
19 | diff --git a/app/AppKernel.php b/app/AppKernel.php | ||
20 | index 40726f05..c4f465dc 100644 | ||
21 | --- a/app/AppKernel.php | ||
22 | +++ b/app/AppKernel.php | ||
23 | @@ -42,6 +42,10 @@ class AppKernel extends Kernel | ||
24 | new OldSound\RabbitMqBundle\OldSoundRabbitMqBundle(), | ||
25 | ]; | ||
26 | |||
27 | + if (class_exists('FR3D\\LdapBundle\\FR3DLdapBundle')) { | ||
28 | + $bundles[] = new FR3D\LdapBundle\FR3DLdapBundle(); | ||
29 | + } | ||
30 | + | ||
31 | if (in_array($this->getEnvironment(), ['dev', 'test'], true)) { | ||
32 | $bundles[] = new Symfony\Bundle\DebugBundle\DebugBundle(); | ||
33 | $bundles[] = new Symfony\Bundle\WebProfilerBundle\WebProfilerBundle(); | ||
34 | diff --git a/app/DoctrineMigrations/Version20170710113900.php b/app/DoctrineMigrations/Version20170710113900.php | ||
35 | new file mode 100644 | ||
36 | index 00000000..7be83110 | ||
37 | --- /dev/null | ||
38 | +++ b/app/DoctrineMigrations/Version20170710113900.php | ||
39 | @@ -0,0 +1,54 @@ | ||
40 | +<?php | ||
41 | + | ||
42 | +namespace Application\Migrations; | ||
43 | + | ||
44 | +use Doctrine\DBAL\Migrations\AbstractMigration; | ||
45 | +use Doctrine\DBAL\Schema\Schema; | ||
46 | +use Symfony\Component\DependencyInjection\ContainerAwareInterface; | ||
47 | +use Symfony\Component\DependencyInjection\ContainerInterface; | ||
48 | + | ||
49 | +/** | ||
50 | + * Added dn field on wallabag_users | ||
51 | + */ | ||
52 | +class Version20170710113900 extends AbstractMigration implements ContainerAwareInterface | ||
53 | +{ | ||
54 | + /** | ||
55 | + * @var ContainerInterface | ||
56 | + */ | ||
57 | + private $container; | ||
58 | + | ||
59 | + public function setContainer(ContainerInterface $container = null) | ||
60 | + { | ||
61 | + $this->container = $container; | ||
62 | + } | ||
63 | + | ||
64 | + private function getTable($tableName) | ||
65 | + { | ||
66 | + return $this->container->getParameter('database_table_prefix').$tableName; | ||
67 | + } | ||
68 | + | ||
69 | + /** | ||
70 | + * @param Schema $schema | ||
71 | + */ | ||
72 | + public function up(Schema $schema) | ||
73 | + { | ||
74 | + $usersTable = $schema->getTable($this->getTable('user')); | ||
75 | + | ||
76 | + $this->skipIf($usersTable->hasColumn('dn'), 'It seems that you already played this migration.'); | ||
77 | + | ||
78 | + $usersTable->addColumn('dn', 'text', [ | ||
79 | + 'default' => null, | ||
80 | + 'notnull' => false, | ||
81 | + ]); | ||
82 | + } | ||
83 | + | ||
84 | + /** | ||
85 | + * @param Schema $schema | ||
86 | + */ | ||
87 | + public function down(Schema $schema) | ||
88 | + { | ||
89 | + $usersTable = $schema->getTable($this->getTable('user')); | ||
90 | + $usersTable->dropColumn('dn'); | ||
91 | + } | ||
92 | +} | ||
93 | + | ||
94 | diff --git a/app/config/parameters.yml.dist b/app/config/parameters.yml.dist | ||
95 | index 6b0cb8e8..cfd41b69 100644 | ||
96 | --- a/app/config/parameters.yml.dist | ||
97 | +++ b/app/config/parameters.yml.dist | ||
98 | @@ -62,3 +62,23 @@ parameters: | ||
99 | redis_port: 6379 | ||
100 | redis_path: null | ||
101 | redis_password: null | ||
102 | + | ||
103 | + # ldap configuration | ||
104 | + # To enable, you need to require fr3d/ldap-bundle | ||
105 | + ldap_enabled: false | ||
106 | + ldap_host: localhost | ||
107 | + ldap_port: 389 | ||
108 | + ldap_tls: false | ||
109 | + ldap_ssl: false | ||
110 | + ldap_bind_requires_dn: true | ||
111 | + ldap_base: dc=example,dc=com | ||
112 | + ldap_manager_dn: ou=Manager,dc=example,dc=com | ||
113 | + ldap_manager_pw: password | ||
114 | + ldap_filter: (&(ObjectClass=Person)) | ||
115 | + # optional (if null: no ldap user is admin) | ||
116 | + ldap_admin_filter: (&(memberOf=ou=admins,dc=example,dc=com)(uid=%s)) | ||
117 | + ldap_username_attribute: uid | ||
118 | + ldap_email_attribute: mail | ||
119 | + ldap_name_attribute: cn | ||
120 | + # optional (default sets user as enabled unconditionally) | ||
121 | + ldap_enabled_attribute: ~ | ||
122 | diff --git a/app/config/security.yml b/app/config/security.yml | ||
123 | index 796dc361..59f48626 100644 | ||
124 | --- a/app/config/security.yml | ||
125 | +++ b/app/config/security.yml | ||
126 | @@ -6,6 +6,7 @@ security: | ||
127 | ROLE_ADMIN: ROLE_USER | ||
128 | ROLE_SUPER_ADMIN: [ ROLE_USER, ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH ] | ||
129 | |||
130 | + # /!\ This list is modified in WallabagUserBundle when LDAP is enabled | ||
131 | providers: | ||
132 | administrators: | ||
133 | entity: | ||
134 | @@ -36,6 +37,7 @@ security: | ||
135 | pattern: ^/login$ | ||
136 | anonymous: ~ | ||
137 | |||
138 | + # /!\ This section is modified in WallabagUserBundle when LDAP is enabled | ||
139 | secured_area: | ||
140 | pattern: ^/ | ||
141 | form_login: | ||
142 | diff --git a/composer.json b/composer.json | ||
143 | index dca274ed..f115d229 100644 | ||
144 | --- a/composer.json | ||
145 | +++ b/composer.json | ||
146 | @@ -87,6 +87,9 @@ | ||
147 | "defuse/php-encryption": "^2.1", | ||
148 | "html2text/html2text": "^4.1" | ||
149 | }, | ||
150 | + "suggest": { | ||
151 | + "fr3d/ldap-bundle": "If you want to authenticate via LDAP" | ||
152 | + }, | ||
153 | "require-dev": { | ||
154 | "doctrine/doctrine-fixtures-bundle": "~2.2", | ||
155 | "doctrine/data-fixtures": "~1.1", | ||
156 | diff --git a/scripts/install.sh b/scripts/install.sh | ||
157 | index 62a46f4f..5ea3933c 100644 | ||
158 | --- a/scripts/install.sh | ||
159 | +++ b/scripts/install.sh | ||
160 | @@ -12,5 +12,8 @@ ENV=$1 | ||
161 | TAG=$(git describe --tags $(git rev-list --tags --max-count=1)) | ||
162 | |||
163 | git checkout $TAG | ||
164 | +if [ -n "$LDAP_ENABLED" ]; then | ||
165 | + SYMFONY_ENV=$ENV $COMPOSER_COMMAND require --no-update fr3d/ldap-bundle | ||
166 | +fi | ||
167 | SYMFONY_ENV=$ENV $COMPOSER_COMMAND install --no-dev -o --prefer-dist | ||
168 | php bin/console wallabag:install --env=$ENV | ||
169 | diff --git a/scripts/update.sh b/scripts/update.sh | ||
170 | index d0598135..753ccbc3 100644 | ||
171 | --- a/scripts/update.sh | ||
172 | +++ b/scripts/update.sh | ||
173 | @@ -18,6 +18,9 @@ git fetch origin | ||
174 | git fetch --tags | ||
175 | TAG=$(git describe --tags $(git rev-list --tags --max-count=1)) | ||
176 | git checkout $TAG --force | ||
177 | +if [ -n "$LDAP_ENABLED" ]; then | ||
178 | + SYMFONY_ENV=$ENV $COMPOSER_COMMAND require --no-update fr3d/ldap-bundle | ||
179 | +fi | ||
180 | SYMFONY_ENV=$ENV $COMPOSER_COMMAND install --no-dev -o --prefer-dist | ||
181 | php bin/console doctrine:migrations:migrate --no-interaction --env=$ENV | ||
182 | php bin/console cache:clear --env=$ENV | ||
183 | diff --git a/src/Wallabag/UserBundle/DependencyInjection/WallabagUserExtension.php b/src/Wallabag/UserBundle/DependencyInjection/WallabagUserExtension.php | ||
184 | index 5ca3482e..904a6af1 100644 | ||
185 | --- a/src/Wallabag/UserBundle/DependencyInjection/WallabagUserExtension.php | ||
186 | +++ b/src/Wallabag/UserBundle/DependencyInjection/WallabagUserExtension.php | ||
187 | @@ -6,9 +6,34 @@ use Symfony\Component\Config\FileLocator; | ||
188 | use Symfony\Component\DependencyInjection\ContainerBuilder; | ||
189 | use Symfony\Component\DependencyInjection\Loader; | ||
190 | use Symfony\Component\HttpKernel\DependencyInjection\Extension; | ||
191 | +use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface; | ||
192 | |||
193 | -class WallabagUserExtension extends Extension | ||
194 | +class WallabagUserExtension extends Extension implements PrependExtensionInterface | ||
195 | { | ||
196 | + public function prepend(ContainerBuilder $container) | ||
197 | + { | ||
198 | + $ldap = $container->getParameter('ldap_enabled'); | ||
199 | + | ||
200 | + if ($ldap) { | ||
201 | + $container->prependExtensionConfig('security', array( | ||
202 | + 'providers' => array( | ||
203 | + 'chain_provider' => array(), | ||
204 | + ), | ||
205 | + )); | ||
206 | + $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); | ||
207 | + $loader->load('ldap.yml'); | ||
208 | + } elseif ($container->hasExtension('fr3d_ldap')) { | ||
209 | + $container->prependExtensionConfig('fr3_d_ldap', array( | ||
210 | + 'driver' => array( | ||
211 | + 'host' => 'localhost', | ||
212 | + ), | ||
213 | + 'user' => array( | ||
214 | + 'baseDn' => 'dc=example,dc=com', | ||
215 | + ), | ||
216 | + )); | ||
217 | + } | ||
218 | + } | ||
219 | + | ||
220 | public function load(array $configs, ContainerBuilder $container) | ||
221 | { | ||
222 | $configuration = new Configuration(); | ||
223 | @@ -16,6 +41,9 @@ class WallabagUserExtension extends Extension | ||
224 | |||
225 | $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config')); | ||
226 | $loader->load('services.yml'); | ||
227 | + if ($container->getParameter('ldap_enabled')) { | ||
228 | + $loader->load('ldap_services.yml'); | ||
229 | + } | ||
230 | $container->setParameter('wallabag_user.registration_enabled', $config['registration_enabled']); | ||
231 | } | ||
232 | |||
233 | diff --git a/src/Wallabag/UserBundle/Entity/User.php b/src/Wallabag/UserBundle/Entity/User.php | ||
234 | index 48446e3c..f93c59c7 100644 | ||
235 | --- a/src/Wallabag/UserBundle/Entity/User.php | ||
236 | +++ b/src/Wallabag/UserBundle/Entity/User.php | ||
237 | @@ -1,5 +1,15 @@ | ||
238 | <?php | ||
239 | |||
240 | +// This permits to have the LdapUserInterface even when fr3d/ldap-bundle is not | ||
241 | +// in the packages | ||
242 | +namespace FR3D\LdapBundle\Model; | ||
243 | + | ||
244 | +interface LdapUserInterface | ||
245 | +{ | ||
246 | + public function setDn($dn); | ||
247 | + public function getDn(); | ||
248 | +} | ||
249 | + | ||
250 | namespace Wallabag\UserBundle\Entity; | ||
251 | |||
252 | use Doctrine\Common\Collections\ArrayCollection; | ||
253 | @@ -16,6 +26,7 @@ use Wallabag\ApiBundle\Entity\Client; | ||
254 | use Wallabag\CoreBundle\Entity\Config; | ||
255 | use Wallabag\CoreBundle\Entity\Entry; | ||
256 | use Wallabag\CoreBundle\Helper\EntityTimestampsTrait; | ||
257 | +use FR3D\LdapBundle\Model\LdapUserInterface; | ||
258 | |||
259 | /** | ||
260 | * User. | ||
261 | @@ -28,7 +39,7 @@ use Wallabag\CoreBundle\Helper\EntityTimestampsTrait; | ||
262 | * @UniqueEntity("email") | ||
263 | * @UniqueEntity("username") | ||
264 | */ | ||
265 | -class User extends BaseUser implements TwoFactorInterface, TrustedComputerInterface | ||
266 | +class User extends BaseUser implements TwoFactorInterface, TrustedComputerInterface, LdapUserInterface | ||
267 | { | ||
268 | use EntityTimestampsTrait; | ||
269 | |||
270 | @@ -67,6 +78,13 @@ class User extends BaseUser implements TwoFactorInterface, TrustedComputerInterf | ||
271 | */ | ||
272 | protected $email; | ||
273 | |||
274 | + /** | ||
275 | + * @var string | ||
276 | + * | ||
277 | + * @ORM\Column(name="dn", type="text", nullable=true) | ||
278 | + */ | ||
279 | + protected $dn; | ||
280 | + | ||
281 | /** | ||
282 | * @var \DateTime | ||
283 | * | ||
284 | @@ -309,4 +327,33 @@ class User extends BaseUser implements TwoFactorInterface, TrustedComputerInterf | ||
285 | return $this->clients->first(); | ||
286 | } | ||
287 | } | ||
288 | + | ||
289 | + /** | ||
290 | + * Set dn. | ||
291 | + * | ||
292 | + * @param string $dn | ||
293 | + * | ||
294 | + * @return User | ||
295 | + */ | ||
296 | + public function setDn($dn) | ||
297 | + { | ||
298 | + $this->dn = $dn; | ||
299 | + | ||
300 | + return $this; | ||
301 | + } | ||
302 | + | ||
303 | + /** | ||
304 | + * Get dn. | ||
305 | + * | ||
306 | + * @return string | ||
307 | + */ | ||
308 | + public function getDn() | ||
309 | + { | ||
310 | + return $this->dn; | ||
311 | + } | ||
312 | + | ||
313 | + public function isLdapUser() | ||
314 | + { | ||
315 | + return $this->dn !== null; | ||
316 | + } | ||
317 | } | ||
318 | diff --git a/src/Wallabag/UserBundle/LdapHydrator.php b/src/Wallabag/UserBundle/LdapHydrator.php | ||
319 | new file mode 100644 | ||
320 | index 00000000..cea2450f | ||
321 | --- /dev/null | ||
322 | +++ b/src/Wallabag/UserBundle/LdapHydrator.php | ||
323 | @@ -0,0 +1,103 @@ | ||
324 | +<?php | ||
325 | + | ||
326 | +namespace Wallabag\UserBundle; | ||
327 | + | ||
328 | +use FR3D\LdapBundle\Hydrator\HydratorInterface; | ||
329 | +use FOS\UserBundle\FOSUserEvents; | ||
330 | +use FOS\UserBundle\Event\UserEvent; | ||
331 | + | ||
332 | +class LdapHydrator implements HydratorInterface | ||
333 | +{ | ||
334 | + private $userManager; | ||
335 | + private $eventDispatcher; | ||
336 | + private $attributesMap; | ||
337 | + private $enabledAttribute; | ||
338 | + private $ldapBaseDn; | ||
339 | + private $ldapAdminFilter; | ||
340 | + private $ldapDriver; | ||
341 | + | ||
342 | + public function __construct( | ||
343 | + $user_manager, | ||
344 | + $event_dispatcher, | ||
345 | + array $attributes_map, | ||
346 | + $ldap_base_dn, | ||
347 | + $ldap_admin_filter, | ||
348 | + $ldap_driver | ||
349 | + ) { | ||
350 | + $this->userManager = $user_manager; | ||
351 | + $this->eventDispatcher = $event_dispatcher; | ||
352 | + | ||
353 | + $this->attributesMap = array( | ||
354 | + 'setUsername' => $attributes_map[0], | ||
355 | + 'setEmail' => $attributes_map[1], | ||
356 | + 'setName' => $attributes_map[2], | ||
357 | + ); | ||
358 | + $this->enabledAttribute = $attributes_map[3]; | ||
359 | + | ||
360 | + $this->ldapBaseDn = $ldap_base_dn; | ||
361 | + $this->ldapAdminFilter = $ldap_admin_filter; | ||
362 | + $this->ldapDriver = $ldap_driver; | ||
363 | + } | ||
364 | + | ||
365 | + public function hydrate(array $ldapEntry) | ||
366 | + { | ||
367 | + $user = $this->userManager->findUserBy(array('dn' => $ldapEntry['dn'])); | ||
368 | + | ||
369 | + if (!$user) { | ||
370 | + $user = $this->userManager->createUser(); | ||
371 | + $user->setDn($ldapEntry['dn']); | ||
372 | + $user->setPassword(''); | ||
373 | + $user->setSalt(''); | ||
374 | + $this->updateUserFields($user, $ldapEntry); | ||
375 | + | ||
376 | + $event = new UserEvent($user); | ||
377 | + $this->eventDispatcher->dispatch(FOSUserEvents::USER_CREATED, $event); | ||
378 | + | ||
379 | + $this->userManager->reloadUser($user); | ||
380 | + } else { | ||
381 | + $this->updateUserFields($user, $ldapEntry); | ||
382 | + } | ||
383 | + | ||
384 | + return $user; | ||
385 | + } | ||
386 | + | ||
387 | + private function updateUserFields($user, $ldapEntry) | ||
388 | + { | ||
389 | + foreach ($this->attributesMap as $key => $value) { | ||
390 | + if (is_array($ldapEntry[$value])) { | ||
391 | + $ldap_value = $ldapEntry[$value][0]; | ||
392 | + } else { | ||
393 | + $ldap_value = $ldapEntry[$value]; | ||
394 | + } | ||
395 | + | ||
396 | + call_user_func([$user, $key], $ldap_value); | ||
397 | + } | ||
398 | + | ||
399 | + if ($this->enabledAttribute !== null) { | ||
400 | + $user->setEnabled($ldapEntry[$this->enabledAttribute]); | ||
401 | + } else { | ||
402 | + $user->setEnabled(true); | ||
403 | + } | ||
404 | + | ||
405 | + if ($this->isAdmin($user)) { | ||
406 | + $user->addRole('ROLE_SUPER_ADMIN'); | ||
407 | + } else { | ||
408 | + $user->removeRole('ROLE_SUPER_ADMIN'); | ||
409 | + } | ||
410 | + | ||
411 | + $this->userManager->updateUser($user, true); | ||
412 | + } | ||
413 | + | ||
414 | + private function isAdmin($user) | ||
415 | + { | ||
416 | + if ($this->ldapAdminFilter === null) { | ||
417 | + return false; | ||
418 | + } | ||
419 | + | ||
420 | + $escaped_username = ldap_escape($user->getUsername(), '', LDAP_ESCAPE_FILTER); | ||
421 | + $filter = sprintf($this->ldapAdminFilter, $escaped_username); | ||
422 | + $entries = $this->ldapDriver->search($this->ldapBaseDn, $filter); | ||
423 | + | ||
424 | + return $entries['count'] == 1; | ||
425 | + } | ||
426 | +} | ||
427 | diff --git a/src/Wallabag/UserBundle/OAuthStorageLdapWrapper.php b/src/Wallabag/UserBundle/OAuthStorageLdapWrapper.php | ||
428 | new file mode 100644 | ||
429 | index 00000000..8a851f12 | ||
430 | --- /dev/null | ||
431 | +++ b/src/Wallabag/UserBundle/OAuthStorageLdapWrapper.php | ||
432 | @@ -0,0 +1,43 @@ | ||
433 | +<?php | ||
434 | + | ||
435 | +namespace Wallabag\UserBundle; | ||
436 | + | ||
437 | +use FOS\OAuthServerBundle\Storage\OAuthStorage; | ||
438 | +use OAuth2\Model\IOAuth2Client; | ||
439 | +use Symfony\Component\Security\Core\Exception\AuthenticationException; | ||
440 | + | ||
441 | +class OAuthStorageLdapWrapper extends OAuthStorage | ||
442 | +{ | ||
443 | + private $ldapManager; | ||
444 | + | ||
445 | + public function setLdapManager($ldap_manager) | ||
446 | + { | ||
447 | + $this->ldapManager = $ldap_manager; | ||
448 | + } | ||
449 | + | ||
450 | + public function checkUserCredentials(IOAuth2Client $client, $username, $password) | ||
451 | + { | ||
452 | + try { | ||
453 | + $user = $this->userProvider->loadUserByUsername($username); | ||
454 | + } catch (AuthenticationException $e) { | ||
455 | + return false; | ||
456 | + } | ||
457 | + | ||
458 | + if ($user->isLdapUser()) { | ||
459 | + return $this->checkLdapUserCredentials($user, $password); | ||
460 | + } else { | ||
461 | + return parent::checkUserCredentials($client, $username, $password); | ||
462 | + } | ||
463 | + } | ||
464 | + | ||
465 | + private function checkLdapUserCredentials($user, $password) | ||
466 | + { | ||
467 | + if ($this->ldapManager->bind($user, $password)) { | ||
468 | + return array( | ||
469 | + 'data' => $user, | ||
470 | + ); | ||
471 | + } else { | ||
472 | + return false; | ||
473 | + } | ||
474 | + } | ||
475 | +} | ||
476 | diff --git a/src/Wallabag/UserBundle/Resources/config/ldap.yml b/src/Wallabag/UserBundle/Resources/config/ldap.yml | ||
477 | new file mode 100644 | ||
478 | index 00000000..5ec16088 | ||
479 | --- /dev/null | ||
480 | +++ b/src/Wallabag/UserBundle/Resources/config/ldap.yml | ||
481 | @@ -0,0 +1,28 @@ | ||
482 | +fr3d_ldap: | ||
483 | + service: | ||
484 | + user_hydrator: ldap_user_hydrator | ||
485 | + driver: | ||
486 | + host: "%ldap_host%" | ||
487 | + port: "%ldap_port%" | ||
488 | + useSsl: "%ldap_ssl%" | ||
489 | + useStartTls: "%ldap_tls%" | ||
490 | + bindRequiresDn: "%ldap_bind_requires_dn%" | ||
491 | + username: "%ldap_manager_dn%" | ||
492 | + password: "%ldap_manager_pw%" | ||
493 | + user: | ||
494 | + baseDn: "%ldap_base%" | ||
495 | + filter: "%ldap_filter%" | ||
496 | + usernameAttribute: "%ldap_username_attribute%" | ||
497 | +security: | ||
498 | + providers: | ||
499 | + chain_provider: | ||
500 | + chain: | ||
501 | + providers: [ fr3d_ldapbundle, fos_userbundle ] | ||
502 | + fr3d_ldapbundle: | ||
503 | + id: fr3d_ldap.security.user.provider | ||
504 | + firewalls: | ||
505 | + secured_area: | ||
506 | + fr3d_ldap: ~ | ||
507 | + form_login: | ||
508 | + provider: chain_provider | ||
509 | + | ||
510 | diff --git a/src/Wallabag/UserBundle/Resources/config/ldap_services.yml b/src/Wallabag/UserBundle/Resources/config/ldap_services.yml | ||
511 | new file mode 100644 | ||
512 | index 00000000..b3e3fd8a | ||
513 | --- /dev/null | ||
514 | +++ b/src/Wallabag/UserBundle/Resources/config/ldap_services.yml | ||
515 | @@ -0,0 +1,22 @@ | ||
516 | +services: | ||
517 | + fos_oauth_server.server: | ||
518 | + class: OAuth2\OAuth2 | ||
519 | + arguments: | ||
520 | + - "@oauth_storage_ldap_wrapper" | ||
521 | + - "%fos_oauth_server.server.options%" | ||
522 | + oauth_storage_ldap_wrapper: | ||
523 | + class: Wallabag\UserBundle\OAuthStorageLdapWrapper | ||
524 | + parent: fos_oauth_server.storage | ||
525 | + calls: | ||
526 | + - [setLdapManager, ["@fr3d_ldap.ldap_manager"]] | ||
527 | + | ||
528 | + ldap_user_hydrator: | ||
529 | + class: Wallabag\UserBundle\LdapHydrator | ||
530 | + arguments: | ||
531 | + - "@fos_user.user_manager" | ||
532 | + - "@event_dispatcher" | ||
533 | + - [ "%ldap_username_attribute%", "%ldap_email_attribute%", "%ldap_name_attribute%", "%ldap_enabled_attribute%" ] | ||
534 | + - "%ldap_base%" | ||
535 | + - "%ldap_admin_filter%" | ||
536 | + - "@fr3d_ldap.ldap_driver" | ||
537 | + | ||