Merge remote-tracking branch 'origin/master' into job-docker-images
[arvados.git] / services / api / app / models / user.rb
index 6db1d3ec3c01140bd8935938b127781ea3fab7d8..677685d67abdb60270b113ffeb46d6bb5edea81c 100644 (file)
@@ -1,14 +1,18 @@
+require 'can_be_an_owner'
+
 class User < ArvadosModel
-  include AssignUuid
+  include HasUuid
   include KindAndEtag
   include CommonApiTemplate
+  include CanBeAnOwner
+
   serialize :prefs, Hash
   has_many :api_client_authorizations
   before_update :prevent_privilege_escalation
   before_update :prevent_inactive_admin
   before_create :check_auto_admin
   after_create :add_system_group_permission_link
-  after_create AdminNotifier
+  after_create :send_admin_notifications
 
   has_many :authorized_keys, :foreign_key => :authorized_user_uuid, :primary_key => :uuid
 
@@ -27,7 +31,7 @@ class User < ArvadosModel
   ALL_PERMISSIONS = {read: true, write: true, manage: true}
 
   def full_name
-    "#{first_name} #{last_name}"
+    "#{first_name} #{last_name}".strip
   end
 
   def is_invited
@@ -37,7 +41,11 @@ class User < ArvadosModel
   end
 
   def groups_i_can(verb)
-    self.group_permissions.select { |uuid, mask| mask[verb] }.keys
+    my_groups = self.group_permissions.select { |uuid, mask| mask[verb] }.keys
+    if verb == :read
+      my_groups << anonymous_group_uuid
+    end
+    my_groups
   end
 
   def can?(actions)
@@ -80,10 +88,11 @@ class User < ArvadosModel
         Group.where('owner_uuid in (?)', lookup_uuids).each do |group|
           newgroups << [group.owner_uuid, group.uuid, 'can_manage']
         end
-        Link.where('tail_uuid in (?) and link_class = ? and head_kind in (?)',
+        Link.where('tail_uuid in (?) and link_class = ? and (head_uuid like ? or head_uuid like ?)',
                    lookup_uuids,
                    'permission',
-                   ['arvados#group', 'arvados#user']).each do |link|
+                   Group.uuid_like_pattern,
+                   User.uuid_like_pattern).each do |link|
           newgroups << [link.tail_uuid, link.head_uuid, link.name]
         end
         newgroups.each do |tail_uuid, head_uuid, perm_name|
@@ -111,46 +120,23 @@ class User < ArvadosModel
   end
 
   def self.setup(user, openid_prefix, repo_name=nil, vm_uuid=nil)
-    login_perm_props = {identity_url_prefix: openid_prefix}
-
-    # Check oid_login_perm
-    oid_login_perms = Link.where(tail_uuid: user.email,
-                                   head_kind: 'arvados#user',
-                                   link_class: 'permission',
-                                   name: 'can_login')
-
-    if !oid_login_perms.any?
-      # create openid login permission
-      oid_login_perm = Link.create(link_class: 'permission',
-                                   name: 'can_login',
-                                   tail_kind: 'email',
-                                   tail_uuid: user.email,
-                                   head_kind: 'arvados#user',
-                                   head_uuid: user.uuid,
-                                   properties: login_perm_props
-                                  )
-      logger.info { "openid login permission: " + oid_login_perm[:uuid] }
-    else
-      oid_login_perm = oid_login_perms.first
-    end
-
-    return [oid_login_perm] + user.setup_repo_vm_links(repo_name, vm_uuid)
+    return user.setup_repo_vm_links(repo_name, vm_uuid, openid_prefix)
   end
 
   # create links
-  def setup_repo_vm_links(repo_name, vm_uuid)
+  def setup_repo_vm_links(repo_name, vm_uuid, openid_prefix)
+    oid_login_perm = create_oid_login_perm openid_prefix
     repo_perm = create_user_repo_link repo_name
     vm_login_perm = create_vm_login_permission_link vm_uuid, repo_name
     group_perm = create_user_group_link
 
-    return [repo_perm, vm_login_perm, group_perm, self].compact
+    return [oid_login_perm, repo_perm, vm_login_perm, group_perm, self].compact
   end
 
   # delete user signatures, login, repo, and vm perms, and mark as inactive
   def unsetup
     # delete oid_login_perms for this user
     oid_login_perms = Link.where(tail_uuid: self.email,
-                                 head_kind: 'arvados#user',
                                  link_class: 'permission',
                                  name: 'can_login')
     oid_login_perms.each do |perm|
@@ -159,7 +145,6 @@ class User < ArvadosModel
 
     # delete repo_perms for this user
     repo_perms = Link.where(tail_uuid: self.uuid,
-                            head_kind: 'arvados#repository',
                             link_class: 'permission',
                             name: 'can_write')
     repo_perms.each do |perm|
@@ -168,16 +153,26 @@ class User < ArvadosModel
 
     # delete vm_login_perms for this user
     vm_login_perms = Link.where(tail_uuid: self.uuid,
-                                head_kind: 'arvados#virtualMachine',
                                 link_class: 'permission',
                                 name: 'can_login')
     vm_login_perms.each do |perm|
       Link.delete perm
     end
 
+    # delete "All users' group read permissions for this user
+    group = Group.where(name: 'All users').select do |g|
+      g[:uuid].match /-f+$/
+    end.first
+    group_perms = Link.where(tail_uuid: self.uuid,
+                             head_uuid: group[:uuid],
+                             link_class: 'permission',
+                             name: 'can_read')
+    group_perms.each do |perm|
+      Link.delete perm
+    end
+
     # delete any signatures by this user
     signed_uuids = Link.where(link_class: 'signature',
-                              tail_kind: 'arvados#user',
                               tail_uuid: self.uuid)
     signed_uuids.each do |sign|
       Link.delete sign
@@ -190,6 +185,10 @@ class User < ArvadosModel
 
   protected
 
+  def ensure_ownership_path_leads_to_user
+    true
+  end
+
   def permission_to_update
     # users must be able to update themselves (even if they are
     # inactive) in order to create sessions
@@ -257,6 +256,30 @@ class User < ArvadosModel
     merged
   end
 
+  def create_oid_login_perm (openid_prefix)
+    login_perm_props = { "identity_url_prefix" => openid_prefix}
+
+    # Check oid_login_perm
+    oid_login_perms = Link.where(tail_uuid: self.email,
+                                   link_class: 'permission',
+                                   name: 'can_login').where("head_uuid = ?", self.uuid)
+
+    if !oid_login_perms.any?
+      # create openid login permission
+      oid_login_perm = Link.create(link_class: 'permission',
+                                   name: 'can_login',
+                                   tail_uuid: self.email,
+                                   head_uuid: self.uuid,
+                                   properties: login_perm_props
+                                  )
+      logger.info { "openid login permission: " + oid_login_perm[:uuid] }
+    else
+      oid_login_perm = oid_login_perms.first
+    end
+
+    return oid_login_perm
+  end
+
   def create_user_repo_link(repo_name)
     # repo_name is optional
     if not repo_name
@@ -272,7 +295,6 @@ class User < ArvadosModel
 
       # Look for existing repository access for this repo
       repo_perms = Link.where(tail_uuid: self.uuid,
-                              head_kind: 'arvados#repository',
                               head_uuid: repo[:uuid],
                               link_class: 'permission',
                               name: 'can_write')
@@ -287,9 +309,7 @@ class User < ArvadosModel
     repo ||= Repository.create(name: repo_name)
     logger.info { "repo uuid: " + repo[:uuid] }
 
-    repo_perm = Link.create(tail_kind: 'arvados#user',
-                            tail_uuid: self.uuid,
-                            head_kind: 'arvados#repository',
+    repo_perm = Link.create(tail_uuid: self.uuid,
                             head_uuid: repo[:uuid],
                             link_class: 'permission',
                             name: 'can_write')
@@ -317,29 +337,26 @@ class User < ArvadosModel
 
       login_perms = Link.where(tail_uuid: self.uuid,
                               head_uuid: vm[:uuid],
-                              head_kind: 'arvados#virtualMachine',
                               link_class: 'permission',
                               name: 'can_login')
 
       perm_exists = false
       login_perms.each do |perm|
-        if perm.properties[:username] == repo_name
-          perm_exists = true
+        if perm.properties['username'] == repo_name
+          perm_exists = perm
           break
         end
       end
 
-      if !perm_exists
-        login_perm = Link.create(tail_kind: 'arvados#user',
-                                 tail_uuid: self.uuid,
-                                 head_kind: 'arvados#virtualMachine',
+      if perm_exists
+        login_perm = perm_exists
+      else
+        login_perm = Link.create(tail_uuid: self.uuid,
                                  head_uuid: vm[:uuid],
                                  link_class: 'permission',
                                  name: 'can_login',
-                                 properties: {username: repo_name})
+                                 properties: {'username' => repo_name})
         logger.info { "login permission: " + login_perm[:uuid] }
-      else
-        login_perm = login_perms.first
       end
 
       return login_perm
@@ -361,14 +378,11 @@ class User < ArvadosModel
 
       group_perms = Link.where(tail_uuid: self.uuid,
                               head_uuid: group[:uuid],
-                              head_kind: 'arvados#group',
                               link_class: 'permission',
                               name: 'can_read')
 
       if !group_perms.any?
-        group_perm = Link.create(tail_kind: 'arvados#user',
-                                 tail_uuid: self.uuid,
-                                 head_kind: 'arvados#group',
+        group_perm = Link.create(tail_uuid: self.uuid,
                                  head_uuid: group[:uuid],
                                  link_class: 'permission',
                                  name: 'can_read')
@@ -385,11 +399,19 @@ class User < ArvadosModel
   # all of this user's stuff.
   #
   def add_system_group_permission_link
-    Link.create(link_class: 'permission',
-                name: 'can_manage',
-                tail_kind: 'arvados#group',
-                tail_uuid: system_group_uuid,
-                head_kind: 'arvados#user',
-                head_uuid: self.uuid)
+    act_as_system_user do
+      Link.create(link_class: 'permission',
+                  name: 'can_manage',
+                  tail_uuid: system_group_uuid,
+                  head_uuid: self.uuid)
+    end
+  end
+
+  # Send admin notifications
+  def send_admin_notifications
+    AdminNotifier.new_user(self).deliver
+    if not self.is_active then
+      AdminNotifier.new_inactive_user(self).deliver
+    end
   end
 end