Merge branch 'master' into 3153-auto-setup-user
[arvados.git] / services / api / test / unit / user_test.rb
1 require 'test_helper'
2
3 class UserTest < ActiveSupport::TestCase
4   include CurrentApiClient
5
6   # The fixture services/api/test/fixtures/users.yml serves as the input for this test case
7   setup do
8     # Make sure system_user exists before making "pre-test users" list
9     system_user
10   end
11
12   test "check non-admin active user properties" do
13     @active_user = users(:active)     # get the active user
14     assert !@active_user.is_admin, 'is_admin should not be set for a non-admin user'
15     assert @active_user.is_active, 'user should be active'
16     assert @active_user.is_invited, 'is_invited should be set'
17     assert_not_nil @active_user.prefs, "user's preferences should be non-null, but may be size zero"
18     assert (@active_user.can? :read=>"#{@active_user.uuid}"), "user should be able to read own object"
19     assert (@active_user.can? :write=>"#{@active_user.uuid}"), "user should be able to write own object"
20     assert (@active_user.can? :manage=>"#{@active_user.uuid}"), "user should be able to manage own object"
21
22     assert @active_user.groups_i_can(:read).size > 0, "active user should be able read at least one group"
23
24     # non-admin user cannot manage or write other user objects
25     @uninvited_user = users(:inactive_uninvited)     # get the uninvited user
26     assert !(@active_user.can? :read=>"#{@uninvited_user.uuid}")
27     assert !(@active_user.can? :write=>"#{@uninvited_user.uuid}")
28     assert !(@active_user.can? :manage=>"#{@uninvited_user.uuid}")
29   end
30
31   test "check admin user properties" do
32     @admin_user = users(:admin)     # get the admin user
33     assert @admin_user.is_admin, 'is_admin should be set for admin user'
34     assert @admin_user.is_active, 'admin user cannot be inactive'
35     assert @admin_user.is_invited, 'is_invited should be set'
36     assert_not_nil @admin_user.uuid.size, "user's uuid should be non-null"
37     assert_not_nil @admin_user.prefs, "user's preferences should be non-null, but may be size zero"
38     assert @admin_user.identity_url.size > 0, "user's identity url is expected"
39     assert @admin_user.can? :read=>"#{@admin_user.uuid}"
40     assert @admin_user.can? :write=>"#{@admin_user.uuid}"
41     assert @admin_user.can? :manage=>"#{@admin_user.uuid}"
42
43     assert @admin_user.groups_i_can(:read).size > 0, "admin active user should be able read at least one group"
44     assert @admin_user.groups_i_can(:write).size > 0, "admin active user should be able write to at least one group"
45     assert @admin_user.groups_i_can(:manage).size > 0, "admin active user should be able manage at least one group"
46
47     # admin user can also write or manage other users
48     @uninvited_user = users(:inactive_uninvited)     # get the uninvited user
49     assert @admin_user.can? :read=>"#{@uninvited_user.uuid}"
50     assert @admin_user.can? :write=>"#{@uninvited_user.uuid}"
51     assert @admin_user.can? :manage=>"#{@uninvited_user.uuid}"
52   end
53
54   test "check inactive and uninvited user properties" do
55     @uninvited_user = users(:inactive_uninvited)     # get the uninvited user
56     assert !@uninvited_user.is_admin, 'is_admin should not be set for a non-admin user'
57     assert !@uninvited_user.is_active, 'user should be inactive'
58     assert !@uninvited_user.is_invited, 'is_invited should not be set'
59     assert @uninvited_user.can? :read=>"#{@uninvited_user.uuid}"
60     assert @uninvited_user.can? :write=>"#{@uninvited_user.uuid}"
61     assert @uninvited_user.can? :manage=>"#{@uninvited_user.uuid}"
62
63     assert @uninvited_user.groups_i_can(:read).size == 1, "inactive and uninvited user can only read anonymous user group"
64     assert @uninvited_user.groups_i_can(:read).first.ends_with? 'anonymouspublic' , "inactive and uninvited user can only read anonymous user group"
65     assert @uninvited_user.groups_i_can(:write).size == 0, "inactive and uninvited user should not be able write to any groups"
66     assert @uninvited_user.groups_i_can(:manage).size == 0, "inactive and uninvited user should not be able manage any groups"
67   end
68
69   test "find user method checks" do
70     User.find(:all).each do |user|
71       assert_not_nil user.uuid, "non-null uuid expected for " + user.full_name
72     end
73
74     user = users(:active)     # get the active user
75
76     found_user = User.find(user.id)   # find a user by the row id
77
78     assert_equal found_user.full_name, user.first_name + ' ' + user.last_name
79     assert_equal found_user.identity_url, user.identity_url
80   end
81
82   test "full name should not contain spurious whitespace" do
83     set_user_from_auth :admin
84
85     user = User.create ({uuid: 'zzzzz-tpzed-abcdefghijklmno', email: 'foo@example.com' })
86
87     assert_equal '', user.full_name
88
89     user.first_name = 'John'
90     user.last_name = 'Smith'
91
92     assert_equal user.first_name + ' ' + user.last_name, user.full_name
93   end
94
95   test "create new user" do
96     set_user_from_auth :admin
97
98     @all_users = User.find(:all)
99
100     user = User.new
101     user.first_name = "first_name_for_newly_created_user"
102     user.save
103
104     # verify there is one extra user in the db now
105     assert_equal @all_users.size+1, User.find(:all).size
106
107     user = User.find(user.id)   # get the user back
108     assert_equal(user.first_name, 'first_name_for_newly_created_user')
109     assert_not_nil user.uuid, 'uuid should be set for newly created user'
110     assert_nil user.email, 'email should be null for newly created user, because it was not passed in'
111     assert_nil user.identity_url, 'identity_url should be null for newly created user, because it was not passed in'
112
113     user.first_name = 'first_name_for_newly_created_user_updated'
114     user.save
115     user = User.find(user.id)   # get the user back
116     assert_equal(user.first_name, 'first_name_for_newly_created_user_updated')
117   end
118
119   test "create new user with notifications" do
120     set_user_from_auth :admin
121
122     create_user_and_verify_setup_and_notifications true, 'active-notify-address@example.com', 'inactive-notify-address@example.com', nil, false
123     create_user_and_verify_setup_and_notifications true, 'active-notify-address@example.com', [], nil, false
124     create_user_and_verify_setup_and_notifications true, [], [], nil, false
125     create_user_and_verify_setup_and_notifications false, 'active-notify-address@example.com', 'inactive-notify-address@example.com', nil, false
126     create_user_and_verify_setup_and_notifications false, [], 'inactive-notify-address@example.com', nil, false
127     create_user_and_verify_setup_and_notifications false, [], [], nil, false
128   end
129
130   [
131     [false, 'active-notify@example.com', 'inactive-notify@example.com', 'inactive-none@example.com', false, false, true],
132     [false, 'active-notify@example.com', 'inactive-notify@example.com', 'inactive-vm@example.com', true, false, true],
133     [false, 'active-notify@example.com', 'inactive-notify@example.com', 'inactive-repo@example.com', false, true, true],
134     [false, 'active-notify@example.com', 'inactive-notify@example.com', 'inactive-both@example.com', true, true, true],
135
136     [false, [], [], 'inactive-none-no-notifications@example.com', false, false, true],
137     [false, [], [], 'inactive-vm-no-notifications@example.com', true, false, true],
138     [false, [], [], 'inactive-repo-no-notifications@example.com', false, true, true],
139     [false, [], [], 'inactive-both-no-notifications@example.com', true, true, true],
140
141     [true, 'active-notify@example.com', 'inactive-notify@example.com', 'active-none@example.com', false, false, true],
142     [true, 'active-notify@example.com', 'inactive-notify@example.com', 'active-vm@example.com', true, false, true],
143     [true, 'active-notify@example.com', 'inactive-notify@example.com', 'active-repo@example.com', false, true, true],
144     [true, 'active-notify@example.com', 'inactive-notify@example.com', 'active-both@example.com', true, true, true],
145
146     [true, [], [], 'active-none-no-notifications@example.com', false, false, true],
147     [true, [], [], 'active-vm-no-notifications@example.com', true, false, true],
148     [true, [], [], 'active-notify-no-notifications@example.com', 'inactive-repo@example.com', false, true, true],
149     [true, [], [], 'active-both-no-notifications@example.com', true, true, true],
150
151     [false, [], [], nil, true, true, false],
152     [false, [], [], 'arvados', true, true, false],
153     [false, [], [], '@example.com', true, true, false],
154     [false, [], [], '^^incorrect_format@example.com', true, true, false],
155
156     [false, 'active-notify@example.com', 'inactive-notify@example.com', 'foo@example.com', true, true, true],  # existing repository name 'foo'
157     [false, 'active-notify@example.com', 'inactive-notify@example.com', 'foo@example.com', true, false, true],  # existing repository name 'foo'
158     [false, 'active-notify@example.com', 'inactive-notify@example.com', 'foo@example.com', false, true, true],  # existing repository name 'foo'
159     [false, 'active-notify@example.com', 'inactive-notify@example.com', 'foo@example.com', false, false, true],  # existing repository name 'foo', but we are not creating repo or login link
160     [false, 'active-notify@example.com', 'inactive-notify@example.com', 'xyz_can_login_to_vm@example.com', true, true, true], # existing vm login name
161     [false, 'active-notify@example.com', 'inactive-notify@example.com', 'xyz_can_login_to_vm@example.com', true, false, true], # existing vm login name
162     [false, 'active-notify@example.com', 'inactive-notify@example.com', 'xyz_can_login_to_vm@example.com', false, true, true], # existing vm login name
163     [false, 'active-notify@example.com', 'inactive-notify@example.com', 'xyz_can_login_to_vm@example.com', false, false, true], # existing vm login name, but we are not creating repo or login link
164   ].each do |active, active_recipients, inactive_recipients, email, auto_setup_vm, auto_setup_repo, valid_email_format|
165     test "create new user with auto setup #{email} #{auto_setup_vm} #{auto_setup_repo}" do
166       auto_setup_new_users = Rails.configuration.auto_setup_new_users
167       auto_setup_new_users_with_vm_uuid = Rails.configuration.auto_setup_new_users_with_vm_uuid
168       auto_setup_new_users_with_repository = Rails.configuration.auto_setup_new_users_with_repository
169
170       begin
171         set_user_from_auth :admin
172
173         Rails.configuration.auto_setup_new_users = true
174
175         if auto_setup_vm
176           Rails.configuration.auto_setup_new_users_with_vm_uuid = virtual_machines(:testvm)['uuid']
177         else
178           Rails.configuration.auto_setup_new_users_with_vm_uuid = false
179         end
180
181         Rails.configuration.auto_setup_new_users_with_repository = auto_setup_repo
182
183         create_user_and_verify_setup_and_notifications active, active_recipients, inactive_recipients, email, valid_email_format
184       ensure
185         Rails.configuration.auto_setup_new_users = auto_setup_new_users
186         Rails.configuration.auto_setup_new_users_with_vm_uuid = auto_setup_new_users_with_vm_uuid
187         Rails.configuration.auto_setup_new_users_with_repository = auto_setup_new_users_with_repository
188       end
189     end
190   end
191
192   test "update existing user" do
193     set_user_from_auth :active    # set active user as current user
194
195     @active_user = users(:active)     # get the active user
196
197     @active_user.first_name = "first_name_changed"
198     @active_user.save
199
200     @active_user = User.find(@active_user.id)   # get the user back
201     assert_equal(@active_user.first_name, 'first_name_changed')
202
203     # admin user also should be able to update the "active" user info
204     set_user_from_auth :admin # set admin user as current user
205     @active_user.first_name = "first_name_changed_by_admin_for_active_user"
206     @active_user.save
207
208     @active_user = User.find(@active_user.id)   # get the user back
209     assert_equal(@active_user.first_name, 'first_name_changed_by_admin_for_active_user')
210   end
211
212   test "delete a user and verify" do
213     @active_user = users(:active)     # get the active user
214     active_user_uuid = @active_user.uuid
215
216     set_user_from_auth :admin
217     @active_user.delete
218
219     found_deleted_user = false
220     User.find(:all).each do |user|
221       if user.uuid == active_user_uuid
222         found_deleted_user = true
223         break
224       end
225     end
226     assert !found_deleted_user, "found deleted user: "+active_user_uuid
227
228   end
229
230   test "create new user as non-admin user" do
231     set_user_from_auth :active
232
233     begin
234       user = User.new
235       user.save
236     rescue ArvadosModel::PermissionDeniedError => e
237     end
238     assert (e.message.include? 'PermissionDeniedError'),
239         'Expected PermissionDeniedError'
240   end
241
242   test "setup new user" do
243     set_user_from_auth :admin
244
245     email = 'foo@example.com'
246     openid_prefix = 'http://openid/prefix'
247
248     user = User.create ({uuid: 'zzzzz-tpzed-abcdefghijklmno', email: email})
249
250     vm = VirtualMachine.create
251
252     response = User.setup user, openid_prefix, 'test_repo', vm.uuid
253
254     resp_user = find_obj_in_resp response, 'User'
255     verify_user resp_user, email
256
257     oid_login_perm = find_obj_in_resp response, 'Link', 'arvados#user'
258
259     verify_link oid_login_perm, 'permission', 'can_login', resp_user[:email],
260         resp_user[:uuid]
261
262     assert_equal openid_prefix, oid_login_perm[:properties]['identity_url_prefix'],
263         'expected identity_url_prefix not found for oid_login_perm'
264
265     group_perm = find_obj_in_resp response, 'Link', 'arvados#group'
266     verify_link group_perm, 'permission', 'can_read', resp_user[:uuid], nil
267
268     repo_perm = find_obj_in_resp response, 'Link', 'arvados#repository'
269     verify_link repo_perm, 'permission', 'can_manage', resp_user[:uuid], nil
270
271     vm_perm = find_obj_in_resp response, 'Link', 'arvados#virtualMachine'
272     verify_link vm_perm, 'permission', 'can_login', resp_user[:uuid], vm.uuid
273   end
274
275   test "setup new user with junk in database" do
276     set_user_from_auth :admin
277
278     email = 'foo@example.com'
279     openid_prefix = 'http://openid/prefix'
280
281     user = User.create ({uuid: 'zzzzz-tpzed-abcdefghijklmno', email: email})
282
283     vm = VirtualMachine.create
284
285     # Set up the bogus Link
286     bad_uuid = 'zzzzz-tpzed-xyzxyzxyzxyzxyz'
287
288     resp_link = Link.create ({tail_uuid: email, link_class: 'permission',
289         name: 'can_login', head_uuid: bad_uuid})
290     resp_link.save(validate: false)
291
292     verify_link resp_link, 'permission', 'can_login', email, bad_uuid
293
294     response = User.setup user, openid_prefix, 'test_repo', vm.uuid
295
296     resp_user = find_obj_in_resp response, 'User'
297     verify_user resp_user, email
298
299     oid_login_perm = find_obj_in_resp response, 'Link', 'arvados#user'
300
301     verify_link oid_login_perm, 'permission', 'can_login', resp_user[:email],
302         resp_user[:uuid]
303
304     assert_equal openid_prefix, oid_login_perm[:properties]['identity_url_prefix'],
305         'expected identity_url_prefix not found for oid_login_perm'
306
307     group_perm = find_obj_in_resp response, 'Link', 'arvados#group'
308     verify_link group_perm, 'permission', 'can_read', resp_user[:uuid], nil
309
310     repo_perm = find_obj_in_resp response, 'Link', 'arvados#repository'
311     verify_link repo_perm, 'permission', 'can_manage', resp_user[:uuid], nil
312
313     vm_perm = find_obj_in_resp response, 'Link', 'arvados#virtualMachine'
314     verify_link vm_perm, 'permission', 'can_login', resp_user[:uuid], vm.uuid
315   end
316
317
318
319   test "setup new user in multiple steps" do
320     set_user_from_auth :admin
321
322     email = 'foo@example.com'
323     openid_prefix = 'http://openid/prefix'
324
325     user = User.create ({uuid: 'zzzzz-tpzed-abcdefghijklmno', email: email})
326
327     response = User.setup user, openid_prefix
328
329     resp_user = find_obj_in_resp response, 'User'
330     verify_user resp_user, email
331
332     oid_login_perm = find_obj_in_resp response, 'Link', 'arvados#user'
333     verify_link oid_login_perm, 'permission', 'can_login', resp_user[:email],
334         resp_user[:uuid]
335     assert_equal openid_prefix, oid_login_perm[:properties]['identity_url_prefix'],
336         'expected identity_url_prefix not found for oid_login_perm'
337
338     group_perm = find_obj_in_resp response, 'Link', 'arvados#group'
339     verify_link group_perm, 'permission', 'can_read', resp_user[:uuid], nil
340
341     # invoke setup again with repo_name
342     response = User.setup user, openid_prefix, 'test_repo'
343     resp_user = find_obj_in_resp response, 'User', nil
344     verify_user resp_user, email
345     assert_equal user.uuid, resp_user[:uuid], 'expected uuid not found'
346
347     group_perm = find_obj_in_resp response, 'Link', 'arvados#group'
348     verify_link group_perm, 'permission', 'can_read', resp_user[:uuid], nil
349
350     repo_perm = find_obj_in_resp response, 'Link', 'arvados#repository'
351     verify_link repo_perm, 'permission', 'can_manage', resp_user[:uuid], nil
352
353     # invoke setup again with a vm_uuid
354     vm = VirtualMachine.create
355
356     response = User.setup user, openid_prefix, 'test_repo', vm.uuid
357
358     resp_user = find_obj_in_resp response, 'User', nil
359     verify_user resp_user, email
360     assert_equal user.uuid, resp_user[:uuid], 'expected uuid not found'
361
362     group_perm = find_obj_in_resp response, 'Link', 'arvados#group'
363     verify_link group_perm, 'permission', 'can_read', resp_user[:uuid], nil
364
365     repo_perm = find_obj_in_resp response, 'Link', 'arvados#repository'
366     verify_link repo_perm, 'permission', 'can_manage', resp_user[:uuid], nil
367
368     vm_perm = find_obj_in_resp response, 'Link', 'arvados#virtualMachine'
369     verify_link vm_perm, 'permission', 'can_login', resp_user[:uuid], vm.uuid
370   end
371
372   def find_obj_in_resp (response_items, object_type, head_kind=nil)
373     return_obj = nil
374     response_items.each { |x|
375       if !x
376         next
377       end
378
379       if object_type == 'User'
380         if ArvadosModel::resource_class_for_uuid(x['uuid']) == User
381           return_obj = x
382           break
383         end
384       else  # looking for a link
385         if ArvadosModel::resource_class_for_uuid(x['head_uuid']).kind == head_kind
386           return_obj = x
387           break
388         end
389       end
390     }
391     return return_obj
392   end
393
394   def verify_user (resp_user, email)
395     assert_not_nil resp_user, 'expected user object'
396     assert_not_nil resp_user['uuid'], 'expected user object'
397     assert_equal email, resp_user['email'], 'expected email not found'
398
399   end
400
401   def verify_link (link_object, link_class, link_name, tail_uuid, head_uuid)
402     assert_not_nil link_object, "expected link for #{link_class} #{link_name}"
403     assert_not_nil link_object[:uuid],
404         "expected non-nil uuid for link for #{link_class} #{link_name}"
405     assert_equal link_class, link_object[:link_class],
406         "expected link_class not found for #{link_class} #{link_name}"
407     assert_equal link_name, link_object[:name],
408         "expected link_name not found for #{link_class} #{link_name}"
409     assert_equal tail_uuid, link_object[:tail_uuid],
410         "expected tail_uuid not found for #{link_class} #{link_name}"
411     if head_uuid
412       assert_equal head_uuid, link_object[:head_uuid],
413           "expected head_uuid not found for #{link_class} #{link_name}"
414     end
415   end
416
417   def create_user_and_verify_setup_and_notifications (active, active_recipients, inactive_recipients, email, valid_email_format)
418     Rails.configuration.new_user_notification_recipients = active_recipients
419     Rails.configuration.new_inactive_user_notification_recipients = inactive_recipients
420
421     assert_equal active_recipients, Rails.configuration.new_user_notification_recipients
422     assert_equal inactive_recipients, Rails.configuration.new_inactive_user_notification_recipients
423
424     ActionMailer::Base.deliveries = []
425
426     user = User.new
427     user.first_name = "first_name_for_newly_created_user"
428     user.email = email
429     user.is_active = active
430     user.save
431
432     # check user setup
433     group = Group.where(name: 'All users').select do |g|
434       g[:uuid].match /-f+$/
435     end.first
436
437     username = email.partition('@')[0] if email
438
439     if !Rails.configuration.auto_setup_new_users || !valid_email_format
440       # verify that the user is not added to "All groups" by auto_setup
441       verify_link_exists false, group[:uuid], user.uuid, 'permission', 'can_read', nil, nil
442
443       # check oid login link not created by auto_setup
444       verify_link_exists false, user.uuid, user.email, 'permission', 'can_login', nil, nil
445     else
446       # verify that auto_setup took place
447       # verify that the user is added to "All groups"
448       verify_link_exists true, group[:uuid], user.uuid, 'permission', 'can_read', nil, nil
449
450       # check oid login link
451       verify_link_exists true, user.uuid, user.email, 'permission', 'can_login', nil, nil
452
453       username = user.email.partition('@')[0]
454
455       # check vm uuid
456       vm_uuid = Rails.configuration.auto_setup_new_users_with_vm_uuid
457       if vm_uuid
458         verify_link_exists true, vm_uuid, user.uuid, 'permission', 'can_login', 'username', username
459       else
460         verify_link_exists false, vm_uuid, user.uuid, 'permission', 'can_login', 'username', username
461       end
462
463       # check repo
464       if Rails.configuration.auto_setup_new_users_with_repository
465         repos = Repository.where('name like ?', "%#{username}%")
466         assert_not_nil repos, 'repository not found'
467         assert_equal true, repos.any?, 'repository not found'
468         repo_uuids = []
469         repos.each do |repo|
470           repo_uuids << repo[:uuid]
471         end
472         verify_link_exists true, repo_uuids, user.uuid, 'permission', 'can_manage', nil, nil
473       end
474     end
475
476     # check email notifications
477     new_user_email = nil
478     new_inactive_user_email = nil
479
480     ActionMailer::Base.deliveries.each do |d|
481       if d.subject == "#{Rails.configuration.email_subject_prefix}New user notification" then
482         new_user_email = d
483       elsif d.subject == "#{Rails.configuration.email_subject_prefix}New inactive user notification" then
484         new_inactive_user_email = d
485       end
486     end
487
488     if not active
489       if not inactive_recipients.empty? then
490         assert_not_nil new_inactive_user_email, 'Expected new inactive user email after setup'
491         assert_equal Rails.configuration.user_notifier_email_from, new_inactive_user_email.from[0]
492         assert_equal inactive_recipients, new_inactive_user_email.to[0]
493         assert_equal "#{Rails.configuration.email_subject_prefix}New inactive user notification", new_inactive_user_email.subject
494       else
495         assert_nil new_inactive_user_email, 'Did not expect new inactive user email after setup'
496       end
497     end
498
499     if active
500       assert_nil new_inactive_user_email, 'Expected no inactive user email after setting up active user'
501       if not active_recipients.empty? then
502         assert_not_nil new_user_email, 'Expected new user email after setup'
503         assert_equal Rails.configuration.user_notifier_email_from, new_user_email.from[0]
504         assert_equal active_recipients, new_user_email.to[0]
505         assert_equal "#{Rails.configuration.email_subject_prefix}New user notification", new_user_email.subject
506       else
507         assert_nil new_user_email, 'Did not expect new user email after setup'
508       end
509     end
510     ActionMailer::Base.deliveries = []
511
512   end
513
514   def verify_link_exists link_exists, head_uuid, tail_uuid, link_class, link_name, property_name, property_value
515     all_links = Link.where(head_uuid: head_uuid,
516                            tail_uuid: tail_uuid,
517                            link_class: link_class,
518                            name: link_name)
519     assert_equal link_exists, all_links.any?, "Link #{'not' if link_exists} found #{property_value}"
520     if link_exists && property_name && property_value
521       all_links.each do |link|
522         assert_equal true, all_links.first.properties[property_name].start_with?(property_value), 'Property not found in link'
523       end
524     end
525   end
526
527 end