Rails: single sign on session based authentication - ruby-on-rails

I am using a single sign on authentication system in front of my rails application so you cannot access the application at all until you have authenticated through our business authentication system.
Once authenticated I want to set up role based Authorization but I believe I still need to set up some sort of User model for this to work.
I am keen to use cancan for authorization, and possibly easy-roles for the roles. but how do I go about registering the current logged in user? I have simply been accessing the session variables up until now.
I cannot use the session variables for the roles as I do not have any control over our single sign on system.
I have searched for some simply how to's but haven't been able to find one.

I have created a controller for Admins and entered all the admin users into that and am simply going to implement very basic authorisation like in ryan bates early railcast : http://railscasts.com/episodes/20-restricting-access
I am restricting access on each controller and in the views. I feel its a little dirty, but it works.
In the admin checking function I check to see if the sessions user credentials are in the table:
helper_method :admin?
def admin?
admin = Admin.find_all_by_username(request.env["SPEP_ATTR_uid"])
if admin.empty?
false
else
true
end
end
def authorize
unless admin?
flash[:error] = "unauthorized access"
redirect_to home_url
false
end
end

Related

Rails block user account if failed test during registration process

I want to build User registration flow where user signup to the blog_app and after account confirmation (via email link) he/she will be able to log in but have no ability to access their posts if he/she doesn't pass Legal Test (after the User account is confirmed, they should be presented with the Legal Test before they can do anything else, user needs to pass the test only once).
For authentication I'm using Devise gem.
I'm wondering should I use some Devise build-in module such case? or should I create additional DB column in Users table with status e.g. status: 'passed' or status: 'faild' and use pundit policy to block access in case User didn't passed the Legal Test?
Yes, you should an authorization gem like Pundit to manage authorization.
To accomplish something like this in Devise you would need separate roles for a "passed user" and a "failed user". It will quickly get messy and confusing as it's really not what it's meant for.
Using an authorization gem like Pundit is the way to go for your use case.
Yes, you will have to add a new column like status where you store the status and then override the devise's active_for_authentication? method so that the user is not allowed to login if he/she is marked as failed/banned:
def active_for_authentication?
super && self.status != 'failed'
end

Sign out specific user with Devise in Rails

I have Devise for user authentication.
I want to sign out a user with a specific id.
in my controller
def exit
#user = User.find(5)
sign_out(#user) # this line here signs out the current_user
end
The sign out command of devise, even though I pass the #user, it signs out the current_user.
How can I select a user from the database and sign him out with the devise commands?
I am assuming this is part of some admin module, where you want to sign out a particular user.
However, this is not easy to solve. Whether or not a user is signed in or not is stored in the session. So to sign out another user, you would have to have access to its session.
Note: afaik the sign_out method only works in the current session, or maybe through warden (do not know warden well enough) it could extend to all sessions this current server has ever touched. However: if you use passenger, or some form of rails server cluster (which is pretty common), afaik this will not work. I would be interested to hear otherwise, with some explanation :) The sign_out uses the given parameter to determine the scope to sign out from in (afaik) the current session.
So what we generally did was add a kind of emergency button to sign out all users: which destroys all sessions. Note this is of course only possible if you use some database or document-store backed session-store.
Alternatively you could open all sessions, and look for the correct session (for your user), and then destroy those sessions.
To read data from a specific session in stored in activerecord, you can write the following:
#session = ActiveRecord::Base.connection.select_all( "SELECT * FROM sessions WHERE session_id = '#{sess_id}'" )
Marshal.load(ActiveSupport::Base64.decode64(#session.data))
There are alternative approaches:
use Timeoutable module, and force a timeout for a user?
if you use Rememberable you could do #user.forget_me, but I am not sure that this actually affects the current session?
from the device api doc http://rubydoc.info/github/plataformatec/devise/master/Devise/Controllers/SignInOut#sign_out-instance_method the sign_out(#user) method should works. Is it possible that the current_user by chance has the id 5?

rails authentication for an API

I'm currently working on an application that in addition to the usual visual web application goop also will expose a few RESTful API services for use by outside applications. I am using Devise to manage user authentication but I'm struggling with how to "manually" authenticate a user given certain input.
The case I have is that I want a user of the API to log in w/o actually going to the visual log in screen etc. I want them to submit a username and password and then authenticate and sign them in in my API services.
I know that you can sign a user in using the sign_in method that Devise provides, but that seems to ignore authentication entirely. here's what I wanted to do explained in a bit more detail:
Assume a GET route called connect in the user controller. the controller is replacing entirely the Devise registrations controller, but not the session one. The URL to my service would be:
<server>/users/connect
and it would expect 'email', 'password' parameters in addition to some service specific and unimportant to my question goop.
What I want to know is how to implement something that is equivalent to the following pseudocode:
def connect
user = User.find_by_email(params[:email])
password = params[:password]
# here is the part I'm pseudo coding out
if user.is_valid_password(password)
...do my stuff...
end
render :json ...etc...
end
I have been unable to find a method in the Devise source to do this--it's so generalized in so many ways that I'm likely just missing it.
Anyone have any ideas? I'm hoping not to a) have to implement my own thing and b) not have to move away from Devise. It provides me with so much for the non-API services...
thanks!
I've left out th
Devise's token_authenticatable is the way to go for this. We've successfully used it many times to do api-based logins.
In config/initializers/devise.rb
config.token_authentication_key = :nameofyourapikeyhere
In user.rb:
devise … token_authenticatable, ...
In the above, you can name the api key anything and then have your route as /users/connect?apikey=whatever (using apikey as an example). In the database, it'll be authentication_token, but it'll work fine.
To clarify, if the user has an authentication_token and it's sent in the params (or it's alias- in the above example: apikey), they'll login.

Do Rails' Devise, AuthLogic, Restful Authentication all use the same method names or mechanism such as current_user and session[:user_id]?

I see similar usage all the time, even in Rails guide such as http://guides.rubyonrails.org/security.html
For example, current_user returns the current logged in user, logged_in? returns whether there is a logged in user, #current_user stores
the logged in user (so no need to look into DB again), session[:user_id] stores the user id
of the current logged in user so as to know what the logged in user is on a second or later webpage request (need to look into DB), remember_token is the users table field to check against cookies[:auth_token],
so as to remember the user even when the user closes the browser (so the session ends and session cookie disappears)
Do Devise, AuthLogic, and Restful Authentication all use these names / mechanism?
I am not sure but I think they don't because restful uses logged_in? while devise uses user_signed_in? where user can be replaced by your model...

How do I tell a signup page where to redirect to after submission in ruby on rails?

I have a ruby on rails app that has a signup page. Different pages redirect to the signup page and need to set another page to redirect to after the sign up is complete. What is the best way to do this? I'm currently doing this:
link_to '/signup?redirect=/blah/page6
...and getting the redirect variable in the signup controller and using that to set the after signup page. I'm worried that this may cause some security issues, but I'm not really sure.
Is this acceptable or is there a better way?
I use these 2 methods to help with this in my application_controller.rb:
def store_location
session[:return_to] = params[:redirect]
end
def redirect_back_or_default(default)
redirect_to(session[:return_to] || default)
session[:return_to] = nil
end
When they reach the signup page, just run store_location, and when it's finished and complete, use the redirect_back_or_default method.
(Of course modify this to your liking)
Have you used a plugin/gem for authentication? I suggest Clearance or Devise if you haven't. Clearance redirect you to 'where you came from' automagically, and both are as secure as the 100's of dev's who are working on them and using them have let it become (so that means pretty secure).
Right now I prefer Devise having said all that.
Garrett's solution looks like it comes from Restful authentication, which is another good authentication plugin.

Resources