Rails block user account if failed test during registration process - ruby-on-rails

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

Related

How do I update a user without a token while using Devise token Auth?

As a part of my application, when I send an invitation out to other users, I need to set a bunch of parameters for the newly created user before they even sign into the application. So, before switching to DeviseTokenAuth(and rails api), I used devise and it allowed me to make user changes from the back-end. For example, if I go to the console and do a user.save, it returns true.
Now after switching to DeviseTokenAuth, I had to enter the following in concerns file within the User model:
include DeviseTokenAuth::Concerns::User
Once i included this, I am unable to make changes to the user from the backend, (for example, rails console> user.save returns false). I presume that it requires a Token every time a user is updated? How can I skip this for specific controller actions where for instance, I would need to update the user withouth the user/client actually calling the action. (sending a token)
In case somebody else comes across this issue: I spent a few hours shooting in the dark finally to realize that it that the uid field for the User object needs to be populated with DeviseTokenAuth. If not, user will not be updatable. i.e.user.save will return false
In my case, I was sending an invitation using devise_invitable which is currently outside the bounds of DeviseTokenAuth defaults. So, when you create a new user using the invite method of Devise_invitable gem, the UID, provider fields are not automatically set. I just needed to add 2 line of code post invitation:
u= User.invite!(params[:email])
u.uid=params[:email] #added
u.provider='email' #added
u.save #added
Now the user object works fine, it had nothing to do with the token itself - so my previous assumption stated in the question was humbug.

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.

Rails: single sign on session based authentication

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

Authlogic and multiple sessions for the same user

I'm using Authlogic to manage the sessions in my application.
However, by default, authlogic allows a user to be logged in many times from different computers.
I don't want that (the user pays to get access and I want to avoid users sharing their accounts).
Looking in the Authlogic documentation, I've found about the perishable_token. But when trying to implement it, I just get an error saying the persistence_token is required (when it shouldn't be as I use the perishable one).
How would you do this using the Authlogic's features ?
Thanks :)
Ok so the perishable token was absolutely not the right path ;)
We "just" need to reset the persistence token every time a user logs in or logs out.
With this in my UserSession model, every user gets logged off from any other session when logging in.
class UserSession < Authlogic::Session::Base
before_destroy :reset_persistence_token
before_create :reset_persistence_token
def reset_persistence_token
record.reset_persistence_token
end
end

Resources