Merge branch '15877-accept-json-in-json'
[arvados.git] / services / api / test / functional / arvados / v1 / users_controller_test.rb
1 # Copyright (C) The Arvados Authors. All rights reserved.
2 #
3 # SPDX-License-Identifier: AGPL-3.0
4
5 require 'test_helper'
6 require 'helpers/users_test_helper'
7
8 class Arvados::V1::UsersControllerTest < ActionController::TestCase
9   include CurrentApiClient
10   include UsersTestHelper
11
12   setup do
13     @initial_link_count = Link.count
14     @vm_uuid = virtual_machines(:testvm).uuid
15     ActionMailer::Base.deliveries = []
16   end
17
18   test "activate a user after signing UA" do
19     authorize_with :inactive_but_signed_user_agreement
20     post :activate, params: {id: users(:inactive_but_signed_user_agreement).uuid}
21     assert_response :success
22     assert_not_nil assigns(:object)
23     me = JSON.parse(@response.body)
24     assert_equal true, me['is_active']
25   end
26
27   test "refuse to activate a user before signing UA" do
28     act_as_system_user do
29     required_uuids = Link.where("owner_uuid = ? and link_class = ? and name = ? and tail_uuid = ? and head_uuid like ?",
30                                 system_user_uuid,
31                                 'signature',
32                                 'require',
33                                 system_user_uuid,
34                                 Collection.uuid_like_pattern).
35       collect(&:head_uuid)
36
37       assert required_uuids.length > 0
38
39       signed_uuids = Link.where(owner_uuid: system_user_uuid,
40                                 link_class: 'signature',
41                                 name: 'click',
42                                 tail_uuid: users(:inactive).uuid,
43                                 head_uuid: required_uuids).
44                           collect(&:head_uuid)
45
46       assert_equal 0, signed_uuids.length
47     end
48
49     authorize_with :inactive
50     assert_equal false, users(:inactive).is_active
51
52     post :activate, params: {id: users(:inactive).uuid}
53     assert_response 403
54
55     resp = json_response
56     assert resp['errors'].first.include? 'Cannot activate without user agreements'
57     assert_nil resp['is_active']
58   end
59
60   test "activate an already-active user" do
61     authorize_with :active
62     post :activate, params: {id: users(:active).uuid}
63     assert_response :success
64     me = JSON.parse(@response.body)
65     assert_equal true, me['is_active']
66   end
67
68   test "respond 401 if given token exists but user record is missing" do
69     authorize_with :valid_token_deleted_user
70     get :current, {format: :json}
71     assert_response 401
72   end
73
74   test "create new user with user as input" do
75     authorize_with :admin
76     post :create, params: {
77       user: {
78         first_name: "test_first_name",
79         last_name: "test_last_name",
80         email: "foo@example.com"
81       }
82     }
83     assert_response :success
84     created = JSON.parse(@response.body)
85     assert_equal 'test_first_name', created['first_name']
86     assert_not_nil created['uuid'], 'expected uuid for the newly created user'
87     assert_not_nil created['email'], 'expected non-nil email'
88     assert_nil created['identity_url'], 'expected no identity_url'
89   end
90
91   test "create user with user, vm and repo as input" do
92     authorize_with :admin
93     repo_name = 'usertestrepo'
94
95     post :setup, params: {
96       repo_name: repo_name,
97       openid_prefix: 'https://www.google.com/accounts/o8/id',
98       user: {
99         uuid: 'zzzzz-tpzed-abcdefghijklmno',
100         first_name: "in_create_test_first_name",
101         last_name: "test_last_name",
102         email: "foo@example.com"
103       }
104     }
105     assert_response :success
106     response_items = JSON.parse(@response.body)['items']
107
108     created = find_obj_in_resp response_items, 'User', nil
109
110     assert_equal 'in_create_test_first_name', created['first_name']
111     assert_not_nil created['uuid'], 'expected non-null uuid for the new user'
112     assert_equal 'zzzzz-tpzed-abcdefghijklmno', created['uuid']
113     assert_not_nil created['email'], 'expected non-nil email'
114     assert_nil created['identity_url'], 'expected no identity_url'
115
116     # repo link and link add user to 'All users' group
117     verify_links_added 3
118
119     verify_link response_items, 'arvados#repository', true, 'permission', 'can_manage',
120         "foo/#{repo_name}", created['uuid'], 'arvados#repository', true, 'Repository'
121
122     verify_link response_items, 'arvados#group', true, 'permission', 'can_read',
123         'All users', created['uuid'], 'arvados#group', true, 'Group'
124
125     verify_link response_items, 'arvados#virtualMachine', false, 'permission', 'can_login',
126         nil, created['uuid'], 'arvados#virtualMachine', false, 'VirtualMachine'
127
128     verify_system_group_permission_link_for created['uuid']
129   end
130
131   test "setup user with bogus uuid and expect error" do
132     authorize_with :admin
133
134     post :setup, params: {
135       uuid: 'bogus_uuid',
136       repo_name: 'usertestrepo',
137       vm_uuid: @vm_uuid
138     }
139     response_body = JSON.parse(@response.body)
140     response_errors = response_body['errors']
141     assert_not_nil response_errors, 'Expected error in response'
142     assert (response_errors.first.include? 'Path not found'), 'Expected 404'
143   end
144
145   test "setup user with bogus uuid in user and expect error" do
146     authorize_with :admin
147
148     post :setup, params: {
149       user: {uuid: 'bogus_uuid'},
150       repo_name: 'usertestrepo',
151       vm_uuid: @vm_uuid,
152       openid_prefix: 'https://www.google.com/accounts/o8/id'
153     }
154     response_body = JSON.parse(@response.body)
155     response_errors = response_body['errors']
156     assert_not_nil response_errors, 'Expected error in response'
157     assert (response_errors.first.include? 'ArgumentError: Require user email'),
158       'Expected RuntimeError'
159   end
160
161   test "setup user with no uuid and user, expect error" do
162     authorize_with :admin
163
164     post :setup, params: {
165       repo_name: 'usertestrepo',
166       vm_uuid: @vm_uuid,
167       openid_prefix: 'https://www.google.com/accounts/o8/id'
168     }
169     response_body = JSON.parse(@response.body)
170     response_errors = response_body['errors']
171     assert_not_nil response_errors, 'Expected error in response'
172     assert (response_errors.first.include? 'Required uuid or user'),
173         'Expected ArgumentError'
174   end
175
176   test "setup user with no uuid and email, expect error" do
177     authorize_with :admin
178
179     post :setup, params: {
180       user: {},
181       repo_name: 'usertestrepo',
182       vm_uuid: @vm_uuid,
183       openid_prefix: 'https://www.google.com/accounts/o8/id'
184     }
185     response_body = JSON.parse(@response.body)
186     response_errors = response_body['errors']
187     assert_not_nil response_errors, 'Expected error in response'
188     assert (response_errors.first.include? '<ArgumentError: Require user email'),
189         'Expected ArgumentError'
190   end
191
192   test "invoke setup with existing uuid, vm and repo and verify links" do
193     authorize_with :admin
194     inactive_user = users(:inactive)
195
196     post :setup, params: {
197       uuid: users(:inactive).uuid,
198       repo_name: 'usertestrepo',
199       vm_uuid: @vm_uuid
200     }
201
202     assert_response :success
203
204     response_items = JSON.parse(@response.body)['items']
205     resp_obj = find_obj_in_resp response_items, 'User', nil
206
207     assert_not_nil resp_obj['uuid'], 'expected uuid for the new user'
208     assert_equal inactive_user['uuid'], resp_obj['uuid']
209     assert_equal inactive_user['email'], resp_obj['email'],
210         'expecting inactive user email'
211
212     # expect repo and vm links
213     verify_link response_items, 'arvados#repository', true, 'permission', 'can_manage',
214         'inactiveuser/usertestrepo', resp_obj['uuid'], 'arvados#repository', true, 'Repository'
215
216     verify_link response_items, 'arvados#virtualMachine', true, 'permission', 'can_login',
217         @vm_uuid, resp_obj['uuid'], 'arvados#virtualMachine', false, 'VirtualMachine'
218   end
219
220   test "invoke setup with existing uuid but different email, expect original email" do
221     authorize_with :admin
222     inactive_user = users(:inactive)
223
224     post :setup, params: {
225       uuid: inactive_user['uuid'],
226       user: {email: 'junk_email'}
227     }
228
229     assert_response :success
230
231     response_items = JSON.parse(@response.body)['items']
232     resp_obj = find_obj_in_resp response_items, 'User', nil
233
234     assert_not_nil resp_obj['uuid'], 'expected uuid for the new user'
235     assert_equal inactive_user['uuid'], resp_obj['uuid']
236     assert_equal inactive_user['email'], resp_obj['email'],
237         'expecting inactive user email'
238   end
239
240   test "setup user with valid email and repo as input" do
241     authorize_with :admin
242
243     post :setup, params: {
244       repo_name: 'usertestrepo',
245       user: {email: 'foo@example.com'},
246       openid_prefix: 'https://www.google.com/accounts/o8/id'
247     }
248
249     assert_response :success
250     response_items = JSON.parse(@response.body)['items']
251     response_object = find_obj_in_resp response_items, 'User', nil
252     assert_not_nil response_object['uuid'], 'expected uuid for the new user'
253     assert_equal response_object['email'], 'foo@example.com', 'expected given email'
254
255     # three extra links; system_group, group and repo perms
256     verify_links_added 3
257   end
258
259   test "setup user with fake vm and expect error" do
260     authorize_with :admin
261
262     post :setup, params: {
263       repo_name: 'usertestrepo',
264       vm_uuid: 'no_such_vm',
265       user: {email: 'foo@example.com'},
266       openid_prefix: 'https://www.google.com/accounts/o8/id'
267     }
268
269     response_body = JSON.parse(@response.body)
270     response_errors = response_body['errors']
271     assert_not_nil response_errors, 'Expected error in response'
272     assert (response_errors.first.include? "No vm found for no_such_vm"),
273           'Expected RuntimeError: No vm found for no_such_vm'
274   end
275
276   test "setup user with valid email, repo and real vm as input" do
277     authorize_with :admin
278
279     post :setup, params: {
280       repo_name: 'usertestrepo',
281       openid_prefix: 'https://www.google.com/accounts/o8/id',
282       vm_uuid: @vm_uuid,
283       user: {email: 'foo@example.com'}
284     }
285
286     assert_response :success
287     response_items = JSON.parse(@response.body)['items']
288     response_object = find_obj_in_resp response_items, 'User', nil
289     assert_not_nil response_object['uuid'], 'expected uuid for the new user'
290     assert_equal response_object['email'], 'foo@example.com', 'expected given email'
291
292     # four extra links; system_group, group, vm, repo
293     verify_links_added 4
294   end
295
296   test "setup user with valid email, no vm and no repo as input" do
297     authorize_with :admin
298
299     post :setup, params: {
300       user: {email: 'foo@example.com'},
301       openid_prefix: 'https://www.google.com/accounts/o8/id'
302     }
303
304     assert_response :success
305     response_items = JSON.parse(@response.body)['items']
306     response_object = find_obj_in_resp response_items, 'User', nil
307     assert_not_nil response_object['uuid'], 'expected uuid for new user'
308     assert_equal response_object['email'], 'foo@example.com', 'expected given email'
309
310     # two extra links; system_group, and group
311     verify_links_added 2
312
313     verify_link response_items, 'arvados#group', true, 'permission', 'can_read',
314         'All users', response_object['uuid'], 'arvados#group', true, 'Group'
315
316     verify_link response_items, 'arvados#repository', false, 'permission', 'can_manage',
317         'foo/usertestrepo', response_object['uuid'], 'arvados#repository', true, 'Repository'
318
319     verify_link response_items, 'arvados#virtualMachine', false, 'permission', 'can_login',
320         nil, response_object['uuid'], 'arvados#virtualMachine', false, 'VirtualMachine'
321   end
322
323   test "setup user with email, first name, repo name and vm uuid" do
324     authorize_with :admin
325
326     post :setup, params: {
327       openid_prefix: 'https://www.google.com/accounts/o8/id',
328       repo_name: 'usertestrepo',
329       vm_uuid: @vm_uuid,
330       user: {
331         first_name: 'test_first_name',
332         email: 'foo@example.com'
333       }
334     }
335
336     assert_response :success
337     response_items = JSON.parse(@response.body)['items']
338     response_object = find_obj_in_resp response_items, 'User', nil
339     assert_not_nil response_object['uuid'], 'expected uuid for new user'
340     assert_equal response_object['email'], 'foo@example.com', 'expected given email'
341     assert_equal 'test_first_name', response_object['first_name'],
342         'expecting first name'
343
344     # four extra links; system_group, group, repo and vm
345     verify_links_added 4
346   end
347
348   test "setup user with an existing user email and check different object is created" do
349     authorize_with :admin
350     inactive_user = users(:inactive)
351
352     post :setup, params: {
353       openid_prefix: 'https://www.google.com/accounts/o8/id',
354       repo_name: 'usertestrepo',
355       user: {
356         email: inactive_user['email']
357       }
358     }
359
360     assert_response :success
361     response_items = JSON.parse(@response.body)['items']
362     response_object = find_obj_in_resp response_items, 'User', nil
363     assert_not_nil response_object['uuid'], 'expected uuid for new user'
364     assert_not_equal response_object['uuid'], inactive_user['uuid'],
365         'expected different uuid after create operation'
366     assert_equal inactive_user['email'], response_object['email'], 'expected given email'
367     # system_group, group, and repo. No vm link.
368     verify_links_added 3
369   end
370
371   test "setup user with openid prefix" do
372     authorize_with :admin
373
374     post :setup, params: {
375       repo_name: 'usertestrepo',
376       openid_prefix: 'http://www.example.com/account',
377       user: {
378         first_name: "in_create_test_first_name",
379         last_name: "test_last_name",
380         email: "foo@example.com"
381       }
382     }
383
384     assert_response :success
385
386     response_items = JSON.parse(@response.body)['items']
387     created = find_obj_in_resp response_items, 'User', nil
388
389     assert_equal 'in_create_test_first_name', created['first_name']
390     assert_not_nil created['uuid'], 'expected uuid for new user'
391     assert_not_nil created['email'], 'expected non-nil email'
392     assert_nil created['identity_url'], 'expected no identity_url'
393
394     # verify links
395     # three new links: system_group, repo, and 'All users' group.
396     verify_links_added 3
397
398     verify_link response_items, 'arvados#repository', true, 'permission', 'can_manage',
399         'foo/usertestrepo', created['uuid'], 'arvados#repository', true, 'Repository'
400
401     verify_link response_items, 'arvados#group', true, 'permission', 'can_read',
402         'All users', created['uuid'], 'arvados#group', true, 'Group'
403
404     verify_link response_items, 'arvados#virtualMachine', false, 'permission', 'can_login',
405         nil, created['uuid'], 'arvados#virtualMachine', false, 'VirtualMachine'
406   end
407
408   test "invoke setup with no openid prefix, expect error" do
409     authorize_with :admin
410
411     post :setup, params: {
412       repo_name: 'usertestrepo',
413       user: {
414         first_name: "in_create_test_first_name",
415         last_name: "test_last_name",
416         email: "foo@example.com"
417       }
418     }
419
420     response_body = JSON.parse(@response.body)
421     response_errors = response_body['errors']
422     assert_not_nil response_errors, 'Expected error in response'
423     assert (response_errors.first.include? 'openid_prefix parameter is missing'),
424         'Expected ArgumentError'
425   end
426
427   test "setup user with user, vm and repo and verify links" do
428     authorize_with :admin
429
430     post :setup, params: {
431       user: {
432         first_name: "in_create_test_first_name",
433         last_name: "test_last_name",
434         email: "foo@example.com"
435       },
436       vm_uuid: @vm_uuid,
437       repo_name: 'usertestrepo',
438       openid_prefix: 'https://www.google.com/accounts/o8/id'
439     }
440
441     assert_response :success
442
443     response_items = JSON.parse(@response.body)['items']
444     created = find_obj_in_resp response_items, 'User', nil
445
446     assert_equal 'in_create_test_first_name', created['first_name']
447     assert_not_nil created['uuid'], 'expected uuid for new user'
448     assert_not_nil created['email'], 'expected non-nil email'
449     assert_nil created['identity_url'], 'expected no identity_url'
450
451     # four new links: system_group, repo, vm and 'All users' group link
452     verify_links_added 4
453
454     # system_group isn't part of the response.  See User#add_system_group_permission_link
455
456     verify_link response_items, 'arvados#repository', true, 'permission', 'can_manage',
457         'foo/usertestrepo', created['uuid'], 'arvados#repository', true, 'Repository'
458
459     verify_link response_items, 'arvados#group', true, 'permission', 'can_read',
460         'All users', created['uuid'], 'arvados#group', true, 'Group'
461
462     verify_link response_items, 'arvados#virtualMachine', true, 'permission', 'can_login',
463         @vm_uuid, created['uuid'], 'arvados#virtualMachine', false, 'VirtualMachine'
464   end
465
466   test "create user as non admin user and expect error" do
467     authorize_with :active
468
469     post :create, params: {
470       user: {email: 'foo@example.com'}
471     }
472
473     response_body = JSON.parse(@response.body)
474     response_errors = response_body['errors']
475     assert_not_nil response_errors, 'Expected error in response'
476     assert (response_errors.first.include? 'PermissionDenied'),
477           'Expected PermissionDeniedError'
478   end
479
480   test "setup user as non admin user and expect error" do
481     authorize_with :active
482
483     post :setup, params: {
484       openid_prefix: 'https://www.google.com/accounts/o8/id',
485       user: {email: 'foo@example.com'}
486     }
487
488     response_body = JSON.parse(@response.body)
489     response_errors = response_body['errors']
490     assert_not_nil response_errors, 'Expected error in response'
491     assert (response_errors.first.include? 'Forbidden'),
492           'Expected Forbidden error'
493   end
494
495   test "setup active user with repo and no vm" do
496     authorize_with :admin
497     active_user = users(:active)
498
499     # invoke setup with a repository
500     post :setup, params: {
501       repo_name: 'usertestrepo',
502       uuid: active_user['uuid']
503     }
504
505     assert_response :success
506
507     response_items = JSON.parse(@response.body)['items']
508     created = find_obj_in_resp response_items, 'User', nil
509
510     assert_equal active_user[:email], created['email'], 'expected input email'
511
512      # verify links
513     verify_link response_items, 'arvados#group', true, 'permission', 'can_read',
514         'All users', created['uuid'], 'arvados#group', true, 'Group'
515
516     verify_link response_items, 'arvados#repository', true, 'permission', 'can_manage',
517         'active/usertestrepo', created['uuid'], 'arvados#repository', true, 'Repository'
518
519     verify_link response_items, 'arvados#virtualMachine', false, 'permission', 'can_login',
520         nil, created['uuid'], 'arvados#virtualMachine', false, 'VirtualMachine'
521   end
522
523   test "setup active user with vm and no repo" do
524     authorize_with :admin
525     active_user = users(:active)
526     repos_query = Repository.where(owner_uuid: active_user.uuid)
527     repo_link_query = Link.where(tail_uuid: active_user.uuid,
528                                  link_class: "permission", name: "can_manage")
529     repos_count = repos_query.count
530     repo_link_count = repo_link_query.count
531
532     # invoke setup with a repository
533     post :setup, params: {
534       vm_uuid: @vm_uuid,
535       uuid: active_user['uuid'],
536       email: 'junk_email'
537     }
538
539     assert_response :success
540
541     response_items = JSON.parse(@response.body)['items']
542     created = find_obj_in_resp response_items, 'User', nil
543
544     assert_equal active_user['email'], created['email'], 'expected original email'
545
546     # verify links
547     verify_link response_items, 'arvados#group', true, 'permission', 'can_read',
548         'All users', created['uuid'], 'arvados#group', true, 'Group'
549
550     assert_equal(repos_count, repos_query.count)
551     assert_equal(repo_link_count, repo_link_query.count)
552
553     verify_link response_items, 'arvados#virtualMachine', true, 'permission', 'can_login',
554         @vm_uuid, created['uuid'], 'arvados#virtualMachine', false, 'VirtualMachine'
555   end
556
557   test "unsetup active user" do
558     active_user = users(:active)
559     assert_not_nil active_user['uuid'], 'expected uuid for the active user'
560     assert active_user['is_active'], 'expected is_active for active user'
561
562     verify_link_existence active_user['uuid'], active_user['email'],
563           false, true, true, true, true
564
565     authorize_with :admin
566
567     # now unsetup this user
568     post :unsetup, params: {id: active_user['uuid']}
569     assert_response :success
570
571     response_user = JSON.parse(@response.body)
572     assert_not_nil response_user['uuid'], 'expected uuid for the upsetup user'
573     assert_equal active_user['uuid'], response_user['uuid'], 'expected uuid not found'
574     assert !response_user['is_active'], 'expected user to be inactive'
575     assert !response_user['is_invited'], 'expected user to be uninvited'
576
577     verify_link_existence response_user['uuid'], response_user['email'],
578           false, false, false, false, false
579
580     active_user = User.find_by_uuid(users(:active).uuid)
581     readable_groups = active_user.groups_i_can(:read)
582     all_users_group = Group.all.collect(&:uuid).select { |g| g.match(/-f+$/) }
583     refute_includes(readable_groups, all_users_group,
584                     "active user can read All Users group after being deactivated")
585     assert_equal(false, active_user.is_invited,
586                  "active user is_invited after being deactivated & reloaded")
587   end
588
589   test "setup user with send notification param false and verify no email" do
590     authorize_with :admin
591
592     post :setup, params: {
593       openid_prefix: 'http://www.example.com/account',
594       send_notification_email: 'false',
595       user: {
596         email: "foo@example.com"
597       }
598     }
599
600     assert_response :success
601     response_items = JSON.parse(@response.body)['items']
602     created = find_obj_in_resp response_items, 'User', nil
603     assert_not_nil created['uuid'], 'expected uuid for the new user'
604     assert_equal created['email'], 'foo@example.com', 'expected given email'
605
606     setup_email = ActionMailer::Base.deliveries.last
607     assert_nil setup_email, 'expected no setup email'
608   end
609
610   test "setup user with send notification param true and verify email" do
611     authorize_with :admin
612
613     post :setup, params: {
614       openid_prefix: 'http://www.example.com/account',
615       send_notification_email: 'true',
616       user: {
617         email: "foo@example.com"
618       }
619     }
620
621     assert_response :success
622     response_items = JSON.parse(@response.body)['items']
623     created = find_obj_in_resp response_items, 'User', nil
624     assert_not_nil created['uuid'], 'expected uuid for the new user'
625     assert_equal created['email'], 'foo@example.com', 'expected given email'
626
627     setup_email = ActionMailer::Base.deliveries.last
628     assert_not_nil setup_email, 'Expected email after setup'
629
630     assert_equal Rails.configuration.Users.UserNotifierEmailFrom, setup_email.from[0]
631     assert_equal 'foo@example.com', setup_email.to[0]
632     assert_equal 'Welcome to Arvados - shell account enabled', setup_email.subject
633     assert (setup_email.body.to_s.include? 'Your Arvados shell account has been set up'),
634         'Expected Your Arvados shell account has been set up in email body'
635     assert (setup_email.body.to_s.include? "#{Rails.configuration.Services.Workbench1.ExternalURL}users/#{created['uuid']}/virtual_machines"), 'Expected virtual machines url in email body'
636   end
637
638   test "setup inactive user by changing is_active to true" do
639     authorize_with :admin
640     active_user = users(:active)
641
642     # invoke setup with a repository
643     put :update, params: {
644           id: active_user['uuid'],
645           user: {
646             is_active: true,
647           }
648         }
649     assert_response :success
650     assert_equal active_user['uuid'], json_response['uuid']
651     updated = User.where(uuid: active_user['uuid']).first
652     assert_equal(true, updated.is_active)
653     assert_equal({read: true}, updated.group_permissions[all_users_group_uuid])
654   end
655
656   test "non-admin user can get basic information about readable users" do
657     authorize_with :spectator
658     get(:index)
659     check_non_admin_index
660     check_readable_users_index [:spectator], [:inactive, :active]
661   end
662
663   test "non-admin user gets only safe attributes from users#show" do
664     g = act_as_system_user do
665       create :group
666     end
667     users = create_list :active_user, 2, join_groups: [g]
668     token = create :token, user: users[0]
669     authorize_with_token token
670     get :show, params: {id: users[1].uuid}
671     check_non_admin_show
672   end
673
674   [2, 4].each do |limit|
675     test "non-admin user can limit index to #{limit}" do
676       g = act_as_system_user do
677         create :group
678       end
679       users = create_list :active_user, 4, join_groups: [g]
680       token = create :token, user: users[0]
681
682       authorize_with_token token
683       get(:index, params: {limit: limit})
684       check_non_admin_index
685       assert_equal(limit, json_response["items"].size,
686                    "non-admin index limit was ineffective")
687     end
688   end
689
690   test "admin has full index powers" do
691     authorize_with :admin
692     check_inactive_user_findable
693   end
694
695   test "reader token can grant admin index powers" do
696     authorize_with :spectator
697     check_inactive_user_findable(reader_tokens: [api_token(:admin)])
698   end
699
700   test "admin can filter on user.is_active" do
701     authorize_with :admin
702     get(:index, params: {filters: [["is_active", "=", "true"]]})
703     assert_response :success
704     check_readable_users_index [:active, :spectator], [:inactive]
705   end
706
707   test "admin can search where user.is_active" do
708     authorize_with :admin
709     get(:index, params: {where: {is_active: true}})
710     assert_response :success
711     check_readable_users_index [:active, :spectator], [:inactive]
712   end
713
714   test "update active_no_prefs user profile and expect notification email" do
715     authorize_with :admin
716
717     put :update, params: {
718       id: users(:active_no_prefs).uuid,
719       user: {
720         prefs: {:profile => {'organization' => 'example.com'}}
721       }
722     }
723     assert_response :success
724
725     found_email = false
726     ActionMailer::Base.deliveries.andand.each do |email|
727       if email.subject == "Profile created by #{users(:active_no_prefs).email}"
728         found_email = true
729         break
730       end
731     end
732     assert_equal true, found_email, 'Expected email after creating profile'
733   end
734
735   test "update active_no_prefs_profile user profile and expect notification email" do
736     authorize_with :admin
737
738     user = {}
739     user[:prefs] = users(:active_no_prefs_profile_no_getting_started_shown).prefs
740     user[:prefs][:profile] = {:profile => {'organization' => 'example.com'}}
741     put :update, params: {
742       id: users(:active_no_prefs_profile_no_getting_started_shown).uuid,
743       user: user
744     }
745     assert_response :success
746
747     found_email = false
748     ActionMailer::Base.deliveries.andand.each do |email|
749       if email.subject == "Profile created by #{users(:active_no_prefs_profile_no_getting_started_shown).email}"
750         found_email = true
751         break
752       end
753     end
754     assert_equal true, found_email, 'Expected email after creating profile'
755   end
756
757   test "update active user profile and expect no notification email" do
758     authorize_with :admin
759
760     put :update, params: {
761       id: users(:active).uuid,
762       user: {
763         prefs: {:profile => {'organization' => 'anotherexample.com'}}
764       }
765     }
766     assert_response :success
767
768     found_email = false
769     ActionMailer::Base.deliveries.andand.each do |email|
770       if email.subject == "Profile created by #{users(:active).email}"
771         found_email = true
772         break
773       end
774     end
775     assert_equal false, found_email, 'Expected no email after updating profile'
776   end
777
778   test "user API response includes writable_by" do
779     authorize_with :active
780     get :current
781     assert_response :success
782     assert_includes(json_response["writable_by"], users(:active).uuid,
783                     "user's writable_by should include self")
784     assert_includes(json_response["writable_by"], users(:active).owner_uuid,
785                     "user's writable_by should include its owner_uuid")
786   end
787
788   [
789     [:admin, true],
790     [:active, false],
791   ].each do |auth_user, expect_success|
792     test "update_uuid as #{auth_user}" do
793       authorize_with auth_user
794       orig_uuid = users(:active).uuid
795       post :update_uuid, params: {
796              id: orig_uuid,
797              new_uuid: 'zbbbb-tpzed-abcde12345abcde',
798            }
799       if expect_success
800         assert_response :success
801         assert_empty User.where(uuid: orig_uuid)
802       else
803         assert_response 403
804         assert_not_empty User.where(uuid: orig_uuid)
805       end
806     end
807   end
808
809   test "merge with redirect_to_user_uuid=false" do
810     authorize_with :project_viewer_trustedclient
811     tok = api_client_authorizations(:project_viewer).api_token
812     post :merge, params: {
813            new_user_token: api_client_authorizations(:active_trustedclient).api_token,
814            new_owner_uuid: users(:active).uuid,
815            redirect_to_new_user: false,
816          }
817     assert_response(:success)
818     assert_nil(User.unscoped.find_by_uuid(users(:project_viewer).uuid).redirect_to_user_uuid)
819
820     # because redirect_to_new_user=false, token owned by
821     # project_viewer should be deleted
822     auth = ApiClientAuthorization.validate(token: tok)
823     assert_nil(auth)
824   end
825
826   test "merge remote to local as admin" do
827     authorize_with :admin
828
829     remoteuser = User.create!(uuid: "zbbbb-tpzed-remotremotremot")
830     tok = ApiClientAuthorization.create!(user: remoteuser, api_client: api_clients(:untrusted)).api_token
831
832     auth = ApiClientAuthorization.validate(token: tok)
833     assert_not_nil(auth)
834     assert_nil(remoteuser.redirect_to_user_uuid)
835
836     post :merge, params: {
837            new_user_uuid: users(:active).uuid,
838            old_user_uuid: remoteuser.uuid,
839            new_owner_uuid: users(:active).uuid,
840            redirect_to_new_user: true,
841          }
842     assert_response(:success)
843     remoteuser.reload
844     assert_equal(users(:active).uuid, remoteuser.redirect_to_user_uuid)
845
846     # token owned by remoteuser should be deleted
847     auth = ApiClientAuthorization.validate(token: tok)
848     assert_nil(auth)
849   end
850
851   test "refuse to merge user into self" do
852     authorize_with(:active_trustedclient)
853     post(:merge, params: {
854            new_user_token: api_client_authorizations(:active_trustedclient).api_token,
855            new_owner_uuid: users(:active).uuid,
856            redirect_to_new_user: true,
857          })
858     assert_response(422)
859   end
860
861   [[:active, :project_viewer_trustedclient],
862    [:active_trustedclient, :project_viewer]].each do |src, dst|
863     test "refuse to merge with untrusted token (#{src} -> #{dst})" do
864       authorize_with(src)
865       post(:merge, params: {
866              new_user_token: api_client_authorizations(dst).api_token,
867              new_owner_uuid: api_client_authorizations(dst).user.uuid,
868              redirect_to_new_user: true,
869            })
870       assert_response(403)
871     end
872   end
873
874   [[:expired_trustedclient, :project_viewer_trustedclient],
875    [:project_viewer_trustedclient, :expired_trustedclient]].each do |src, dst|
876     test "refuse to merge with expired token (#{src} -> #{dst})" do
877       authorize_with(src)
878       post(:merge, params: {
879              new_user_token: api_client_authorizations(dst).api_token,
880              new_owner_uuid: api_client_authorizations(dst).user.uuid,
881              redirect_to_new_user: true,
882            })
883       assert_response(401)
884     end
885   end
886
887   [['src', :active_trustedclient],
888    ['dst', :project_viewer_trustedclient]].each do |which_scoped, auth|
889     test "refuse to merge with scoped #{which_scoped} token" do
890       act_as_system_user do
891         api_client_authorizations(auth).update_attributes(scopes: ["GET /", "POST /", "PUT /"])
892       end
893       authorize_with(:active_trustedclient)
894       post(:merge, params: {
895              new_user_token: api_client_authorizations(:project_viewer_trustedclient).api_token,
896              new_owner_uuid: users(:project_viewer).uuid,
897              redirect_to_new_user: true,
898            })
899       assert_response(403)
900     end
901   end
902
903   test "refuse to merge if new_owner_uuid is not writable" do
904     authorize_with(:project_viewer_trustedclient)
905     post(:merge, params: {
906            new_user_token: api_client_authorizations(:active_trustedclient).api_token,
907            new_owner_uuid: groups(:anonymously_accessible_project).uuid,
908            redirect_to_new_user: true,
909          })
910     assert_response(403)
911   end
912
913   test "refuse to merge if new_owner_uuid is empty" do
914     authorize_with(:project_viewer_trustedclient)
915     post(:merge, params: {
916            new_user_token: api_client_authorizations(:active_trustedclient).api_token,
917            new_owner_uuid: "",
918            redirect_to_new_user: true,
919          })
920     assert_response(422)
921   end
922
923   test "refuse to merge if new_owner_uuid is not provided" do
924     authorize_with(:project_viewer_trustedclient)
925     post(:merge, params: {
926            new_user_token: api_client_authorizations(:active_trustedclient).api_token,
927            redirect_to_new_user: true,
928          })
929     assert_response(422)
930   end
931
932   test "refuse to update redirect_to_user_uuid directly" do
933     authorize_with(:active_trustedclient)
934     patch(:update, params: {
935             id: users(:active).uuid,
936             user: {
937               redirect_to_user_uuid: users(:active).uuid,
938             },
939           })
940     assert_response(403)
941   end
942
943   test "merge 'project_viewer' account into 'active' account" do
944     authorize_with(:project_viewer_trustedclient)
945     post(:merge, params: {
946            new_user_token: api_client_authorizations(:active_trustedclient).api_token,
947            new_owner_uuid: users(:active).uuid,
948            redirect_to_new_user: true,
949          })
950     assert_response(:success)
951     assert_equal(users(:active).uuid, User.unscoped.find_by_uuid(users(:project_viewer).uuid).redirect_to_user_uuid)
952
953     auth = ApiClientAuthorization.validate(token: api_client_authorizations(:project_viewer).api_token)
954     assert_not_nil(auth)
955     assert_not_nil(auth.user)
956     assert_equal(users(:active).uuid, auth.user.uuid)
957   end
958
959
960   test "merge 'project_viewer' account into 'active' account using uuids" do
961     authorize_with(:admin)
962     post(:merge, params: {
963            old_user_uuid: users(:project_viewer).uuid,
964            new_user_uuid: users(:active).uuid,
965            new_owner_uuid: users(:active).uuid,
966            redirect_to_new_user: true,
967          })
968     assert_response(:success)
969     assert_equal(users(:active).uuid, User.unscoped.find_by_uuid(users(:project_viewer).uuid).redirect_to_user_uuid)
970
971     auth = ApiClientAuthorization.validate(token: api_client_authorizations(:project_viewer).api_token)
972     assert_not_nil(auth)
973     assert_not_nil(auth.user)
974     assert_equal(users(:active).uuid, auth.user.uuid)
975   end
976
977   test "merge 'project_viewer' account into 'active' account using uuids denied for non-admin" do
978     authorize_with(:active)
979     post(:merge, params: {
980            old_user_uuid: users(:project_viewer).uuid,
981            new_user_uuid: users(:active).uuid,
982            new_owner_uuid: users(:active).uuid,
983            redirect_to_new_user: true,
984          })
985     assert_response(403)
986     assert_nil(users(:project_viewer).redirect_to_user_uuid)
987   end
988
989   test "merge 'project_viewer' account into 'active' account using uuids denied missing old_user_uuid" do
990     authorize_with(:admin)
991     post(:merge, params: {
992            new_user_uuid: users(:active).uuid,
993            new_owner_uuid: users(:active).uuid,
994            redirect_to_new_user: true,
995          })
996     assert_response(422)
997     assert_nil(users(:project_viewer).redirect_to_user_uuid)
998   end
999
1000   test "merge 'project_viewer' account into 'active' account using uuids denied missing new_user_uuid" do
1001     authorize_with(:admin)
1002     post(:merge, params: {
1003            old_user_uuid: users(:project_viewer).uuid,
1004            new_owner_uuid: users(:active).uuid,
1005            redirect_to_new_user: true,
1006          })
1007     assert_response(422)
1008     assert_nil(users(:project_viewer).redirect_to_user_uuid)
1009   end
1010
1011   test "merge 'project_viewer' account into 'active' account using uuids denied bogus old_user_uuid" do
1012     authorize_with(:admin)
1013     post(:merge, params: {
1014            old_user_uuid: "zzzzz-tpzed-bogusbogusbogus",
1015            new_user_uuid: users(:active).uuid,
1016            new_owner_uuid: users(:active).uuid,
1017            redirect_to_new_user: true,
1018          })
1019     assert_response(422)
1020     assert_nil(users(:project_viewer).redirect_to_user_uuid)
1021   end
1022
1023   test "merge 'project_viewer' account into 'active' account using uuids denied bogus new_user_uuid" do
1024     authorize_with(:admin)
1025     post(:merge, params: {
1026            old_user_uuid: users(:project_viewer).uuid,
1027            new_user_uuid: "zzzzz-tpzed-bogusbogusbogus",
1028            new_owner_uuid: users(:active).uuid,
1029            redirect_to_new_user: true,
1030          })
1031     assert_response(422)
1032     assert_nil(users(:project_viewer).redirect_to_user_uuid)
1033   end
1034
1035   test "batch update fails for non-admin" do
1036     authorize_with(:active)
1037     patch(:batch_update, params: {updates: {}})
1038     assert_response(403)
1039   end
1040
1041   test "batch update" do
1042     existinguuid = 'remot-tpzed-foobarbazwazqux'
1043     newuuid = 'remot-tpzed-newnarnazwazqux'
1044     act_as_system_user do
1045       User.create!(uuid: existinguuid, email: 'root@existing.example.com')
1046     end
1047
1048     authorize_with(:admin)
1049     patch(:batch_update,
1050           params: {
1051             updates: {
1052               existinguuid => {
1053                 'first_name' => 'root',
1054                 'email' => 'root@remot.example.com',
1055                 'is_active' => true,
1056                 'is_admin' => true,
1057                 'prefs' => {'foo' => 'bar'},
1058               },
1059               newuuid => {
1060                 'first_name' => 'noot',
1061                 'email' => 'root@remot.example.com',
1062               },
1063             }})
1064     assert_response(:success)
1065
1066     assert_equal('root', User.find_by_uuid(existinguuid).first_name)
1067     assert_equal('root@remot.example.com', User.find_by_uuid(existinguuid).email)
1068     assert_equal(true, User.find_by_uuid(existinguuid).is_active)
1069     assert_equal(true, User.find_by_uuid(existinguuid).is_admin)
1070     assert_equal({'foo' => 'bar'}, User.find_by_uuid(existinguuid).prefs)
1071
1072     assert_equal('noot', User.find_by_uuid(newuuid).first_name)
1073     assert_equal('root@remot.example.com', User.find_by_uuid(newuuid).email)
1074   end
1075
1076   NON_ADMIN_USER_DATA = ["uuid", "kind", "is_active", "email", "first_name",
1077                          "last_name", "username"].sort
1078
1079   def check_non_admin_index
1080     assert_response :success
1081     response_items = json_response["items"]
1082     assert_not_nil response_items
1083     response_items.each do |user_data|
1084       check_non_admin_item user_data
1085       assert(user_data["is_active"], "non-admin index returned inactive user")
1086     end
1087   end
1088
1089   def check_non_admin_show
1090     assert_response :success
1091     check_non_admin_item json_response
1092   end
1093
1094   def check_non_admin_item user_data
1095     assert_equal(NON_ADMIN_USER_DATA, user_data.keys.sort,
1096                  "data in response had missing or extra attributes")
1097     assert_equal("arvados#user", user_data["kind"])
1098   end
1099
1100
1101   def check_readable_users_index expect_present, expect_missing
1102     response_uuids = json_response["items"].map { |u| u["uuid"] }
1103     expect_present.each do |user_key|
1104       assert_includes(response_uuids, users(user_key).uuid,
1105                       "#{user_key} missing from index")
1106     end
1107     expect_missing.each do |user_key|
1108       refute_includes(response_uuids, users(user_key).uuid,
1109                       "#{user_key} included in index")
1110     end
1111   end
1112
1113   def check_inactive_user_findable(params={})
1114     inactive_user = users(:inactive)
1115     get(:index, params: params.merge(filters: [["email", "=", inactive_user.email]]))
1116     assert_response :success
1117     user_list = json_response["items"]
1118     assert_equal(1, user_list.andand.count)
1119     # This test needs to check a column non-admins have no access to,
1120     # to ensure that admins see all user information.
1121     assert_equal(inactive_user.identity_url, user_list.first["identity_url"],
1122                  "admin's filtered index did not return inactive user")
1123   end
1124
1125   def verify_links_added more
1126     assert_equal @initial_link_count+more, Link.count,
1127         "Started with #{@initial_link_count} links, expected #{more} more"
1128   end
1129
1130   def find_obj_in_resp (response_items, object_type, head_kind=nil)
1131     return_obj = nil
1132     response_items.each { |x|
1133       if !x
1134         next
1135       end
1136
1137       if object_type == 'User'
1138         if ArvadosModel::resource_class_for_uuid(x['uuid']) == User
1139           return_obj = x
1140           break
1141         end
1142       else  # looking for a link
1143         if x['head_uuid'] and ArvadosModel::resource_class_for_uuid(x['head_uuid']).kind == head_kind
1144           return_obj = x
1145           break
1146         end
1147       end
1148     }
1149     return return_obj
1150   end
1151 end