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