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