Implementing a simple sign up/log in system in Rails using cookies - ruby-on-rails

I'm fairly new to Rails and I'm trying to implement a really basic user authentication system. My main problem right now is that I do not have a clue what's a good design for this.
What I have now
My Rails app is not a website; it's a webservice that communicates with an iPhone app. All communication is in JSON.
When a user signs up, the app sends a POST request to /users.json with name and password as JSON in the HTTP body. Rails then saves the user id in a cookie:
cookies.signed[:user_id] = #user.id
When a user logs out, the app sends a POST request to /logout.json. Rails gets the user id from the cookie, updates the database and deletes the cookie.
Later, when the user wants to log in again, the app sends a POST request to /login.json with name and password as JSON in the HTTP body. Rails sets the cookie again.
My question(s)
Is this design RESTful? Because login and logout aren't resources.
Is it secure to use cookies like this? I'm planning to use SSL.
Is there a better way to do this?

Tt's a very basic approach
A more RESTful way:
Create a controller called sessions with a create and destroy action. Throw the login/logout out of your head and start thinking in sessions. A login is just a username/password combination. When you login you create/start a session, when you log out you destroy the session. The login is not affected.
Instead of using cookies.signed[:user_id] you should use session[:user_id]
SSL is a big plus, because the password can't be sniffed through the network.
And there are lots of out-of-the-box authentication systems.
My favourite is Devise:
https://github.com/plataformatec/devise
http://asciicasts.com/episodes/209-introducing-devise
http://railscasts.com/episodes/209-introducing-devise

there is a nice screencast ryan bates did on authentication from scratch
http://railscasts.com/episodes/250-authentication-from-scratch

No, for the reason you stated.
No, you need to pass a second parameter to encrypt the user's id.
Well, you could use a gem, there's a few about.
If you do want to code it yourself, then I'd recommend looking at a tutorial. The one at railstutorial.org is pretty good.
The basic idea is to create a user model with an encrypted password, which uses a salt formed from the current time and password. You then create a sessions controller and make it RESTful, but using cookies instead of another resource. Make sure to encrypt the cookie with the salt as well:
cookies.permanent.signed[:remember_token] = [user.id, user.salt]

Related

Devise: How to use remember_me cookie after user sign out?

I'm working on a Rails 4.2 Application and using devise gem for authentication.
For remember_me feature, devise generates a cookie remember_user_token which gets destroy after sign_out.
Is there a way such that Devise should not destroy remember_user_token ?
I tried to false the below config in the initializer
config.expire_all_remember_me_on_sign_out = false
But it didn't help.
I need that cookie after sign-out such that it will populate the login form.
Please help.
Thanks
Coupling authentication with form pre-filling isn't necessarily a good idea. You can store the login in a cookie upon successful login. You can override the create method in your SessionsController, call super to call Devise::SessionsController#create and pass it a block. The block will be executed after a successful log in and will receive the user as a parameter.
class SessionsController < Devise::SessionsController
def create
super do |user|
cookies[:login] = user.login
end
end
end
Here is the low down on cookie store. First off, everything in a cookie is there permanently once it's set or until the user deletes the cookie manually somehow. This means, that if you set user_id and user_group_id, it's there for good in the cookie until updated or deleted. This is different from a session since the session is like ram on a computer, once the browser is closed, the session closes with it as well as all of it's data.
So, this means that when you log out your user, you need to specify that their cookie empties anything you don't wan't it to have. When your user logs in, you set anything that you want the user to have while they are logged in. So, since the session and cookie are separate things completely, they never interact together unless you choose to make them. So your session will never dump its self into the cookie store unless you make it do that.
Every time your users go to your site, you could have a single handshake that makes sure that the cookie matches the db if necessary. Otherwise, you could have differing data what only gets updated on login or what not and without the handshake, the user would have to keep logging in to make sure they are still valid which defeats the purpose of having a cookie in the first place.
The downside of client side cookie storage is security concerns. Depending on how you use the cookie to store data, a person could hijack somebodies cookie on your site and pretend they are them. This can be avoided by careful design, but just assume that whatever is in your cookie store is fair game to everybody so use it carefully and for only non secret data.
Hope this helps!

Persisting user sessions when switching to a new domain name (Ruby on Rails)

My Rails app is currently available at example.org, but I want to switch to example.com
Doing a wildcard 301 redirect in routes.rb isn't a problem, but I would like to persist the user sessions as well. Since the new domain won't have access to the cookies of the old domain, what's the best (secure and as easy as possible) way to redirect the user to the new domain and still have him/her signed in?
I've found numerous of threads talking about setting up cross-domain web apps using complicated authentication tokens methods, but I'm looking for a one-time one-way migration so I'm hoping the solution will be simpler for this.
Any suggestions?
I'm using Ruby on Rails 3, OmniAuth, and using the default 'cookie_store' as my session store.
You could just do it the same way as when you might send an email link with an authentication token. Check to verify that the cookie is correct on example.org and, if it is, redirect them to:
http://example.com?token=<their token>
and then check to make sure the token matches the one you have in the DB when they arrive. If the token does match, create the session cookie for the example.com domain and then change the token in the database.
This will successfully transfer from one domain to another while providing persistent login on the new domain (via cookie) and shutting the door behind them by changing the authentication token in the DB.
EDIT
To answer your question below, I don't think you need middleware or anything fancy. You could do a simple before filter in the application controller of example.org, something like:
before_filter :redirect_to_dot_com
...
def redirect_to_dot_com
url = "http://example.com" + request.fullpath
url= destination + (url.include?('?') ? '&' : '?') + "token=#{current_user.token}" if signed_in?
redirect_to url, status: 301
end
That will redirect the user either way, and append the token to the query if the user is signed in on the .org site.

session management in rails without User model

I have an rails app which relies on authenticating username/password entered to an external webservice. Rails app will not have a user model. When a user enters login/password and it makes a post request to check that login/password. External application will return back a cookie or token which can be used for subsequent requests made from rails app.
There is no User model in the rails app since all the users are stored in an external application.
Is there a gem which let me strictly do session management? I'm planning on storing that token in a session.
why not just create a sessions controller that saves the token into a session? I don't see a need for a gem.
something like
sessions[:token] = token
If you are dealing with a tokens that expire like facebook you can take a look at this
http://developers.facebook.com/blog/post/2011/05/13/how-to--handle-expired-access-tokens/
hope it helps
I might look at the way Michael Hartl does user sessions in his Rails tutorial. What you want is something slightly different, but you might be able to reuse some of what he did there. http://ruby.railstutorial.org/chapters/sign-in-sign-out#sec-current_user
(It's also just a good tutorial to go through, regardless of your level of Rails experience.)

On signup - creating a duplicate account with the same credentials on another site

I am using Devise to handle registration process.
How can I create a duplicate account via ajax on another site using the same credentials?
I can overwrite Registration controller, but don't know how to get unencrypted password.
You need to override the Devise Registration Controller.
On the create method, get the user input, send it to your other website, then call super to handle registration by devise.
You certainly want to send datas to other website through an API, because of the CSRF protection.
You can't get the unencrypted password.
Devise uses Bcrypt, which a one way encryption algorithm. The only way to get create an exact duplicate is top copy the encrypted password directly, rather than using the unencrypted version.
However I'd strongly recommend against this, what are you trying to achieve? Is there a better way to handle this problem - OAuth?

Question about rails webservice and authentication

What I am doing is rails web service API that let user create traveling log when they access any sites, by using firefox plugin.For this requirement I needed 2 things.
skip_before_filter :verify_authenticity_token in specific controller (Because I let user create it through API not the form, so I disable this).
user have to provided username and password every request (e.g. curl -u username:pass -d "..." http://localhost:3000/logs).
What I want to ask are
can I made it easier by letting my
firefox plugin ask for user login
then use cookies, so no need to send
username password every time with
request.
Does skip_before_filter :verify_authenticity_token is bad thing or necessary thing to do for this ?
Thanks
When Rails renders a form, it includes a hidden field with a long string (authenticity token). The verify_authenticity_token filter ensures that the user submitted a form that the server actually rendered (as opposed to forging a POST request, as hackers will do). If you use cookies and sessions you should really read about how this works and try to customize it to work with your plugin.
However, why not use HTTP basic authentication instead? It's slightly faster than sending a cookie on every page view and should be much simpler to set up. As you say, you can have your plugin prompt for a username/password, and then send them with every request.
If you need to store user data in sessions, though, you'll have to use cookies.

Resources