foreman/app/models/user.rb @ 8a65dff7
686cb440 | Ohad Levy | require 'digest/sha1'
|
|
475cdc84 | Ohad Levy | require 'foreman/threadsession'
|
|
686cb440 | Ohad Levy | ||
1ba05a93 | Ohad Levy | class User < ActiveRecord::Base
|
|
9fd7478e | Paul Kelly | include Authorization
|
|
475cdc84 | Ohad Levy | include Foreman::ThreadSession::UserModel
|
|
7a4ec5cf | Paul Kelly | attr_protected :password_hash, :password_salt, :admin
|
|
572a19c3 | Paul Kelly | attr_accessor :password, :password_confirmation, :editing_self
|
|
7a4ec5cf | Paul Kelly | ||
1ba05a93 | Ohad Levy | belongs_to :auth_source
|
|
f685dd61 | Ohad Levy | has_many :changes, :class_name => 'Audit', :as => :user
|
|
9c0e127b | Paul Kelly | has_many :usergroups, :through => :usergroup_member
|
|
has_many :direct_hosts, :as => :owner, :class_name => "Host"
|
|||
27210309 | Paul Kelly | has_and_belongs_to_many :notices, :join_table => 'user_notices'
|
|
9fd7478e | Paul Kelly | has_many :user_roles
|
|
has_many :roles, :through => :user_roles
|
|||
has_and_belongs_to_many :domains, :join_table => "user_domains"
|
|||
has_and_belongs_to_many :hostgroups, :join_table => "user_hostgroups"
|
|||
has_many :user_facts, :dependent => :destroy
|
|||
has_many :facts, :through => :user_facts, :source => :fact_name
|
|||
accepts_nested_attributes_for :user_facts, :reject_if => lambda { |a| a[:criteria].blank? }, :allow_destroy => true
|
|||
6874bbd9 | Paul Kelly | ||
1ba05a93 | Ohad Levy | validates_uniqueness_of :login, :message => "already exists"
|
|
7a4ec5cf | Paul Kelly | validates_presence_of :login, :mail, :auth_source_id
|
|
validates_presence_of :password_hash, :if => Proc.new {|user| user.manage_password?}
|
|||
validates_confirmation_of :password, :if => Proc.new {|user| user.manage_password?}, :unless => Proc.new {|user| user.password.empty?}
|
|||
1ba05a93 | Ohad Levy | validates_format_of :login, :with => /^[a-z0-9_\-@\.]*$/i
|
|
validates_length_of :login, :maximum => 30
|
|||
validates_format_of :firstname, :lastname, :with => /^[\w\s\'\-\.]*$/i, :allow_nil => true
|
|||
validates_length_of :firstname, :lastname, :maximum => 30, :allow_nil => true
|
|||
validates_format_of :mail, :with => /^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i, :allow_nil => true
|
|||
validates_length_of :mail, :maximum => 60, :allow_nil => true
|
|||
f5df7d44 | Paul Kelly | before_destroy Ensure_not_used_by.new(:hosts), :ensure_admin_is_not_deleted
|
|
7a4ec5cf | Paul Kelly | validate :name_used_in_a_usergroup
|
|
before_validation :prepare_password
|
|||
9fd7478e | Paul Kelly | after_destroy Proc.new {|user| user.domains.clear; user.hostgroups.clear}
|
|
4a8190ef | Ohad Levy | scoped_search :on => :login, :complete_value => :true
|
|
scoped_search :on => :firstname, :complete_value => :true
|
|||
scoped_search :on => :lastname, :complete_value => :true
|
|||
scoped_search :on => :mail, :complete_value => :true
|
|||
scoped_search :on => :admin, :complete_value => {:true => true, :false => false}
|
|||
scoped_search :on => :last_login_on, :complete_value => :true
|
|||
1ba05a93 | Ohad Levy | def to_label
|
|
"#{firstname} #{lastname}"
|
|||
end
|
|||
9c0e127b | Paul Kelly | alias_method :name, :to_label
|
|
def <=>(other)
|
|||
9fd7478e | Paul Kelly | self.name.downcase <=> other.name.downcase
|
|
9c0e127b | Paul Kelly | end
|
|
# The text item to see in a select dropdown menu
|
|||
def select_title
|
|||
6874bbd9 | Paul Kelly | to_label + " (#{login})"
|
|
9c0e127b | Paul Kelly | end
|
|
1ba05a93 | Ohad Levy | ||
f5df7d44 | Paul Kelly | def self.create_admin
|
|
76607ed5 | Ohad Levy | email = Setting[:administrator]
|
|
f5df7d44 | Paul Kelly | user = User.create(:login => "admin", :firstname => "Admin", :lastname => "User",
|
|
9fd7478e | Paul Kelly | :mail => email, :auth_source => AuthSourceInternal.first, :password => "changeme")
|
|
f5df7d44 | Paul Kelly | user.update_attribute :admin, true
|
|
user
|
|||
end
|
|||
9fd7478e | Paul Kelly | # Tries to find the user in the DB and then authenticate against their authentication source
|
|
# If the user is not in the DB then try to login the user on each available athentication source
|
|||
# If this succeeds then copy the user's details from the authentication source into the User table
|
|||
# Returns : User object OR nil
|
|||
1ba05a93 | Ohad Levy | def self.try_to_login(login, password)
|
|
# Make sure no one can sign in with an empty password
|
|||
return nil if password.to_s.empty?
|
|||
9fd7478e | Paul Kelly | ||
if user = find_by_login(login)
|
|||
1ba05a93 | Ohad Levy | # user is already in local database
|
|
9fd7478e | Paul Kelly | if user.auth_source and user.auth_source.authenticate(login, password)
|
|
# user has an authentication method and the authentication was successful
|
|||
User.current = user
|
|||
user.update_attribute(:last_login_on, Time.now.utc)
|
|||
else
|
|||
7e64f911 | Ohad Levy | User.current = user = nil
|
|
1ba05a93 | Ohad Levy | end
|
|
else
|
|||
# user is not yet registered, try to authenticate with available sources
|
|||
attrs = AuthSource.authenticate(login, password)
|
|||
if attrs
|
|||
user = new(*attrs)
|
|||
user.login = login
|
|||
8a685d40 | Ohad Levy | # The default user can't auto create users, we need to change to Admin for this to work
|
|
User.current = User.find_by_login "admin"
|
|||
1ba05a93 | Ohad Levy | if user.save
|
|
user.reload
|
|||
7a4ec5cf | Paul Kelly | logger.info "User '#{user.login}' auto-created from #{user.auth_source}"
|
|
9fd7478e | Paul Kelly | user.update_attribute(:last_login_on, Time.now.utc)
|
|
1ba05a93 | Ohad Levy | else
|
|
7a4ec5cf | Paul Kelly | logger.info "Failed to save User '#{user.login}' #{user.errors.full_messages}"
|
|
9fd7478e | Paul Kelly | user = nil
|
|
1ba05a93 | Ohad Levy | end
|
|
8a685d40 | Ohad Levy | User.current = user
|
|
1ba05a93 | Ohad Levy | end
|
|
end
|
|||
9fd7478e | Paul Kelly | anonymous = Role.find_by_name("Anonymous")
|
|
User.current.roles << anonymous unless user.nil? or User.current.roles.include?(anonymous)
|
|||
7a4ec5cf | Paul Kelly | return user
|
|
1ba05a93 | Ohad Levy | rescue => text
|
|
raise text
|
|||
end
|
|||
7a4ec5cf | Paul Kelly | def matching_password?(pass)
|
|
self.password_hash == encrypt_password(pass)
|
|||
end
|
|||
9fd7478e | Paul Kelly | def my_usergroups
|
|
9c0e127b | Paul Kelly | all_groups = []
|
|
for usergroup in usergroups
|
|||
all_groups += usergroup.all_usergroups
|
|||
end
|
|||
9fd7478e | Paul Kelly | all_groups.uniq
|
|
end
|
|||
def indirect_hosts
|
|||
my_usergroups.map{|g| g.hosts}.flatten.uniq
|
|||
9c0e127b | Paul Kelly | end
|
|
def hosts
|
|||
direct_hosts + indirect_hosts
|
|||
end
|
|||
def recipients
|
|||
[mail]
|
|||
end
|
|||
7a4ec5cf | Paul Kelly | def manage_password?
|
|
auth_source and auth_source.can_set_password?
|
|||
end
|
|||
9fd7478e | Paul Kelly | # Return true if the user is allowed to do the specified action
|
|
# action can be:
|
|||
# * a parameter-like Hash (eg. :controller => 'projects', :action => 'edit')
|
|||
# * a permission Symbol (eg. :edit_project)
|
|||
def allowed_to?(action, options={})
|
|||
return true if admin?
|
|||
572a19c3 | Paul Kelly | return true if editing_self
|
|
9fd7478e | Paul Kelly | return false if roles.empty?
|
|
roles.detect {|role| role.allowed_to?(action)}
|
|||
end
|
|||
def logged?
|
|||
true
|
|||
end
|
|||
# Indicates whether the user has host filtering enabled
|
|||
# Returns : Boolean
|
|||
def filtering?
|
|||
filter_on_owner or
|
|||
domains.any? or
|
|||
hostgroups.any? or
|
|||
facts.any?
|
|||
end
|
|||
7a4ec5cf | Paul Kelly | private
|
|
def prepare_password
|
|||
unless password.blank?
|
|||
self.password_salt = Digest::SHA1.hexdigest([Time.now, rand].join)
|
|||
self.password_hash = encrypt_password(password)
|
|||
end
|
|||
end
|
|||
def encrypt_password(pass)
|
|||
Digest::SHA1.hexdigest([pass, password_salt].join)
|
|||
end
|
|||
9c0e127b | Paul Kelly | ||
9fd7478e | Paul Kelly | protected
|
|
7a4ec5cf | Paul Kelly | def name_used_in_a_usergroup
|
|
9c0e127b | Paul Kelly | if Usergroup.all.map(&:name).include?(self.login)
|
|
errors.add_to_base "A usergroup already exists with this name"
|
|||
end
|
|||
end
|
|||
f5df7d44 | Paul Kelly | # The internal Admin Account is always available
|
|
# this is required as when not using external authentication, the systems logs you in with the
|
|||
# admin account automatically
|
|||
def ensure_admin_is_not_deleted
|
|||
if login == "admin"
|
|||
9fd7478e | Paul Kelly | errors.add_to_base "Can't delete internal admin account"
|
|
logger.warn "Unable to delete internal admin account"
|
|||
f5df7d44 | Paul Kelly | return false
|
|
end
|
|||
end
|
|||
4a8190ef | Ohad Levy | def as_json opts
|
|
{login => {:firstname => firstname, :lastname => lastname, :mail => mail}}
|
|||
end
|
|||
1ba05a93 | Ohad Levy | end
|