]> git.immae.eu Git - perso/Immae/Config/Nix/NUR.git/blame_incremental - pkgs/webapps/diaspora/ldap.patch
Initial commit published for NUR
[perso/Immae/Config/Nix/NUR.git] / pkgs / webapps / diaspora / ldap.patch
... / ...
CommitLineData
1commit 936a14e225037aca4cdeac11c843c7985e636c88
2Author: Ismaƫl Bouya <ismael.bouya@normalesup.org>
3Date: Mon Jul 24 19:58:24 2017 +0200
4
5 Add LDAP to diaspora
6
7diff --git a/Gemfile b/Gemfile
8index 414b0138d..2a934e9c9 100644
9--- a/Gemfile
10+++ b/Gemfile
11@@ -217,6 +217,9 @@ gem "thor", "0.19.1"
12
13 # gem "therubyracer", :platform => :ruby
14
15+# LDAP
16+gem 'net-ldap', '~> 0.16'
17+
18 group :production do # we don"t install these on travis to speed up test runs
19 # Analytics
20
21diff --git a/Gemfile.lock b/Gemfile.lock
22index 84f8172e4..cdbf19fcd 100644
23--- a/Gemfile.lock 2019-01-13 19:55:52.538561762 +0100
24+++ b/Gemfile.lock 2019-01-13 19:58:11.087099067 +0100
25@@ -398,6 +398,7 @@
26 mysql2 (0.5.2)
27 naught (1.1.0)
28 nenv (0.3.0)
29+ net-ldap (0.16.1)
30 nio4r (2.3.1)
31 nokogiri (1.8.5)
32 mini_portile2 (~> 2.3.0)
33@@ -820,6 +821,7 @@
34 minitest
35 mobile-fu (= 1.4.0)
36 mysql2 (= 0.5.2)
37+ net-ldap (~> 0.16)
38 nokogiri (= 1.8.5)
39 omniauth (= 1.8.1)
40 omniauth-tumblr (= 1.2)
41diff --git a/app/models/user.rb b/app/models/user.rb
42index 940a48f25..d1e2beeee 100644
43--- a/app/models/user.rb
44+++ b/app/models/user.rb
45@@ -337,6 +337,12 @@ class User < ActiveRecord::Base
46 end
47
48 def send_confirm_email
49+ if skip_email_confirmation?
50+ self.email = unconfirmed_email
51+ self.unconfirmed_email = nil
52+ save
53+ end
54+
55 return if unconfirmed_email.blank?
56 Workers::Mail::ConfirmEmail.perform_async(id)
57 end
58@@ -554,6 +560,14 @@ class User < ActiveRecord::Base
59 end
60 end
61
62+ def ldap_user?
63+ AppConfig.ldap.enable? && ldap_dn.present?
64+ end
65+
66+ def skip_email_confirmation?
67+ ldap_user? && AppConfig.ldap.skip_email_confirmation?
68+ end
69+
70 private
71
72 def clearable_fields
73diff --git a/config/defaults.yml b/config/defaults.yml
74index c046aff07..66e9afa13 100644
75--- a/config/defaults.yml
76+++ b/config/defaults.yml
77@@ -202,6 +202,20 @@ defaults:
78 scope: tags
79 include_user_tags: false
80 pod_tags:
81+ ldap:
82+ enable: false
83+ host: localhost
84+ port: 389
85+ only_ldap: true
86+ mail_attribute: mail
87+ skip_email_confirmation: true
88+ use_bind_dn: true
89+ bind_dn: "cn=diaspora,dc=example,dc=com"
90+ bind_pw: "password"
91+ search_base: "dc=example,dc=com"
92+ search_filter: "uid=%{username}"
93+ bind_template: "uid=%{username},dc=example,dc=com"
94+
95
96 development:
97 environment:
98diff --git a/config/diaspora.yml.example b/config/diaspora.yml.example
99index b2573625d..c357c8651 100644
100--- a/config/diaspora.yml.example
101+++ b/config/diaspora.yml.example
102@@ -710,6 +710,36 @@ configuration: ## Section
103 ## If scope is 'tags', a comma separated list of tags here can be set.
104 ## For example "linux,diaspora", to receive posts related to these tags
105 #pod_tags:
106+ ldap:
107+ # Uncomment next line if you want to use LDAP on your instance
108+ enable: true
109+ host: localhost
110+ port: 389
111+ # Use only LDAP authentication (don't try other means)
112+ only_ldap: true
113+ # LDAP attribute to find the user's e-mail. Necessary to create accounts
114+ # for not existing users
115+ mail_attribute: mail
116+ # Skip e-mail confirmation when creating an account via LDAP.
117+ skip_email_confirmation: true
118+ # ----- Using bind_dn and bind_pw
119+ # bind_dn and bind_pw may be used if the diaspora instance
120+ # should be able to connect to LDAP to find and search for users.
121+
122+ use_bind_dn: true
123+ bind_dn: "cn=diaspora,dc=example,dc=com"
124+ bind_pw: "password"
125+ search_base: "dc=example,dc=com"
126+ # This is the filter with which to search for the user. %{username} will
127+ # be replaced by the given login.
128+ search_filter: "uid=%{username}"
129+ #
130+ # ----- Using template
131+ # This setting doesn't require a diaspora LDAP user. Use a template, and
132+ # diaspora will try to login with the templated dn and password
133+ #
134+ # bind_template: "uid=%{username},dc=example,dc=com"
135+
136
137 ## Here you can override settings defined above if you need
138 ## to have them different in different environments.
139diff --git a/config/initializers/0_ldap_authenticatable.rb b/config/initializers/0_ldap_authenticatable.rb
140new file mode 100644
141index 000000000..49846502f
142--- /dev/null
143+++ b/config/initializers/0_ldap_authenticatable.rb
144@@ -0,0 +1,82 @@
145+require 'net/ldap'
146+require 'devise/strategies/authenticatable'
147+
148+module Devise
149+ module Strategies
150+ class LdapAuthenticatable < Authenticatable
151+ def valid?
152+ AppConfig.ldap.enable? && params[:user].present?
153+ end
154+
155+ def authenticate!
156+ ldap = Net::LDAP.new(
157+ host: AppConfig.ldap.host,
158+ port: AppConfig.ldap.port,
159+ encryption: :simple_tls,
160+ )
161+
162+ if AppConfig.ldap.use_bind_dn?
163+ ldap.auth AppConfig.ldap.bind_dn, AppConfig.ldap.bind_pw
164+
165+ if !ldap.bind
166+ return fail(:ldap_configuration_error)
167+ end
168+
169+ search_filter = AppConfig.ldap.search_filter % { username: params[:user][:username] }
170+
171+ result = ldap.search(base: AppConfig.ldap.search_base, filter: search_filter, result_set: true)
172+
173+ if result.count != 1
174+ return login_fail
175+ end
176+
177+ user_dn = result.first.dn
178+ user_email = result.first[AppConfig.ldap.mail_attribute].first
179+ else
180+ user_dn = AppConfig.ldap.bind_template % { username: params[:user][:username] }
181+ end
182+
183+ ldap.auth user_dn, params[:user][:password]
184+
185+ if ldap.bind
186+ user = User.find_by(ldap_dn: user_dn)
187+
188+ # We don't want to trust too much the email attribute from
189+ # LDAP: if the user can edit it himself, he may login as
190+ # anyone
191+ if user.nil?
192+ if !AppConfig.ldap.use_bind_dn?
193+ result = ldap.search(base: user_dn, scope: Net::LDAP::SearchScope_BaseObject, filter: "(objectClass=*)", result_set: true)
194+ user_email = result.first[AppConfig.ldap.mail_attribute].first
195+ end
196+
197+ if user_email.present? && User.find_by(email: user_email).nil?
198+ # Password is used for remember_me token
199+ user = User.build(email: user_email, ldap_dn: user_dn, password: SecureRandom.hex, username: params[:user][:username])
200+ user.save
201+ user.seed_aspects
202+ elsif User.find_by(email: user_email).present?
203+ return fail(:ldap_existing_email)
204+ else
205+ return fail(:ldap_cannot_create_account_without_email)
206+ end
207+ end
208+
209+ success!(user)
210+ else
211+ return login_fail
212+ end
213+ end
214+
215+ def login_fail
216+ if AppConfig.ldap.only_ldap?
217+ return fail(:ldap_invalid_login)
218+ else
219+ return pass
220+ end
221+ end
222+ end
223+ end
224+end
225+
226+Warden::Strategies.add(:ldap_authenticatable, Devise::Strategies::LdapAuthenticatable)
227diff --git a/config/initializers/devise.rb b/config/initializers/devise.rb
228index 3698e2373..14e88063e 100644
229--- a/config/initializers/devise.rb
230+++ b/config/initializers/devise.rb
231@@ -250,10 +250,9 @@ Devise.setup do |config|
232 # If you want to use other strategies, that are not supported by Devise, or
233 # change the failure app, you can configure them inside the config.warden block.
234 #
235- # config.warden do |manager|
236- # manager.intercept_401 = false
237- # manager.default_strategies(:scope => :user).unshift :some_external_strategy
238- # end
239+ config.warden do |manager|
240+ manager.default_strategies(scope: :user).unshift :ldap_authenticatable
241+ end
242
243 # ==> Mountable engine configurations
244 # When using Devise inside an engine, let's call it `MyEngine`, and this engine
245diff --git a/db/migrate/20170724182100_add_ldap_dn_to_users.rb b/db/migrate/20170724182100_add_ldap_dn_to_users.rb
246new file mode 100644
247index 000000000..f5cc84d11
248--- /dev/null
249+++ b/db/migrate/20170724182100_add_ldap_dn_to_users.rb
250@@ -0,0 +1,6 @@
251+class AddLdapDnToUsers < ActiveRecord::Migration
252+ def change
253+ add_column :users, :ldap_dn, :text, null: true, default: nil
254+ add_index :users, ['ldap_dn'], :length => { "ldap_dn" => 191 }
255+ end
256+end