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