Merged master
[arvados.git] / services / api / app / models / user.rb
index ae3f31acbe1bba5f1410fb6a8f6ae08303b0be88..41858e8b3adb3cb2394c0eb55d5a3cfc24a1d42e 100644 (file)
@@ -7,6 +7,7 @@ class User < ArvadosModel
   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
 
   has_many :authorized_keys, :foreign_key => :authorized_user_uuid, :primary_key => :uuid
@@ -79,10 +80,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 = ?',
+        Link.where('tail_uuid in (?) and link_class = ? and (head_uuid like ? or head_uuid like ?)',
                    lookup_uuids,
                    'permission',
-                   'arvados#group').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|
@@ -110,69 +112,73 @@ class User < ArvadosModel
   end
 
   def self.setup(user, openid_prefix, repo_name=nil, vm_uuid=nil)
-    login_perm_props = {identity_url_prefix: openid_prefix}
-
-    if user.uuid
-      found = User.find_by_uuid user.uuid
-      if found
-        user = found
-      end
-    end
+    return user.setup_repo_vm_links(repo_name, vm_uuid, openid_prefix)
+  end
 
-    if !found
-      if !user.email
-        raise "No email found in the input. Aborting user creation."
-      end
+  # create links
+  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
 
-      user.save!
-    
-      # Check oid_login_perm
-      oid_login_perms = Link.where(tail_uuid: user.email,
-                                   head_kind: 'arvados#user',
-                                   link_class: 'permission',
-                                   name: 'can_login')
+    return [oid_login_perm, repo_perm, vm_login_perm, group_perm, self].compact
+  end
 
-      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
+  # 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|
+      Link.delete perm
     end
 
-    # create repo, vm, and group links
-    response = {user: user, oid_login_perm: oid_login_perm}
-
-    user.setup_repo_vm_links(repo_name, vm_uuid, response)
-
-    return response
-  end 
+    # 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|
+      Link.delete perm
+    end
 
-  # create links
-  def setup_repo_vm_links(repo_name, vm_uuid, response)
-    repo_perm = create_user_repo_link repo_name
-    if repo_perm
-      response[:repo_perm] = repo_perm
+    # 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
 
-    vm_login_perm = create_vm_login_permission_link vm_uuid, repo_name
-    if vm_login_perm
-      response[:vm_login_perm] = vm_login_perm
+    # 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],
+                             head_kind: 'arvados#group',
+                             link_class: 'permission',
+                             name: 'can_read')
+    group_perms.each do |perm|
+      Link.delete perm
     end
 
-    group_perm = create_user_group_link
-    if group_perm
-      response[:group_perm] = group_perm
+    # 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
     end
-  end 
+
+    # mark the user as inactive
+    self.is_active = false
+    self.save!
+  end
 
   protected
 
@@ -243,6 +249,33 @@ 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,
+                                   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: self.email,
+                                   head_kind: 'arvados#user',
+                                   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
@@ -263,7 +296,7 @@ class User < ArvadosModel
                               link_class: 'permission',
                               name: 'can_write')
       if repo_perms.any?
-        logger.warn "User already has repository access " + 
+        logger.warn "User already has repository access " +
             repo_perms.collect { |p| p[:uuid] }.inspect
         return repo_perms.first
       end
@@ -286,9 +319,9 @@ class User < ArvadosModel
   # create login permission for the given vm_uuid, if it does not already exist
   def create_vm_login_permission_link(vm_uuid, repo_name)
     begin
-              
+
       # vm uuid is optional
-      if vm_uuid 
+      if vm_uuid
         vm = VirtualMachine.where(uuid: vm_uuid).first
 
         if not vm
@@ -296,7 +329,7 @@ class User < ArvadosModel
           raise "No vm found for #{vm_uuid}"
         end
       else
-        return 
+        return
       end
 
       logger.info { "vm uuid: " + vm[:uuid] }
@@ -306,7 +339,16 @@ class User < ArvadosModel
                               head_kind: 'arvados#virtualMachine',
                               link_class: 'permission',
                               name: 'can_login')
-      if !login_perms.any?
+
+      perm_exists = false
+      login_perms.each do |perm|
+        if perm.properties[:username] == repo_name
+          perm_exists = true
+          break
+        end
+      end
+
+      if !perm_exists
         login_perm = Link.create(tail_kind: 'arvados#user',
                                  tail_uuid: self.uuid,
                                  head_kind: 'arvados#virtualMachine',
@@ -350,7 +392,7 @@ class User < ArvadosModel
                                  link_class: 'permission',
                                  name: 'can_read')
         logger.info { "group permission: " + group_perm[:uuid] }
-      else 
+      else
         group_perm = group_perms.first
       end
 
@@ -358,4 +400,17 @@ class User < ArvadosModel
     end
   end
 
+  # Give the special "System group" permission to manage this user and
+  # all of this user's stuff.
+  #
+  def add_system_group_permission_link
+    act_as_system_user do
+      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)
+    end
+  end
 end