views:

415

answers:

3

Hey there,

I am trying to get up a simple authentication system with Rails' Restful-Authentication plugin, and am just wondering how it works, b/c I can't seem to figure out what the requirements are for cookies, and how to make it so the browser always remembers you (for 6+ months).

Few questions:

1) How do you do remember_me's for ruby's restful_authentication? I can't seem to find a good one-liner to solve this problem...

If a user signs up and checks "Remember Me", how does the rails application get the session/cookie without the user doing anything but going to the page the next time they go to the page, say 3 months later?

2) Do I need to send some sort of info to the server, like their IP address or something? What is cookies[:auth_token], where is that defined?

The goal is: I don't want them to have to enter their email/password again, like how StackOverflow works :)

A: 

I'm honestly not sure aboout that particular implementation. But a common RESTful method of authentication is to pass a hashed version of the user/password with each request as a header. Alternatively you can use a hashed cookie value as a header.

I've also seen hybrid systems that involve both. You pass in the session, if you know it, in addition to the user/pass. Then server side if the session is valid it uses that and can cache the session - > user relationship for performance. If the session is invalid, it attempts to authenticate using the user/pass.

In this type of system you'd pass the session back on the response as a header.

Of course that's just a quick rundown of how a system might work, not how ruby's library does.

Bryan McLemore
+1  A: 

Here's what we're doing (largely taken from authenticated system) ... this is the controller method that handles login that we're running...

def login
  if logged_in?
    flash[:notice] = "You are already logged in."
    redirect_to "/" and return
  end
  unless request.post?
    render :layout => 'task' and return
  end
  self.current_user = User.authenticate(params[:login], params[:password])
  if logged_in?
    if params[:remember_me].to_i == 1
      self.current_user.remember_me
      cookies[:auth_token] = {:domain => "#{DOMAIN}", :value => self.current_user.remember_token , :expires => self.current_user.remember_token_expires_at }
    else
      self.current_user.forget_me
      cookies.delete(:auth_token, :domain => "#{DOMAIN}")
      cookies[:auth_token] = nil
    end
    current_user.last_seen_at = Time.now 
    current_user.save
    session[:notice] = "You logged in successfully"
    flash[:notice] = "You logged in successfully"
    redirect_back_or_default(:controller => 'dashboard') and return
    #redirect_back_or_default(:controller => 'index', :action => 'index') and return
  else
    if $failed_login_counter.add_attempt(params[:login]) > MAXIMUM_LOGIN_ATTEMPTS
      logger.info("login rate limiter kicking in, #{MAXIMUM_LOGIN_ATTEMPTS} login attempts failed")
      redirect_to "/denied.html" and return
    end
    flash[:error] = "Unable to authenticate username and password"
    render(:layout => 'task') and return
  end
end

And use this for logout

def logout
  current_user.last_seen_at = Time.now 
  current_user.save
  self.current_user.forget_me if logged_in?
  cookies.delete(:auth_token, :domain => "#{DOMAIN}")
  reset_session
  flash[:notice] = "You have been logged out."
  #redirect_to :back
  redirect_back_or_default(:controller => 'index', :action => 'index') and return
end

Then - in your application.rb you'll need something like:

before_filter :login_from_cookie

def login_from_cookie
  return unless cookies[:auth_token] && !logged_in?
  user = User.find_by_remember_token(cookies[:auth_token])
  if user && user.remember_token?
    user.remember_me
    self.current_user = user
    cookies[:auth_token] = { :domain => "#{DOMAIN}", :value => self.current_user.remember_token , :expires => self.current_user.remember_token_expires_at }
    flash[:notice] = "#{self.current_user.login}, you have logged in successfully"
  end
end

And - in your User model have some methods like this:

# Encrypts some data with the salt.
def self.encrypt(password, salt)
  Digest::SHA1.hexdigest("--#{salt}--#{password}--")
end

# Encrypts the password with the user salt
def encrypt(password)
  self.class.encrypt(password, salt)
end

def remember_token?
  remember_token_expires_at && Time.now.utc < remember_token_expires_at 
end

# These create and unset the fields required for remembering users between browser closes
def remember_me
  self.remember_token_expires_at = 2.weeks.from_now.utc
  self.remember_token            = encrypt("#{email}--#{remember_token_expires_at}")
  save(false)
end

def forget_me
  self.remember_token_expires_at = nil
  self.remember_token            = nil
  save(false)
end
Ben Wiseley
A: 

You can find here a whole tutorial about restful authentication. http://railsforum.com/viewtopic.php?id=14216&amp;p=13

dombesz