5737: Rename "skip" to "omit"
[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   test "can_manage permission on a non-group object" do
146     omit "bug #3091"
147     set_user_from_auth :admin
148
149     ob = Specimen.create!
150     # grant can_manage permission to active
151     perm_link = Link.create!(tail_uuid: users(:active).uuid,
152                              head_uuid: ob.uuid,
153                              link_class: 'permission',
154                              name: 'can_manage')
155     # ob is owned by :admin, the link is owned by root
156     assert_equal users(:admin).uuid, ob.owner_uuid
157     assert_equal system_user_uuid, perm_link.owner_uuid
158
159     # user "active" can modify the permission link
160     set_user_from_auth :active_trustedclient
161     perm_link.properties["foo"] = 'bar'
162     assert perm_link.save, "could not save modified link"
163
164     assert_equal 'bar', perm_link.properties['foo'], "link properties do not include foo = bar"
165   end
166
167   test "user without can_manage permission may not modify permission link" do
168     set_user_from_auth :admin
169
170     ob = Specimen.create!
171     # grant can_manage permission to active
172     perm_link = Link.create!(tail_uuid: users(:active).uuid,
173                              head_uuid: ob.uuid,
174                              link_class: 'permission',
175                              name: 'can_read')
176     # ob is owned by :admin, the link is owned by root
177     assert_equal ob.owner_uuid, users(:admin).uuid
178     assert_equal perm_link.owner_uuid, system_user_uuid
179
180     # user "active" may not modify the permission link
181     set_user_from_auth :active_trustedclient
182     perm_link.name = 'can_manage'
183     assert_raises ArvadosModel::PermissionDeniedError do
184       perm_link.save
185     end
186   end
187
188   test "manager user gets permission to minions' articles via can_manage link" do
189     manager = create :active_user, first_name: "Manage", last_name: "Er"
190     minion = create :active_user, first_name: "Min", last_name: "Ion"
191     minions_specimen = act_as_user minion do
192       Specimen.create!
193     end
194     # Manager creates a group. (Make sure it doesn't magically give
195     # anyone any additional permissions.)
196     g = nil
197     act_as_user manager do
198       g = create :group, name: "NoBigSecret Lab"
199       assert_empty(User.readable_by(manager).where(uuid: minion.uuid),
200                    "saw a user I shouldn't see")
201       assert_raises(ArvadosModel::PermissionDeniedError,
202                     ActiveRecord::RecordInvalid,
203                     "gave can_read permission to a user I shouldn't see") do
204         create(:permission_link,
205                name: 'can_read', tail_uuid: minion.uuid, head_uuid: g.uuid)
206       end
207       %w(can_manage can_write can_read).each do |perm_type|
208         assert_raises(ArvadosModel::PermissionDeniedError,
209                       ActiveRecord::RecordInvalid,
210                       "escalated privileges") do
211           create(:permission_link,
212                  name: perm_type, tail_uuid: g.uuid, head_uuid: minion.uuid)
213         end
214       end
215       assert_empty(User.readable_by(manager).where(uuid: minion.uuid),
216                    "manager saw minion too soon")
217       assert_empty(User.readable_by(minion).where(uuid: manager.uuid),
218                    "minion saw manager too soon")
219       assert_empty(Group.readable_by(minion).where(uuid: g.uuid),
220                    "minion saw manager's new NoBigSecret Lab group too soon")
221
222       # Manager declares everybody on the system should be able to see
223       # the NoBigSecret Lab group.
224       create(:permission_link,
225              name: 'can_read',
226              tail_uuid: 'zzzzz-j7d0g-fffffffffffffff',
227              head_uuid: g.uuid)
228       # ...but nobody has joined the group yet. Manager still can't see
229       # minion.
230       assert_empty(User.readable_by(manager).where(uuid: minion.uuid),
231                    "manager saw minion too soon")
232     end
233
234     act_as_user minion do
235       # Minion can see the group.
236       assert_not_empty(Group.readable_by(minion).where(uuid: g.uuid),
237                        "minion could not see the NoBigSecret Lab group")
238       # Minion joins the group.
239       create(:permission_link,
240              name: 'can_read',
241              tail_uuid: g.uuid,
242              head_uuid: minion.uuid)
243     end
244
245     act_as_user manager do
246       # Now, manager can see minion.
247       assert_not_empty(User.readable_by(manager).where(uuid: minion.uuid),
248                        "manager could not see minion")
249       # But cannot obtain further privileges this way.
250       assert_raises(ArvadosModel::PermissionDeniedError,
251                     "escalated privileges") do
252         create(:permission_link,
253                name: 'can_manage', tail_uuid: manager.uuid, head_uuid: minion.uuid)
254       end
255       assert_empty(Specimen
256                      .readable_by(manager)
257                      .where(uuid: minions_specimen.uuid),
258                    "manager saw the minion's private stuff")
259       assert_raises(ArvadosModel::PermissionDeniedError,
260                    "manager could update minion's private stuff") do
261         minions_specimen.update_attributes(properties: {'x' => 'y'})
262       end
263     end
264
265     act_as_system_user do
266       # Root can give Manager more privileges over Minion.
267       create(:permission_link,
268              name: 'can_manage', tail_uuid: g.uuid, head_uuid: minion.uuid)
269     end
270
271     act_as_user manager do
272       # Now, manager can read and write Minion's stuff.
273       assert_not_empty(Specimen
274                          .readable_by(manager)
275                          .where(uuid: minions_specimen.uuid),
276                        "manager could not find minion's specimen by uuid")
277       assert_equal(true,
278                    minions_specimen.update_attributes(properties: {'x' => 'y'}),
279                    "manager could not update minion's specimen object")
280     end
281   end
282
283   test "users with bidirectional read permission in group can see each other, but cannot see each other's private articles" do
284     a = create :active_user, first_name: "A"
285     b = create :active_user, first_name: "B"
286     other = create :active_user, first_name: "OTHER"
287     act_as_system_user do
288       g = create :group
289       [a,b].each do |u|
290         create(:permission_link,
291                name: 'can_read', tail_uuid: u.uuid, head_uuid: g.uuid)
292         create(:permission_link,
293                name: 'can_read', head_uuid: u.uuid, tail_uuid: g.uuid)
294       end
295     end
296     a_specimen = act_as_user a do
297       Specimen.create!
298     end
299     assert_not_empty(Specimen.readable_by(a).where(uuid: a_specimen.uuid),
300                      "A cannot read own Specimen, following test probably useless.")
301     assert_empty(Specimen.readable_by(b).where(uuid: a_specimen.uuid),
302                  "B can read A's Specimen")
303     [a,b].each do |u|
304       assert_empty(User.readable_by(u).where(uuid: other.uuid),
305                    "#{u.first_name} can see OTHER in the user list")
306       assert_empty(User.readable_by(other).where(uuid: u.uuid),
307                    "OTHER can see #{u.first_name} in the user list")
308       act_as_user u do
309         assert_raises ArvadosModel::PermissionDeniedError, "wrote without perm" do
310           other.update_attributes!(prefs: {'pwned' => true})
311         end
312         assert_equal(true, u.update_attributes!(prefs: {'thisisme' => true}),
313                      "#{u.first_name} can't update its own prefs")
314       end
315       act_as_user other do
316         assert_raises(ArvadosModel::PermissionDeniedError,
317                         "OTHER wrote #{u.first_name} without perm") do
318           u.update_attributes!(prefs: {'pwned' => true})
319         end
320         assert_equal(true, other.update_attributes!(prefs: {'thisisme' => true}),
321                      "OTHER can't update its own prefs")
322       end
323     end
324   end
325
326   test "cannot create with owner = unwritable user" do
327     set_user_from_auth :rominiadmin
328     assert_raises ArvadosModel::PermissionDeniedError, "created with owner = unwritable user" do
329       Specimen.create!(owner_uuid: users(:active).uuid)
330     end
331   end
332
333   test "cannot change owner to unwritable user" do
334     set_user_from_auth :rominiadmin
335     ob = Specimen.create!
336     assert_raises ArvadosModel::PermissionDeniedError, "changed owner to unwritable user" do
337       ob.update_attributes!(owner_uuid: users(:active).uuid)
338     end
339   end
340
341   test "cannot create with owner = unwritable group" do
342     set_user_from_auth :rominiadmin
343     assert_raises ArvadosModel::PermissionDeniedError, "created with owner = unwritable group" do
344       Specimen.create!(owner_uuid: groups(:aproject).uuid)
345     end
346   end
347
348   test "cannot change owner to unwritable group" do
349     set_user_from_auth :rominiadmin
350     ob = Specimen.create!
351     assert_raises ArvadosModel::PermissionDeniedError, "changed owner to unwritable group" do
352       ob.update_attributes!(owner_uuid: groups(:aproject).uuid)
353     end
354   end
355
356   def container_logs(container, user)
357     Log.readable_by(users(user)).
358       where(object_uuid: containers(container).uuid, event_type: "test")
359   end
360
361   test "container logs created by dispatch are visible to container requestor" do
362     set_user_from_auth :dispatch1
363     Log.create!(object_uuid: containers(:running).uuid,
364                 event_type: "test")
365
366     assert_not_empty container_logs(:running, :admin)
367     assert_not_empty container_logs(:running, :active)
368     assert_empty container_logs(:running, :spectator)
369   end
370
371   test "container logs created by dispatch are public if container request is public" do
372     set_user_from_auth :dispatch1
373     Log.create!(object_uuid: containers(:running_older).uuid,
374                 event_type: "test")
375
376     assert_not_empty container_logs(:running_older, :anonymous)
377   end
378 end