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 "adding can_read links from group to collection, user to group, then trash group" do
277 # try to read collection as spectator
278 get "/arvados/v1/collections/#{collections(:foo_file).uuid}",
279 params: {:format => :json},
280 headers: auth(:spectator)
283 # add permission for group to read collection
284 post "/arvados/v1/links",
288 tail_uuid: groups(:private_role).uuid,
289 link_class: 'permission',
291 head_uuid: collections(:foo_file).uuid,
295 headers: auth(:admin)
296 assert_response :success
298 # try to read collection as spectator
299 get "/arvados/v1/collections/#{collections(:foo_file).uuid}",
300 params: {:format => :json},
301 headers: auth(:spectator)
304 # add permission for spectator to read group
305 post "/arvados/v1/links",
309 tail_uuid: users(:spectator).uuid,
310 link_class: 'permission',
312 head_uuid: groups(:private_role).uuid,
316 headers: auth(:admin)
317 u = json_response['uuid']
318 assert_response :success
320 # try to read collection as spectator
321 get "/arvados/v1/collections/#{collections(:foo_file).uuid}",
322 params: {:format => :json},
323 headers: auth(:spectator)
324 assert_response :success
326 # put the group in the trash, this should keep the group members
327 # but delete the permissions.
328 post "/arvados/v1/groups/#{groups(:private_role).uuid}/trash",
329 params: {:format => :json},
330 headers: auth(:admin)
331 assert_response :success
333 # try to read collection as spectator, should fail now
334 get "/arvados/v1/collections/#{collections(:foo_file).uuid}",
335 params: {:format => :json},
336 headers: auth(:spectator)
339 # should not be able to grant permission to a trashed group
340 post "/arvados/v1/links",
344 tail_uuid: groups(:private_role).uuid,
345 link_class: 'permission',
347 head_uuid: collections(:foo_file).uuid,
351 headers: auth(:admin)
354 # can't take group out of the trash
355 post "/arvados/v1/groups/#{groups(:private_role).uuid}/untrash",
356 params: {:format => :json},
357 headers: auth(:admin)
360 # when a role group is untrashed the permissions don't
361 # automatically come back
362 get "/arvados/v1/collections/#{collections(:foo_file).uuid}",
363 params: {:format => :json},
364 headers: auth(:spectator)
367 # can't add permission for group to read collection either
368 post "/arvados/v1/links",
372 tail_uuid: groups(:private_role).uuid,
373 link_class: 'permission',
375 head_uuid: collections(:foo_file).uuid,
379 headers: auth(:admin)
382 # still can't read foo file
383 get "/arvados/v1/collections/#{collections(:foo_file).uuid}",
384 params: {:format => :json},
385 headers: auth(:spectator)
389 test "read-only group-admin cannot modify administered user" do
390 put "/arvados/v1/users/#{users(:active).uuid}",
393 first_name: 'KilroyWasHere'
397 headers: auth(:rominiadmin)
401 test "read-only group-admin cannot read or update non-administered user" do
402 get "/arvados/v1/users/#{users(:spectator).uuid}",
403 params: {:format => :json},
404 headers: auth(:rominiadmin)
407 put "/arvados/v1/users/#{users(:spectator).uuid}",
410 first_name: 'KilroyWasHere'
414 headers: auth(:rominiadmin)
418 test "RO group-admin finds user's collections, RW group-admin can update" do
419 other_user_collection = act_as_user(users(:user_foo_in_sharing_group)) do
422 [[:rominiadmin, false],
423 [:miniadmin, true]].each do |which_user, update_should_succeed|
424 get "/arvados/v1/collections",
425 params: {:format => :json},
426 headers: auth(which_user)
427 assert_response :success
428 resp_uuids = json_response['items'].collect { |i| i['uuid'] }
429 [[true, collections(:collection_owned_by_active).uuid],
430 [true, collections(:foo_collection_in_aproject).uuid],
431 [false, other_user_collection.uuid],
432 ].each do |should_find, uuid|
433 assert_equal(should_find, !resp_uuids.index(uuid).nil?,
434 "%s should%s see %s in collection list" %
436 should_find ? '' : ' not',
438 put "/arvados/v1/collections/#{uuid}",
442 miniadmin_was_here: true
447 headers: auth(which_user)
450 elsif !update_should_succeed
453 assert_response :success
459 test "get_permissions returns list" do
460 # First confirm that user :active cannot get permissions on group :public
461 get "/arvados/v1/permissions/#{groups(:public).uuid}",
463 headers: auth(:active)
466 get "/arvados/v1/links",
468 :filters => [["link_class", "=", "permission"], ["head_uuid", "=", groups(:public).uuid]].to_json
470 headers: auth(:active)
471 assert_response :success
472 assert_equal [], json_response['items']
474 ### add some permissions, including can_manage
475 ### permission for user :active
476 post "/arvados/v1/links",
480 tail_uuid: users(:spectator).uuid,
481 link_class: 'permission',
483 head_uuid: groups(:public).uuid,
487 headers: auth(:admin)
488 assert_response :success
489 can_read_uuid = json_response['uuid']
491 post "/arvados/v1/links",
495 tail_uuid: users(:inactive).uuid,
496 link_class: 'permission',
498 head_uuid: groups(:public).uuid,
502 headers: auth(:admin)
503 assert_response :success
504 can_write_uuid = json_response['uuid']
506 # Still should not be able read these permission links
507 get "/arvados/v1/permissions/#{groups(:public).uuid}",
509 headers: auth(:active)
512 get "/arvados/v1/links",
514 :filters => [["link_class", "=", "permission"], ["head_uuid", "=", groups(:public).uuid]].to_json
516 headers: auth(:active)
517 assert_response :success
518 assert_equal [], json_response['items']
520 # Shouldn't be able to read links directly either
521 get "/arvados/v1/links/#{can_read_uuid}",
523 headers: auth(:active)
526 ### Now add a can_manage link
527 post "/arvados/v1/links",
531 tail_uuid: users(:active).uuid,
532 link_class: 'permission',
534 head_uuid: groups(:public).uuid,
538 headers: auth(:admin)
539 assert_response :success
540 can_manage_uuid = json_response['uuid']
542 # user :active should be able to retrieve permissions
543 # on group :public using get_permissions
544 get("/arvados/v1/permissions/#{groups(:public).uuid}",
545 params: { :format => :json },
546 headers: auth(:active))
547 assert_response :success
549 perm_uuids = json_response['items'].map { |item| item['uuid'] }
550 assert_includes perm_uuids, can_read_uuid, "can_read_uuid not found"
551 assert_includes perm_uuids, can_write_uuid, "can_write_uuid not found"
552 assert_includes perm_uuids, can_manage_uuid, "can_manage_uuid not found"
554 # user :active should be able to retrieve permissions
555 # on group :public using link list
556 get "/arvados/v1/links",
558 :filters => [["link_class", "=", "permission"], ["head_uuid", "=", groups(:public).uuid]].to_json
560 headers: auth(:active)
561 assert_response :success
563 perm_uuids = json_response['items'].map { |item| item['uuid'] }
564 assert_includes perm_uuids, can_read_uuid, "can_read_uuid not found"
565 assert_includes perm_uuids, can_write_uuid, "can_write_uuid not found"
566 assert_includes perm_uuids, can_manage_uuid, "can_manage_uuid not found"
568 # Should be able to read links directly too
569 get "/arvados/v1/links/#{can_read_uuid}",
570 headers: auth(:active)
571 assert_response :success
573 ### Create some objects of different types (other than projects)
574 ### inside a subproject inside the shared project, and share those
575 ### individual objects with a 3rd user ("spectator").
576 post '/arvados/v1/groups',
579 owner_uuid: groups(:public).uuid,
580 name: 'permission test subproject',
581 group_class: 'project',
584 headers: auth(:admin)
585 assert_response :success
586 subproject_uuid = json_response['uuid']
588 test_types = ['collection', 'workflow', 'container_request']
589 test_type_create_attrs = {
590 'container_request' => {
591 command: ["echo", "foo"],
592 container_image: links(:docker_image_collection_tag).name,
595 mounts: {"/out" => {kind: "tmp", capacity: 1000000}},
597 runtime_constraints: {"vcpus" => 1, "ram" => 2},
602 test_object_perm_link = {}
603 test_types.each do |test_type|
604 post "/arvados/v1/#{test_type}s",
606 test_type.to_sym => {
607 owner_uuid: subproject_uuid,
608 name: "permission test #{test_type} in subproject",
609 }.merge(test_type_create_attrs[test_type] || {}).to_json,
611 headers: auth(:admin)
612 assert_response :success
613 test_object[test_type] = json_response
615 post '/arvados/v1/links',
618 tail_uuid: users(:spectator).uuid,
619 link_class: 'permission',
621 head_uuid: test_object[test_type]['uuid'],
624 headers: auth(:admin)
625 assert_response :success
626 test_object_perm_link[test_type] = json_response
629 # The "active-can_manage-project" permission should cause the
630 # "spectator-can_read-object" links to be visible to the "active"
632 test_types.each do |test_type|
633 get "/arvados/v1/permissions/#{test_object[test_type]['uuid']}",
634 headers: auth(:active)
635 assert_response :success
636 perm_uuids = json_response['items'].map { |item| item['uuid'] }
637 assert_includes perm_uuids, test_object_perm_link[test_type]['uuid'], "can_read_uuid not found"
639 get "/arvados/v1/links/#{test_object_perm_link[test_type]['uuid']}",
640 headers: auth(:active)
641 assert_response :success
644 ['head_uuid', '=', test_object[test_type]['uuid']],
645 ['head_uuid', 'in', [test_object[test_type]['uuid']]],
646 ['head_uuid', 'in', [users(:admin).uuid, test_object[test_type]['uuid']]],
648 get "/arvados/v1/links",
650 filters: ([['link_class', '=', 'permission'], filter]).to_json,
652 headers: auth(:active)
653 assert_response :success
654 assert_not_empty json_response['items'], "could not find can_read link using index with filter #{filter}"
655 assert_equal test_object_perm_link[test_type]['uuid'], json_response['items'][0]['uuid']
658 # The "spectator-can_read-object" link should be visible to the
659 # subject user ("spectator") in a filter query, even without
660 # can_manage permission on the target object.
662 ['tail_uuid', '=', users(:spectator).uuid],
664 get "/arvados/v1/links",
666 filters: ([['link_class', '=', 'permission'], filter]).to_json,
668 headers: auth(:spectator)
669 assert_response :success
670 perm_uuids = json_response['items'].map { |item| item['uuid'] }
671 assert_includes perm_uuids, test_object_perm_link[test_type]['uuid'], "could not find can_read link using index with filter #{filter}"
675 ### Now delete the can_manage link
676 delete "/arvados/v1/links/#{can_manage_uuid}",
677 headers: auth(:active)
678 assert_response :success
680 # Should not be able read these permission links again
681 test_types.each do |test_type|
682 get "/arvados/v1/permissions/#{groups(:public).uuid}",
683 headers: auth(:active)
686 get "/arvados/v1/permissions/#{test_object[test_type]['uuid']}",
687 headers: auth(:active)
690 get "/arvados/v1/links",
692 filters: [["link_class", "=", "permission"], ["head_uuid", "=", groups(:public).uuid]].to_json
694 headers: auth(:active)
695 assert_response :success
696 assert_equal [], json_response['items']
699 ['head_uuid', '=', test_object[test_type]['uuid']],
700 ['head_uuid', 'in', [users(:admin).uuid, test_object[test_type]['uuid']]],
701 ['head_uuid', 'in', []],
703 get "/arvados/v1/links",
705 :filters => [["link_class", "=", "permission"], filter].to_json
707 headers: auth(:active)
708 assert_response :success
709 assert_equal [], json_response['items']
712 # Should not be able to read links directly either
713 get "/arvados/v1/links/#{can_read_uuid}",
714 headers: auth(:active)
717 test_types.each do |test_type|
718 get "/arvados/v1/links/#{test_object_perm_link[test_type]['uuid']}",
719 headers: auth(:active)
724 ### Create a collection, and share it with a direct permission
725 ### link (as opposed to sharing its parent project)
726 post "/arvados/v1/collections",
729 name: 'permission test',
732 headers: auth(:admin)
733 assert_response :success
734 collection_uuid = json_response['uuid']
735 post "/arvados/v1/links",
738 tail_uuid: users(:spectator).uuid,
739 link_class: 'permission',
741 head_uuid: collection_uuid,
745 headers: auth(:admin)
746 assert_response :success
747 can_read_collection_uuid = json_response['uuid']
749 # Should not be able read the permission link via permissions API,
750 # because permission is only can_read, not can_manage
751 get "/arvados/v1/permissions/#{collection_uuid}",
752 headers: auth(:active)
755 # Should not be able to read the permission link directly, for
757 get "/arvados/v1/links/#{can_read_collection_uuid}",
758 headers: auth(:active)
761 ### Now add a can_manage link
762 post "/arvados/v1/links",
765 tail_uuid: users(:active).uuid,
766 link_class: 'permission',
768 head_uuid: collection_uuid,
772 headers: auth(:admin)
773 assert_response :success
774 can_manage_collection_uuid = json_response['uuid']
776 # Should be able read both permission links via permissions API
777 get "/arvados/v1/permissions/#{collection_uuid}",
778 headers: auth(:active)
779 assert_response :success
780 perm_uuids = json_response['items'].map { |item| item['uuid'] }
781 assert_includes perm_uuids, can_read_collection_uuid, "can_read_uuid not found"
782 assert_includes perm_uuids, can_manage_collection_uuid, "can_manage_uuid not found"
784 # Should be able to read both permission links directly
785 [can_read_collection_uuid, can_manage_collection_uuid].each do |uuid|
786 get "/arvados/v1/links/#{uuid}",
787 headers: auth(:active)
788 assert_response :success
792 test "get_permissions returns 404 for nonexistent uuid" do
793 nonexistent = Group.generate_uuid
794 # make sure it really doesn't exist
795 get "/arvados/v1/groups/#{nonexistent}", params: nil, headers: auth(:admin)
798 get "/arvados/v1/permissions/#{nonexistent}", params: nil, headers: auth(:active)
802 test "get_permissions returns 403 if user can read but not manage" do
803 post "/arvados/v1/links",
806 tail_uuid: users(:active).uuid,
807 link_class: 'permission',
809 head_uuid: groups(:public).uuid,
813 headers: auth(:admin)
814 assert_response :success
816 get "/arvados/v1/permissions/#{groups(:public).uuid}",
818 headers: auth(:active)
822 test "active user can read the empty collection" do
823 # The active user should be able to read the empty collection.
825 get("/arvados/v1/collections/#{empty_collection_pdh}",
826 params: {:format => :json},
827 headers: auth(:active))
828 assert_response :success
829 assert_empty json_response['manifest_text'], "empty collection manifest_text is not empty"
832 [['can_write', 'can_read', 'can_write'],
833 ['can_manage', 'can_write', 'can_manage'],
834 ['can_manage', 'can_read', 'can_manage'],
835 ['can_read', 'can_write', 'can_write'],
836 ['can_read', 'can_manage', 'can_manage'],
837 ['can_write', 'can_manage', 'can_manage'],
838 ].each do |perm1, perm2, expect|
839 test "creating #{perm2} permission returns existing #{perm1} link as #{expect}" do
840 link1 = act_as_system_user do
842 link_class: "permission",
843 tail_uuid: users(:active).uuid,
844 head_uuid: collections(:baz_file).uuid,
848 post "/arvados/v1/links",
851 link_class: "permission",
852 tail_uuid: users(:active).uuid,
853 head_uuid: collections(:baz_file).uuid,
857 headers: auth(:admin)
858 assert_response :success
859 assert_equal link1.uuid, json_response["uuid"]
860 assert_equal expect, json_response["name"]
862 assert_equal expect, link1.name
866 test "creating duplicate login permission returns existing link" do
867 link1 = act_as_system_user do
869 link_class: "permission",
870 tail_uuid: users(:active).uuid,
871 head_uuid: virtual_machines(:testvm2).uuid,
873 properties: {"username": "foo1"}
876 link2 = act_as_system_user do
878 link_class: "permission",
879 tail_uuid: users(:active).uuid,
880 head_uuid: virtual_machines(:testvm2).uuid,
882 properties: {"username": "foo2"}
885 link3 = act_as_system_user do
887 link_class: "permission",
888 tail_uuid: users(:active).uuid,
889 head_uuid: virtual_machines(:testvm2).uuid,
893 post "/arvados/v1/links",
896 link_class: "permission",
897 tail_uuid: users(:active).uuid,
898 head_uuid: virtual_machines(:testvm2).uuid,
900 properties: {"username": "foo2"},
903 headers: auth(:admin)
904 assert_response :success
905 assert_equal link2.uuid, json_response["uuid"]
906 assert_equal link2.created_at.to_date, json_response["created_at"].to_date
907 assert_equal "can_login", json_response["name"]
908 assert_equal "foo2", json_response["properties"]["username"]
910 assert_equal "foo1", link1.properties["username"]
912 assert_equal "foo2", link2.properties["username"]