require "mongoid" require_relative "role" module Devops module Model class User include ::Mongoid::Document include ::Mongoid::Timestamps::CreatedInt include ::ActiveModel::Validations store_in collection: "users" ROOT_USER_NAME = 'root' ROOT_PASSWORD = 'super_user' USER_NAME_REGEX = /[\w-]+/ ALL_POLICIES_KEY = 'all' field :_id, as: :'id', overwrite: true, type: String field :password, type: String field :email, type: String field :roles, type: Array, default: ->{ [] } validates_presence_of :id, message: "'id' is undefined" validates_length_of :id, minimum: 1, maximum: 100 validates_format_of :id, with: USER_NAME_REGEX, message: "invalid id, it should contains '_a-zA-Z0-9-.' symbols" validates_uniqueness_of :id, on: :create validates_presence_of :password, message: "'password' is undefined" validates_length_of :password, maximum: 31, minimum: 5 validates_format_of :email, with: /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i, message: "Invalid email" validate :validate_roles def initialize hash raise InvalidRecord.new("Parameter 'id' is not a string") unless hash["id"].is_a?(String) raise InvalidRecord.new("Parameter 'password' is not a string") unless hash["password"].is_a?(String) raise InvalidRecord.new("Parameter 'email' is not a string") unless hash["email"].is_a?(String) raise InvalidRecord.new("Parameter 'roles' is not an array") unless hash["roles"].is_a?(Array) super(hash) end def validate_roles dbroles = Role.in({'_id' => self.roles}) dbroles = dbroles.map{|r| r.id} buf = self.roles - dbroles unless buf.empty? errors.add(:roles, "Invalid roles: #{buf.join(', ')}") end end def self.create_root unless Role.where(:id => Role::SUPER_USER_ROLE).exists? role = Role.new({'id' => Role::SUPER_USER_ROLE, 'name' => Role::SUPER_USER_ROLE, 'description' => "All policies", 'policies' => ['all']}) role.save! DevopsLogger.logger.info("Role '#{Role::SUPER_USER_ROLE}' has been created") end unless User.where(:id => ROOT_USER_NAME).exists? root = Devops::Model::User.new({'id' => ROOT_USER_NAME, 'password' => ROOT_PASSWORD, 'email' => "#{ROOT_USER_NAME}@host.ru", 'roles' => []}) root.save! DevopsLogger.logger.info("User '#{ROOT_USER_NAME}' has been created") root end end def self.auth login, password User.find_by({id: login, password: password}) rescue Mongoid::Errors::DocumentNotFound nil end def to_hash hash = self.attributes hash.delete("password") hash["id"] = hash.delete("_id") hash end def check_policy policy return true if self.id == ROOT_USER_NAME policies = Set.new Devops::Model::Role.find(self.roles).each{|r| policies.merge(r.policies)} return true if policies.include?(ALL_POLICIES_KEY) raise Devops::Exception::Unauthorized.new("Access denied for user '#{self.id}'") unless policies.include?(policy.to_s) true rescue Mongoid::Errors::DocumentNotFound raise Devops::Exception::Unauthorized.new("Access denied for user '#{self.id}', no roles with policy '#{policy}' found") end end end end