1 # Copyright (C) The Arvados Authors. All rights reserved.
3 # SPDX-License-Identifier: AGPL-3.0
7 class PermissionTest < ActiveSupport::TestCase
8 include CurrentApiClient
10 test "Grant permissions on an object I own" do
11 set_user_from_auth :active_trustedclient
13 ob = Collection.create
16 # Ensure I have permission to manage this group even when its owner changes
17 perm_link = Link.create(tail_uuid: users(:active).uuid,
19 link_class: 'permission',
21 assert perm_link.save, "should give myself permission on my own object"
24 test "Delete permission links when deleting an object" do
25 set_user_from_auth :active_trustedclient
27 ob = Collection.create!
28 Link.create!(tail_uuid: users(:active).uuid,
30 link_class: 'permission',
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")
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,
43 link_class: 'permission',
45 assert_equal system_user_uuid, perm_link.owner_uuid
49 set_user_from_auth :admin
51 ob = Collection.create!
52 Link.create!(tail_uuid: users(:active).uuid,
54 link_class: 'permission',
56 assert Collection.readable_by(users(:active)).where(uuid: ob.uuid).any?, "user does not have read permission"
60 set_user_from_auth :admin
62 ob = Collection.create!
63 Link.create!(tail_uuid: users(:active).uuid,
65 link_class: 'permission',
67 assert ob.writable_by.include?(users(:active).uuid), "user does not have write permission"
70 test "update permission link" do
71 set_user_from_auth :admin
73 grp = Group.create! name: "blah project", group_class: "project"
74 ob = Collection.create! owner_uuid: grp.uuid
76 assert !users(:active).can?(write: ob)
77 assert !users(:active).can?(read: ob)
79 l1 = Link.create!(tail_uuid: users(:active).uuid,
81 link_class: 'permission',
84 assert users(:active).can?(write: ob)
85 assert users(:active).can?(read: ob)
87 l1.update!(name: 'can_read')
89 assert !users(:active).can?(write: ob)
90 assert users(:active).can?(read: ob)
94 assert !users(:active).can?(write: ob)
95 assert !users(:active).can?(read: ob)
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)
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],
106 "writers list should just have owner_uuid")
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',
114 group.permissions.reload
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")
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")
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',
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',
143 group.permissions.reload
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")
152 test "user owns group, group can_manage object's group, user can add permissions" do
153 set_user_from_auth :admin
155 owner_grp = Group.create!(owner_uuid: users(:active).uuid, group_class: "role")
157 sp_grp = Group.create!(group_class: "project")
159 Link.create!(link_class: 'permission',
161 tail_uuid: owner_grp.uuid,
162 head_uuid: sp_grp.uuid)
164 sp = Collection.create!(owner_uuid: sp_grp.uuid)
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,
171 link_class: 'permission',
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"
178 skip "can_manage permission on a non-group object" do
179 set_user_from_auth :admin
181 ob = Collection.create!
182 # grant can_manage permission to active
183 perm_link = Link.create!(tail_uuid: users(:active).uuid,
185 link_class: 'permission',
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
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"
196 assert_equal 'bar', perm_link.properties['foo'], "link properties do not include foo = bar"
199 test "user without can_manage permission may not modify permission link" do
200 set_user_from_auth :admin
202 ob = Collection.create!
203 # grant can_manage permission to active
204 perm_link = Link.create!(tail_uuid: users(:active).uuid,
206 link_class: 'permission',
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
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
220 test "manager user gets permission to minions' articles via can_manage link" do
221 Rails.configuration.Users.RoleGroupsVisibleToAll = false
222 Rails.configuration.Users.ActivatedUsersAreVisibleToOthers = false
223 manager = create :active_user, first_name: "Manage", last_name: "Er"
224 minion = create :active_user, first_name: "Min", last_name: "Ion"
225 minions_specimen = act_as_user minion do
226 g = Group.create! name: "minon project", group_class: "project"
227 Collection.create! owner_uuid: g.uuid
229 # Manager creates a group. (Make sure it doesn't magically give
230 # anyone any additional permissions.)
232 act_as_user manager do
233 g = create :group, name: "NoBigSecret Lab", group_class: "role"
234 assert_empty(User.readable_by(manager).where(uuid: minion.uuid),
235 "saw a user I shouldn't see")
236 assert_raises(ArvadosModel::PermissionDeniedError,
237 ActiveRecord::RecordInvalid,
238 "gave can_read permission to a user I shouldn't see") do
239 create(:permission_link,
240 name: 'can_read', tail_uuid: minion.uuid, head_uuid: g.uuid)
242 %w(can_manage can_write can_read).each do |perm_type|
243 assert_raises(ArvadosModel::PermissionDeniedError,
244 ActiveRecord::RecordInvalid,
245 "escalated privileges") do
246 create(:permission_link,
247 name: perm_type, tail_uuid: g.uuid, head_uuid: minion.uuid)
250 assert_empty(User.readable_by(manager).where(uuid: minion.uuid),
251 "manager saw minion too soon")
252 assert_empty(User.readable_by(minion).where(uuid: manager.uuid),
253 "minion saw manager too soon")
254 assert_empty(Group.readable_by(minion).where(uuid: g.uuid),
255 "minion saw manager's new NoBigSecret Lab group too soon")
257 # Manager declares everybody on the system should be able to see
258 # the NoBigSecret Lab group.
259 create(:permission_link,
261 tail_uuid: 'zzzzz-j7d0g-fffffffffffffff',
263 # ...but nobody has joined the group yet. Manager still can't see
265 assert_empty(User.readable_by(manager).where(uuid: minion.uuid),
266 "manager saw minion too soon")
269 act_as_user minion do
270 # Minion can see the group.
271 assert_not_empty(Group.readable_by(minion).where(uuid: g.uuid),
272 "minion could not see the NoBigSecret Lab group")
273 # Minion joins the group.
274 create(:permission_link,
277 head_uuid: minion.uuid)
280 act_as_user manager do
281 # Now, manager can see minion.
282 assert_not_empty(User.readable_by(manager).where(uuid: minion.uuid),
283 "manager could not see minion")
284 # But cannot obtain further privileges this way.
285 assert_raises(ArvadosModel::PermissionDeniedError,
286 "escalated privileges") do
287 create(:permission_link,
288 name: 'can_manage', tail_uuid: manager.uuid, head_uuid: minion.uuid)
290 assert_empty(Collection
291 .readable_by(manager)
292 .where(uuid: minions_specimen.uuid),
293 "manager saw the minion's private stuff")
294 assert_raises(ArvadosModel::PermissionDeniedError,
295 "manager could update minion's private stuff") do
296 minions_specimen.update(properties: {'x' => 'y'})
300 act_as_system_user do
301 # Root can give Manager more privileges over Minion.
302 create(:permission_link,
303 name: 'can_manage', tail_uuid: g.uuid, head_uuid: minion.uuid)
306 act_as_user manager do
307 # Now, manager can read and write Minion's stuff.
308 assert_not_empty(Collection
309 .readable_by(manager)
310 .where(uuid: minions_specimen.uuid),
311 "manager could not find minion's specimen by uuid")
313 minions_specimen.update(properties: {'x' => 'y'}),
314 "manager could not update minion's specimen object")
318 test "users with bidirectional read permission in group can see each other, but cannot see each other's private articles" do
319 Rails.configuration.Users.ActivatedUsersAreVisibleToOthers = false
320 a = create :active_user, first_name: "A"
321 b = create :active_user, first_name: "B"
322 other = create :active_user, first_name: "OTHER"
324 assert_empty(User.readable_by(b).where(uuid: a.uuid),
325 "#{b.first_name} should not be able to see 'a' in the user list")
326 assert_empty(User.readable_by(a).where(uuid: b.uuid),
327 "#{a.first_name} should not be able to see 'b' in the user list")
329 act_as_system_user do
330 g = create :group, group_class: "role"
332 create(:permission_link,
333 name: 'can_read', tail_uuid: u.uuid, head_uuid: g.uuid)
334 create(:permission_link,
335 name: 'can_read', head_uuid: u.uuid, tail_uuid: g.uuid)
339 assert_not_empty(User.readable_by(b).where(uuid: a.uuid),
340 "#{b.first_name} should be able to see 'a' in the user list")
341 assert_not_empty(User.readable_by(a).where(uuid: b.uuid),
342 "#{a.first_name} should be able to see 'b' in the user list")
344 a_specimen = act_as_user a do
347 assert_not_empty(Collection.readable_by(a).where(uuid: a_specimen.uuid),
348 "A cannot read own Collection, following test probably useless.")
349 assert_empty(Collection.readable_by(b).where(uuid: a_specimen.uuid),
350 "B can read A's Collection")
352 assert_empty(User.readable_by(u).where(uuid: other.uuid),
353 "#{u.first_name} can see OTHER in the user list")
354 assert_empty(User.readable_by(other).where(uuid: u.uuid),
355 "OTHER can see #{u.first_name} in the user list")
357 assert_raises ArvadosModel::PermissionDeniedError, "wrote without perm" do
358 other.update!(prefs: {'pwned' => true})
360 assert_equal(true, u.update!(prefs: {'thisisme' => true}),
361 "#{u.first_name} can't update its own prefs")
364 assert_raises(ArvadosModel::PermissionDeniedError,
365 "OTHER wrote #{u.first_name} without perm") do
366 u.update!(prefs: {'pwned' => true})
368 assert_equal(true, other.update!(prefs: {'thisisme' => true}),
369 "OTHER can't update its own prefs")
374 test "cannot create with owner = unwritable user" do
375 set_user_from_auth :rominiadmin
376 assert_raises ArvadosModel::PermissionDeniedError, "created with owner = unwritable user" do
377 Collection.create!(owner_uuid: users(:active).uuid)
381 test "cannot change owner to unwritable user" do
382 set_user_from_auth :rominiadmin
383 ob = Collection.create!
384 assert_raises ArvadosModel::PermissionDeniedError, "changed owner to unwritable user" do
385 ob.update!(owner_uuid: users(:active).uuid)
389 test "cannot create with owner = unwritable group" do
390 set_user_from_auth :rominiadmin
391 assert_raises ArvadosModel::PermissionDeniedError, "created with owner = unwritable group" do
392 Collection.create!(owner_uuid: groups(:aproject).uuid)
396 test "cannot change owner to unwritable group" do
397 set_user_from_auth :rominiadmin
398 ob = Collection.create!
399 assert_raises ArvadosModel::PermissionDeniedError, "changed owner to unwritable group" do
400 ob.update!(owner_uuid: groups(:aproject).uuid)
404 def container_logs(container, user)
405 Log.readable_by(users(user)).
406 where(object_uuid: containers(container).uuid, event_type: "test")
409 test "container logs created by dispatch are visible to container requestor" do
410 set_user_from_auth :dispatch1
411 Log.create!(object_uuid: containers(:running).uuid,
414 assert_not_empty container_logs(:running, :admin)
415 assert_not_empty container_logs(:running, :active)
416 assert_empty container_logs(:running, :spectator)
419 test "container logs created by dispatch are public if container request is public" do
420 set_user_from_auth :dispatch1
421 Log.create!(object_uuid: containers(:running_older).uuid,
424 assert_not_empty container_logs(:running_older, :anonymous)
427 test "add user to group, then remove them" do
428 set_user_from_auth :admin
429 grp = Group.create!(owner_uuid: system_user_uuid, group_class: "role")
430 col = Collection.create!(owner_uuid: system_user_uuid)
432 l0 = Link.create!(tail_uuid: grp.uuid,
434 link_class: 'permission',
437 assert_empty Collection.readable_by(users(:active)).where(uuid: col.uuid)
438 assert_empty User.readable_by(users(:active)).where(uuid: users(:project_viewer).uuid)
440 l1 = Link.create!(tail_uuid: users(:active).uuid,
442 link_class: 'permission',
444 l2 = Link.create!(tail_uuid: grp.uuid,
445 head_uuid: users(:active).uuid,
446 link_class: 'permission',
449 l3 = Link.create!(tail_uuid: users(:project_viewer).uuid,
451 link_class: 'permission',
453 l4 = Link.create!(tail_uuid: grp.uuid,
454 head_uuid: users(:project_viewer).uuid,
455 link_class: 'permission',
458 assert Collection.readable_by(users(:active)).where(uuid: col.uuid).first
459 assert User.readable_by(users(:active)).where(uuid: users(:project_viewer).uuid).first
464 assert_empty Collection.readable_by(users(:active)).where(uuid: col.uuid)
465 assert_empty User.readable_by(users(:active)).where(uuid: users(:project_viewer).uuid)
470 test "add user to group, then change permission level" do
471 set_user_from_auth :admin
472 grp = Group.create!(owner_uuid: system_user_uuid, group_class: "project")
473 col = Collection.create!(owner_uuid: grp.uuid)
474 assert_empty Collection.readable_by(users(:active)).where(uuid: col.uuid)
475 assert_empty User.readable_by(users(:active)).where(uuid: users(:project_viewer).uuid)
477 l1 = Link.create!(tail_uuid: users(:active).uuid,
479 link_class: 'permission',
482 assert Collection.readable_by(users(:active)).where(uuid: col.uuid).first
483 assert users(:active).can?(read: col.uuid)
484 assert users(:active).can?(write: col.uuid)
485 assert users(:active).can?(manage: col.uuid)
490 assert Collection.readable_by(users(:active)).where(uuid: col.uuid).first
491 assert users(:active).can?(read: col.uuid)
492 assert !users(:active).can?(write: col.uuid)
493 assert !users(:active).can?(manage: col.uuid)
495 l1.name = 'can_write'
498 assert Collection.readable_by(users(:active)).where(uuid: col.uuid).first
499 assert users(:active).can?(read: col.uuid)
500 assert users(:active).can?(write: col.uuid)
501 assert !users(:active).can?(manage: col.uuid)
505 test "add user to group, then add overlapping permission link to group" do
506 set_user_from_auth :admin
507 grp = Group.create!(owner_uuid: system_user_uuid, group_class: "project")
508 col = Collection.create!(owner_uuid: grp.uuid)
509 assert_empty Collection.readable_by(users(:active)).where(uuid: col.uuid)
510 assert_empty User.readable_by(users(:active)).where(uuid: users(:project_viewer).uuid)
512 l1 = Link.create!(tail_uuid: users(:active).uuid,
514 link_class: 'permission',
517 assert Collection.readable_by(users(:active)).where(uuid: col.uuid).first
518 assert users(:active).can?(read: col.uuid)
519 assert users(:active).can?(write: col.uuid)
520 assert users(:active).can?(manage: col.uuid)
522 l3 = Link.create!(tail_uuid: users(:active).uuid,
524 link_class: 'permission',
527 assert Collection.readable_by(users(:active)).where(uuid: col.uuid).first
528 assert users(:active).can?(read: col.uuid)
529 assert users(:active).can?(write: col.uuid)
530 assert users(:active).can?(manage: col.uuid)
532 # Creating l3 should have automatically deleted l1 and upgraded to
533 # the max permission of {l1, l3}, i.e., can_manage (see #18693) so
534 # there should be no can_read link now.
535 refute Link.where(tail_uuid: l3.tail_uuid,
536 head_uuid: l3.head_uuid,
537 link_class: 'permission',
538 name: 'can_read').any?
540 assert Collection.readable_by(users(:active)).where(uuid: col.uuid).first
541 assert users(:active).can?(read: col.uuid)
542 assert users(:active).can?(write: col.uuid)
543 assert users(:active).can?(manage: col.uuid)
547 test "add user to group, then add overlapping permission link to subproject" do
548 set_user_from_auth :admin
549 grp = Group.create!(owner_uuid: system_user_uuid, group_class: "role")
550 prj = Group.create!(owner_uuid: system_user_uuid, group_class: "project")
552 l0 = Link.create!(tail_uuid: grp.uuid,
554 link_class: 'permission',
557 assert_empty Group.readable_by(users(:active)).where(uuid: prj.uuid)
558 assert_empty User.readable_by(users(:active)).where(uuid: users(:project_viewer).uuid)
560 l1 = Link.create!(tail_uuid: users(:active).uuid,
562 link_class: 'permission',
564 l2 = Link.create!(tail_uuid: grp.uuid,
565 head_uuid: users(:active).uuid,
566 link_class: 'permission',
569 assert Group.readable_by(users(:active)).where(uuid: prj.uuid).first
570 assert users(:active).can?(read: prj.uuid)
571 assert users(:active).can?(write: prj.uuid)
572 assert users(:active).can?(manage: prj.uuid)
574 l3 = Link.create!(tail_uuid: grp.uuid,
576 link_class: 'permission',
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)
584 # Creating l3 should have automatically deleted l0 and upgraded to
585 # the max permission of {l0, l3}, i.e., can_manage (see #18693) so
586 # there should be no can_read link now.
587 refute Link.where(tail_uuid: l3.tail_uuid,
588 head_uuid: l3.head_uuid,
589 link_class: 'permission',
590 name: 'can_read').any?
592 assert Group.readable_by(users(:active)).where(uuid: prj.uuid).first
593 assert users(:active).can?(read: prj.uuid)
594 assert users(:active).can?(write: prj.uuid)
595 assert users(:active).can?(manage: prj.uuid)
598 [system_user_uuid, anonymous_user_uuid].each do |u|
599 test "cannot delete system user #{u}" do
600 act_as_system_user do
601 assert_raises ArvadosModel::PermissionDeniedError do
602 User.find_by_uuid(u).destroy
608 [system_group_uuid, anonymous_group_uuid, public_project_uuid].each do |g|
609 test "cannot delete system group #{g}" do
610 act_as_system_user do
611 assert_raises ArvadosModel::PermissionDeniedError do
612 Group.find_by_uuid(g).destroy
618 # Show query plan for readable_by query. The plan for a test db
619 # might not resemble the plan for a production db, but it doesn't
620 # hurt to show the test db plan in test logs, and the .
621 [false, true].each do |include_trash|
622 test "query plan, include_trash=#{include_trash}" do
623 sql = Collection.readable_by(users(:active), include_trash: include_trash).to_sql
624 sql = "explain analyze #{sql}"
626 q = ActiveRecord::Base.connection.exec_query(sql)
627 q.rows.each do |row| STDERR.puts(row) end