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