Added a new helper AuthenticatedSystem, used by application.rb to check authentication
Modified main.rhtml a bit because now we have a working auth system.
# Filters added to this controller will be run for all controllers in the application.
# Likewise, all the methods added will be available for all controllers.
class ApplicationController < ActionController::Base
-end
\ No newline at end of file
+ include AuthenticatedSystem
+ before_filter :logged_in?
+end
@@ -6,10 +6,6 @@ class UserController < ApplicationController
redirect_to :action => "rules"
end
- def rules
- redirect_to :action => "rules"
- end
-
def list
@users = User.find :all
end
@@ -34,18 +30,6 @@ class UserController < ApplicationController
@user = User.new(user_obj)
@user.username = user_obj[:username]
if @user.save
- flash[:notice] = "User registered"
- redirect_to :controller => "forum"
- else
- render :action => "new"
- end
- end
-
- def create
- user_obj = @params[:user]
- @user = User.new(user_obj)
- @user.username = user_obj[:username]
- if @user.save
@flash[:notice] = "User registered"
redirect_to :controller => "forum", :action => "list"
else
@@ -54,12 +38,17 @@ class UserController < ApplicationController
end
def logout
- @flash[:notice] = "Logged out"
- redirect_to :controller => "forum", :action => "list"
+ self.current_user = nil
+ flash[:notice] = "You have been logged out."
+ redirect_back_or_default :controller => "forum", :action => "list"
end
def login
- @flash[:notice] = "Logged in"
- redirect_to :controller => "forum", :action => "list"
+ return unless request.post?
+ self.current_user = User.authenticate(params[:username], params[:password])
+ if current_user
+ flash[:notice] = "Logged in successfully"
+ redirect_back_or_default :controller => "forum", :action => "list"
+ end
end
end
class User < ActiveRecord::Base
- validates_presence_of :username, :email
- validates_uniqueness_of :username, :email
- validates_length_of :username, :minimum => 4
- validates_length_of :password, :minimum => 6
- validates_confirmation_of :password, :email
+ # Virtual attribute for the unencrypted password
+ attr_accessor :passwd
+
+ validates_presence_of :username
+ validates_length_of :username, :within => 3..40
+
+ validates_presence_of :passwd, :passwd_confirmation
+ validates_length_of :passwd, :within => 5..40
+ validates_confirmation_of :passwd
+ before_save :encrypt_password
+
+ validates_presence_of :email, :email_confirmation
+ validates_length_of :email, :within => 3..100
+ validates_confirmation_of :email
validates_format_of :email, :with => /^([^@\s]+)@((?:[-a-z0-9]+.)+[a-z]{2,})$/
+
+ validates_uniqueness_of :username, :email
attr_protected :group_id, :username
+
+ # Authenticates a user by their login name and unencrypted password. Returns the user or nil.
+ def self.authenticate(username, passwd)
+ u = find_by_username(username) # need to get the salt
+ u && u.authenticated?(passwd) ? u : nil
+ end
+
+ # Encrypts some data with the salt.
+ def self.encrypt(passwd, salt)
+ Digest::SHA1.hexdigest("--#{salt}--#{passwd}--")
+ end
+
+ # Encrypts the password with the user salt
+ def encrypt(passwd)
+ self.class.encrypt(passwd, salt)
+ end
+
+ def authenticated?(passwd)
+ password == encrypt(passwd)
+ end
+
+ protected
+ # before filter
+ def encrypt_password
+ return if passwd.blank?
+ self.salt = Digest::SHA1.hexdigest("--#{Time.now.to_s}--#{username}--") if new_record?
+ self.password = encrypt(passwd)
+ end
end
<li id="navindex"><%= link_to "User list", :controller => "user", :action => "list" %>
<li id="navindex"><%= link_to "Rules", :controller => "user", :action => "list" %>
<li id="navindex"><%= link_to "Search", :controller => "search" %>
- <li id="navindex"><%= link_to "Register", :controller => "user", :action => "register" %>
- <li id="navindex"><%= link_to "Login", :controller => "user", :action => "login" %>
+<% if @current_user %>
<li id="navindex"><%= link_to "Profile", :controller => "user", :action => "profile" %>
<li id="navindex"><%= link_to "Logout", :controller => "user", :action => "logout" %>
+<% else %>
+ <li id="navindex"><%= link_to "Register", :controller => "user", :action => "register" %>
+ <li id="navindex"><%= link_to "Login", :controller => "user", :action => "login" %>
+<% end %>
</div>
<!--pun_status-->
<div id="brdwelcome" class="inbox">
--- /dev/null
+<div class="blockform">
+ <h2><span>Login</span></h2>
+ <div class="box">
+ <form id="login" method="post" action="<%= url_for :controller => "user", :action => "login" %>" onsubmit="return process_form(this)">
+ <div class="inform">
+ <fieldset>
+ <legend>Login legend</legend>
+ <div class="infldset">
+ <input type="hidden" name="form_sent" value="1" />
+ <input type="hidden" name="redirect_url" value="<?php echo $redirect_url ?>" />
+ <label class="conl"><strong>Username</strong><br /><input type="text" name="username" size="25" maxlength="25" tabindex="1" /><br /></label>
+ <label class="conl"><strong>Password</strong><br /><input type="password" name="password" size="16" maxlength="16" tabindex="2" /><br /></label>
+ <p class="clearb">Login info</p>
+ <p><%= link_to "Not registered", :controller => "user", :action => "register" %>
+ <%= link_to "Forgotten pass", :controller => "user", :action => "passreq" %></p>
+ </div>
+ </fieldset>
+ </div>
+ <p><input type="submit" name="login" value="Login" tabindex="3" /></p>
+ </form>
+ </div>
+</div>
<fieldset>
<legend>Pass legend 1</legend>
<div class="infldset">
- <label class="conl"><strong>Password</strong><br /><input type="password" name="user[password]" size="16" maxlength="16" /><br /></label>
- <label class="conl"><strong>Confirm pass</strong><br /><input type="password" name="user[password_confirmation]" size="16" maxlength="16" /><br /></label>
+ <label class="conl"><strong>Password</strong><br /><input type="password" name="user[passwd]" size="16" maxlength="16" /><br /></label>
+ <label class="conl"><strong>Confirm pass</strong><br /><input type="password" name="user[passwd_confirmation]" size="16" maxlength="16" /><br /></label>
<p class="clearb">Pass info</p>
</div>
</fieldset>
--- /dev/null
+<div class="blockform">
+ <h2><span>Request pass</span></h2>
+ <div class="box">
+ <form id="request_pass" method="post" action="<%= url_for :controller => "user", :action => "login" %>" onsubmit="this.request_pass.disabled=true;if(process_form(this)){return true;}else{this.request_pass.disabled=false;return false;}">
+ <div class="inform">
+ <fieldset>
+ <legend>Request pass legend</legend>
+ <div class="infldset">
+ <input type="hidden" name="form_sent" value="1" />
+ <input id="req_email" type="text" name="req_email" size="50" maxlength="50" />
+ <p>Request pass info</p>
+ </div>
+ </fieldset>
+ </div>
+ <p><input type="submit" name="request_pass" value="Submit" /><a href="javascript:history.go(-1)">Go back</a></p>
+ </form>
+ </div>
+</div>
--- /dev/null
+module AuthenticatedSystem
+ protected
+ def logged_in?
+ current_user
+ end
+
+ # Accesses the current user from the session.
+ def current_user
+ @current_user ||= session[:user] ? User.find_by_id(session[:user]) : nil
+ end
+
+ # Store the given user in the session.
+ def current_user=(new_user)
+ session[:user] = new_user.nil? ? nil : new_user.id
+ @current_user = new_user
+ 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 authorize?(user)
+ # user.login != "bob"
+ # end
+ def authorized?(user)
+ true
+ end
+
+ # Check whether or not to protect an action.
+ #
+ # Override this method in your controllers if you only want to protect
+ # certain actions.
+ #
+ # Example:
+ #
+ # # don't protect the login and the about method
+ # def protect?(action)
+ # if ['action', 'about'].include?(action)
+ # return false
+ # else
+ # return true
+ # end
+ # end
+ def protect?(action)
+ true
+ 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
+ # Skip this filter if the requested action is not protected
+ return true unless protect?(action_name)
+
+ # Check if user is logged in and authorized
+ return true if logged_in? and authorized?(current_user)
+
+ # Store current location so that we can redirect back after login
+ store_location
+
+ # Call access_denied for an appropriate redirect and stop the filter
+ # chain here
+ access_denied and return false
+ 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
+ redirect_to :controller => 'user', :action => 'login'
+ 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)
+ session[:return_to] ? redirect_to_url(session[:return_to]) : redirect_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
+end
--- /dev/null
+module AuthenticatedTestHelper
+ # Sets the current u in the session from the u fixtures.
+ def login_as(user)
+ @request.session[:user] = us(user).id
+ end
+
+ # Assert the block redirects to the login
+ #
+ # assert_requires_login(:bob) { get :edit, :id => 1 }
+ #
+ def assert_requires_login(user = nil, &block)
+ login_as(user) if user
+ block.call
+ assert_redirected_to :controller => 'user', :action => 'login'
+ end
+
+ # Assert the block accepts the login
+ #
+ # assert_accepts_login(:bob) { get :edit, :id => 1 }
+ #
+ # Accepts anonymous logins:
+ #
+ # assert_accepts_login { get :list }
+ #
+ def assert_accepts_login(user = nil, &block)
+ login_as(user) if user
+ block.call
+ assert_response :success
+ end
+
+ # http://project.ioni.st/post/217#post-217
+ #
+ # def test_new_publication
+ # assert_difference(Publication, :count) do
+ # post :create, :publication => {...}
+ # # ...
+ # end
+ # end
+ #
+ def assert_difference(object, method = nil, difference = 1)
+ initial_value = object.send(method)
+ yield
+ assert_equal initial_value + difference, object.send(method), "#{object}##{method}"
+ end
+
+ def assert_no_difference(object, method, &block)
+ assert_difference object, method, 0, &block
+ end
+end