X-Git-Url: https://git.arvados.org/arvados.git/blobdiff_plain/533ee50c604e3900c390b77fafac1455b28a15d0..3d5a1c29aad86476f2e789e1e54cabf8b4605aa2:/services/api/app/models/user.rb diff --git a/services/api/app/models/user.rb b/services/api/app/models/user.rb index bbdd9c2843..dbacf9c017 100644 --- a/services/api/app/models/user.rb +++ b/services/api/app/models/user.rb @@ -34,6 +34,7 @@ class User < ArvadosModel before_create :set_initial_username, :if => Proc.new { username.nil? and email } + before_create :active_is_not_nil after_create :after_ownership_change after_create :setup_on_activate after_create :add_system_group_permission_link @@ -56,8 +57,8 @@ class User < ArvadosModel before_destroy :clear_permissions after_destroy :remove_self_from_permissions - has_many :authorized_keys, :foreign_key => :authorized_user_uuid, :primary_key => :uuid - has_many :repositories, foreign_key: :owner_uuid, primary_key: :uuid + has_many :authorized_keys, foreign_key: 'authorized_user_uuid', primary_key: 'uuid' + has_many :repositories, foreign_key: 'owner_uuid', primary_key: 'uuid' default_scope { where('redirect_to_user_uuid is null') } @@ -104,6 +105,10 @@ class User < ArvadosModel self.groups_i_can(:read).select { |x| x.match(/-f+$/) }.first) end + def self.ignored_select_attributes + super + ["full_name", "is_invited"] + end + def groups_i_can(verb) my_groups = self.group_permissions(VAL_FOR_PERM[verb]).keys if verb == :read @@ -145,10 +150,10 @@ SELECT 1 FROM #{PERMISSION_VIEW} }, # "name" arg is a query label that appears in logs: "user_can_query", - [[nil, self.uuid], - [nil, target_uuid], - [nil, VAL_FOR_PERM[action]], - [nil, target_owner_uuid]] + [self.uuid, + target_uuid, + VAL_FOR_PERM[action], + target_owner_uuid] ).any? return false end @@ -237,7 +242,7 @@ SELECT target_uuid, perm_level # "name" arg is a query label that appears in logs: "User.group_permissions", # "binds" arg is an array of [col_id, value] for '$1' vars: - [[nil, uuid]]). + [uuid]). rows.each do |group_uuid, max_p_val| @group_perms[group_uuid] = PERMS_FOR_VAL[max_p_val.to_i] end @@ -382,7 +387,7 @@ SELECT target_uuid, perm_level end def set_initial_username(requested: false) - if !requested.is_a?(String) || requested.empty? + if (!requested.is_a?(String) || requested.empty?) and email email_parts = email.partition("@") local_parts = email_parts.first.partition("+") if email_parts.any?(&:empty?) @@ -393,13 +398,20 @@ SELECT target_uuid, perm_level requested = email_parts.first end end - requested.sub!(/^[^A-Za-z]+/, "") - requested.gsub!(/[^A-Za-z0-9]/, "") - unless requested.empty? + if requested + requested.sub!(/^[^A-Za-z]+/, "") + requested.gsub!(/[^A-Za-z0-9]/, "") + end + unless !requested || requested.empty? self.username = find_usable_username_from(requested) end end + def active_is_not_nil + self.is_active = false if self.is_active.nil? + self.is_admin = false if self.is_admin.nil? + end + # Move this user's (i.e., self's) owned items to new_owner_uuid and # new_user_uuid (for things normally owned directly by the user). # @@ -497,14 +509,14 @@ SELECT target_uuid, perm_level end if redirect_to_new_user - update_attributes!(redirect_to_user_uuid: new_user.uuid, username: nil) + update!(redirect_to_user_uuid: new_user.uuid, username: nil) end skip_check_permissions_against_full_refresh do - update_permissions self.uuid, self.uuid, CAN_MANAGE_PERM - update_permissions new_user.uuid, new_user.uuid, CAN_MANAGE_PERM - update_permissions new_user.owner_uuid, new_user.uuid, CAN_MANAGE_PERM + update_permissions self.uuid, self.uuid, CAN_MANAGE_PERM, nil, true + update_permissions new_user.uuid, new_user.uuid, CAN_MANAGE_PERM, nil, true + update_permissions new_user.owner_uuid, new_user.uuid, CAN_MANAGE_PERM, nil, true end - update_permissions self.owner_uuid, self.uuid, CAN_MANAGE_PERM + update_permissions self.owner_uuid, self.uuid, CAN_MANAGE_PERM, nil, true end end @@ -592,6 +604,98 @@ SELECT target_uuid, perm_level primary_user end + def self.update_remote_user remote_user + remote_user = remote_user.symbolize_keys + begin + user = User.find_or_create_by(uuid: remote_user[:uuid]) + rescue ActiveRecord::RecordNotUnique + retry + end + + remote_user_prefix = user.uuid[0..4] + user.with_lock do + needupdate = {} + [:email, :username, :first_name, :last_name, :prefs].each do |k| + v = remote_user[k] + if !v.nil? && user.send(k) != v + needupdate[k] = v + end + end + + user.email = needupdate[:email] if needupdate[:email] + + loginCluster = Rails.configuration.Login.LoginCluster + if user.username.nil? || user.username == "" + # Don't have a username yet, set one + needupdate[:username] = user.set_initial_username(requested: remote_user[:username]) + elsif remote_user_prefix != loginCluster + # Upstream is not login cluster, don't try to change the + # username once set. + needupdate.delete :username + end + + if needupdate.length > 0 + begin + user.update!(needupdate) + rescue ActiveRecord::RecordInvalid + if remote_user_prefix == loginCluster && !needupdate[:username].nil? + local_user = User.find_by_username(needupdate[:username]) + # The username of this record conflicts with an existing, + # different user record. This can happen because the + # username changed upstream on the login cluster, or + # because we're federated with another cluster with a user + # by the same username. The login cluster is the source + # of truth, so change the username on the conflicting + # record and retry the update operation. + if local_user.uuid != user.uuid + new_username = "#{needupdate[:username]}#{rand(99999999)}" + Rails.logger.warn("cached username '#{needupdate[:username]}' collision with user '#{local_user.uuid}' - renaming to '#{new_username}' before retrying") + local_user.update!({username: new_username}) + retry + end + end + raise # Not the issue we're handling above + end + end + + if user.is_invited && remote_user[:is_invited] == false + # Remote user is not "invited" state, they should be unsetup, which + # also makes them inactive. + user.unsetup + else + if !user.is_invited && remote_user[:is_invited] and + (remote_user_prefix == Rails.configuration.Login.LoginCluster or + Rails.configuration.Users.AutoSetupNewUsers or + Rails.configuration.Users.NewUsersAreActive or + Rails.configuration.RemoteClusters[remote_user_prefix].andand["ActivateUsers"]) + # Remote user is 'invited' and should be set up + user.setup + end + + if !user.is_active && remote_user[:is_active] && user.is_invited and + (remote_user_prefix == Rails.configuration.Login.LoginCluster or + Rails.configuration.Users.NewUsersAreActive or + Rails.configuration.RemoteClusters[remote_user_prefix].andand["ActivateUsers"]) + # remote user is active and invited, we need to activate them + user.update!(is_active: true) + elsif user.is_active && remote_user[:is_active] == false + # remote user is not active, we need to de-activate them + user.update!(is_active: false) + end + + if remote_user_prefix == Rails.configuration.Login.LoginCluster and + user.is_active and + !remote_user[:is_admin].nil? and + user.is_admin != remote_user[:is_admin] + # Remote cluster controls our user database, including the + # admin flag. + user.update!(is_admin: remote_user[:is_admin]) + end + end + end + user + end + protected def self.attributes_required_columns