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 :cannot_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 rsc_class = ArvadosModel::resource_class_for_uuid tail_uuid
55 tail_obj = Group.find_by_uuid(tail_uuid)
57 errors.add(:tail_uuid, "does not exist")
60 if tail_obj.group_class != "role"
61 errors.add(:tail_uuid, "must be a role, was #{tail_obj.group_class}")
64 elsif rsc_class != User
65 errors.add(:tail_uuid, "must be a user or role")
69 # Administrators can grant permissions
70 return true if current_user.is_admin
72 head_obj = ArvadosModel.find_by_uuid(head_uuid)
74 # No permission links can be pointed to past collection versions
75 if head_obj.is_a?(Collection) && head_obj.current_version_uuid != head_uuid
76 errors.add(:head_uuid, "cannot point to a past version of a collection")
80 # All users can grant permissions on objects they own or can manage
81 return true if current_user.can?(manage: head_obj)
87 def cannot_alter_permissions
88 return true if self.link_class != 'permission' && self.link_class_was != 'permission'
90 return true if current_user.andand.uuid == system_user.uuid
92 if link_class_changed? || name_changed? || tail_uuid_changed? || head_uuid_changed?
93 raise "Cannot alter a permission link"
104 def call_update_permissions
105 if self.link_class == 'permission'
106 update_permissions tail_uuid, head_uuid, PERM_LEVEL[name], self.uuid
110 def clear_permissions
111 if self.link_class == 'permission'
112 update_permissions tail_uuid, head_uuid, REVOKE_PERM, self.uuid
116 def check_permissions
117 if self.link_class == 'permission'
118 check_permissions_against_full_refresh
122 def name_links_are_obsolete
123 if link_class == 'name'
124 errors.add('name', 'Name links are obsolete')
131 # A user is permitted to create, update or modify a permission link
132 # if and only if they have "manage" permission on the object
133 # indicated by the permission link's head_uuid.
135 # All other links are treated as regular ArvadosModel objects.
137 def ensure_owner_uuid_is_permitted
138 if link_class == 'permission'
139 ob = ArvadosModel.find_by_uuid(head_uuid)
140 raise PermissionDeniedError unless current_user.can?(manage: ob)
141 # All permission links should be owned by the system user.
142 self.owner_uuid = system_user_uuid