1

I'm using Rails 4 with Devise and I've got a situation where I need to log someone in where the password is made up of 2 separate input fields. After submitting, I need to combine the 2 inputs to form the password before the params get used to authenticate them.

I know the login details are correct because if I have a single password field it all works as expected.

As a test I've tried to submit a blank password and then intercept the params in the sessions controller by temporarily hard coding the correct password - e.g.

class SessionsController < Devise::SessionsController
  def create
    params[:user][:password] = "ABCDE-12345"

    [... the rest of the standard devise sessions controller ... ]
  end
end 

But that simply doesn't work. Something is happening before hitting this controller and any pointers on how I can intercept the submitted parameters would be appreciated. Code for the Devise controller is here:

https://github.com/plataformatec/devise/blob/master/app/controllers/devise/sessions_controller.rb

Do I need to write a custom Warden strategy perhaps?

Chris Lewis
  • 1,315
  • 10
  • 25

2 Answers2

1

Your test may have failed because authentication may have happened earlier before the action is processed (or even before the before_filter callback). For example, an extension that calls current_user early in the execution chain. After you altered the params, warden.authenticate! is still called but the strategies aren't performed because they've been performed before (when the presumably current_user was called), that's how warden does things.

So I guess that leaves you with three options:

  1. Find where the authentication is early performed and alter your params accordingly before it
  2. Implement a custom strategy
  3. Override params_auth_hash method in an initializer
Ahmad Sherif
  • 5,923
  • 3
  • 21
  • 27
0

Well I've ended up with a custom Warden strategy (in config/initializers/xyz_authentication_strategy.rb):

Warden::Strategies.add(:xyz_authentication_strategy) do
  def valid?
    true
  end

  def authenticate!
    return fail! unless params[:user]
    user = User.find_by(login: params[:user][:login])
    return fail! unless user

    password = "#{params[:user][:input1]}#{params[:user][:input2]}"
    user.valid_password?(password) ? success!(user) : fail!
  end
end

and in config/initializers/devise.rb:

config.warden do |manager|
  manager.default_strategies(scope: :user).unshift :xyz_authentication_strategy
end

Further reading on custom strategies: Custom authentication strategy for devise

Community
  • 1
  • 1
Chris Lewis
  • 1,315
  • 10
  • 25