blob: f6c4f8b6d4c1097c8e1acda98ccbd0562cd9ecdd [file] [log] [blame]
# This controller takes care of security.
#--######################################################################
# Copyright (c) 2006 Logica
#
# All rights reserved. This program and the accompanying materials
# are made available under the terms of the Eclipse Public License v1.0
# which accompanies this distribution, and is available at
# http://www.eclipse.org/legal/epl-v10.html
#
# Contributors:
#
# Onno van der Straaten:: initial implementation
#++######################################################################
# {Copyright (c) 2006 Logica}[link:files/COPYRIGHT.html]
class LoginController < ApplicationController
layout 'management'
before_filter :authenticate, :except => [:index, :sign_up2, :sign_up, :login, :lost_password, :new_cadmin,
:confirm_account, :report_password_reset_attempt, :auto_complete_for_user_email, :resend]
before_filter :authenticate_admin, :only => [:resend]
verify :method => :post, :only => [:resend],:add_flash => {'error' => ::FLASH_USE_POST_NOT_GET}, :redirect_to => { :controller => 'other', :action => 'error' }
filter_parameter_logging :password, :password_confirmation
FLASH_CENTRAL_ADMIN_ALREADY_CREATED = 'You can only create the central admin if this user has not been created yet!'
FLASH_INVALID_PW = 'Invalid combination of username password!'
FLASH_NO_VALID_TOKEN = 'Not a valid token!'
FLASH_PASSWORD_ACTIVATED = 'New password activated!'
FLASH_LOST_PASSWORD_ABUSE = 'A notification was sent to the administrator reporting the abuse of your email address'
FLASH_CENTRAL_ADMIN_CREATED = 'Central admin user created!'
FLASH_PW_CONFIRMATION_EMAIL_SENT = 'A confirmation email has been sent to your email address. Please confirm your account by clicking on the hyperlink in this email'
FLASH_EMAIL_NOT_FOUND = 'Email address not found!'
FLASH_UNOT_ADMIN = "You are not an admin user!"
FLASH_UNOT_CADMIN = "You are not the central administrator!"
# Is be used to create the first user, the central admin account
def new_cadmin
if User.count > 0
flash['error'] = FLASH_CENTRAL_ADMIN_ALREADY_CREATED
redirect_to :action => 'login'
else
if request.get?
@user = User.new
else
@user = User.new_cadmin(params[:user])
if @user.save
flash['success'] = FLASH_CENTRAL_ADMIN_CREATED
redirect_to :action => 'login'
else
render :action => 'new_cadmin'
end
end
end
end
# Action #sign_up creates the account or displays the form to create the account.
# Passwords can be generated or supplied by the user.
# If passwords are supplied by the user the account needs to be confirmed,
# see #confirm_account
def sign_up
if request.get?
@user = User.new
else
@user = User.new_signup(params[:user])
if @user.save
flash['success'] = FLASH_PW_CONFIRMATION_EMAIL_SENT
Notifier::deliver_welcome_pw_confirmationlink(@user, request.host + (request.port == 80 ? '' : ':' + request.port.to_s))
redirect_to :action => "login"
else
logger.info("Failed to save user on signup #{@user.inspect}")
@user.email = @user.email.gsub(@user.email_extension,"") if @user.email && @user.email_extension
@user.password = ""
@user.password_confirmation = ""
end
end
end
# Action #confirm_account is used to confirm a new password send by email. Without confirmation anyone could reset passwords.
# The token used for confirmation is just the new password hashed twice. The new password is stored in the column <tt>confirmation_token</tt>.
# Action #resend_password is used to request a new password.
def confirm_account
@user = User.find(params[:id])
if @user.confirm_account(params[:tk])
if @user.save
flash['success'] = FLASH_PASSWORD_ACTIVATED
else
raise "Failed to activate account for #{@user.email}"
end
else
flash['error'] = FLASH_NO_VALID_TOKEN
end
redirect_to :action => 'login'
end
# Action #change_password allows a user to change the password
#--
# TODO security enhancement: require the old password
# TODO like to use flash.now here but functional tests will fail! Is a bug?
#++
def change_password
@user= User.find(session['user'].id)
if request.get?
else
@user.errors.add(:password, "Can't be blank") if params[:user][:password].blank? # blank? returns true if its receiver is nil or an empty string
@user.change_password(User.new(params[:user]))
if @user.save
flash['success'] = 'Password was succesfully changed'
else
@user= User.find(session['user'].id)
end
end
end
def index
redirect_to :action => 'login'
end
# Generate a new password for a user and sends it in a email.
# The new password is activated after the user confirms it. The old passwords remains
# active, otherwise any user can disable accounts!
def lost_password
if request.get?
@user = User.new
else
@user = User.new(params[:user])
logger.info('Finding user with email: ' + @user.email.downcase)
@user_by_email = User.find_by_email(@user.email.downcase)
if @user_by_email
@user_by_email.password = @user.password
@user_by_email.password_confirmation = @user.password_confirmation
if @user_by_email.valid?
@user_by_email.set_new_pw(@user_by_email.password)
if @user_by_email.save
urls = [url_for(:controller => 'login', :action => 'confirm_account', :id => @user_by_email.id, :tk => @user_by_email.token_new)]
Notifier::deliver_lost_password(@user_by_email, urls)
flash['success'] = FLASH_PW_CONFIRMATION_EMAIL_SENT
redirect_to :action => "login"
end
else
end
else
@user.email = ""
flash['notice'] = FLASH_EMAIL_NOT_FOUND
end
end
end
# Action #login checks if there is a cookie. With 'posts' we try to login using User.try_to_login. If the user
# wants to be remembered a cookie is created. 'Gets' can login the user if the user has a good cookie.
def login
@wikis = Wiki.find(:all, :conditions => ['obsolete_on is null'])
@login_message = AdminMessage.text('Login')
if request.get?
if cookies[:epfwiki_id] && User.exists?(cookies[:epfwiki_id])
logger.info("Found cookie and user with id " + cookies[:epfwiki_id])
@user = User.find(cookies[:epfwiki_id])
token = cookies[:epfwiki_token]
if @user.confirm_account(token)
logger.info("Token good, refresh cookies and login user")
create_cookie(@user) # refresh van cookie
@user.update_attributes({:http_user_agent => request.env['HTTP_USER_AGENT'], :ip_address => request.env['REMOTE_ADDR'] , :last_logon => Time.now, :logon_count => @user.logon_count + 1, :logon_using_cookie_count => @user.logon_using_cookie_count + 1})
session['user'] = @user
redirect2page
else
logger.info("An account was found but the token was not correct #{request.env.inspect}")
expire_cookie
session['user'] = nil
@user = User.new
end
else
logger.debug("Cookie not found, or user not found with id in cookie: #{cookies.inspect}, cookies['epfwiki_id']: #{cookies['epfwiki_id']}, User.exists?(cookies[:epfwiki_id]): #{User.exists?(cookies[:epfwiki_id])}")
expire_cookie # if it exists, it is invalid
@cadmin = User.find_central_admin
if @cadmin
logger.debug('Cadmin found, displaying the login form')
session['user'] = nil
@user = User.new
else
logger.debug('Cadmin not found, displaying form to create cadmin user')
redirect_to :action => 'new_cadmin'
end
end
else
@user = User.new(params[:user])
@logged_in_user = @user.try_to_login
if @logged_in_user
logger.info("Login succesfull")
session['user'] = @logged_in_user
if @user.remember_me == "0" # remember_me = 0, do not remember_me is 1
create_cookie(@logged_in_user)
end
@logged_in_user.update_attributes({:http_user_agent => request.env['HTTP_USER_AGENT'], :ip_address => request.env['REMOTE_ADDR'] , :last_logon => Time.now, :logon_count => @logged_in_user.logon_count + 1})
redirect2page
else
@user = User.new
flash['notice'] = FLASH_INVALID_PW
logger.info("Invalid combination of username password for #{@user.email}")
end
end
end
# destroy the session and cookie redirect to #login
def logout
session['user'] = nil
flash[:notice] = "Logged out"
redirect_to :action => "login"
expire_cookie
end
def redirect2page
if session["return_to"]
redirect_to(session["return_to"])
session["return_to"] = nil
else
redirect_to :controller => "users", :action => "account"
end
end
def auto_complete_for_user_email
search = params[:user][:email]
logger.debug("search:" + search)
@users = User.find(:all, :conditions => ["email like ?", search + "%"], :order => "email ASC") unless search.blank?
if @users.length == 1
render :inline => "<ul class=\"autocomplete_list\"><li class=\"autocomplete_item\"><%= @users[0].email %></li></ul>"
else
render :inline => "<ul class=\"autocomplete_list\"></ul>"
end
end
end