# The HTTP authorization code is # derived from an example published by Maximillian Dornseif at # http://blogs.23.nu/c0re/stories/7409/ # which was released for use under any license. # # I started out with the Salted Hash login generator, and essentially rewrote # the whole thing, learning a lot from the previous versions. This is not a # criticism of the previous work, my goals were different. So, it's fair to # say that this is derived from the work of Joe Hosteny and Tobias Leutke. # class UserController < ApplicationController # helper ModelSecurity private # Require_admin will require an administrative login before the action # can be called. It uses Modal, so it will continue to the action if the # login is successful. before_filter :require_admin, :only => [ :destroy ] # Require_login will require a login before the action # can be called. It uses Modal, so it will continue to the action if the # login is successful. before_filter :require_login, :only => [ :list, :show ] # Cause HTTP Basic validation. # FIX: Basic is not secure. Change to Digest authentication. def http_authorize(realm=@request.domain(2)) # This will cause the browser to send HTTP authorization information. @response.headers["Status"] = "Unauthorized" @response.headers["WWW-Authenticate"] = "Basic realm=\"#{realm}\"" render :status => 401 end def initialize end public scaffold :user private public # Activate a new user, having logged in with a security token. All of the # work goes on in user_support. def activate end # Destroy a user object. def destroy user = User.find(@params[:id]) user.destroy flash['notice'] = 'User destroyed.' redirect_to :action => :list end # Edit a user. Will only allow you to edit what your security clearance # allows, due to the magic of model security. def edit case @request.method when :get @user = User.find(@params[:id]) when :post @user = User.find(@params[:id]) @user.attributes = @params['user'] @user.save redirect_to :action => :list end end # Send out a forgot-password email. def forgot_password case @request.method when :get @user = User.new when :post @user = User.find_first(['email = ?', @params['user']['email']]) if @user url = url_for(:controller => 'user', :action => 'activate', :id => @user.id, :token => @user.new_token) UserMailer.deliver_forgot_password(@user, url) render :action => 'forgot_password_done' else flash['notice'] = "Can't find a user with email #{@params['email']}." @user = User.new end end end # Tell the user the email's on the way. def forgot_password_done end # List users. # FIX: Get away from the scaffold here, and use the login instead of the ID # to access a user record. Using an ID gives outsiders a way to enumerate # the users, which has security implications. def list options = { :per_page => 10, :order_by => 'name, id' } @user_pages, @users = paginate(:user, options) end # Attempt HTTP authentication, and fall back on a login form. # If this method is called login_admin (it's an alias), keep trying # until an administrator logs in or the user pushes the "back" button. def login if User.current and (admin? or action_name != 'login_admin') redirect_back_or_default :action => :success return end @user = User.new http_authorize end # Log in an administrator. If a non-administrator logs in, keep trying # until an administrator logs in or the user pushes the "back" button. alias login_admin login # Log out the current user, attempt HTTP authentication to log in a new # user. The session information skip_user_setup=true tells the server to # generate a new HTTP authentication request and ignore the current HTTP # authentication data. # We have to request new HTTP authentication here to make the browser # forget the old authentication data. Otherwise, the browser keeps sending # it! def logout User.sign_off session[:user_id] = nil session[:skip_user_setup] = true redirect_to :action => 'login' end # Create a new user. def new case @request.method when :get @user = User.new when :post p = @params['user'] @user = User.new(p) if @user.save flash['notice'] = 'User created.' # Promote the very first user to be an administrator. if @user.id == 1 @user.admin = 1 @user.activated = 1 @user.save User.sign_on_by_session(1) render :file => 'app/views/user/admin_created.rhtml' # Mail the user instructions on how to activate their account. else url_params = { :controller => 'user', :action => 'activate', :id => @user.id, :token => @user.new_token } url = url_for(url_params) UserMailer.deliver_new_user(p, url, @user.token_expiry) render :file => 'app/views/user/created.rhtml' end else flash['notice'] = 'Creation of new user failed.' end end end # Display a user's information. # FIX: Use the user's login instead of the record ID. # Using the record ID provides an easy way for outsiders to enumerate the # users, which has security implications. def show @user = User.find(@params[:id]) end # Tell the user that an action succeeded. def success end end