devise_ldap_authentication for your domain email on top of database_authenticatable

I have a devise user model named LoginUser whose authentication key is :login. I want normal users of the system to be database_authenticatable.

However, I want to be able to authenticate previously added users via internal LDAP. Furthermore, I didn't want the underlying database_authenticatable password to be used or to expire on me (also using devise_security_extensions). Most of the work is in the LocalOverride custom strategy's authenticate! method, with a few other hooks (such as default strategy added to devise.yml).


To allow all other strategies to be used, but still trap our domains for one-off LDAP auth, I added devise :ldap_authenticatable to a singleton class inherited from the user loaded by the custom strategy.

Also, removed the other two "fails" from the code. Not necessary and will result in a "Failed to Login" message for too many other Devise-related Unauthorized events.

In config/initializers/local_override.rb:

module Devise
  module Strategies
    class LocalOverride < Authenticatable
      def valid?
      def authenticate!
        if params[:login_user]
          user = LoginUser.find_by_login(params[:login_user][:login])
          # trap our domain only
          if params[:login_user][:login] =~ /
            # fail! halts the authentication chain completely
            return fail! unless ::Devise::LDAP::Adapter.valid_login?(params[:login_user][:login])
            class << user
              # make use of ldap_authenticatable for custom strategy only
              devise :ldap_authenticatable
            return fail! unless user.valid_ldap_authentication?(params[:login_user][:password])
            # use the after_ldap_authentication hook
            return success!(user)
Warden::Strategies.add(:local_override, Devise::Strategies::LocalOverride)

In config/initializers/devise.rb:

  # use local_override as default strategy
  config.warden do |manager|
    manager.default_strategies(:scope => :login_user).unshift :local_override

In config/models/login_user.rb:

class LoginUser < ActiveRecord::Base
  devise :database_authenticatable,
         :recoverable, :trackable, :secure_validatable,
         :authentication_keys => [:login]
  def after_ldap_authentication
    # force fresh password every log in
    self.password = self.password_confirmation =
defaults:  &defaults
  host: our.ldap
  port: 636
  attribute: mail
  base: dc=IDENT,o=Orgname
  admin_password: adminpassw0rd
  ssl: sslmethod

See local_override.rb for original tip that got me there.

devise_security_extension undefined method authenticate for nil:NilClass on Rspec Tests for Controller That Skips Authentication

After installing the Devise Security Extension to add password expiration to my Devise models, I started getting the following error on an RSpec test for a controller that does not perform authentication of the user:

     Failure/Error: get :index
       undefined method `authenticate?' for nil:NilClass

After a bit of digging, I found that the helpers.rb in the gem includes an additional before_filter that needs to be skipped:

module DeviseSecurityExtension
  module Controllers
    module Helpers
      extend ActiveSupport::Concern
      included do
        before_filter :handle_password_change

So while I'm skipping authenticate_user! in my controller, I still needed an additional:

  skip_before_filter :handle_password_change

Interestingly enough, the controller itself doesn't break, just the tests. The downside is that I'm referencing two different Devise filters/actions just to not use them.