How to debug devise/warden? - ruby-on-rails

I am trying to setup devise in my rails app. It was working nicely, but now I am not able to login as any of my users I get 'Invalid email or password.' I would like to get more insight why its not authenticating.
Is there any devise configuration settings that shed some more light? i.e. what is the query being used to find the user, et c ...
Thanks!

Normally Devise not provide an accurate logging system, maybe overriding the default controller you can catch what is going wrong. Try something like this:
# app/controllers/sessions_controller.rb
class SessionsController < Devise::SessionsController
def new
super # or perform some custom task
end
end
Remember then to configure the routes too.
# app/config/routes.rb
devise_for :users, :controllers => {:sessions => "sessions"}
For more details about the default Devise sessions controller take a look at this:
https://github.com/plataformatec/devise/blob/master/app/controllers/devise/sessions_controller.rb
OR
You can login with ssh to your remote server, run rails console and do manually some checks (check that users exist, try a login via console,...), alternatively you can create a rake task with some testing and run remotely.

Related

Devise close registration but seed database with admin account

I'm looking to completely close off my registration system (temporarily) and only have 1 admin account that can be either raked into the database or seeded.
Is this possible with Devise at all? Or will a closed off registration also close off the seed/rake task with my admin user in it?
I currently have a user model with the typical devise setup, with an admin column that is a boolean - I'm currently setting that column in development by going into rails console and manually changing it.
Any help would be brilliant!
Thanks
There is a detailed step by step in the devise wiki; but basically you can either skip generating the registrations routes:
devise_for :users, :skip => :registrations
Which would make it a single user system by making it impossible to register.
This requires the first user to be created with either a seed file or through the console.
Or you could create your own controller to handle registrations which cuts off after the first user:
devise_for :users, :controllers => {:registrations => "registrations"}
# app/controllers/registrations_controller.rb
class RegistrationsController < Devise::RegistrationsController
def create
if User.any?
redirect_to root_path, alert: 'Only one user allowed!' and return
end
super
end
end
Unless your seed / rake task is doing something really strange like automating a web browser then this will have no effect on your seed / rake task since they usually involve directly manipulating the DB through models and do not go though controllers at all:
# Example of seeding an admin user:
admin = User.create_with(surename: 'Doe', forename: 'John').find_or_create_by(email: 'admin#example.com')
admin.add_role(:admin)
You should be able to remove the devise routes for registration and still seed in the user. That user would then be able to login/logout, as long as you still have the devise routes for sessions.

Ruby on Rails Devise code after login

I have an RoR app using Devise for logins. There is some code that is executed when a new User record is created, by being put in the user.rb file as an after_create call/macro/whatever. I need to make this code run after each login, instead of running on new user creation.
With some Googling, it seems that one option is to place Warden callbacks in the devise.rb code. My questions are:
Is this right, and/or is there a better way to do this?
If this is the right approach ...
Should the Warden::Manager... method defs go in devise.rb inside of Devise.setup, or after it?
Is after_authentication the callback I should use? I'm just checking to see if a directory based on the user's name exists, and if not, creating it.
Just subclass Devise's sessions controller and put your custom behaviour there:
# config/routes.rb
devise_for :users, :controllers => { :sessions => "custom_sessions" }
And then create your controller like this:
# app/controllers/custom_sessions_controller.rb
class CustomSessionsController < Devise::SessionsController
## for rails 5+, use before_action, after_action
before_filter :before_login, :only => :create
after_filter :after_login, :only => :create
def before_login
end
def after_login
end
end
I found that using the Devise Warden hook cleanly allowed after login event trapping by looking for the ":set_user" :event.
In user.rb:
class User < ApplicationRecord
Warden::Manager.after_set_user do |user, auth, opts|
if (opts[:scope] == :user && opts[:event] == :set_user)
# < Do your after login work here >
end
end
end
I think this is an duplicate question. Yes you can execute code after every successful log in. you could write the code in your ApplicationController. Also have a look at http://github.com/plataformatec/devise/wiki/How-To:-Redirect-to-a-specific-page-on-successful-sign-in. Also, check out How to redirect to a specific page on successful sign up using rails devise gem? for some ideas.
You can do something like:
def after_sign_in_path_for(resource_or_scope)
Your Code Here
end
Reference Can I execute custom actions after successful sign in with Devise?
You could also inherit from devise session's class and use after_filter for logins.
UPDATED 2022
Warden now has built-in callbacks for executing your own code on after_authentication:
Warden::Manager.after_authentication do |user, _auth, _opts|
TelegramService.send("#{account.name} just logged in")
end
Source: https://github.com/wardencommunity/warden/wiki/Callbacks#after_authentication

rails: how to check admin user for setting up a route?

I need to set up a route that is only valid if the logged in user is admin (user.admin?) using devise. I'm doing this for sidekiq, but the question is valid for any similar use.
Here is my route code:
class AdminConstraint
def matches?(request)
!request.session['warden.user.user.key'].nil? and request.session['warden'].user.admin?
end
end
require 'sidekiq/web'
mount Sidekiq::Web => '/sidekiq', :constraints => AdminConstraint.new
I got this code from the sidekiq wiki: https://github.com/mperham/sidekiq/wiki/Monitoring
I tried the code they posted, which didn't work so I made some modifications as I just posted. The code above doesn't work as user evaluates to nil.
What is the correct secure way to deal with this?
thanks for any help!
If you are using devise to authenticate users, what you need to do is as follows:
Inside your routes.rb file, replace this line:
mount Sidekiq::Web => '/sidekiq', :constraints => AdminConstraint.new
with this block:
authenticate :user, lambda { |u| u.has_role? :admin } do
mount Sidekiq::Web => '/sidekiq'
end
What the block does, is telling to your devise mechanism to check first if the user is authenticated (the authenticate method is a devise method), and also that the user has the admin role (which the lambda block checks), before defining the route to the sidekiq UI.
This way, only users with an admin role will be able to access this route. Other users will get routing error in development and 404 error in production.
One more thing, the has_role? method is a rolify gem which in my case I use, but you can replace it with any other method/query that checks if the user is admin.
You're not really trying to change the route depending on who the user is (I'm not even sure if it's possible in rails without a lot of hacking), you're trying to authorize a user's action.
There are several good authorization libraries. Personally I like CanCan, but there are many others.
if you are doing any type of filtering in the controller for devise you can use the helpers
class ###Controller < ApplicationController
before_filter: :authenticate_admin!
def index
end
or whichever devise model you are trying to allow access for i.e
before_filter: :authenticate_user!
before_filter: :authenticate_author!
like bdares said. you can use the CanCan gem for authorization if the helper methods in devise isn't enough
hope it helps!

Devise: user has to login again each time he closes the browser

I'm using Devise and Omniauth for user authentication.
I want the users to stay signed in for 2 weeks after the authentication. However, whenever the user closes the browser window and reopen it, he gets the login screen again.
What is the correct configuration for the user to stay connected even after the browser was closed and re-opened?
Check out this page on Devise's wiki:
https://github.com/plataformatec/devise/wiki/Omniauthable,-sign-out-action-and-rememberable
Basically, Devise does not call rememberable by default when using omniauth. If you wish to do so, simple call remember_me(#user) on your omniauth callback and Devise will do the hardwork for you. It will also use all the configuration options set in your devise initializer.
You have to extend the devise SessionsController to add cookies on log in and log out, so the controller will look like this one:
class SessionsController < Devise::SessionsController
# POST /resource/sign_in
def create
cookies[:sign_in] = "Sign in info you want to store"
# add this for expiration { :expires => 2.weeks.from_now }
super
end
# GET /resource/sign_out
def destroy
cookies[:sign_out] = "Sign out info you want to store"
super
end
end
Then you would have to add the following to your routes.rb:
devise_for :users, :controllers => { :sessions => "sessions" }
You may also set the cookie expiration time for 2 weeks.

Devise/Rails - How to allow only admin to create account for others?

I am using devise as my authentication solution and now i am thinking about authorization. In my project I (the admin) is the only person authorized to create account for others.
I wonder if there is a way to do it without to much hack. In fact, Devise doesn't allow user to access to the signup page if he is already logged in.
Thanks for your advice on it!
Setting :skip => :registrations also kills the ability for a user to edit their user info. If that's not what you are after you can instead create a (minimal) custom registrations controller and only remove the new_user_registration_path while preserving the edit_user_registration_path.
# app/controllers/registrations_controller.rb
class RegistrationsController < Devise::RegistrationsController
def new
# If you're not using CanCan, raise some other exception, or redirect as you please
raise CanCan::AccessDenied
end
end
# routes.rb
devise_for :users, :controllers => { :registrations => "registrations" }
Once you do this you also need to move the directory views/devise/registrations to just views/registrations.
You can try the rails_admin gem in conjunction with Devise to handle any admin-specific tasks. You'll need to add more code to set it up, but at least you avoid hacking around the solution in terms of changing your interactions with Devise.
It actually looks like in the later versions of Devise you can just remove the "registerable" declaration from your model and it will take care of this for you.

Resources