Permalink
Browse files

users and test controller

  • Loading branch information...
1 parent 58823f8 commit 49f7a738cf94f8dc4ce89ac55b8141c146acb92f @labria committed Feb 23, 2008
@@ -0,0 +1,31 @@
+# This controller handles the login/logout function of the site.
+class SessionsController < ApplicationController
+ # Be sure to include AuthenticationSystem in Application Controller instead
+ include AuthenticatedSystem
+
+ # render new.rhtml
+ def new
+ end
+
+ def create
+ self.current_user = User.authenticate(params[:login], params[:password])
+ if logged_in?
+ if params[:remember_me] == "1"
+ self.current_user.remember_me
+ cookies[:auth_token] = { :value => self.current_user.remember_token , :expires => self.current_user.remember_token_expires_at }
+ end
+ redirect_back_or_default('/')
+ flash[:notice] = "Logged in successfully"
+ else
+ render :action => 'new'
+ end
+ end
+
+ def destroy
+ self.current_user.forget_me if logged_in?
+ cookies.delete :auth_token
+ reset_session
+ flash[:notice] = "You have been logged out."
+ redirect_back_or_default('/')
+ end
+end
@@ -0,0 +1,2 @@
+class TestController < ApplicationController
+end
@@ -0,0 +1,27 @@
+class UsersController < ApplicationController
+ # Be sure to include AuthenticationSystem in Application Controller instead
+ include AuthenticatedSystem
+
+
+ # render new.rhtml
+ def new
+ end
+
+ def create
+ cookies.delete :auth_token
+ # protects against session fixation attacks, wreaks havoc with
+ # request forgery protection.
+ # uncomment at your own risk
+ # reset_session
+ @user = User.new(params[:user])
+ @user.save
+ if @user.errors.empty?
+ self.current_user = @user
+ redirect_back_or_default('/')
+ flash[:notice] = "Thanks for signing up!"
+ else
+ render :action => 'new'
+ end
+ end
+
+end
@@ -0,0 +1,2 @@
+module SessionsHelper
+end
@@ -0,0 +1,2 @@
+module TestHelper
+end
@@ -0,0 +1,2 @@
+module UsersHelper
+end
View
@@ -0,0 +1,78 @@
+require 'digest/sha1'
+class User < ActiveRecord::Base
+ # Virtual attribute for the unencrypted password
+ attr_accessor :password
+
+ validates_presence_of :login, :email
+ validates_presence_of :password, :if => :password_required?
+ validates_presence_of :password_confirmation, :if => :password_required?
+ validates_length_of :password, :within => 4..40, :if => :password_required?
+ validates_confirmation_of :password, :if => :password_required?
+ validates_length_of :login, :within => 3..40
+ validates_length_of :email, :within => 3..100
+ validates_uniqueness_of :login, :email, :case_sensitive => false
+ before_save :encrypt_password
+
+ # prevents a user from submitting a crafted form that bypasses activation
+ # anything else you want your user to change should be added here.
+ attr_accessible :login, :email, :password, :password_confirmation
+
+ # Authenticates a user by their login name and unencrypted password. Returns the user or nil.
+ def self.authenticate(login, password)
+ u = find_by_login(login) # need to get the salt
+ u && u.authenticated?(password) ? u : nil
+ end
+
+ # 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 authenticated?(password)
+ crypted_password == encrypt(password)
+ 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
+ remember_me_for 2.weeks
+ end
+
+ def remember_me_for(time)
+ remember_me_until time.from_now.utc
+ end
+
+ def remember_me_until(time)
+ self.remember_token_expires_at = time
+ 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
+
+ protected
+ # before filter
+ def encrypt_password
+ return if password.blank?
+ self.salt = Digest::SHA1.hexdigest("--#{Time.now.to_s}--#{login}--") if new_record?
+ self.crypted_password = encrypt(password)
+ end
+
+ def password_required?
+ crypted_password.blank? || !password.blank?
+ end
+
+
+end
@@ -0,0 +1,14 @@
+<% form_tag session_path do -%>
+<p><label for="login">Login</label><br/>
+<%= text_field_tag 'login' %></p>
+
+<p><label for="password">Password</label><br/>
+<%= password_field_tag 'password' %></p>
+
+<!-- Uncomment this if you want this functionality
+<p><label for="remember_me">Remember me:</label>
+<%= check_box_tag 'remember_me' %></p>
+-->
+
+<p><%= submit_tag 'Log in' %></p>
+<% end -%>
@@ -0,0 +1,16 @@
+<%= error_messages_for :user %>
+<% form_for :user, :url => users_path do |f| -%>
+<p><label for="login">Login</label><br/>
+<%= f.text_field :login %></p>
+
+<p><label for="email">Email</label><br/>
+<%= f.text_field :email %></p>
+
+<p><label for="password">Password</label><br/>
+<%= f.password_field :password %></p>
+
+<p><label for="password_confirmation">Confirm Password</label><br/>
+<%= f.password_field :password_confirmation %></p>
+
+<p><%= submit_tag 'Sign up' %></p>
+<% end -%>
View
@@ -1,4 +1,8 @@
ActionController::Routing::Routes.draw do |map|
+ map.resources :users
+
+ map.resource :session
+
# The priority is based upon order of creation: first created -> highest priority.
# Sample of regular route:
@@ -0,0 +1,20 @@
+class CreateUsers < ActiveRecord::Migration
+ def self.up
+ create_table "users", :force => true do |t|
+ t.column :login, :string
+ t.column :email, :string
+ t.column :crypted_password, :string, :limit => 40
+ t.column :salt, :string, :limit => 40
+ t.column :created_at, :datetime
+ t.column :updated_at, :datetime
+ t.column :remember_token, :string
+ t.column :remember_token_expires_at, :datetime
+
+
+ end
+ end
+
+ def self.down
+ drop_table "users"
+ end
+end
View
@@ -0,0 +1,116 @@
+module AuthenticatedSystem
+ protected
+ # Returns true or false if the user is logged in.
+ # Preloads @current_user with the user model if they're logged in.
+ def logged_in?
+ current_user != :false
+ end
+
+ # Accesses the current user from the session. Set it to :false if login fails
+ # so that future calls do not hit the database.
+ def current_user
+ @current_user ||= (login_from_session || login_from_basic_auth || login_from_cookie || :false)
+ end
+
+ # Store the given user id in the session.
+ def current_user=(new_user)
+ session[:user_id] = (new_user.nil? || new_user.is_a?(Symbol)) ? nil : new_user.id
+ @current_user = new_user || :false
+ end
+
+ # Check if the user is authorized
+ #
+ # Override this method in your controllers if you want to restrict access
+ # to only a few actions or if you want to check if the user
+ # has the correct rights.
+ #
+ # Example:
+ #
+ # # only allow nonbobs
+ # def authorized?
+ # current_user.login != "bob"
+ # end
+ def authorized?
+ logged_in?
+ end
+
+ # Filter method to enforce a login requirement.
+ #
+ # To require logins for all actions, use this in your controllers:
+ #
+ # before_filter :login_required
+ #
+ # To require logins for specific actions, use this in your controllers:
+ #
+ # before_filter :login_required, :only => [ :edit, :update ]
+ #
+ # To skip this in a subclassed controller:
+ #
+ # skip_before_filter :login_required
+ #
+ def login_required
+ authorized? || access_denied
+ end
+
+ # Redirect as appropriate when an access request fails.
+ #
+ # The default action is to redirect to the login screen.
+ #
+ # Override this method in your controllers if you want to have special
+ # behavior in case the user is not authorized
+ # to access the requested action. For example, a popup window might
+ # simply close itself.
+ def access_denied
+ respond_to do |format|
+ format.html do
+ store_location
+ redirect_to new_session_path
+ end
+ format.any do
+ request_http_basic_authentication 'Web Password'
+ end
+ end
+ end
+
+ # Store the URI of the current request in the session.
+ #
+ # We can return to this location by calling #redirect_back_or_default.
+ def store_location
+ session[:return_to] = request.request_uri
+ end
+
+ # Redirect to the URI stored by the most recent store_location call or
+ # to the passed default.
+ def redirect_back_or_default(default)
+ redirect_to(session[:return_to] || default)
+ session[:return_to] = nil
+ end
+
+ # Inclusion hook to make #current_user and #logged_in?
+ # available as ActionView helper methods.
+ def self.included(base)
+ base.send :helper_method, :current_user, :logged_in?
+ end
+
+ # Called from #current_user. First attempt to login by the user id stored in the session.
+ def login_from_session
+ self.current_user = User.find(session[:user_id]) if session[:user_id]
+ end
+
+ # Called from #current_user. Now, attempt to login by basic authentication information.
+ def login_from_basic_auth
+ authenticate_with_http_basic do |username, password|
+ self.current_user = User.authenticate(username, password)
+ end
+ end
+
+ # Called from #current_user. Finaly, attempt to login by an expiring token in the cookie.
+ def login_from_cookie
+ user = cookies[:auth_token] && User.find_by_remember_token(cookies[:auth_token])
+ if user && user.remember_token?
+ user.remember_me
+ cookies[:auth_token] = { :value => user.remember_token, :expires => user.remember_token_expires_at }
+ self.current_user = user
+ end
+ end
+end
@@ -0,0 +1,10 @@
+module AuthenticatedTestHelper
+ # Sets the current user in the session from the user fixtures.
+ def login_as(user)
+ @request.session[:user_id] = user ? users(user).id : nil
+ end
+
+ def authorize_as(user)
+ @request.env["HTTP_AUTHORIZATION"] = user ? ActionController::HttpAuthentication::Basic.encode_credentials(users(user).login, 'test') : nil
+ end
+end
View
@@ -0,0 +1,19 @@
+quentin:
+ id: 1
+ login: quentin
+ email: quentin@example.com
+ salt: 7e3041ebc2fc05a40c60028e2c4901a81035d3cd
+ crypted_password: 00742970dc9e6319f8019fd54864d3ea740f04b1 # test
+ created_at: <%= 5.days.ago.to_s :db %>
+
+
+
+aaron:
+ id: 2
+ login: aaron
+ email: aaron@example.com
+ salt: 7e3041ebc2fc05a40c60028e2c4901a81035d3cd
+ crypted_password: 00742970dc9e6319f8019fd54864d3ea740f04b1 # test
+ created_at: <%= 1.days.ago.to_s :db %>
+
+
Oops, something went wrong.

0 comments on commit 49f7a73

Please sign in to comment.