CWL spec -> CWL standards
[arvados.git] / services / api / test / unit / permission_test.rb
1 # Copyright (C) The Arvados Authors. All rights reserved.
2 #
3 # SPDX-License-Identifier: AGPL-3.0
4
5 require 'test_helper'
6
7 class PermissionTest < ActiveSupport::TestCase
8   include CurrentApiClient
9
10   test "Grant permissions on an object I own" do
11     set_user_from_auth :active_trustedclient
12
13     ob = Specimen.create
14     assert ob.save
15
16     # Ensure I have permission to manage this group even when its owner changes
17     perm_link = Link.create(tail_uuid: users(:active).uuid,
18                             head_uuid: ob.uuid,
19                             link_class: 'permission',
20                             name: 'can_manage')
21     assert perm_link.save, "should give myself permission on my own object"
22   end
23
24   test "Delete permission links when deleting an object" do
25     set_user_from_auth :active_trustedclient
26
27     ob = Specimen.create!
28     Link.create!(tail_uuid: users(:active).uuid,
29                  head_uuid: ob.uuid,
30                  link_class: 'permission',
31                  name: 'can_manage')
32     ob_uuid = ob.uuid
33     assert ob.destroy, "Could not destroy object with 1 permission link"
34     assert_empty(Link.where(head_uuid: ob_uuid),
35                  "Permission link was not deleted when object was deleted")
36   end
37
38   test "permission links owned by root" do
39     set_user_from_auth :active_trustedclient
40     ob = Specimen.create!
41     perm_link = Link.create!(tail_uuid: users(:active).uuid,
42                              head_uuid: ob.uuid,
43                              link_class: 'permission',
44                              name: 'can_read')
45     assert_equal system_user_uuid, perm_link.owner_uuid
46   end
47
48   test "readable_by" do
49     set_user_from_auth :active_trustedclient
50
51     ob = Specimen.create!
52     Link.create!(tail_uuid: users(:active).uuid,
53                  head_uuid: ob.uuid,
54                  link_class: 'permission',
55                  name: 'can_read')
56     assert Specimen.readable_by(users(:active)).where(uuid: ob.uuid).any?, "user does not have read permission"
57   end
58
59   test "writable_by" do
60     set_user_from_auth :active_trustedclient
61
62     ob = Specimen.create!
63     Link.create!(tail_uuid: users(:active).uuid,
64                  head_uuid: ob.uuid,
65                  link_class: 'permission',
66                  name: 'can_write')
67     assert ob.writable_by.include?(users(:active).uuid), "user does not have write permission"
68   end
69
70   test "writable_by reports requesting user's own uuid for a writable project" do
71     invited_to_write = users(:project_viewer)
72     group = groups(:asubproject)
73
74     # project_view can read, but cannot see write or see writers list
75     set_user_from_auth :project_viewer
76     assert_equal([group.owner_uuid],
77                  group.writable_by,
78                  "writers list should just have owner_uuid")
79
80     # allow project_viewer to write for the remainder of the test
81     set_user_from_auth :admin
82     Link.create!(tail_uuid: invited_to_write.uuid,
83                  head_uuid: group.uuid,
84                  link_class: 'permission',
85                  name: 'can_write')
86     group.permissions.reload
87
88     # project_viewer should see self in writers list (but not all writers)
89     set_user_from_auth :project_viewer
90     assert_not_nil(group.writable_by,
91                     "can write but cannot see writers list")
92     assert_includes(group.writable_by, invited_to_write.uuid,
93                     "self missing from writers list")
94     assert_includes(group.writable_by, group.owner_uuid,
95                     "project owner missing from writers list")
96     refute_includes(group.writable_by, users(:active).uuid,
97                     "saw :active user in writers list")
98
99     # active user should see full writers list
100     set_user_from_auth :active
101     assert_includes(group.writable_by, invited_to_write.uuid,
102                     "permission just added, but missing from writers list")
103
104     # allow project_viewer to manage for the remainder of the test
105     set_user_from_auth :admin
106     Link.create!(tail_uuid: invited_to_write.uuid,
107                  head_uuid: group.uuid,
108                  link_class: 'permission',
109                  name: 'can_manage')
110     # invite another writer we can test for
111     Link.create!(tail_uuid: users(:spectator).uuid,
112                  head_uuid: group.uuid,
113                  link_class: 'permission',
114                  name: 'can_write')
115     group.permissions.reload
116
117     set_user_from_auth :project_viewer
118     assert_not_nil(group.writable_by,
119                     "can manage but cannot see writers list")
120     assert_includes(group.writable_by, users(:spectator).uuid,
121                     ":spectator missing from writers list")
122   end
123
124   test "user owns group, group can_manage object's group, user can add permissions" do
125     set_user_from_auth :admin
126
127     owner_grp = Group.create!(owner_uuid: users(:active).uuid)
128
129     sp_grp = Group.create!
130     sp = Specimen.create!(owner_uuid: sp_grp.uuid)
131
132     Link.create!(link_class: 'permission',
133                  name: 'can_manage',
134                  tail_uuid: owner_grp.uuid,
135                  head_uuid: sp_grp.uuid)
136
137     # active user owns owner_grp, which has can_manage permission on sp_grp
138     # user should be able to add permissions on sp.
139     set_user_from_auth :active_trustedclient
140     test_perm = Link.create(tail_uuid: users(:active).uuid,
141                             head_uuid: sp.uuid,
142                             link_class: 'permission',
143                             name: 'can_write')
144     assert test_perm.save, "could not save new permission on target object"
145     assert test_perm.destroy, "could not delete new permission on target object"
146   end
147
148   # bug #3091
149   skip "can_manage permission on a non-group object" do
150     set_user_from_auth :admin
151
152     ob = Specimen.create!
153     # grant can_manage permission to active
154     perm_link = Link.create!(tail_uuid: users(:active).uuid,
155                              head_uuid: ob.uuid,
156                              link_class: 'permission',
157                              name: 'can_manage')
158     # ob is owned by :admin, the link is owned by root
159     assert_equal users(:admin).uuid, ob.owner_uuid
160     assert_equal system_user_uuid, perm_link.owner_uuid
161
162     # user "active" can modify the permission link
163     set_user_from_auth :active_trustedclient
164     perm_link.properties["foo"] = 'bar'
165     assert perm_link.save, "could not save modified link"
166
167     assert_equal 'bar', perm_link.properties['foo'], "link properties do not include foo = bar"
168   end
169
170   test "user without can_manage permission may not modify permission link" do
171     set_user_from_auth :admin
172
173     ob = Specimen.create!
174     # grant can_manage permission to active
175     perm_link = Link.create!(tail_uuid: users(:active).uuid,
176                              head_uuid: ob.uuid,
177                              link_class: 'permission',
178                              name: 'can_read')
179     # ob is owned by :admin, the link is owned by root
180     assert_equal ob.owner_uuid, users(:admin).uuid
181     assert_equal perm_link.owner_uuid, system_user_uuid
182
183     # user "active" may not modify the permission link
184     set_user_from_auth :active_trustedclient
185     perm_link.name = 'can_manage'
186     assert_raises ArvadosModel::PermissionDeniedError do
187       perm_link.save
188     end
189   end
190
191   test "manager user gets permission to minions' articles via can_manage link" do
192     manager = create :active_user, first_name: "Manage", last_name: "Er"
193     minion = create :active_user, first_name: "Min", last_name: "Ion"
194     minions_specimen = act_as_user minion do
195       Specimen.create!
196     end
197     # Manager creates a group. (Make sure it doesn't magically give
198     # anyone any additional permissions.)
199     g = nil
200     act_as_user manager do
201       g = create :group, name: "NoBigSecret Lab"
202       assert_empty(User.readable_by(manager).where(uuid: minion.uuid),
203                    "saw a user I shouldn't see")
204       assert_raises(ArvadosModel::PermissionDeniedError,
205                     ActiveRecord::RecordInvalid,
206                     "gave can_read permission to a user I shouldn't see") do
207         create(:permission_link,
208                name: 'can_read', tail_uuid: minion.uuid, head_uuid: g.uuid)
209       end
210       %w(can_manage can_write can_read).each do |perm_type|
211         assert_raises(ArvadosModel::PermissionDeniedError,
212                       ActiveRecord::RecordInvalid,
213                       "escalated privileges") do
214           create(:permission_link,
215                  name: perm_type, tail_uuid: g.uuid, head_uuid: minion.uuid)
216         end
217       end
218       assert_empty(User.readable_by(manager).where(uuid: minion.uuid),
219                    "manager saw minion too soon")
220       assert_empty(User.readable_by(minion).where(uuid: manager.uuid),
221                    "minion saw manager too soon")
222       assert_empty(Group.readable_by(minion).where(uuid: g.uuid),
223                    "minion saw manager's new NoBigSecret Lab group too soon")
224
225       # Manager declares everybody on the system should be able to see
226       # the NoBigSecret Lab group.
227       create(:permission_link,
228              name: 'can_read',
229              tail_uuid: 'zzzzz-j7d0g-fffffffffffffff',
230              head_uuid: g.uuid)
231       # ...but nobody has joined the group yet. Manager still can't see
232       # minion.
233       assert_empty(User.readable_by(manager).where(uuid: minion.uuid),
234                    "manager saw minion too soon")
235     end
236
237     act_as_user minion do
238       # Minion can see the group.
239       assert_not_empty(Group.readable_by(minion).where(uuid: g.uuid),
240                        "minion could not see the NoBigSecret Lab group")
241       # Minion joins the group.
242       create(:permission_link,
243              name: 'can_read',
244              tail_uuid: g.uuid,
245              head_uuid: minion.uuid)
246     end
247
248     act_as_user manager do
249       # Now, manager can see minion.
250       assert_not_empty(User.readable_by(manager).where(uuid: minion.uuid),
251                        "manager could not see minion")
252       # But cannot obtain further privileges this way.
253       assert_raises(ArvadosModel::PermissionDeniedError,
254                     "escalated privileges") do
255         create(:permission_link,
256                name: 'can_manage', tail_uuid: manager.uuid, head_uuid: minion.uuid)
257       end
258       assert_empty(Specimen
259                      .readable_by(manager)
260                      .where(uuid: minions_specimen.uuid),
261                    "manager saw the minion's private stuff")
262       assert_raises(ArvadosModel::PermissionDeniedError,
263                    "manager could update minion's private stuff") do
264         minions_specimen.update_attributes(properties: {'x' => 'y'})
265       end
266     end
267
268     act_as_system_user do
269       # Root can give Manager more privileges over Minion.
270       create(:permission_link,
271              name: 'can_manage', tail_uuid: g.uuid, head_uuid: minion.uuid)
272     end
273
274     act_as_user manager do
275       # Now, manager can read and write Minion's stuff.
276       assert_not_empty(Specimen
277                          .readable_by(manager)
278                          .where(uuid: minions_specimen.uuid),
279                        "manager could not find minion's specimen by uuid")
280       assert_equal(true,
281                    minions_specimen.update_attributes(properties: {'x' => 'y'}),
282                    "manager could not update minion's specimen object")
283     end
284   end
285
286   test "users with bidirectional read permission in group can see each other, but cannot see each other's private articles" do
287     a = create :active_user, first_name: "A"
288     b = create :active_user, first_name: "B"
289     other = create :active_user, first_name: "OTHER"
290
291     assert_empty(User.readable_by(b).where(uuid: a.uuid),
292                      "#{b.first_name} should not be able to see 'a' in the user list")
293     assert_empty(User.readable_by(a).where(uuid: b.uuid),
294                      "#{a.first_name} should not be able to see 'b' in the user list")
295
296     act_as_system_user do
297       g = create :group
298       [a,b].each do |u|
299         create(:permission_link,
300                name: 'can_read', tail_uuid: u.uuid, head_uuid: g.uuid)
301         create(:permission_link,
302                name: 'can_read', head_uuid: u.uuid, tail_uuid: g.uuid)
303       end
304     end
305
306     assert_not_empty(User.readable_by(b).where(uuid: a.uuid),
307                      "#{b.first_name} should be able to see 'a' in the user list")
308     assert_not_empty(User.readable_by(a).where(uuid: b.uuid),
309                      "#{a.first_name} should be able to see 'b' in the user list")
310
311     a_specimen = act_as_user a do
312       Specimen.create!
313     end
314     assert_not_empty(Specimen.readable_by(a).where(uuid: a_specimen.uuid),
315                      "A cannot read own Specimen, following test probably useless.")
316     assert_empty(Specimen.readable_by(b).where(uuid: a_specimen.uuid),
317                  "B can read A's Specimen")
318     [a,b].each do |u|
319       assert_empty(User.readable_by(u).where(uuid: other.uuid),
320                    "#{u.first_name} can see OTHER in the user list")
321       assert_empty(User.readable_by(other).where(uuid: u.uuid),
322                    "OTHER can see #{u.first_name} in the user list")
323       act_as_user u do
324         assert_raises ArvadosModel::PermissionDeniedError, "wrote without perm" do
325           other.update_attributes!(prefs: {'pwned' => true})
326         end
327         assert_equal(true, u.update_attributes!(prefs: {'thisisme' => true}),
328                      "#{u.first_name} can't update its own prefs")
329       end
330       act_as_user other do
331         assert_raises(ArvadosModel::PermissionDeniedError,
332                         "OTHER wrote #{u.first_name} without perm") do
333           u.update_attributes!(prefs: {'pwned' => true})
334         end
335         assert_equal(true, other.update_attributes!(prefs: {'thisisme' => true}),
336                      "OTHER can't update its own prefs")
337       end
338     end
339   end
340
341   test "cannot create with owner = unwritable user" do
342     set_user_from_auth :rominiadmin
343     assert_raises ArvadosModel::PermissionDeniedError, "created with owner = unwritable user" do
344       Specimen.create!(owner_uuid: users(:active).uuid)
345     end
346   end
347
348   test "cannot change owner to unwritable user" do
349     set_user_from_auth :rominiadmin
350     ob = Specimen.create!
351     assert_raises ArvadosModel::PermissionDeniedError, "changed owner to unwritable user" do
352       ob.update_attributes!(owner_uuid: users(:active).uuid)
353     end
354   end
355
356   test "cannot create with owner = unwritable group" do
357     set_user_from_auth :rominiadmin
358     assert_raises ArvadosModel::PermissionDeniedError, "created with owner = unwritable group" do
359       Specimen.create!(owner_uuid: groups(:aproject).uuid)
360     end
361   end
362
363   test "cannot change owner to unwritable group" do
364     set_user_from_auth :rominiadmin
365     ob = Specimen.create!
366     assert_raises ArvadosModel::PermissionDeniedError, "changed owner to unwritable group" do
367       ob.update_attributes!(owner_uuid: groups(:aproject).uuid)
368     end
369   end
370
371   def container_logs(container, user)
372     Log.readable_by(users(user)).
373       where(object_uuid: containers(container).uuid, event_type: "test")
374   end
375
376   test "container logs created by dispatch are visible to container requestor" do
377     set_user_from_auth :dispatch1
378     Log.create!(object_uuid: containers(:running).uuid,
379                 event_type: "test")
380
381     assert_not_empty container_logs(:running, :admin)
382     assert_not_empty container_logs(:running, :active)
383     assert_empty container_logs(:running, :spectator)
384   end
385
386   test "container logs created by dispatch are public if container request is public" do
387     set_user_from_auth :dispatch1
388     Log.create!(object_uuid: containers(:running_older).uuid,
389                 event_type: "test")
390
391     assert_not_empty container_logs(:running_older, :anonymous)
392   end
393 end