From f3a93987b6c3af92aee11fdb4424b8791a67e448 Mon Sep 17 00:00:00 2001 From: ntl-purism <57806346+ntl-purism@users.noreply.github.com> Date: Sat, 30 Nov 2019 12:44:59 -0600 Subject: LDAP & PAM added to OAuth password grant strategy (#7999) (#12390) When authenticating via OAuth, the resource owner password grant strategy is allowed by Mastodon, but (without this PR), it does not attempt to authenticate against LDAP or PAM. As a result, LDAP or PAM authenticated users cannot sign in to Mastodon with their email/password credentials via OAuth (for instance, for native/mobile app users). This PR fleshes out the authentication strategy supplied to doorkeeper in its initializer by looking up the user with LDAP and/or PAM when devise is configured to use LDAP/PAM backends. It attempts to follow the same logic as the Auth::SessionsController for handling email/password credentials. Note #1: Since this pull request affects an initializer, it's unclear how to add test automation. Note #2: The PAM authentication path has not been manually tested. It was added for completeness sake, and it is hoped that it can be manually tested before merging. --- config/initializers/doorkeeper.rb | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) (limited to 'config/initializers') diff --git a/config/initializers/doorkeeper.rb b/config/initializers/doorkeeper.rb index a5c9caa4a..7784bec62 100644 --- a/config/initializers/doorkeeper.rb +++ b/config/initializers/doorkeeper.rb @@ -8,8 +8,20 @@ Doorkeeper.configure do end resource_owner_from_credentials do |_routes| - user = User.find_by(email: request.params[:username]) - user if !user&.otp_required_for_login? && user&.valid_password?(request.params[:password]) + if Devise.ldap_authentication + user = User.authenticate_with_ldap({ :email => request.params[:username], :password => request.params[:password] }) + end + + if Devise.pam_authentication + user ||= User.authenticate_with_ldap({ :email => request.params[:username], :password => request.params[:password] }) + end + + if user.nil? + user = User.find_by(email: request.params[:username]) + user = nil unless user.valid_password?(request.params[:password]) + end + + user if !user&.otp_required_for_login? end # If you want to restrict access to the web interface for adding oauth authorized applications, you need to declare the block below. -- cgit From d70268f0991ba69568112d4da5768e821d5983dd Mon Sep 17 00:00:00 2001 From: Mathieu Brunot Date: Sun, 1 Dec 2019 07:21:28 +0100 Subject: :sparkles: Convert LDAP username (#12461) * :sparkles: Convert LDAP username #12021 Signed-off-by: mathieu.brunot * :bug: Fix conversion var use Signed-off-by: mathieu.brunot * :bug: Fix LDAP uid conversion test Signed-off-by: mathieu.brunot * :ok_hand: Remove comments with ref to PR Signed-off-by: mathieu.brunot * :ok_hand: Remove unnecessary paranthesis Signed-off-by: mathieu.brunot * :wrench: Move space in conversion string Signed-off-by: mathieu.brunot --- .env.nanobox | 3 +++ .env.production.sample | 3 +++ app/models/concerns/ldap_authenticable.rb | 12 ++++++++++-- config/initializers/devise.rb | 9 +++++++++ 4 files changed, 25 insertions(+), 2 deletions(-) (limited to 'config/initializers') diff --git a/.env.nanobox b/.env.nanobox index cfbe487fb..fc6c3c42f 100644 --- a/.env.nanobox +++ b/.env.nanobox @@ -183,6 +183,9 @@ SMTP_FROM_ADDRESS=notifications@${APP_NAME}.nanoapp.io # LDAP_BIND_DN= # LDAP_PASSWORD= # LDAP_UID=cn +# LDAP_UID_CONVERSION_ENABLED=true +# LDAP_UID_CONVERSION_SEARCH=., - +# LDAP_UID_CONVERSION_REPLACE=_ # PAM authentication (optional) # PAM authentication uses for the email generation the "email" pam variable diff --git a/.env.production.sample b/.env.production.sample index f9a8bb7c1..6b078c7b2 100644 --- a/.env.production.sample +++ b/.env.production.sample @@ -179,6 +179,9 @@ STREAMING_CLUSTER_NUM=1 # LDAP_PASSWORD= # LDAP_UID=cn # LDAP_SEARCH_FILTER=%{uid}=%{email} +# LDAP_UID_CONVERSION_ENABLED=true +# LDAP_UID_CONVERSION_SEARCH=., - +# LDAP_UID_CONVERSION_REPLACE=_ # PAM authentication (optional) # PAM authentication uses for the email generation the "email" pam variable diff --git a/app/models/concerns/ldap_authenticable.rb b/app/models/concerns/ldap_authenticable.rb index 117993947..2d2e1edbb 100644 --- a/app/models/concerns/ldap_authenticable.rb +++ b/app/models/concerns/ldap_authenticable.rb @@ -14,10 +14,18 @@ module LdapAuthenticable end def ldap_get_user(attributes = {}) - resource = joins(:account).find_by(accounts: { username: attributes[Devise.ldap_uid.to_sym].first }) + safe_username = attributes[Devise.ldap_uid.to_sym].first + if Devise.ldap_uid_conversion_enabled + keys = Regexp.union(Devise.ldap_uid_conversion_search.chars) + replacement = Devise.ldap_uid_conversion_replace + + safe_username = safe_username.gsub(keys, replacement) + end + + resource = joins(:account).find_by(accounts: { username: safe_username }) if resource.blank? - resource = new(email: attributes[:mail].first, agreement: true, account_attributes: { username: attributes[Devise.ldap_uid.to_sym].first }, admin: false, external: true, confirmed_at: Time.now.utc) + resource = new(email: attributes[:mail].first, agreement: true, account_attributes: { username: safe_username }, admin: false, external: true, confirmed_at: Time.now.utc) resource.save! end diff --git a/config/initializers/devise.rb b/config/initializers/devise.rb index fd9a5a8b9..fa9fd8cc4 100644 --- a/config/initializers/devise.rb +++ b/config/initializers/devise.rb @@ -61,6 +61,12 @@ module Devise @@ldap_tls_no_verify = false mattr_accessor :ldap_search_filter @@ldap_search_filter = nil + mattr_accessor :ldap_uid_conversion_enabled + @@ldap_uid_conversion_enabled = false + mattr_accessor :ldap_uid_conversion_search + @@ldap_uid_conversion_search = nil + mattr_accessor :ldap_uid_conversion_replace + @@ldap_uid_conversion_replace = nil class Strategies::PamAuthenticatable def valid? @@ -365,5 +371,8 @@ Devise.setup do |config| config.ldap_uid = ENV.fetch('LDAP_UID', 'cn') config.ldap_tls_no_verify = ENV['LDAP_TLS_NO_VERIFY'] == 'true' config.ldap_search_filter = ENV.fetch('LDAP_SEARCH_FILTER', '%{uid}=%{email}') + config.ldap_uid_conversion_enabled = ENV['LDAP_UID_CONVERSION_ENABLED'] == 'true' + config.ldap_uid_conversion_search = ENV.fetch('LDAP_UID_CONVERSION_SEARCH', '.,- ') + config.ldap_uid_conversion_replace = ENV.fetch('LDAP_UID_CONVERSION_REPLACE', '_') end end -- cgit