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