aboutsummaryrefslogtreecommitdiff
path: root/nixops/modules/websites
diff options
context:
space:
mode:
authorIsmaël Bouya <ismael.bouya@normalesup.org>2019-05-07 15:19:24 +0200
committerIsmaël Bouya <ismael.bouya@normalesup.org>2019-05-07 15:19:24 +0200
commitfd2d83bd2bf20fafc63daf5041db0151a4b4d17d (patch)
tree596e374d639bcc94ad6619c3e2f317d503e4e485 /nixops/modules/websites
parente6abbae25ce533e8d38a0e8318b1d5d5a35d813d (diff)
downloadNix-fd2d83bd2bf20fafc63daf5041db0151a4b4d17d.tar.gz
Nix-fd2d83bd2bf20fafc63daf5041db0151a4b4d17d.tar.zst
Nix-fd2d83bd2bf20fafc63daf5041db0151a4b4d17d.zip
Move wallabag to pkgs
Diffstat (limited to 'nixops/modules/websites')
-rw-r--r--nixops/modules/websites/tools/tools/default.nix5
-rw-r--r--nixops/modules/websites/tools/tools/wallabag.nix338
-rw-r--r--nixops/modules/websites/tools/tools/wallabag_ldap.patch698
3 files changed, 147 insertions, 894 deletions
diff --git a/nixops/modules/websites/tools/tools/default.nix b/nixops/modules/websites/tools/tools/default.nix
index 22588fb..addb2c3 100644
--- a/nixops/modules/websites/tools/tools/default.nix
+++ b/nixops/modules/websites/tools/tools/default.nix
@@ -16,7 +16,10 @@ let
16 kanboard = pkgs.callPackage ./kanboard.nix { 16 kanboard = pkgs.callPackage ./kanboard.nix {
17 env = myconfig.env.tools.kanboard; 17 env = myconfig.env.tools.kanboard;
18 }; 18 };
19 wallabag = pkgs.callPackage ./wallabag.nix { env = myconfig.env.tools.wallabag; }; 19 wallabag = pkgs.callPackage ./wallabag.nix {
20 inherit (pkgs.webapps) wallabag;
21 env = myconfig.env.tools.wallabag;
22 };
20 yourls = pkgs.callPackage ./yourls.nix { 23 yourls = pkgs.callPackage ./yourls.nix {
21 inherit (pkgs.webapps) yourls yourls-plugins; 24 inherit (pkgs.webapps) yourls yourls-plugins;
22 env = myconfig.env.tools.yourls; 25 env = myconfig.env.tools.yourls;
diff --git a/nixops/modules/websites/tools/tools/wallabag.nix b/nixops/modules/websites/tools/tools/wallabag.nix
index 596b9bc..d6e5882 100644
--- a/nixops/modules/websites/tools/tools/wallabag.nix
+++ b/nixops/modules/websites/tools/tools/wallabag.nix
@@ -1,200 +1,148 @@
1{ stdenv, fetchurl, writeText, env, composerEnv, phpPackages, php, which }: 1{ env, wallabag }:
2let 2rec {
3 wallabag = rec { 3 varDir = "/var/lib/wallabag";
4 varDir = "/var/lib/wallabag"; 4 keys = [{
5 keys = [{ 5 dest = "webapps/tools-wallabag";
6 dest = "webapps/tools-wallabag"; 6 user = apache.user;
7 user = apache.user; 7 group = apache.group;
8 group = apache.group; 8 permissions = "0400";
9 permissions = "0400"; 9 text = ''
10 text = '' 10 # This file is auto-generated during the composer install
11 # This file is auto-generated during the composer install 11 parameters:
12 parameters: 12 database_driver: pdo_pgsql
13 database_driver: pdo_pgsql 13 database_driver_class: Wallabag\CoreBundle\Doctrine\DBAL\Driver\CustomPostgreSQLDriver
14 database_driver_class: Wallabag\CoreBundle\Doctrine\DBAL\Driver\CustomPostgreSQLDriver 14 database_host: ${env.postgresql.socket}
15 database_host: ${env.postgresql.socket} 15 database_port: ${env.postgresql.port}
16 database_port: ${env.postgresql.port} 16 database_name: ${env.postgresql.database}
17 database_name: ${env.postgresql.database} 17 database_user: ${env.postgresql.user}
18 database_user: ${env.postgresql.user} 18 database_password: ${env.postgresql.password}
19 database_password: ${env.postgresql.password} 19 database_path: null
20 database_path: null 20 database_table_prefix: wallabag_
21 database_table_prefix: wallabag_ 21 database_socket: null
22 database_socket: null 22 database_charset: utf8
23 database_charset: utf8 23 domain_name: https://tools.immae.eu/wallabag
24 domain_name: https://tools.immae.eu/wallabag 24 mailer_transport: sendmail
25 mailer_transport: sendmail 25 mailer_host: 127.0.0.1
26 mailer_host: 127.0.0.1 26 mailer_user: null
27 mailer_user: null 27 mailer_password: null
28 mailer_password: null 28 locale: fr
29 locale: fr 29 secret: ${env.secret}
30 secret: ${env.secret} 30 twofactor_auth: true
31 twofactor_auth: true 31 twofactor_sender: wallabag@tools.immae.eu
32 twofactor_sender: wallabag@tools.immae.eu 32 fosuser_registration: false
33 fosuser_registration: false 33 fosuser_confirmation: true
34 fosuser_confirmation: true 34 from_email: wallabag@tools.immae.eu
35 from_email: wallabag@tools.immae.eu 35 rss_limit: 50
36 rss_limit: 50 36 rabbitmq_host: localhost
37 rabbitmq_host: localhost 37 rabbitmq_port: 5672
38 rabbitmq_port: 5672 38 rabbitmq_user: guest
39 rabbitmq_user: guest 39 rabbitmq_password: guest
40 rabbitmq_password: guest 40 rabbitmq_prefetch_count: 10
41 rabbitmq_prefetch_count: 10 41 redis_scheme: unix
42 redis_scheme: unix 42 redis_host: null
43 redis_host: null 43 redis_port: null
44 redis_port: null 44 redis_path: ${env.redis.socket}
45 redis_path: ${env.redis.socket} 45 redis_password: null
46 redis_password: null 46 sites_credentials: { }
47 sites_credentials: { } 47 ldap_enabled: true
48 ldap_enabled: true 48 ldap_host: ldap.immae.eu
49 ldap_host: ldap.immae.eu 49 ldap_port: 636
50 ldap_port: 636 50 ldap_tls: false
51 ldap_tls: false 51 ldap_ssl: true
52 ldap_ssl: true 52 ldap_bind_requires_dn: true
53 ldap_bind_requires_dn: true 53 ldap_base: 'dc=immae,dc=eu'
54 ldap_base: 'dc=immae,dc=eu' 54 ldap_manager_dn: 'cn=wallabag,ou=services,dc=immae,dc=eu'
55 ldap_manager_dn: 'cn=wallabag,ou=services,dc=immae,dc=eu' 55 ldap_manager_pw: ${env.ldap.password}
56 ldap_manager_pw: ${env.ldap.password} 56 ldap_filter: '(&(memberOf=cn=users,cn=wallabag,ou=services,dc=immae,dc=eu))'
57 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_admin_filter: '(&(memberOf=cn=admins,cn=wallabag,ou=services,dc=immae,dc=eu)(uid=%s))' 58 ldap_username_attribute: uid
59 ldap_username_attribute: uid 59 ldap_email_attribute: mail
60 ldap_email_attribute: mail 60 ldap_name_attribute: cn
61 ldap_name_attribute: cn 61 ldap_enabled_attribute: null
62 ldap_enabled_attribute: null 62 services:
63 services: 63 swiftmailer.mailer.default.transport:
64 swiftmailer.mailer.default.transport: 64 class: Swift_SendmailTransport
65 class: Swift_SendmailTransport 65 arguments: ['/run/wrappers/bin/sendmail -bs']
66 arguments: ['/run/wrappers/bin/sendmail -bs']
67 '';
68 }];
69 webappDir = composerEnv.buildPackage rec {
70 packages = {
71 "fr3d/ldap-bundle" = {
72 targetDir = "";
73 src = composerEnv.buildZipPackage {
74 name = "fr3d-ldap-bundle-5a8927c11af45fa06331b97221c6da1a4a237475";
75 src = fetchurl {
76 url = https://api.github.com/repos/Maks3w/FR3DLdapBundle/zipball/5a8927c11af45fa06331b97221c6da1a4a237475;
77 sha256 = "168zkd82j200wd6h0a3lq81g5s2pifg889rv27q2g429nppsbfxc";
78 };
79 };
80 };
81 "zendframework/zend-ldap" = {
82 targetDir = "";
83 src = composerEnv.buildZipPackage {
84 name = "zendframework-zend-ldap-b63c7884a08d3a6bda60ebcf7d6238cf8ad89f49";
85 src = fetchurl {
86 url = https://api.github.com/repos/zendframework/zend-ldap/zipball/b63c7884a08d3a6bda60ebcf7d6238cf8ad89f49;
87 sha256 = "0mn4yqnb5prqhrbbybmw1i2rx7xf4s4wagbdq9qi55fa0vk3jgw9";
88 };
89 };
90 };
91 };
92 noDev = true;
93 doRemoveVendor = false;
94 # Beware when upgrading, I probably messed up with the migrations table
95 # (due to a psql bug in wallabag)
96 version = "2.3.6";
97 name = "wallabag-${version}";
98 src = fetchurl {
99 url = "https://static.wallabag.org/releases/wallabag-release-${version}.tar.gz";
100 sha256 = "0m0dy3r94ks5pfxyb9vbgrsm0vrwdl3jd5wqwg4f5vd107lq90q1";
101 };
102 unpackPhase = ''
103 unpackFile "$src"
104 sourceRoot=${version}
105 src=$PWD/${version}
106 '';
107 patches = [ ./wallabag_ldap.patch ];
108 preInstall = ''
109 export SYMFONY_ENV="prod"
110 ''; 66 '';
111 postInstall = '' 67 }];
112 rm -rf web/assets var/{cache,logs,sessions} app/config/parameters.yml data 68 webappDir = wallabag.override { ldap = true; wallabag_config = "/var/secrets/webapps/tools-wallabag"; };
113 ln -sf /var/secrets/webapps/tools-wallabag app/config/parameters.yml 69 activationScript = ''
114 ln -sf ${varDir}/var/{cache,logs,sessions} var 70 install -m 0755 -o ${apache.user} -g ${apache.group} -d ${varDir} \
115 ln -sf ${varDir}/data data 71 ${varDir}/var ${varDir}/data/db ${varDir}/assets/images
116 ln -sf ${varDir}/assets web/assets 72 '';
117 ''; 73 webRoot = "${webappDir}/web";
118 }; 74 # Domain migration: Table wallabag_entry contains whole
119 activationScript = '' 75 # https://tools.immae.eu/wallabag domain name in preview_picture
120 install -m 0755 -o ${apache.user} -g ${apache.group} -d ${varDir} \ 76 apache = rec {
121 ${varDir}/var ${varDir}/data/db ${varDir}/assets/images 77 user = "wwwrun";
122 ''; 78 group = "wwwrun";
123 webRoot = "${webappDir}/web"; 79 modules = [ "proxy_fcgi" ];
124 # Domain migration: Table wallabag_entry contains whole 80 webappName = "tools_wallabag";
125 # https://tools.immae.eu/wallabag domain name in preview_picture 81 root = "/run/current-system/webapps/${webappName}";
126 apache = rec { 82 vhostConf = ''
127 user = "wwwrun"; 83 Alias /wallabag "${root}"
128 group = "wwwrun"; 84 <Directory "${root}">
129 modules = [ "proxy_fcgi" ]; 85 AllowOverride None
130 webappName = "tools_wallabag"; 86 Require all granted
131 root = "/run/current-system/webapps/${webappName}"; 87 # For OAuth (apps)
132 vhostConf = '' 88 CGIPassAuth On
133 Alias /wallabag "${root}"
134 <Directory "${root}">
135 AllowOverride None
136 Require all granted
137 # For OAuth (apps)
138 CGIPassAuth On
139 89
140 <FilesMatch "\.php$"> 90 <FilesMatch "\.php$">
141 SetHandler "proxy:unix:${phpFpm.socket}|fcgi://localhost" 91 SetHandler "proxy:unix:${phpFpm.socket}|fcgi://localhost"
142 </FilesMatch> 92 </FilesMatch>
143 93
144 <IfModule mod_rewrite.c> 94 <IfModule mod_rewrite.c>
145 Options -MultiViews 95 Options -MultiViews
146 RewriteEngine On 96 RewriteEngine On
147 RewriteCond %{REQUEST_FILENAME} !-f 97 RewriteCond %{REQUEST_FILENAME} !-f
148 RewriteRule ^(.*)$ app.php [QSA,L] 98 RewriteRule ^(.*)$ app.php [QSA,L]
149 </IfModule> 99 </IfModule>
150 </Directory> 100 </Directory>
151 <Directory "${root}/bundles"> 101 <Directory "${root}/bundles">
152 <IfModule mod_rewrite.c> 102 <IfModule mod_rewrite.c>
153 RewriteEngine Off 103 RewriteEngine Off
154 </IfModule> 104 </IfModule>
155 </Directory> 105 </Directory>
156 <Directory "${varDir}/assets"> 106 <Directory "${varDir}/assets">
157 AllowOverride None 107 AllowOverride None
158 Require all granted 108 Require all granted
159 </Directory> 109 </Directory>
160 ''; 110 '';
161 }; 111 };
162 phpFpm = rec { 112 phpFpm = rec {
163 preStart = '' 113 preStart = ''
164 if [ ! -f "${varDir}/currentWebappDir" -o \ 114 if [ ! -f "${varDir}/currentWebappDir" -o \
165 ! -f "${varDir}/currentKey" -o \ 115 ! -f "${varDir}/currentKey" -o \
166 "${webappDir}" != "$(cat ${varDir}/currentWebappDir 2>/dev/null)" ] \ 116 "${webappDir}" != "$(cat ${varDir}/currentWebappDir 2>/dev/null)" ] \
167 || ! sha512sum -c --status ${varDir}/currentKey; then 117 || ! sha512sum -c --status ${varDir}/currentKey; then
168 pushd ${webappDir} > /dev/null 118 pushd ${webappDir} > /dev/null
169 /run/wrappers/bin/sudo -u wwwrun ./bin/console --env=prod cache:clear 119 /run/wrappers/bin/sudo -u wwwrun ./bin/console --env=prod cache:clear
170 rm -rf /var/lib/wallabag/var/cache/pro_ 120 rm -rf /var/lib/wallabag/var/cache/pro_
171 /run/wrappers/bin/sudo -u wwwrun ./bin/console --env=prod doctrine:migrations:migrate --no-interaction 121 /run/wrappers/bin/sudo -u wwwrun ./bin/console --env=prod doctrine:migrations:migrate --no-interaction
172 popd > /dev/null 122 popd > /dev/null
173 echo -n "${webappDir}" > ${varDir}/currentWebappDir 123 echo -n "${webappDir}" > ${varDir}/currentWebappDir
174 sha512sum /var/secrets/webapps/tools-wallabag > ${varDir}/currentKey 124 sha512sum /var/secrets/webapps/tools-wallabag > ${varDir}/currentKey
175 fi 125 fi
176 ''; 126 '';
177 serviceDeps = [ "postgresql.service" "openldap.service" ]; 127 serviceDeps = [ "postgresql.service" "openldap.service" ];
178 basedir = builtins.concatStringsSep ":" [ webappDir "/var/secrets/webapps/tools-wallabag" varDir ]; 128 basedir = builtins.concatStringsSep ":" [ webappDir "/var/secrets/webapps/tools-wallabag" varDir ];
179 socket = "/var/run/phpfpm/wallabag.sock"; 129 socket = "/var/run/phpfpm/wallabag.sock";
180 pool = '' 130 pool = ''
181 listen = ${socket} 131 listen = ${socket}
182 user = ${apache.user} 132 user = ${apache.user}
183 group = ${apache.group} 133 group = ${apache.group}
184 listen.owner = ${apache.user} 134 listen.owner = ${apache.user}
185 listen.group = ${apache.group} 135 listen.group = ${apache.group}
186 pm = dynamic 136 pm = dynamic
187 pm.max_children = 60 137 pm.max_children = 60
188 pm.start_servers = 2 138 pm.start_servers = 2
189 pm.min_spare_servers = 1 139 pm.min_spare_servers = 1
190 pm.max_spare_servers = 10 140 pm.max_spare_servers = 10
191 141
192 ; Needed to avoid clashes in browser cookies (same domain) 142 ; Needed to avoid clashes in browser cookies (same domain)
193 php_value[session.name] = WallabagPHPSESSID 143 php_value[session.name] = WallabagPHPSESSID
194 php_admin_value[open_basedir] = "/run/wrappers/bin/sendmail:${basedir}:/tmp" 144 php_admin_value[open_basedir] = "/run/wrappers/bin/sendmail:${basedir}:/tmp"
195 php_value[max_execution_time] = 300 145 php_value[max_execution_time] = 300
196 ''; 146 '';
197 };
198 }; 147 };
199in 148}
200 wallabag
diff --git a/nixops/modules/websites/tools/tools/wallabag_ldap.patch b/nixops/modules/websites/tools/tools/wallabag_ldap.patch
deleted file mode 100644
index 9caf7da..0000000
--- a/nixops/modules/websites/tools/tools/wallabag_ldap.patch
+++ /dev/null
@@ -1,698 +0,0 @@
1diff --git a/.travis.yml b/.travis.yml
2index 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
13diff --git a/app/AppKernel.php b/app/AppKernel.php
14index 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();
28diff --git a/app/DoctrineMigrations/Version20170710113900.php b/app/DoctrineMigrations/Version20170710113900.php
29new file mode 100644
30index 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+
88diff --git a/app/config/parameters.yml.dist b/app/config/parameters.yml.dist
89index 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: ~
116diff --git a/app/config/security.yml b/app/config/security.yml
117index 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:
136diff --git a/composer.json b/composer.json
137index 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",
153diff --git a/composer.lock b/composer.lock
154index 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",
317diff --git a/scripts/install.sh b/scripts/install.sh
318index 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
330diff --git a/scripts/update.sh b/scripts/update.sh
331index 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
344diff --git a/src/Wallabag/UserBundle/DependencyInjection/WallabagUserExtension.php b/src/Wallabag/UserBundle/DependencyInjection/WallabagUserExtension.php
345index 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
394diff --git a/src/Wallabag/UserBundle/Entity/User.php b/src/Wallabag/UserBundle/Entity/User.php
395index 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 }
479diff --git a/src/Wallabag/UserBundle/LdapHydrator.php b/src/Wallabag/UserBundle/LdapHydrator.php
480new file mode 100644
481index 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+}
588diff --git a/src/Wallabag/UserBundle/OAuthStorageLdapWrapper.php b/src/Wallabag/UserBundle/OAuthStorageLdapWrapper.php
589new file mode 100644
590index 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+}
637diff --git a/src/Wallabag/UserBundle/Resources/config/ldap.yml b/src/Wallabag/UserBundle/Resources/config/ldap.yml
638new file mode 100644
639index 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+
671diff --git a/src/Wallabag/UserBundle/Resources/config/ldap_services.yml b/src/Wallabag/UserBundle/Resources/config/ldap_services.yml
672new file mode 100644
673index 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+