1 # Copyright (C) The Arvados Authors. All rights reserved.
3 # SPDX-License-Identifier: AGPL-3.0
7 class PermissionsTest < ActionDispatch::IntegrationTest
9 fixtures :users, :groups, :api_client_authorizations, :collections
11 test "adding and removing direct can_read links" do
12 # try to read collection as spectator
13 get "/arvados/v1/collections/#{collections(:foo_file).uuid}",
14 params: {:format => :json},
15 headers: auth(:spectator)
18 # try to add permission as spectator
19 post "/arvados/v1/links",
23 tail_uuid: users(:spectator).uuid,
24 link_class: 'permission',
26 head_uuid: collections(:foo_file).uuid,
30 headers: auth(:spectator)
33 # add permission as admin
34 post "/arvados/v1/links",
38 tail_uuid: users(:spectator).uuid,
39 link_class: 'permission',
41 head_uuid: collections(:foo_file).uuid,
46 u = json_response['uuid']
47 assert_response :success
49 # read collection as spectator
50 get "/arvados/v1/collections/#{collections(:foo_file).uuid}",
51 params: {:format => :json},
52 headers: auth(:spectator)
53 assert_response :success
55 # try to delete permission as spectator
56 delete "/arvados/v1/links/#{u}",
57 params: {:format => :json},
58 headers: auth(:spectator)
61 # delete permission as admin
62 delete "/arvados/v1/links/#{u}",
63 params: {:format => :json},
65 assert_response :success
67 # try to read collection as spectator
68 get "/arvados/v1/collections/#{collections(:foo_file).uuid}",
69 params: {:format => :json},
70 headers: auth(:spectator)
75 test "adding can_read links from user to group, group to collection" do
76 # try to read collection as spectator
77 get "/arvados/v1/collections/#{collections(:foo_file).uuid}",
78 params: {:format => :json},
79 headers: auth(:spectator)
82 # add permission for spectator to read group
83 post "/arvados/v1/links",
87 tail_uuid: users(:spectator).uuid,
88 link_class: 'permission',
90 head_uuid: groups(:private_role).uuid,
95 assert_response :success
97 # try to read collection as spectator
98 get "/arvados/v1/collections/#{collections(:foo_file).uuid}",
99 params: {:format => :json},
100 headers: auth(:spectator)
103 # add permission for group to read collection
104 post "/arvados/v1/links",
108 tail_uuid: groups(:private_role).uuid,
109 link_class: 'permission',
111 head_uuid: collections(:foo_file).uuid,
115 headers: auth(:admin)
116 u = json_response['uuid']
117 assert_response :success
119 # try to read collection as spectator
120 get "/arvados/v1/collections/#{collections(:foo_file).uuid}",
121 params: {:format => :json},
122 headers: auth(:spectator)
123 assert_response :success
125 # delete permission for group to read collection
126 delete "/arvados/v1/links/#{u}",
127 params: {:format => :json},
128 headers: auth(:admin)
129 assert_response :success
131 # try to read collection as spectator
132 get "/arvados/v1/collections/#{collections(:foo_file).uuid}",
133 params: {:format => :json},
134 headers: auth(:spectator)
140 test "adding can_read links from group to collection, user to group" do
141 # try to read collection as spectator
142 get "/arvados/v1/collections/#{collections(:foo_file).uuid}",
143 params: {:format => :json},
144 headers: auth(:spectator)
147 # add permission for group to read collection
148 post "/arvados/v1/links",
152 tail_uuid: groups(:private_role).uuid,
153 link_class: 'permission',
155 head_uuid: collections(:foo_file).uuid,
159 headers: auth(:admin)
160 assert_response :success
162 # try to read collection as spectator
163 get "/arvados/v1/collections/#{collections(:foo_file).uuid}",
164 params: {:format => :json},
165 headers: auth(:spectator)
168 # add permission for spectator to read group
169 post "/arvados/v1/links",
173 tail_uuid: users(:spectator).uuid,
174 link_class: 'permission',
176 head_uuid: groups(:private_role).uuid,
180 headers: auth(:admin)
181 u = json_response['uuid']
182 assert_response :success
184 # try to read collection as spectator
185 get "/arvados/v1/collections/#{collections(:foo_file).uuid}",
186 params: {:format => :json},
187 headers: auth(:spectator)
188 assert_response :success
190 # delete permission for spectator to read group
191 delete "/arvados/v1/links/#{u}",
192 params: {:format => :json},
193 headers: auth(:admin)
194 assert_response :success
196 # try to read collection as spectator
197 get "/arvados/v1/collections/#{collections(:foo_file).uuid}",
198 params: {:format => :json},
199 headers: auth(:spectator)
204 test "adding can_read links from user to group, group to group, group to collection" do
205 # try to read collection as spectator
206 get "/arvados/v1/collections/#{collections(:foo_file).uuid}",
207 params: {:format => :json},
208 headers: auth(:spectator)
211 # add permission for user to read group
212 post "/arvados/v1/links",
216 tail_uuid: users(:spectator).uuid,
217 link_class: 'permission',
219 head_uuid: groups(:private_role).uuid,
223 headers: auth(:admin)
224 assert_response :success
226 # add permission for group to read group
227 post "/arvados/v1/links",
231 tail_uuid: groups(:private_role).uuid,
232 link_class: 'permission',
234 head_uuid: groups(:empty_lonely_group).uuid,
238 headers: auth(:admin)
239 assert_response :success
241 # add permission for group to read collection
242 post "/arvados/v1/links",
246 tail_uuid: groups(:empty_lonely_group).uuid,
247 link_class: 'permission',
249 head_uuid: collections(:foo_file).uuid,
253 headers: auth(:admin)
254 u = json_response['uuid']
255 assert_response :success
257 # try to read collection as spectator
258 get "/arvados/v1/collections/#{collections(:foo_file).uuid}",
259 params: {:format => :json},
260 headers: auth(:spectator)
261 assert_response :success
263 # delete permission for group to read collection
264 delete "/arvados/v1/links/#{u}",
265 params: {:format => :json},
266 headers: auth(:admin)
267 assert_response :success
269 # try to read collection as spectator
270 get "/arvados/v1/collections/#{collections(:foo_file).uuid}",
271 params: {:format => :json},
272 headers: auth(:spectator)
276 test "read-only group-admin cannot modify administered user" do
277 put "/arvados/v1/users/#{users(:active).uuid}",
280 first_name: 'KilroyWasHere'
284 headers: auth(:rominiadmin)
288 test "read-only group-admin cannot read or update non-administered user" do
289 get "/arvados/v1/users/#{users(:spectator).uuid}",
290 params: {:format => :json},
291 headers: auth(:rominiadmin)
294 put "/arvados/v1/users/#{users(:spectator).uuid}",
297 first_name: 'KilroyWasHere'
301 headers: auth(:rominiadmin)
305 test "RO group-admin finds user's collections, RW group-admin can update" do
306 other_user_collection = act_as_user(users(:user_foo_in_sharing_group)) do
309 [[:rominiadmin, false],
310 [:miniadmin, true]].each do |which_user, update_should_succeed|
311 get "/arvados/v1/collections",
312 params: {:format => :json},
313 headers: auth(which_user)
314 assert_response :success
315 resp_uuids = json_response['items'].collect { |i| i['uuid'] }
316 [[true, collections(:collection_owned_by_active).uuid],
317 [true, collections(:foo_collection_in_aproject).uuid],
318 [false, other_user_collection.uuid],
319 ].each do |should_find, uuid|
320 assert_equal(should_find, !resp_uuids.index(uuid).nil?,
321 "%s should%s see %s in collection list" %
323 should_find ? '' : ' not',
325 put "/arvados/v1/collections/#{uuid}",
329 miniadmin_was_here: true
334 headers: auth(which_user)
337 elsif !update_should_succeed
340 assert_response :success
346 test "get_permissions returns list" do
347 # First confirm that user :active cannot get permissions on group :public
348 get "/arvados/v1/permissions/#{groups(:public).uuid}",
350 headers: auth(:active)
353 get "/arvados/v1/links",
355 :filters => [["link_class", "=", "permission"], ["head_uuid", "=", groups(:public).uuid]].to_json
357 headers: auth(:active)
358 assert_response :success
359 assert_equal [], json_response['items']
361 ### add some permissions, including can_manage
362 ### permission for user :active
363 post "/arvados/v1/links",
367 tail_uuid: users(:spectator).uuid,
368 link_class: 'permission',
370 head_uuid: groups(:public).uuid,
374 headers: auth(:admin)
375 assert_response :success
376 can_read_uuid = json_response['uuid']
378 post "/arvados/v1/links",
382 tail_uuid: users(:inactive).uuid,
383 link_class: 'permission',
385 head_uuid: groups(:public).uuid,
389 headers: auth(:admin)
390 assert_response :success
391 can_write_uuid = json_response['uuid']
393 # Still should not be able read these permission links
394 get "/arvados/v1/permissions/#{groups(:public).uuid}",
396 headers: auth(:active)
399 get "/arvados/v1/links",
401 :filters => [["link_class", "=", "permission"], ["head_uuid", "=", groups(:public).uuid]].to_json
403 headers: auth(:active)
404 assert_response :success
405 assert_equal [], json_response['items']
407 # Shouldn't be able to read links directly either
408 get "/arvados/v1/links/#{can_read_uuid}",
410 headers: auth(:active)
413 ### Now add a can_manage link
414 post "/arvados/v1/links",
418 tail_uuid: users(:active).uuid,
419 link_class: 'permission',
421 head_uuid: groups(:public).uuid,
425 headers: auth(:admin)
426 assert_response :success
427 can_manage_uuid = json_response['uuid']
429 # user :active should be able to retrieve permissions
430 # on group :public using get_permissions
431 get("/arvados/v1/permissions/#{groups(:public).uuid}",
432 params: { :format => :json },
433 headers: auth(:active))
434 assert_response :success
436 perm_uuids = json_response['items'].map { |item| item['uuid'] }
437 assert_includes perm_uuids, can_read_uuid, "can_read_uuid not found"
438 assert_includes perm_uuids, can_write_uuid, "can_write_uuid not found"
439 assert_includes perm_uuids, can_manage_uuid, "can_manage_uuid not found"
441 # user :active should be able to retrieve permissions
442 # on group :public using link list
443 get "/arvados/v1/links",
445 :filters => [["link_class", "=", "permission"], ["head_uuid", "=", groups(:public).uuid]].to_json
447 headers: auth(:active)
448 assert_response :success
450 perm_uuids = json_response['items'].map { |item| item['uuid'] }
451 assert_includes perm_uuids, can_read_uuid, "can_read_uuid not found"
452 assert_includes perm_uuids, can_write_uuid, "can_write_uuid not found"
453 assert_includes perm_uuids, can_manage_uuid, "can_manage_uuid not found"
455 # Should be able to read links directly too
456 get "/arvados/v1/links/#{can_read_uuid}",
457 headers: auth(:active)
458 assert_response :success
460 ### Create some objects of different types (other than projects)
461 ### inside a subproject inside the shared project, and share those
462 ### individual objects with a 3rd user ("spectator").
463 post '/arvados/v1/groups',
466 owner_uuid: groups(:public).uuid,
467 name: 'permission test subproject',
468 group_class: 'project',
471 headers: auth(:admin)
472 assert_response :success
473 subproject_uuid = json_response['uuid']
475 test_types = ['collection', 'workflow', 'container_request']
476 test_type_create_attrs = {
477 'container_request' => {
478 command: ["echo", "foo"],
479 container_image: links(:docker_image_collection_tag).name,
482 mounts: {"/out" => {kind: "tmp", capacity: 1000000}},
484 runtime_constraints: {"vcpus" => 1, "ram" => 2},
489 test_object_perm_link = {}
490 test_types.each do |test_type|
491 post "/arvados/v1/#{test_type}s",
493 test_type.to_sym => {
494 owner_uuid: subproject_uuid,
495 name: "permission test #{test_type} in subproject",
496 }.merge(test_type_create_attrs[test_type] || {}).to_json,
498 headers: auth(:admin)
499 assert_response :success
500 test_object[test_type] = json_response
502 post '/arvados/v1/links',
505 tail_uuid: users(:spectator).uuid,
506 link_class: 'permission',
508 head_uuid: test_object[test_type]['uuid'],
511 headers: auth(:admin)
512 assert_response :success
513 test_object_perm_link[test_type] = json_response
516 # The "active-can_manage-project" permission should cause the
517 # "spectator-can_read-object" links to be visible to the "active"
519 test_types.each do |test_type|
520 get "/arvados/v1/permissions/#{test_object[test_type]['uuid']}",
521 headers: auth(:active)
522 assert_response :success
523 perm_uuids = json_response['items'].map { |item| item['uuid'] }
524 assert_includes perm_uuids, test_object_perm_link[test_type]['uuid'], "can_read_uuid not found"
526 get "/arvados/v1/links/#{test_object_perm_link[test_type]['uuid']}",
527 headers: auth(:active)
528 assert_response :success
531 ['head_uuid', '=', test_object[test_type]['uuid']],
532 ['head_uuid', 'in', [test_object[test_type]['uuid']]],
533 ['head_uuid', 'in', [users(:admin).uuid, test_object[test_type]['uuid']]],
535 get "/arvados/v1/links",
537 filters: ([['link_class', '=', 'permission'], filter]).to_json,
539 headers: auth(:active)
540 assert_response :success
541 assert_not_empty json_response['items'], "could not find can_read link using index with filter #{filter}"
542 assert_equal test_object_perm_link[test_type]['uuid'], json_response['items'][0]['uuid']
545 # The "spectator-can_read-object" link should be visible to the
546 # subject user ("spectator") in a filter query, even without
547 # can_manage permission on the target object.
549 ['tail_uuid', '=', users(:spectator).uuid],
551 get "/arvados/v1/links",
553 filters: ([['link_class', '=', 'permission'], filter]).to_json,
555 headers: auth(:spectator)
556 assert_response :success
557 perm_uuids = json_response['items'].map { |item| item['uuid'] }
558 assert_includes perm_uuids, test_object_perm_link[test_type]['uuid'], "could not find can_read link using index with filter #{filter}"
562 ### Now delete the can_manage link
563 delete "/arvados/v1/links/#{can_manage_uuid}",
564 headers: auth(:active)
565 assert_response :success
567 # Should not be able read these permission links again
568 test_types.each do |test_type|
569 get "/arvados/v1/permissions/#{groups(:public).uuid}",
570 headers: auth(:active)
573 get "/arvados/v1/permissions/#{test_object[test_type]['uuid']}",
574 headers: auth(:active)
577 get "/arvados/v1/links",
579 filters: [["link_class", "=", "permission"], ["head_uuid", "=", groups(:public).uuid]].to_json
581 headers: auth(:active)
582 assert_response :success
583 assert_equal [], json_response['items']
586 ['head_uuid', '=', test_object[test_type]['uuid']],
587 ['head_uuid', 'in', [users(:admin).uuid, test_object[test_type]['uuid']]],
588 ['head_uuid', 'in', []],
590 get "/arvados/v1/links",
592 :filters => [["link_class", "=", "permission"], filter].to_json
594 headers: auth(:active)
595 assert_response :success
596 assert_equal [], json_response['items']
599 # Should not be able to read links directly either
600 get "/arvados/v1/links/#{can_read_uuid}",
601 headers: auth(:active)
604 test_types.each do |test_type|
605 get "/arvados/v1/links/#{test_object_perm_link[test_type]['uuid']}",
606 headers: auth(:active)
611 ### Create a collection, and share it with a direct permission
612 ### link (as opposed to sharing its parent project)
613 post "/arvados/v1/collections",
616 name: 'permission test',
619 headers: auth(:admin)
620 assert_response :success
621 collection_uuid = json_response['uuid']
622 post "/arvados/v1/links",
625 tail_uuid: users(:spectator).uuid,
626 link_class: 'permission',
628 head_uuid: collection_uuid,
632 headers: auth(:admin)
633 assert_response :success
634 can_read_collection_uuid = json_response['uuid']
636 # Should not be able read the permission link via permissions API,
637 # because permission is only can_read, not can_manage
638 get "/arvados/v1/permissions/#{collection_uuid}",
639 headers: auth(:active)
642 # Should not be able to read the permission link directly, for
644 get "/arvados/v1/links/#{can_read_collection_uuid}",
645 headers: auth(:active)
648 ### Now add a can_manage link
649 post "/arvados/v1/links",
652 tail_uuid: users(:active).uuid,
653 link_class: 'permission',
655 head_uuid: collection_uuid,
659 headers: auth(:admin)
660 assert_response :success
661 can_manage_collection_uuid = json_response['uuid']
663 # Should be able read both permission links via permissions API
664 get "/arvados/v1/permissions/#{collection_uuid}",
665 headers: auth(:active)
666 assert_response :success
667 perm_uuids = json_response['items'].map { |item| item['uuid'] }
668 assert_includes perm_uuids, can_read_collection_uuid, "can_read_uuid not found"
669 assert_includes perm_uuids, can_manage_collection_uuid, "can_manage_uuid not found"
671 # Should be able to read both permission links directly
672 [can_read_collection_uuid, can_manage_collection_uuid].each do |uuid|
673 get "/arvados/v1/links/#{uuid}",
674 headers: auth(:active)
675 assert_response :success
679 test "get_permissions returns 404 for nonexistent uuid" do
680 nonexistent = Group.generate_uuid
681 # make sure it really doesn't exist
682 get "/arvados/v1/groups/#{nonexistent}", params: nil, headers: auth(:admin)
685 get "/arvados/v1/permissions/#{nonexistent}", params: nil, headers: auth(:active)
689 test "get_permissions returns 403 if user can read but not manage" do
690 post "/arvados/v1/links",
693 tail_uuid: users(:active).uuid,
694 link_class: 'permission',
696 head_uuid: groups(:public).uuid,
700 headers: auth(:admin)
701 assert_response :success
703 get "/arvados/v1/permissions/#{groups(:public).uuid}",
705 headers: auth(:active)
709 test "active user can read the empty collection" do
710 # The active user should be able to read the empty collection.
712 get("/arvados/v1/collections/#{empty_collection_pdh}",
713 params: {:format => :json},
714 headers: auth(:active))
715 assert_response :success
716 assert_empty json_response['manifest_text'], "empty collection manifest_text is not empty"
719 [['can_write', 'can_read', 'can_write'],
720 ['can_manage', 'can_write', 'can_manage'],
721 ['can_manage', 'can_read', 'can_manage'],
722 ['can_read', 'can_write', 'can_write'],
723 ['can_read', 'can_manage', 'can_manage'],
724 ['can_write', 'can_manage', 'can_manage'],
725 ].each do |perm1, perm2, expect|
726 test "creating #{perm2} permission returns existing #{perm1} link as #{expect}" do
727 link1 = act_as_system_user do
729 link_class: "permission",
730 tail_uuid: users(:active).uuid,
731 head_uuid: collections(:baz_file).uuid,
735 post "/arvados/v1/links",
738 link_class: "permission",
739 tail_uuid: users(:active).uuid,
740 head_uuid: collections(:baz_file).uuid,
744 headers: auth(:admin)
745 assert_response :success
746 assert_equal link1.uuid, json_response["uuid"]
747 assert_equal expect, json_response["name"]
749 assert_equal expect, link1.name
753 test "creating duplicate login permission returns existing link" do
754 link1 = act_as_system_user do
756 link_class: "permission",
757 tail_uuid: users(:active).uuid,
758 head_uuid: virtual_machines(:testvm2).uuid,
760 properties: {"username": "foo1"}
763 link2 = act_as_system_user do
765 link_class: "permission",
766 tail_uuid: users(:active).uuid,
767 head_uuid: virtual_machines(:testvm2).uuid,
769 properties: {"username": "foo2"}
772 link3 = act_as_system_user do
774 link_class: "permission",
775 tail_uuid: users(:active).uuid,
776 head_uuid: virtual_machines(:testvm2).uuid,
780 post "/arvados/v1/links",
783 link_class: "permission",
784 tail_uuid: users(:active).uuid,
785 head_uuid: virtual_machines(:testvm2).uuid,
787 properties: {"username": "foo2"},
790 headers: auth(:admin)
791 assert_response :success
792 assert_equal link2.uuid, json_response["uuid"]
793 assert_equal link2.created_at.to_date, json_response["created_at"].to_date
794 assert_equal "can_login", json_response["name"]
795 assert_equal "foo2", json_response["properties"]["username"]
797 assert_equal "foo1", link1.properties["username"]
799 assert_equal "foo2", link2.properties["username"]