0

I'm using a combination of a custom user database with has_secure_password and active dirctory for authentication. If a user is marked as an Active Directory user then I'll authenticate against AD, otherwise against the database.

I want to overide has_secure_password's authenticate method to reflect that.

I know I can handle it in the controller or though a new method that calls authenticate, but would prefer a proper override

Is there a way to do something like this:

class User < ActiveRecord::Base

  # Here is how I make the validation work out, if that matters:
  has_secure_password :validations => false
  validates :active_directory_user, presence: true, unless: :password
  validates :password, presence: true, length: { minimum: 6 }, unless: :active_directory_user
  validates :password_digest, presence: true, unless: :active_directory_user

  # Here is what I want to do
  def authenticate(pass)
    if self.active_directory_user
      active_directory_auth(pass)
    else
      # this doesn't work, I need to somehow reference the non-overriden function
      self.authenticate(pass)
    end
  end
end
OneHoopyFrood
  • 3,829
  • 3
  • 24
  • 39

1 Answers1

0

Alright, I figured it out. I needed to use some monkey patching as detailed here. I used the Method Wrapping section's suggestions.

The end result is:

class User < ActiveRecord::Base
  # Must have either password or be a active directory user
  has_secure_password :validations => false
  validates :active_directory_user, presence: true, unless: :password
  validates :password, presence: true, length: { minimum: 6 }, unless: :active_directory_user
  validates :password_digest, presence: true, unless: :active_directory_user

  # Mokey patch on authenticate to use active directory
  old_autheticate = instance_method(:authenticate)
  define_method(:authenticate) do |pass|
    if self.active_directory_user
      active_directory_auth(pass)
    else
      old_autheticate.bind(self).(pass)
    end
  end

  private
    def active_directory_auth (password)
      domain = "domain"
      ldap = Net::LDAP.new
      ldap.host = '<ad ip>'
      ldap.port = 389
      ldap.auth self.username + "@" + domain, password
      if ldap.bind
        self
      else
        false
      end
    end
end
Community
  • 1
  • 1
OneHoopyFrood
  • 3,829
  • 3
  • 24
  • 39