--- /dev/null
+commit 936a14e225037aca4cdeac11c843c7985e636c88
+Author: Ismaƫl Bouya <ismael.bouya@normalesup.org>
+Date: Mon Jul 24 19:58:24 2017 +0200
+
+ Add LDAP to diaspora
+
+diff --git a/Gemfile b/Gemfile
+index 414b0138d..2a934e9c9 100644
+--- a/Gemfile
++++ b/Gemfile
+@@ -217,6 +217,9 @@ gem "thor", "0.19.1"
+
+ # gem "therubyracer", :platform => :ruby
+
++# LDAP
++gem 'net-ldap', '~> 0.16'
++
+ group :production do # we don"t install these on travis to speed up test runs
+ # Analytics
+
+diff --git a/Gemfile.lock b/Gemfile.lock
+index 84f8172e4..cdbf19fcd 100644
+--- a/Gemfile.lock 2019-01-13 19:55:52.538561762 +0100
++++ b/Gemfile.lock 2019-01-13 19:58:11.087099067 +0100
+@@ -398,6 +398,7 @@
+ mysql2 (0.5.2)
+ naught (1.1.0)
+ nenv (0.3.0)
++ net-ldap (0.16.1)
+ nio4r (2.3.1)
+ nokogiri (1.8.5)
+ mini_portile2 (~> 2.3.0)
+@@ -820,6 +821,7 @@
+ minitest
+ mobile-fu (= 1.4.0)
+ mysql2 (= 0.5.2)
++ net-ldap (~> 0.16)
+ nokogiri (= 1.8.5)
+ omniauth (= 1.8.1)
+ omniauth-tumblr (= 1.2)
+diff --git a/app/models/user.rb b/app/models/user.rb
+index 940a48f25..d1e2beeee 100644
+--- a/app/models/user.rb
++++ b/app/models/user.rb
+@@ -337,6 +337,12 @@ class User < ActiveRecord::Base
+ end
+
+ def send_confirm_email
++ if skip_email_confirmation?
++ self.email = unconfirmed_email
++ self.unconfirmed_email = nil
++ save
++ end
++
+ return if unconfirmed_email.blank?
+ Workers::Mail::ConfirmEmail.perform_async(id)
+ end
+@@ -554,6 +560,14 @@ class User < ActiveRecord::Base
+ end
+ end
+
++ def ldap_user?
++ AppConfig.ldap.enable? && ldap_dn.present?
++ end
++
++ def skip_email_confirmation?
++ ldap_user? && AppConfig.ldap.skip_email_confirmation?
++ end
++
+ private
+
+ def clearable_fields
+diff --git a/config/defaults.yml b/config/defaults.yml
+index c046aff07..66e9afa13 100644
+--- a/config/defaults.yml
++++ b/config/defaults.yml
+@@ -202,6 +202,20 @@ defaults:
+ scope: tags
+ include_user_tags: false
+ pod_tags:
++ ldap:
++ enable: false
++ host: localhost
++ port: 389
++ only_ldap: true
++ mail_attribute: mail
++ skip_email_confirmation: true
++ use_bind_dn: true
++ bind_dn: "cn=diaspora,dc=example,dc=com"
++ bind_pw: "password"
++ search_base: "dc=example,dc=com"
++ search_filter: "uid=%{username}"
++ bind_template: "uid=%{username},dc=example,dc=com"
++
+
+ development:
+ environment:
+diff --git a/config/diaspora.yml.example b/config/diaspora.yml.example
+index b2573625d..c357c8651 100644
+--- a/config/diaspora.yml.example
++++ b/config/diaspora.yml.example
+@@ -710,6 +710,36 @@ configuration: ## Section
+ ## If scope is 'tags', a comma separated list of tags here can be set.
+ ## For example "linux,diaspora", to receive posts related to these tags
+ #pod_tags:
++ ldap:
++ # Uncomment next line if you want to use LDAP on your instance
++ enable: true
++ host: localhost
++ port: 389
++ # Use only LDAP authentication (don't try other means)
++ only_ldap: true
++ # LDAP attribute to find the user's e-mail. Necessary to create accounts
++ # for not existing users
++ mail_attribute: mail
++ # Skip e-mail confirmation when creating an account via LDAP.
++ skip_email_confirmation: true
++ # ----- Using bind_dn and bind_pw
++ # bind_dn and bind_pw may be used if the diaspora instance
++ # should be able to connect to LDAP to find and search for users.
++
++ use_bind_dn: true
++ bind_dn: "cn=diaspora,dc=example,dc=com"
++ bind_pw: "password"
++ search_base: "dc=example,dc=com"
++ # This is the filter with which to search for the user. %{username} will
++ # be replaced by the given login.
++ search_filter: "uid=%{username}"
++ #
++ # ----- Using template
++ # This setting doesn't require a diaspora LDAP user. Use a template, and
++ # diaspora will try to login with the templated dn and password
++ #
++ # bind_template: "uid=%{username},dc=example,dc=com"
++
+
+ ## Here you can override settings defined above if you need
+ ## to have them different in different environments.
+diff --git a/config/initializers/0_ldap_authenticatable.rb b/config/initializers/0_ldap_authenticatable.rb
+new file mode 100644
+index 000000000..49846502f
+--- /dev/null
++++ b/config/initializers/0_ldap_authenticatable.rb
+@@ -0,0 +1,82 @@
++require 'net/ldap'
++require 'devise/strategies/authenticatable'
++
++module Devise
++ module Strategies
++ class LdapAuthenticatable < Authenticatable
++ def valid?
++ AppConfig.ldap.enable? && params[:user].present?
++ end
++
++ def authenticate!
++ ldap = Net::LDAP.new(
++ host: AppConfig.ldap.host,
++ port: AppConfig.ldap.port,
++ encryption: :simple_tls,
++ )
++
++ if AppConfig.ldap.use_bind_dn?
++ ldap.auth AppConfig.ldap.bind_dn, AppConfig.ldap.bind_pw
++
++ if !ldap.bind
++ return fail(:ldap_configuration_error)
++ end
++
++ search_filter = AppConfig.ldap.search_filter % { username: params[:user][:username] }
++
++ result = ldap.search(base: AppConfig.ldap.search_base, filter: search_filter, result_set: true)
++
++ if result.count != 1
++ return login_fail
++ end
++
++ user_dn = result.first.dn
++ user_email = result.first[AppConfig.ldap.mail_attribute].first
++ else
++ user_dn = AppConfig.ldap.bind_template % { username: params[:user][:username] }
++ end
++
++ ldap.auth user_dn, params[:user][:password]
++
++ if ldap.bind
++ user = User.find_by(ldap_dn: user_dn)
++
++ # We don't want to trust too much the email attribute from
++ # LDAP: if the user can edit it himself, he may login as
++ # anyone
++ if user.nil?
++ if !AppConfig.ldap.use_bind_dn?
++ result = ldap.search(base: user_dn, scope: Net::LDAP::SearchScope_BaseObject, filter: "(objectClass=*)", result_set: true)
++ user_email = result.first[AppConfig.ldap.mail_attribute].first
++ end
++
++ if user_email.present? && User.find_by(email: user_email).nil?
++ # Password is used for remember_me token
++ user = User.build(email: user_email, ldap_dn: user_dn, password: SecureRandom.hex, username: params[:user][:username])
++ user.save
++ user.seed_aspects
++ elsif User.find_by(email: user_email).present?
++ return fail(:ldap_existing_email)
++ else
++ return fail(:ldap_cannot_create_account_without_email)
++ end
++ end
++
++ success!(user)
++ else
++ return login_fail
++ end
++ end
++
++ def login_fail
++ if AppConfig.ldap.only_ldap?
++ return fail(:ldap_invalid_login)
++ else
++ return pass
++ end
++ end
++ end
++ end
++end
++
++Warden::Strategies.add(:ldap_authenticatable, Devise::Strategies::LdapAuthenticatable)
+diff --git a/config/initializers/devise.rb b/config/initializers/devise.rb
+index 3698e2373..14e88063e 100644
+--- a/config/initializers/devise.rb
++++ b/config/initializers/devise.rb
+@@ -250,10 +250,9 @@ Devise.setup do |config|
+ # If you want to use other strategies, that are not supported by Devise, or
+ # change the failure app, you can configure them inside the config.warden block.
+ #
+- # config.warden do |manager|
+- # manager.intercept_401 = false
+- # manager.default_strategies(:scope => :user).unshift :some_external_strategy
+- # end
++ config.warden do |manager|
++ manager.default_strategies(scope: :user).unshift :ldap_authenticatable
++ end
+
+ # ==> Mountable engine configurations
+ # When using Devise inside an engine, let's call it `MyEngine`, and this engine
+diff --git a/db/migrate/20170724182100_add_ldap_dn_to_users.rb b/db/migrate/20170724182100_add_ldap_dn_to_users.rb
+new file mode 100644
+index 000000000..f5cc84d11
+--- /dev/null
++++ b/db/migrate/20170724182100_add_ldap_dn_to_users.rb
+@@ -0,0 +1,6 @@
++class AddLdapDnToUsers < ActiveRecord::Migration
++ def change
++ add_column :users, :ldap_dn, :text, null: true, default: nil
++ add_index :users, ['ldap_dn'], :length => { "ldap_dn" => 191 }
++ end
++end