Search code examples
authenticationdeviseruby-on-rails-3.2

Devise log after auth failure


I need to write a log when somebody failes to log in to my app (to track bruteforce attempts). Also I decided to log successful authentications. So I created a SessionsController < Devise::SessionsController and tried to override the sessions#create method like that: https://gist.github.com/3884693

The first part works perfectly, but when the auth failes rails throws some kind of an exception and never reaches the if statement. So I don't know what to do.


Solution

  • This answer to a previous SO question - Devise: Registering log in attempts has the answer.

    The create action in the devise controller calls warden.authenticate!, which attempts to authenticate the user with the supplied params. If authentication fails then authenticate! will call the devise failure app, which then runs the SessionsController#new action. Note, any filters you have for the create action will not run if authentication fails.

    So the solution is to add a filter after the new action which checks the contents of env["warden.options"] and takes the appropriate action.

    I tried out the suggestion, and was able to log both the successful & failed login attempts. Here is the relevant controller code:

    class SessionsController < Devise::SessionsController
      after_filter :log_failed_login, :only => :new
    
      def create
        super
        ::Rails.logger.info "\n***\nSuccessful login with email_id : #{request.filtered_parameters["user"]}\n***\n"
      end
    
      private
      def log_failed_login
        ::Rails.logger.info "\n***\nFailed login with email_id : #{request.filtered_parameters["user"]}\n***\n" if failed_login?
      end 
    
      def failed_login?
        (options = env["warden.options"]) && options[:action] == "unauthenticated"
      end 
    end
    

    The log has the following entries:

    For a successful login

    Started POST "/users/sign_in"
    ...
    ...
    ***
    Successful login with email_id : {"email"=>...
    ***
    ...
    ...
    Completed 302 Found
    

    For a failed login

    Started POST "/users/sign_in"
    ...
    ...
    Completed 401 Unauthorized 
    Processing by SessionsController#new as HTML
    ...
    ...
    ***
    Failed login with email_id : {"email"=>...
    ***
    ...
    ...
    Completed 302 Found