16817: Add Users.ActivatedUsersAreVisibleToOthers config.
[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 = Collection.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 = Collection.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 = Collection.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 :admin
50
51     ob = Collection.create!
52     Link.create!(tail_uuid: users(:active).uuid,
53                  head_uuid: ob.uuid,
54                  link_class: 'permission',
55                  name: 'can_read')
56     assert Collection.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 :admin
61
62     ob = Collection.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 "update permission link" do
71     set_user_from_auth :admin
72
73     grp = Group.create! name: "blah project", group_class: "project"
74     ob = Collection.create! owner_uuid: grp.uuid
75
76     assert !users(:active).can?(write: ob)
77     assert !users(:active).can?(read: ob)
78
79     l1 = Link.create!(tail_uuid: users(:active).uuid,
80                  head_uuid: grp.uuid,
81                  link_class: 'permission',
82                  name: 'can_write')
83
84     assert users(:active).can?(write: ob)
85     assert users(:active).can?(read: ob)
86
87     l1.update_attributes!(name: 'can_read')
88
89     assert !users(:active).can?(write: ob)
90     assert users(:active).can?(read: ob)
91
92     l1.destroy
93
94     assert !users(:active).can?(write: ob)
95     assert !users(:active).can?(read: ob)
96   end
97
98   test "writable_by reports requesting user's own uuid for a writable project" do
99     invited_to_write = users(:project_viewer)
100     group = groups(:asubproject)
101
102     # project_view can read, but cannot see write or see writers list
103     set_user_from_auth :project_viewer
104     assert_equal([group.owner_uuid],
105                  group.writable_by,
106                  "writers list should just have owner_uuid")
107
108     # allow project_viewer to write for the remainder of the test
109     set_user_from_auth :admin
110     Link.create!(tail_uuid: invited_to_write.uuid,
111                  head_uuid: group.uuid,
112                  link_class: 'permission',
113                  name: 'can_write')
114     group.permissions.reload
115
116     # project_viewer should see self in writers list (but not all writers)
117     set_user_from_auth :project_viewer
118     assert_not_nil(group.writable_by,
119                     "can write but cannot see writers list")
120     assert_includes(group.writable_by, invited_to_write.uuid,
121                     "self missing from writers list")
122     assert_includes(group.writable_by, group.owner_uuid,
123                     "project owner missing from writers list")
124     refute_includes(group.writable_by, users(:active).uuid,
125                     "saw :active user in writers list")
126
127     # active user should see full writers list
128     set_user_from_auth :active
129     assert_includes(group.writable_by, invited_to_write.uuid,
130                     "permission just added, but missing from writers list")
131
132     # allow project_viewer to manage for the remainder of the test
133     set_user_from_auth :admin
134     Link.create!(tail_uuid: invited_to_write.uuid,
135                  head_uuid: group.uuid,
136                  link_class: 'permission',
137                  name: 'can_manage')
138     # invite another writer we can test for
139     Link.create!(tail_uuid: users(:spectator).uuid,
140                  head_uuid: group.uuid,
141                  link_class: 'permission',
142                  name: 'can_write')
143     group.permissions.reload
144
145     set_user_from_auth :project_viewer
146     assert_not_nil(group.writable_by,
147                     "can manage but cannot see writers list")
148     assert_includes(group.writable_by, users(:spectator).uuid,
149                     ":spectator missing from writers list")
150   end
151
152   test "user owns group, group can_manage object's group, user can add permissions" do
153     set_user_from_auth :admin
154
155     owner_grp = Group.create!(owner_uuid: users(:active).uuid, group_class: "role")
156
157     sp_grp = Group.create!(group_class: "project")
158
159     Link.create!(link_class: 'permission',
160                  name: 'can_manage',
161                  tail_uuid: owner_grp.uuid,
162                  head_uuid: sp_grp.uuid)
163
164     sp = Collection.create!(owner_uuid: sp_grp.uuid)
165
166     # active user owns owner_grp, which has can_manage permission on sp_grp
167     # user should be able to add permissions on sp.
168     set_user_from_auth :active_trustedclient
169     test_perm = Link.create(tail_uuid: users(:active).uuid,
170                             head_uuid: sp.uuid,
171                             link_class: 'permission',
172                             name: 'can_write')
173     assert test_perm.save, "could not save new permission on target object"
174     assert test_perm.destroy, "could not delete new permission on target object"
175   end
176
177   # bug #3091
178   skip "can_manage permission on a non-group object" do
179     set_user_from_auth :admin
180
181     ob = Collection.create!
182     # grant can_manage permission to active
183     perm_link = Link.create!(tail_uuid: users(:active).uuid,
184                              head_uuid: ob.uuid,
185                              link_class: 'permission',
186                              name: 'can_manage')
187     # ob is owned by :admin, the link is owned by root
188     assert_equal users(:admin).uuid, ob.owner_uuid
189     assert_equal system_user_uuid, perm_link.owner_uuid
190
191     # user "active" can modify the permission link
192     set_user_from_auth :active_trustedclient
193     perm_link.properties["foo"] = 'bar'
194     assert perm_link.save, "could not save modified link"
195
196     assert_equal 'bar', perm_link.properties['foo'], "link properties do not include foo = bar"
197   end
198
199   test "user without can_manage permission may not modify permission link" do
200     set_user_from_auth :admin
201
202     ob = Collection.create!
203     # grant can_manage permission to active
204     perm_link = Link.create!(tail_uuid: users(:active).uuid,
205                              head_uuid: ob.uuid,
206                              link_class: 'permission',
207                              name: 'can_read')
208     # ob is owned by :admin, the link is owned by root
209     assert_equal ob.owner_uuid, users(:admin).uuid
210     assert_equal perm_link.owner_uuid, system_user_uuid
211
212     # user "active" may not modify the permission link
213     set_user_from_auth :active_trustedclient
214     perm_link.name = 'can_manage'
215     assert_raises ArvadosModel::PermissionDeniedError do
216       perm_link.save
217     end
218   end
219
220   test "manager user gets permission to minions' articles via can_manage link" do
221     Rails.configuration.Users.ActivatedUsersAreVisibleToOthers = false
222     manager = create :active_user, first_name: "Manage", last_name: "Er"
223     minion = create :active_user, first_name: "Min", last_name: "Ion"
224     minions_specimen = act_as_user minion do
225       g = Group.create! name: "minon project", group_class: "project"
226       Collection.create! owner_uuid: g.uuid
227     end
228     # Manager creates a group. (Make sure it doesn't magically give
229     # anyone any additional permissions.)
230     g = nil
231     act_as_user manager do
232       g = create :group, name: "NoBigSecret Lab", group_class: "role"
233       assert_empty(User.readable_by(manager).where(uuid: minion.uuid),
234                    "saw a user I shouldn't see")
235       assert_raises(ArvadosModel::PermissionDeniedError,
236                     ActiveRecord::RecordInvalid,
237                     "gave can_read permission to a user I shouldn't see") do
238         create(:permission_link,
239                name: 'can_read', tail_uuid: minion.uuid, head_uuid: g.uuid)
240       end
241       %w(can_manage can_write can_read).each do |perm_type|
242         assert_raises(ArvadosModel::PermissionDeniedError,
243                       ActiveRecord::RecordInvalid,
244                       "escalated privileges") do
245           create(:permission_link,
246                  name: perm_type, tail_uuid: g.uuid, head_uuid: minion.uuid)
247         end
248       end
249       assert_empty(User.readable_by(manager).where(uuid: minion.uuid),
250                    "manager saw minion too soon")
251       assert_empty(User.readable_by(minion).where(uuid: manager.uuid),
252                    "minion saw manager too soon")
253       assert_empty(Group.readable_by(minion).where(uuid: g.uuid),
254                    "minion saw manager's new NoBigSecret Lab group too soon")
255
256       # Manager declares everybody on the system should be able to see
257       # the NoBigSecret Lab group.
258       create(:permission_link,
259              name: 'can_read',
260              tail_uuid: 'zzzzz-j7d0g-fffffffffffffff',
261              head_uuid: g.uuid)
262       # ...but nobody has joined the group yet. Manager still can't see
263       # minion.
264       assert_empty(User.readable_by(manager).where(uuid: minion.uuid),
265                    "manager saw minion too soon")
266     end
267
268     act_as_user minion do
269       # Minion can see the group.
270       assert_not_empty(Group.readable_by(minion).where(uuid: g.uuid),
271                        "minion could not see the NoBigSecret Lab group")
272       # Minion joins the group.
273       create(:permission_link,
274              name: 'can_read',
275              tail_uuid: g.uuid,
276              head_uuid: minion.uuid)
277     end
278
279     act_as_user manager do
280       # Now, manager can see minion.
281       assert_not_empty(User.readable_by(manager).where(uuid: minion.uuid),
282                        "manager could not see minion")
283       # But cannot obtain further privileges this way.
284       assert_raises(ArvadosModel::PermissionDeniedError,
285                     "escalated privileges") do
286         create(:permission_link,
287                name: 'can_manage', tail_uuid: manager.uuid, head_uuid: minion.uuid)
288       end
289       assert_empty(Collection
290                      .readable_by(manager)
291                      .where(uuid: minions_specimen.uuid),
292                    "manager saw the minion's private stuff")
293       assert_raises(ArvadosModel::PermissionDeniedError,
294                    "manager could update minion's private stuff") do
295         minions_specimen.update_attributes(properties: {'x' => 'y'})
296       end
297     end
298
299     act_as_system_user do
300       # Root can give Manager more privileges over Minion.
301       create(:permission_link,
302              name: 'can_manage', tail_uuid: g.uuid, head_uuid: minion.uuid)
303     end
304
305     act_as_user manager do
306       # Now, manager can read and write Minion's stuff.
307       assert_not_empty(Collection
308                          .readable_by(manager)
309                          .where(uuid: minions_specimen.uuid),
310                        "manager could not find minion's specimen by uuid")
311       assert_equal(true,
312                    minions_specimen.update_attributes(properties: {'x' => 'y'}),
313                    "manager could not update minion's specimen object")
314     end
315   end
316
317   test "users with bidirectional read permission in group can see each other, but cannot see each other's private articles" do
318     Rails.configuration.Users.ActivatedUsersAreVisibleToOthers = false
319     a = create :active_user, first_name: "A"
320     b = create :active_user, first_name: "B"
321     other = create :active_user, first_name: "OTHER"
322
323     assert_empty(User.readable_by(b).where(uuid: a.uuid),
324                      "#{b.first_name} should not be able to see 'a' in the user list")
325     assert_empty(User.readable_by(a).where(uuid: b.uuid),
326                      "#{a.first_name} should not be able to see 'b' in the user list")
327
328     act_as_system_user do
329       g = create :group, group_class: "role"
330       [a,b].each do |u|
331         create(:permission_link,
332                name: 'can_read', tail_uuid: u.uuid, head_uuid: g.uuid)
333         create(:permission_link,
334                name: 'can_read', head_uuid: u.uuid, tail_uuid: g.uuid)
335       end
336     end
337
338     assert_not_empty(User.readable_by(b).where(uuid: a.uuid),
339                      "#{b.first_name} should be able to see 'a' in the user list")
340     assert_not_empty(User.readable_by(a).where(uuid: b.uuid),
341                      "#{a.first_name} should be able to see 'b' in the user list")
342
343     a_specimen = act_as_user a do
344       Collection.create!
345     end
346     assert_not_empty(Collection.readable_by(a).where(uuid: a_specimen.uuid),
347                      "A cannot read own Collection, following test probably useless.")
348     assert_empty(Collection.readable_by(b).where(uuid: a_specimen.uuid),
349                  "B can read A's Collection")
350     [a,b].each do |u|
351       assert_empty(User.readable_by(u).where(uuid: other.uuid),
352                    "#{u.first_name} can see OTHER in the user list")
353       assert_empty(User.readable_by(other).where(uuid: u.uuid),
354                    "OTHER can see #{u.first_name} in the user list")
355       act_as_user u do
356         assert_raises ArvadosModel::PermissionDeniedError, "wrote without perm" do
357           other.update_attributes!(prefs: {'pwned' => true})
358         end
359         assert_equal(true, u.update_attributes!(prefs: {'thisisme' => true}),
360                      "#{u.first_name} can't update its own prefs")
361       end
362       act_as_user other do
363         assert_raises(ArvadosModel::PermissionDeniedError,
364                         "OTHER wrote #{u.first_name} without perm") do
365           u.update_attributes!(prefs: {'pwned' => true})
366         end
367         assert_equal(true, other.update_attributes!(prefs: {'thisisme' => true}),
368                      "OTHER can't update its own prefs")
369       end
370     end
371   end
372
373   test "cannot create with owner = unwritable user" do
374     set_user_from_auth :rominiadmin
375     assert_raises ArvadosModel::PermissionDeniedError, "created with owner = unwritable user" do
376       Collection.create!(owner_uuid: users(:active).uuid)
377     end
378   end
379
380   test "cannot change owner to unwritable user" do
381     set_user_from_auth :rominiadmin
382     ob = Collection.create!
383     assert_raises ArvadosModel::PermissionDeniedError, "changed owner to unwritable user" do
384       ob.update_attributes!(owner_uuid: users(:active).uuid)
385     end
386   end
387
388   test "cannot create with owner = unwritable group" do
389     set_user_from_auth :rominiadmin
390     assert_raises ArvadosModel::PermissionDeniedError, "created with owner = unwritable group" do
391       Collection.create!(owner_uuid: groups(:aproject).uuid)
392     end
393   end
394
395   test "cannot change owner to unwritable group" do
396     set_user_from_auth :rominiadmin
397     ob = Collection.create!
398     assert_raises ArvadosModel::PermissionDeniedError, "changed owner to unwritable group" do
399       ob.update_attributes!(owner_uuid: groups(:aproject).uuid)
400     end
401   end
402
403   def container_logs(container, user)
404     Log.readable_by(users(user)).
405       where(object_uuid: containers(container).uuid, event_type: "test")
406   end
407
408   test "container logs created by dispatch are visible to container requestor" do
409     set_user_from_auth :dispatch1
410     Log.create!(object_uuid: containers(:running).uuid,
411                 event_type: "test")
412
413     assert_not_empty container_logs(:running, :admin)
414     assert_not_empty container_logs(:running, :active)
415     assert_empty container_logs(:running, :spectator)
416   end
417
418   test "container logs created by dispatch are public if container request is public" do
419     set_user_from_auth :dispatch1
420     Log.create!(object_uuid: containers(:running_older).uuid,
421                 event_type: "test")
422
423     assert_not_empty container_logs(:running_older, :anonymous)
424   end
425
426   test "add user to group, then remove them" do
427     set_user_from_auth :admin
428     grp = Group.create!(owner_uuid: system_user_uuid, group_class: "role")
429     col = Collection.create!(owner_uuid: system_user_uuid)
430
431     l0 = Link.create!(tail_uuid: grp.uuid,
432                  head_uuid: col.uuid,
433                  link_class: 'permission',
434                  name: 'can_read')
435
436     assert_empty Collection.readable_by(users(:active)).where(uuid: col.uuid)
437     assert_empty User.readable_by(users(:active)).where(uuid: users(:project_viewer).uuid)
438
439     l1 = Link.create!(tail_uuid: users(:active).uuid,
440                  head_uuid: grp.uuid,
441                  link_class: 'permission',
442                  name: 'can_read')
443     l2 = Link.create!(tail_uuid: grp.uuid,
444                  head_uuid: users(:active).uuid,
445                  link_class: 'permission',
446                  name: 'can_read')
447
448     l3 = Link.create!(tail_uuid: users(:project_viewer).uuid,
449                  head_uuid: grp.uuid,
450                  link_class: 'permission',
451                  name: 'can_read')
452     l4 = Link.create!(tail_uuid: grp.uuid,
453                  head_uuid: users(:project_viewer).uuid,
454                  link_class: 'permission',
455                  name: 'can_read')
456
457     assert Collection.readable_by(users(:active)).where(uuid: col.uuid).first
458     assert User.readable_by(users(:active)).where(uuid: users(:project_viewer).uuid).first
459
460     l1.destroy
461     l2.destroy
462
463     assert_empty Collection.readable_by(users(:active)).where(uuid: col.uuid)
464     assert_empty User.readable_by(users(:active)).where(uuid: users(:project_viewer).uuid)
465
466   end
467
468
469   test "add user to group, then change permission level" do
470     set_user_from_auth :admin
471     grp = Group.create!(owner_uuid: system_user_uuid, group_class: "project")
472     col = Collection.create!(owner_uuid: grp.uuid)
473     assert_empty Collection.readable_by(users(:active)).where(uuid: col.uuid)
474     assert_empty User.readable_by(users(:active)).where(uuid: users(:project_viewer).uuid)
475
476     l1 = Link.create!(tail_uuid: users(:active).uuid,
477                  head_uuid: grp.uuid,
478                  link_class: 'permission',
479                  name: 'can_manage')
480
481     assert Collection.readable_by(users(:active)).where(uuid: col.uuid).first
482     assert users(:active).can?(read: col.uuid)
483     assert users(:active).can?(write: col.uuid)
484     assert users(:active).can?(manage: col.uuid)
485
486     l1.name = 'can_read'
487     l1.save!
488
489     assert Collection.readable_by(users(:active)).where(uuid: col.uuid).first
490     assert users(:active).can?(read: col.uuid)
491     assert !users(:active).can?(write: col.uuid)
492     assert !users(:active).can?(manage: col.uuid)
493
494     l1.name = 'can_write'
495     l1.save!
496
497     assert Collection.readable_by(users(:active)).where(uuid: col.uuid).first
498     assert users(:active).can?(read: col.uuid)
499     assert users(:active).can?(write: col.uuid)
500     assert !users(:active).can?(manage: col.uuid)
501   end
502
503
504   test "add user to group, then add overlapping permission link to group" do
505     set_user_from_auth :admin
506     grp = Group.create!(owner_uuid: system_user_uuid, group_class: "project")
507     col = Collection.create!(owner_uuid: grp.uuid)
508     assert_empty Collection.readable_by(users(:active)).where(uuid: col.uuid)
509     assert_empty User.readable_by(users(:active)).where(uuid: users(:project_viewer).uuid)
510
511     l1 = Link.create!(tail_uuid: users(:active).uuid,
512                  head_uuid: grp.uuid,
513                  link_class: 'permission',
514                  name: 'can_manage')
515
516     assert Collection.readable_by(users(:active)).where(uuid: col.uuid).first
517     assert users(:active).can?(read: col.uuid)
518     assert users(:active).can?(write: col.uuid)
519     assert users(:active).can?(manage: col.uuid)
520
521     l3 = Link.create!(tail_uuid: users(:active).uuid,
522                  head_uuid: grp.uuid,
523                  link_class: 'permission',
524                  name: 'can_read')
525
526     assert Collection.readable_by(users(:active)).where(uuid: col.uuid).first
527     assert users(:active).can?(read: col.uuid)
528     assert users(:active).can?(write: col.uuid)
529     assert users(:active).can?(manage: col.uuid)
530
531     l3.destroy!
532
533     assert Collection.readable_by(users(:active)).where(uuid: col.uuid).first
534     assert users(:active).can?(read: col.uuid)
535     assert users(:active).can?(write: col.uuid)
536     assert users(:active).can?(manage: col.uuid)
537   end
538
539
540   test "add user to group, then add overlapping permission link to subproject" do
541     set_user_from_auth :admin
542     grp = Group.create!(owner_uuid: system_user_uuid, group_class: "role")
543     prj = Group.create!(owner_uuid: system_user_uuid, group_class: "project")
544
545     l0 = Link.create!(tail_uuid: grp.uuid,
546                  head_uuid: prj.uuid,
547                  link_class: 'permission',
548                  name: 'can_manage')
549
550     assert_empty Group.readable_by(users(:active)).where(uuid: prj.uuid)
551     assert_empty User.readable_by(users(:active)).where(uuid: users(:project_viewer).uuid)
552
553     l1 = Link.create!(tail_uuid: users(:active).uuid,
554                  head_uuid: grp.uuid,
555                  link_class: 'permission',
556                  name: 'can_manage')
557     l2 = Link.create!(tail_uuid: grp.uuid,
558                  head_uuid: users(:active).uuid,
559                  link_class: 'permission',
560                  name: 'can_read')
561
562     assert Group.readable_by(users(:active)).where(uuid: prj.uuid).first
563     assert users(:active).can?(read: prj.uuid)
564     assert users(:active).can?(write: prj.uuid)
565     assert users(:active).can?(manage: prj.uuid)
566
567     l3 = Link.create!(tail_uuid: grp.uuid,
568                  head_uuid: prj.uuid,
569                  link_class: 'permission',
570                  name: 'can_read')
571
572     assert Group.readable_by(users(:active)).where(uuid: prj.uuid).first
573     assert users(:active).can?(read: prj.uuid)
574     assert users(:active).can?(write: prj.uuid)
575     assert users(:active).can?(manage: prj.uuid)
576
577     l3.destroy!
578
579     assert Group.readable_by(users(:active)).where(uuid: prj.uuid).first
580     assert users(:active).can?(read: prj.uuid)
581     assert users(:active).can?(write: prj.uuid)
582     assert users(:active).can?(manage: prj.uuid)
583   end
584
585   [system_user_uuid, anonymous_user_uuid].each do |u|
586     test "cannot delete system user #{u}" do
587       act_as_system_user do
588         assert_raises ArvadosModel::PermissionDeniedError do
589           User.find_by_uuid(u).destroy
590         end
591       end
592     end
593   end
594
595   [system_group_uuid, anonymous_group_uuid, public_project_uuid].each do |g|
596     test "cannot delete system group #{g}" do
597       act_as_system_user do
598         assert_raises ArvadosModel::PermissionDeniedError do
599           Group.find_by_uuid(g).destroy
600         end
601       end
602     end
603   end
604 end