Search code examples
ruby-on-rails-4authenticationdevise

Devise lockable and custom strategy


I am developing a custom strategy for LDAP authentication, and I have implemented the valid? and authenticate! methods as per http://kyan.com/blog/2013/10/11/devise-authentication-strategies and this Devise wiki. My custom strategy works by itself.

I also want to use the Lockable module (and other Devise modules), but they seem to work only when Database_Authenticatable is also present. I have been reading the Devise source code, but I do not understand how Lockable is able to find the user (resource) in order to increment the :failed_attempts count. How do I pass the user record or resource to Lockable using my custom strategy?

My custom strategy is below. I am using Devise 3.5 and Rails 4.2

require 'net/ldap'
require 'devise/strategies/authenticatable'

module Devise
  module Strategies
   class LdapAuthenticatable < Authenticatable


  def valid?
    params[:user] && login.present? && password.present?
  end

  def authenticate!

    resource = mapping.to.find_for_authentication(email: params[:user][:email])

    if params[:user]
      begin
        ldap = Net::LDAP.new
        ldap.auth(my_ldap_service, my_ldap_service_password)
        ldap.encryption(:simple_tls)
        ldap.base = "base_here"
        ldap.host = my_ldap_host
        ldap.port = "636"
        result_attrs = ["employeenumber", "givenname", "sn", "mail", "department"] 

        result = ldap.bind_as(base: "base_here", filter: "(mail=#{login})", attributes: result_attrs, password: password, time: 3) 


        if result
          #valid ldap credentials
          user = get_user_from_database(result)
          if user
            success!(user)
          else
            fail!(:invalid_login)
          end

        else 
          fail!(:invalid_login)
        end

      rescue => e
        Rails.logger.error e.message
        fail!(:invalid_login)
      end

    end
  end

  def login
    params[:user][:email]
  end

  def password
    params[:user][:password]
  end

end
end
end

Solution

  • I ended up using devise_custom_authenticatable in combination with the resources posted on the original question. For lockable to work, database_authenticable must be present. Toni's answer above should work if you have control over LDAP, which I did not when I posed the question.