blob: 482f41f3c887bb518a6c6278d8dd5725c21c4953 [file] [log] [blame]
require 'digest/sha1'
require 'net/http'
#--
# require 'net/https'
#
# TODO disabled this, because this causes some error and we are not using Bugzilla integration
# see http://jira.codehaus.org/browse/JRUBY-986
#++
# More information:
# * {EPF Wiki Data model}[link:files/doc/DATAMODEL.html]
#--######################################################################
# 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 User < ActiveRecord::Base
DOMAIN_PATTERN = /@.*/
has_many :sites
has_many :checkouts
has_many :versions
has_many :user_versions, :class_name => "Version", :conditions => ['baseline_process_id is null']
has_many :comments
has_many :notifications
has_many :uploads
has_many :versions2review, :class_name => "Version", :foreign_key => "reviewer_id"
has_many :comments2review, :class_name => "Comment", :foreign_key => "reviewer_id"
belongs_to :site # default site of user TODO: not used
validates_confirmation_of :password
validates_presence_of :name, :email
validates_uniqueness_of :name, :email
validates_format_of :email, :with => /^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i
validates_format_of :admin, :with => /Y|N|C/
attr_accessor :password, :remember_me, :email_extension#, :i_agree_to_the_terms_of_use TODO reactivate this
# Changing account to admin or cadmin requires that
# you specify the user that is requesting the change
attr_accessor :user
validates_associated :user
# #new_cadmin creates the central adminstrator user
def self.new_cadmin(params)
raise 'Already create central admin' if User.count > 0
u= User.new(params)
u.hashed_password = hash_pw(u.password) if u.password
u.admin = "C"
u.confirmed_on = Time.now
return u
end
# #new_signup creates an ordinary user account
def self.new_signup(params)
user = User.new(params)
user.email = user.email + user.email_extension if ENV['EPFWIKI_DOMAINS'] && user.email_extension
logger.info("Creating account with supplied password for #{user.email}")
user.hashed_password = hash_pw(user.password) if user.password
return user
end
# #login searches the user on email and hashed_password and returns it, see also #try_to_login
def self.login(email, password)
user = nil
ENV['EPFWIKI_AUTH_METHODS'].split(',').each do |method|
logger.info("Doing login of #{email} using method #{method}")
if method == 'bugzilla' #&& user.nil?
user = User.login_bugzilla(email, password)
elsif method == 'validemail' #&& user.nil?
user = User.login_validemail(email, password)
elsif method == 'basic' #&& user.nil?
user = User.login_basicauthentication(email, password)
end
break if !user.nil?
end
return user
end
def self.login_bugzilla(email, password)
user = nil
host, port = ENV['EPFWIKI_AUTH_BUGZILLA'].split(',')
logger.debug("Login using bugzilla with settings: #{host} with port #{port}")
http = Net::HTTP.new(host, port)
# avoid console message "peer certificate won't be verified in this SSL session"
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
http.use_ssl = true
path = '/bugs/index.cgi'
# POST request -> logging in
data = "Bugzilla_login=#{email}&Bugzilla_password=#{password}&GoAheadAndLogIn=1"
logger.debug('data = ' + data)
headers = {
'Referer' => "https://#{host}/bugs/index.cgi?GoAheadAndLogIn=",
'Content-Type' => 'application/x-www-form-urlencoded'
}
resp, data = http.post(path, data, headers)
logger.info('Code = ' + resp.code)
logger.info('Message = ' + resp.message)
resp.each {|key, val| logger.info(key + ' = ' + val)}
if resp['set-cookie'].nil?
logger.info("Unauthorized (didn't get a cookie)")
else
logger.debug("Authorized #{email}/#{password}")
user = User.find_by_email(email)
if user
logger.info("User #{email} has account")
else
logger.info("Creating account #{email}")
user = User.new(:email => email, :name => email.split('@')[0])
user.set_new_pw
user.password_confirmation = user.password
user.hashed_password = hash_pw(user.password) if user.password
if user.save
logger.info("Succesfully created account: #{user.inspect}")
else
logger.info("Failed to create account #{user.errors.full_messages.join(", ")}")
Notifier::deliver_email(User.find_central_admin,
"[#{ENV['EPFWIKI_APP_NAME']}] Error creating account using bugzilla!",[],
"#{user.errors.full_messages.join(", ")}")
user = nil
end
end
end
return user
end
def self.login_basicauthentication(account, password)
logger.info("Checking un/pw using basic authentication")
user = nil
hostname, fail_code, maildomain = ENV['EPFWIKI_AUTH_BASIC'].split(',')
logger.debug("BASIC AUTH Settings: #{hostname},#{fail_code},#{maildomain}")
Net::HTTP.start(hostname) {|http|
req = Net::HTTP::Get.new('/')
req.basic_auth account, password
response = http.request(req)
logger.debug("response.code: #{response.code.inspect}, fail_code #{fail_code.inspect}")
if response.code == fail_code
logger.debug("Unauthorized #{account}/#{password}: #{response.inspect}")
return nil
else
logger.debug("Authorized #{account}/#{password}: #{response.inspect}")
user = User.find_by_account(account)
if user
logger.info("User #{account} has account")
else
logger.info("Creating account #{account}")
user = User.new(:account => account, :email => "#{account}@#{maildomain}", :name => account)
user.set_new_pw
user.password_confirmation = user.password
user.hashed_password = hash_pw(user.password) if user.password
if user.save
logger.info("Succesfully created account: #{user.inspect}")
else
logger.info("Failed to create account #{user.errors.full_messages.join(", ")}")
Notifier::deliver_email(User.find_central_admin,
"[#{ENV['EPFWIKI_APP_NAME']}] Error creating account using basic authentication!",[],
"#{user.errors.full_messages.join(", ")}")
user = nil
end
#return User.create() if user.nil
end
end
}
return user
end
def self.login_validemail(email, password)
logger.info("Checking un/pw of valid email #{email} hash_pw is #{hash_pw(password)}")
hashed_password = hash_pw(password)
user = find(:first, :conditions => ["email = ? and hashed_password = ?", email.downcase, hashed_password])
return nil if user && (password.nil? || user.confirmed_on.nil?)
return user
end
# #confirm_account is used to confirm new accounts or confirm new passwords in case user requested on
def confirm_account(token)
logger.debug("Confirming account with token: " + token)
logger.debug("Hashed password is: " + self.hashed_password)
logger.debug("Hashed password new is: " + (self.hashed_password_new || ''))
if self.hashed_password && (hash_pw(self.hashed_password) == token)
logger.debug('Confirming new account:' + self.inspect)
self.confirmed_on = Time.now
return true
elsif self.hashed_password_new && (hash_pw(self.hashed_password_new) == token)
logger.debug('Confirming a lost password:' + self.inspect)
self.confirmed_on = Time.now
self.hashed_password = self.hashed_password_new
self.hashed_password_new = nil
return true
else
return false
end
end
# Use #set_new_pw to set and return a new password for a user.
# Needs to be confirmed using #confirm_account
def set_new_pw(new_pw)
self.password = new_pw
self.hashed_password_new = hash_pw(new_pw)
logger.debug("This is the new password #{new_pw}")
end
# Log in if the name and password (after hashing)
# match the database, or if the name matches
# an entry in the database with no password
def try_to_login
User.login(self.email.downcase, self.password)
end
# #change_password changes the password of a User
def change_password(user)
raise "Password can't be blank" if user.password.blank?
self.password = user.password
self.password_confirmation = user.password_confirmation
self.hashed_password = hash_pw(user.password)
self.confirmed_on = Time.now
end
def self.cadmin(from, to)
raise 'From needs to be central admin' if !from.cadmin?
User.transaction do
to.admin = 'C'
to.user = from
from.admin = 'Y'
to.save
from.save
end
end
# Token that can be used to confirm a new account
def token
return hash_pw(self.hashed_password)
end
# Token that can be used to confirm a lost password (existing account)
def token_new
return hash_pw(self.hashed_password_new)
end
def user?
return admin == 'N'
end
def admin?
return admin == 'Y' || admin == 'C'
end
def cadmin?
return admin == 'C'
end
def self.find_central_admin
return User.find(:first, :conditions => ["admin=?", "C"] )
end
def documents_path
return "users/" + id.to_s + "/docs"
end
def images_path
return "users/" + id.to_s + "/images"
end
# #sites returns Site records where user created versions or comments
def sites
return Site.find(:all, :conditions => ['exists (select * from versions where user_id = ? and wiki_id = sites.id) or exists (select * from da_texts where user_id = ? and site_id = sites.id)', id, id])
end
def before_validation_on_update
end
def validate
if ENV['EPFWIKI_DOMAINS']
valid_domain = !ENV['EPFWIKI_DOMAINS'].split(" ").index(DOMAIN_PATTERN.match(email.downcase).to_s).nil?
errors.add(:email, "domain not valid") if !valid_domain && !self.cadmin?
end
end
def validate_on_create
errors.add(:password, "can't be blank") if password.blank? || hashed_password.blank?
errors.add(:password_confirmation, "can't be blank") if password_confirmation.blank?
errors.add("Central admin already exists") if User.count > 0 && admin == 'C'
# all users have to agree to the terms of use (except the first user)
# errors.add_to_base("You have to agree to the terms of use") if i_agree_to_the_terms_of_use != "1" && User.count != 0
end
def validate_on_update
errors.add(:hashed_password, "can't be blank") if hashed_password.blank?
old_admin = User.find(id).admin
if admin == 'C' and old_admin != 'C'
if user.nil? || User.find(user.id).admin != 'C'
errors.add(:admin, 'can only be set to C by the central admin')
end
end
if admin == 'Y' and old_admin == 'N'
errors.add(:admin, 'can only be set by an admin') if user.nil? || user.admin == 'N'
end
if admin == 'N' and !old_admin.index(/Y|C/).nil?
errors.add(:admin, 'can only be revoked by the central admin') if user.nil? || user.admin != 'C'
end
end
def after_create
create_templates if User.count == 1
end
def before_save
self.email = self.email.downcase
end
end