devise_ldap_authenticatable
devise_ldap_authenticatable copied to clipboard
Find existing user based on email when LDAP auth uses username
I have a slight problem that i'm sure there is a solution to, but I can't seem to figure it out.
I'm authing against Active Directory using the AD Username, which is working, but the problem is when it tries to create the user on the local database when that user already exists (but is usually auth'd with an email address)
What I need to do is once the user it authenticated against Active Directory, when it comes back into Devise, look up if the user exists using the email address pulled from active directory and checking against the local DB. Right now, it's checking to see if the username exists, which it won't yet so it tries to create a duplicate user.
Any ideas?
I found a hacky work around for this, but something more official would be nice.
Hey.
I struggled with same issue. Finally solved with callbacks and method override.
class User < ApplicationRecord
attr_accessor :ldap_hash
...
# Guarantee the up-to-dateness of user data
def ldap_before_save
self.email = ldap_hash[:email]
self.firstname = ldap_hash[:firstname]
self.lastname = ldap_hash[:lastname]
end
# Ensure that email is not overwritten by username value
def after_ldap_authentication
self.email = ldap_hash[:email]
end
# Find a user for ldap authentication.
# NB Override Devise::Models::LdapAuthenticatable class method.
def self.find_for_ldap_authentication(attributes={})
auth_key = self.authentication_keys.first
return nil unless attributes[auth_key].present?
auth_key_value = (self.case_insensitive_keys || []).include?(auth_key) ? attributes[auth_key].downcase : attributes[auth_key]
auth_key_value = (self.strip_whitespace_keys || []).include?(auth_key) ? auth_key_value.strip : auth_key_value
# Query additional data from LDAP server
entry = Devise::LDAP::Adapter.get_ldap_entry(auth_key_value)
ldap_hash = {
email: entry[:mail].first.try(:downcase),
firstname: entry[:givenname].join(' '),
lastname: entry[:sn].join(' ')
}
# Find user by e-mail
resource = where(email: ldap_hash[:email]).first if ldap_hash[:email]
if resource.blank?
resource = new
resource[auth_key] = auth_key_value
end
# Store information on resource for later callback calls
resource.ldap_hash = ldap_hash
if ::Devise.ldap_create_user && resource.new_record? && resource.valid_ldap_authentication?(attributes[:password])
resource.ldap_before_save if resource.respond_to?(:ldap_before_save)
resource.save!
end
# Device "needs" same auth key value that came from end-user
resource[auth_key] = auth_key_value
resource
end
end