how to implement second level authentication in rails? - ruby-on-rails

I have a devise authentication already setup in my application.Now i want to implement second level authentication in rails. i want to hard code the email and password in coding in controllers. i want to compare this email and password with the email and password provided by the user. rather than saving in database and picking for second level authentication.,Because these 5 to 6 links are going to be used by only one person in the company at any point of time. i want to implement this for a 5 to 6 actions in my application in controller. how can i implement this? i checked a gem gem 'devise-authy' but it seems it sends a password to mobile for otp authentication. i dont want otp authentication. i want a second level authentication with the same email as devise email but the password should be different from the devise original password.(like in devise table i want to take one more column second_level_password.) is there any gem for this kind of requirement or is this manually coded. if it is manually coded then how can i do that?

You can use before_action in rails controller.
Add following line of code in your controller.
before_action :second_level_access
private
def second_level_access
#You can use your logic to get password
unless current_user.second_level_password == params[:second_level_password]
# signout to user because user is already logged in with devise.
redirect_to session_path
end
end
EDIT
You can use
attr_accessor_with_default :second_level_logged_in, false
add following line to application controller:
before_action :logged_in_with_second_level, if: 'current_user and !second_level_logged_in'
def logged_in_with_second_level
redirect_to 'second_level_logged_in_form_page'
end
in create action of second_level_logged_in
add code current_user.second_level_logged_in=true

Related

Setting Pundit role for user from Devise Registrations New View / Controller

I have both Pundit and Devise setup and working correctly in my rails app. However I am unsure about how to let the user decide their role when signing up.
At the moment:
I have a URL param which is passed to the Devise new view.
In the form_for I set a hidden field called role to the value of the param.
This works.
But I am concerned that a malicious user could change this param to say "Admin" and now they are an admin.
How should I handle this? I don't want to put a restriction in the model as that will cause issues when I want to create an admin. Should I override the devise registrations controller to put a check in there?
You don't need to override Devise's RegistrationsController for what you're trying to do.
If you want admins to be able to create users that have an arbitrary role set, you could simply use your own controller. Devise still makes it easy to create a user yourself, so you'll just have to make a controller handling this. Of course, don't forget to protect it using Pundit so only admins can use this functionality.
This approach still works if you use the Confirmable module. As no confirmation e-mail will be sent on user creation, though, you'll either have to call user.confirm! after saving the model to immediately unlock the account, or manually send the confirmation e-mail using user.send_confirmation_instructions.
Edit:
This Pundit policy may or may not work for what you're trying to do. You will have to override the create action of Devise's RegistrationsController here in order to use Pundit's authorize method. For dryness' sake, you should also move the roles list elsewhere, perhaps into the model.
class UserPolicy < Struct.new(:current_user, :target_user)
def create?
registration_roles.include?(target_user.role) if current_user.nil?
end
private
def registration_roles
%w(RED BLU Spectator)
end
end
After a fair amount of googling I have an answer. First stick some validation in your model for the roles Active Record Validations Guide: See 2.6 inclusion: validator option
After this your roles are validated to ensure they are correct, you could of course have a lookup table as well. Then you have two options:
Use a conditional before_save Callback for new records. Then check if the new record has the role your protecting and if so raise an error. To catch later (in an overridden devise controller (see second option).
Override the Devise registrations controller See this SO question. And put some checks in a completely overridden create action. Use the session to store the url param passed to the new action (also needs to be completely overridden). Then if the create action fails and redirects to new you still have access to the role in the session (as the param will be cleared from the URL unless you manipulate it).
So either way you need to override the registrations controller, its just a case of how much.
I suspect there is a way to do this with just Pundit. But I have yet to be able to get it to work.

Devise log in with one more condition to check

I´m using devise gem in a rails 4 app and I have in my user table a column called valid that by default is false, when the user registers in the site it should send me a email with the information about them and approve it, and put that valid column in true. So then in the log in action it will check that valid is true and let them login to the site.
My question is how modify that login action that takes care of the valid column in users table.
You should look at adding :confirmable to your User model, it may take care of most of what you are looking to do.
Otherwise, if you want to modify whether someone can login, look at the wiki on how to customize account validation.
From the wiki:
def active_for_authentication?
# Uncomment the below debug statement to view the properties of the returned
# self model values.
# logger.debug self.to_yaml
super && account_active?
end

Devise, Ruby on Rails, Change format of login details before authenticating

We were using devise with an email, but we are now transitioning to a mobile login (user gives their mobile number) since this is the only info we need. Email would be good but not required.
I have got it working with mobile number authentication with:
config.authentication_keys = [ :mobile ]
It works, if you enter the number exactly as entered. Though there are many ways people can enter in a number (vs email)
i.e
in the local format
0125551234
or international
27125551234
I actually normalize the mobile number when i store it in the DB, so would like to use the same normalization before authenticating.
Is there a way to do it other then just overriding the sessions controller?
Update:
Used the following method: https://github.com/plataformatec/devise/wiki/How-To:-Allow-users-to-sign-in-using-their-username-or-email-address
The reason is we have some users already, and we need to allow them to login with email as well if they did not capture their mobile.
You can specify a method in your ApplicationController (only since you don't want to override SessionsController) that will convert params[:mobile] to whatever format you want.
prepend_before_filter :format_mobile_param
def format_mobile_param
return unless params[:mobile]
params[:mobile] = your_formatting_method(params[:method])
end
This will alter the params before the call is made to authenticate_user! (assuming you call authenticate_user! in a before filter).
I think the best way would be to override the SessionsController, just add a prepend_before_filter :format_mobile_param. Don't forget to scope this method to the create method of SessionsController.
Also, dont forget to add the controller routes. Hope it helps.

activeadmin change password button

I know how to change the password using devise but I don't know how to create a link to an action for the current admin user. For example adding a link under the email.
Change password
and that would send to an action calling:
send_reset_password_instructions
I can't really find any good documentation for ActiveAdmin, the official site expose some examples but nothing there is really explained. Its unclear where and how things works.
You'll want to look at ActiveAdmin's documentation on custom controller actions. I've accomplished this by creating a "member_action" (a custom controller action which acts upon a single record), and adding an "action_item" to perform it (those are the buttons which appear in the top right when viewing a record). Here's how I make it work:
# in app/admin/admin_users.rb
action_item do
# Link to perform the member_action, "reset_password" defined below
link_to("Reset Password", reset_password_admin_admin_user_path(admin_user))
end
member_action :reset_password do
# Find the user in question
admin_user = AdminUser.find(params[:id])
# Call the method (from Devise) which sends them a password reset email
admin_user.send_reset_password_instructions
# Redirect back to the user's page with a confirmation
redirect_to(admin_admin_user_path(admin_user),
notice: "Password reset email sent to #{admin_user.email}")
end

rails devise hook into on_login

I'm looking to hook into devise after login / after session create. How would I go about doing this?
Basically I want to set a users location every time they login, and to do that I need an after login hook of sorts.
Devise is built on Warden, so you can use Warden's after_authentication hook.
Put this in an initializer:
Warden::Manager.after_authentication do |user,auth,opts|
# do something with user
end
The remote IP address and other request info is stored in auth.request (i.e. auth.request.remote_ip).
See https://github.com/hassox/warden/wiki/callbacks
Devise updates the value of the user.current_sign_in_at timestamp on successful login. So, you could simply add a before_save filter to your User model. In that filter, check to see if the value of this field has changed, and if it has, set the users location.
BTW - I'm not sure what you mean by "location" - if you mean IP address, Devise already stores that for you.
Here's a page from the devise wiki: How To: Redirect to a specific page on successful sign in.
In summary, the recommendation is to add the following method to the application controller:
app/controllers/application_controller.rb
def after_sign_in_path_for(resource)
custom_location_for(resource) || welcome_path
end
In the above code, resource means the object (user, account, etc) that you've implemented devise authentication for. (The object that has the devise_for in your routes.)

Resources