1 # Copyright (C) The Arvados Authors. All rights reserved.
3 # SPDX-License-Identifier: AGPL-3.0
5 class Link < ArvadosModel
8 include CommonApiTemplate
10 # Posgresql JSONB columns should NOT be declared as serialized, Rails 5
11 # already know how to properly treat them.
12 attribute :properties, :jsonbHash, default: {}
14 validate :name_links_are_obsolete
15 validate :permission_to_attach_to_objects
16 before_update :restrict_alter_permissions
17 after_update :call_update_permissions
18 after_create :call_update_permissions
19 before_destroy :clear_permissions
20 after_destroy :check_permissions
22 api_accessible :user, extend: :common do |t|
33 if k = ArvadosModel::resource_class_for_uuid(head_uuid)
39 if k = ArvadosModel::resource_class_for_uuid(tail_uuid)
46 def permission_to_attach_to_objects
47 # Anonymous users cannot write links
48 return false if !current_user
50 # All users can write links that don't affect permissions
51 return true if self.link_class != 'permission'
53 if PERM_LEVEL[self.name].nil?
54 errors.add(:name, "is invalid permission, must be one of 'can_read', 'can_write', 'can_manage', 'can_login'")
58 rsc_class = ArvadosModel::resource_class_for_uuid tail_uuid
60 tail_obj = Group.find_by_uuid(tail_uuid)
62 errors.add(:tail_uuid, "does not exist")
65 if tail_obj.group_class != "role"
66 errors.add(:tail_uuid, "must be a user or role, was group with group_class #{tail_obj.group_class}")
69 elsif rsc_class != User
70 errors.add(:tail_uuid, "must be a user or role")
74 # Administrators can grant permissions
75 return true if current_user.is_admin
77 head_obj = ArvadosModel.find_by_uuid(head_uuid)
79 # No permission links can be pointed to past collection versions
80 if head_obj.is_a?(Collection) && head_obj.current_version_uuid != head_uuid
81 errors.add(:head_uuid, "cannot point to a past version of a collection")
85 # All users can grant permissions on objects they own or can manage
86 return true if current_user.can?(manage: head_obj)
92 def restrict_alter_permissions
93 return true if self.link_class != 'permission' && self.link_class_was != 'permission'
95 return true if current_user.andand.uuid == system_user.uuid
97 if link_class_changed? || tail_uuid_changed? || head_uuid_changed?
98 raise "Can only alter permission link level"
109 def call_update_permissions
110 if self.link_class == 'permission'
111 update_permissions tail_uuid, head_uuid, PERM_LEVEL[name], self.uuid
115 def clear_permissions
116 if self.link_class == 'permission'
117 update_permissions tail_uuid, head_uuid, REVOKE_PERM, self.uuid
121 def check_permissions
122 if self.link_class == 'permission'
123 check_permissions_against_full_refresh
127 def name_links_are_obsolete
128 if link_class == 'name'
129 errors.add('name', 'Name links are obsolete')
136 # A user is permitted to create, update or modify a permission link
137 # if and only if they have "manage" permission on the object
138 # indicated by the permission link's head_uuid.
140 # All other links are treated as regular ArvadosModel objects.
142 def ensure_owner_uuid_is_permitted
143 if link_class == 'permission'
144 ob = ArvadosModel.find_by_uuid(head_uuid)
145 raise PermissionDeniedError unless current_user.can?(manage: ob)
146 # All permission links should be owned by the system user.
147 self.owner_uuid = system_user_uuid