app/controllers/api/users_controller.rb
module Api class UsersController < BaseController INVALID_USER_ATTRS = %w(id href current_group_id settings current_group).freeze # Cannot update other people's settings INVALID_SELF_USER_ATTRS = %w(id href current_group_id current_group).freeze EDITABLE_ATTRS = %w(password email settings).freeze include Subcollections::CustomButtonEvents include Subcollections::Tags skip_before_action :validate_api_action, :only => [:index, :show, :update] def index # rubocop:disable Lint/UselessMethodDefinition # Rails style guide and Rubocop suggest this method to be lexically redefined since we are skipping validate_api_action # See https://rails.rubystyle.guide/#lexically-scoped-action-filter # https://docs.rubocop.org/rubocop-rails/cops_rails.html#railslexicallyscopedactionfilter super end def show validate_api_action unless target_is_api_user? super end def update aname = @req.action if aname == "edit" && !api_user_role_allows?(aname) && target_is_api_user? if (Array(@req.resource.try(:keys)) - EDITABLE_ATTRS).present? raise BadRequestError, "Cannot update attributes other than #{EDITABLE_ATTRS.join(', ')} for the authenticated user" end render_resource(:users, update_collection(:users, @req.collection_id)) else validate_api_action super end end def create_resource(_type, _id, data) validate_user_create_data(data) parse_set_group(data) raise BadRequestError, "Must specify a valid group for creating a user" unless data["miq_groups"] parse_set_settings(data) user = collection_class(:users).create(data) if user.invalid? raise BadRequestError, "Failed to add a new user - #{user.errors.full_messages.join(', ')}" end user end def edit_resource(type, id, data) id.to_i == User.current_user.id ? validate_self_user_data(data) : validate_user_data(data) parse_set_group(data) parse_set_settings(data, resource_search(id, type)) super end def delete_resource_action(type, id = nil, data = nil) raise BadRequestError, "Must specify an id for deleting a user" unless id raise BadRequestError, "Cannot delete user of current request" if id.to_i == User.current_user.id super end Method `set_current_group_resource` has a Cognitive Complexity of 13 (exceeds 11 allowed). Consider refactoring. def set_current_group_resource(_type, id, data) User.current_user.tap do |user| raise "Can only edit authenticated user's current group" unless user.id == id group_id = parse_group(data["current_group"]) raise "Must specify a current_group" unless group_id new_group = user.miq_groups.where(:id => group_id).first raise "User must belong to group" unless new_group # Cannot use update_attributes! due to the allowed ability to switch between groups that may have different RBAC visibility on a user's miq_groups user.update_attribute(:current_group, new_group) end rescue => err raise BadRequestError, "Cannot set current_group - #{err}" end def revoke_sessions_collection(type, data) revoke_sessions_resource(type, current_user.id, data) end def revoke_sessions_resource(type, id, _data) api_action(type, id) do user = target_user(id, type) api_log_info("Revoking all sessions of user #{user.userid}") user.revoke_sessions action_result(true, "All sessions revoked successfully for user #{user.userid}.") rescue => err action_result(false, err.to_s) end end private def target_user(id, type) if id == current_user.id current_user elsif current_user.role_allows?(:identifier => 'revoke_user_sessions') resource_search(id, type) else raise ForbiddenError, "The user is not authorized for this task or item." end end def target_is_api_user? User.current_user.id == @req.collection_id.to_i end def parse_set_group(data) groups = if data.key?("group") group = parse_fetch_group(data.delete("group")) Array(group) if group elsif data.key?("miq_groups") data["miq_groups"].collect do |miq_group| parse_fetch_group(miq_group) end end data["miq_groups"] = groups if groups end def parse_set_settings(data, user = nil) settings = data.delete("settings") if settings.present? current_settings = user.nil? ? {} : user.settings data["settings"] = Hash(current_settings).deep_merge(settings.deep_symbolize_keys) end end def validate_user_data(data = {}) bad_attrs = data.keys.select { |k| INVALID_USER_ATTRS.include?(k) }.compact.join(", ") raise BadRequestError, "Invalid attribute(s) #{bad_attrs} specified for a user" if bad_attrs.present? raise BadRequestError, "Users must be assigned groups" if data.key?("miq_groups") && data["miq_groups"].empty? end def validate_self_user_data(data = {}) bad_attrs = data.keys.select { |k| INVALID_SELF_USER_ATTRS.include?(k) }.compact.join(", ") raise BadRequestError, "Invalid attribute(s) #{bad_attrs} specified for the current user" if bad_attrs.present? end def validate_user_create_data(data) validate_user_data(data) req_attrs = %w(name userid) req_attrs << "password" if ::Settings.authentication.mode == "database" bad_attrs = [] req_attrs.each { |attr| bad_attrs << attr if data[attr].blank? } bad_attrs << "group or miq_groups" if !data['group'] && !data['miq_groups'] raise BadRequestError, "Missing attribute(s) #{bad_attrs.join(', ')} for creating a user" if bad_attrs.present? end endend