Merge branch '14807-dispatch-cloud-fixes'
[arvados.git] / services / api / test / integration / user_sessions_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
7 class UserSessionsApiTest < ActionDispatch::IntegrationTest
8   # remote prefix & return url packed into the return_to param passed around
9   # between API and SSO provider.
10   def client_url(remote: nil)
11     url = ',https://wb.example.com'
12     url = "#{remote}#{url}" unless remote.nil?
13     url
14   end
15
16   def mock_auth_with(email: nil, username: nil, identity_url: nil, remote: nil, expected_response: :redirect)
17     mock = {
18       'provider' => 'josh_id',
19       'uid' => 'https://edward.example.com',
20       'info' => {
21         'identity_url' => 'https://edward.example.com',
22         'name' => 'Edward Example',
23         'first_name' => 'Edward',
24         'last_name' => 'Example',
25       },
26     }
27     mock['info']['email'] = email unless email.nil?
28     mock['info']['username'] = username unless username.nil?
29     mock['info']['identity_url'] = identity_url unless identity_url.nil?
30     post('/auth/josh_id/callback',
31          {return_to: client_url(remote: remote)},
32          {'omniauth.auth' => mock})
33
34     errors = {
35       :redirect => 'Did not redirect to client with token',
36       400 => 'Did not return Bad Request error',
37     }
38     assert_response expected_response, errors[expected_response]
39   end
40
41   test 'assign username from sso' do
42     mock_auth_with(email: 'foo@example.com', username: 'bar')
43     u = assigns(:user)
44     assert_equal 'bar', u.username
45   end
46
47   test 'no assign username from sso' do
48     mock_auth_with(email: 'foo@example.com')
49     u = assigns(:user)
50     assert_equal 'foo', u.username
51   end
52
53   test 'existing user login' do
54     mock_auth_with(identity_url: "https://active-user.openid.local")
55     u = assigns(:user)
56     assert_equal 'zzzzz-tpzed-xurymjxw79nv3jz', u.uuid
57   end
58
59   test 'user redirect_to_user_uuid' do
60     mock_auth_with(identity_url: "https://redirects-to-active-user.openid.local")
61     u = assigns(:user)
62     assert_equal 'zzzzz-tpzed-xurymjxw79nv3jz', u.uuid
63   end
64
65   test 'user double redirect_to_user_uuid' do
66     mock_auth_with(identity_url: "https://double-redirects-to-active-user.openid.local")
67     u = assigns(:user)
68     assert_equal 'zzzzz-tpzed-xurymjxw79nv3jz', u.uuid
69   end
70
71   test 'create new user during omniauth callback' do
72     mock_auth_with(email: 'edward@example.com')
73     assert_equal(0, @response.redirect_url.index(client_url.split(',', 2)[1]),
74                  'Redirected to wrong address after succesful login: was ' +
75                  @response.redirect_url + ', expected ' + client_url.split(',', 2)[1] + '[...]')
76     assert_not_nil(@response.redirect_url.index('api_token='),
77                    'Expected api_token in query string of redirect url ' +
78                    @response.redirect_url)
79   end
80
81   test 'issue salted token from omniauth callback with remote param' do
82     mock_auth_with(email: 'edward@example.com', remote: 'zbbbb')
83     api_client_auth = assigns(:api_client_auth)
84     assert_not_nil api_client_auth
85     assert_includes(@response.redirect_url, 'api_token=' + api_client_auth.salted_token(remote: 'zbbbb'))
86   end
87
88   test 'error out from omniauth callback with invalid remote param' do
89     mock_auth_with(email: 'edward@example.com', remote: 'invalid_cluster_id', expected_response: 400)
90   end
91
92   # Test various combinations of auto_setup configuration and email
93   # address provided during a new user's first session setup.
94   [{result: :nope, email: nil, cfg: {auto: true, repo: true, vm: true}},
95    {result: :yup, email: nil, cfg: {auto: true}},
96    {result: :nope, email: '@example.com', cfg: {auto: true, repo: true, vm: true}},
97    {result: :yup, email: '@example.com', cfg: {auto: true}},
98    {result: :nope, email: 'root@', cfg: {auto: true, repo: true, vm: true}},
99    {result: :nope, email: 'root@', cfg: {auto: true, repo: true}},
100    {result: :nope, email: 'root@', cfg: {auto: true, vm: true}},
101    {result: :yup, email: 'root@', cfg: {auto: true}},
102    {result: :nope, email: 'gitolite@', cfg: {auto: true, repo: true}},
103    {result: :nope, email: '*_*@', cfg: {auto: true, vm: true}},
104    {result: :yup, email: 'toor@', cfg: {auto: true, vm: true, repo: true}},
105    {result: :yup, email: 'foo@', cfg: {auto: true, vm: true},
106      uniqprefix: 'foo'},
107    {result: :yup, email: 'foo@', cfg: {auto: true, repo: true},
108      uniqprefix: 'foo'},
109    {result: :yup, email: 'auto_setup_vm_login@', cfg: {auto: true, repo: true},
110      uniqprefix: 'auto_setup_vm_login'},
111    ].each do |testcase|
112     test "user auto-activate #{testcase.inspect}" do
113       # Configure auto_setup behavior according to testcase[:cfg]
114       Rails.configuration.auto_setup_new_users = testcase[:cfg][:auto]
115       Rails.configuration.auto_setup_new_users_with_vm_uuid =
116         (testcase[:cfg][:vm] ? virtual_machines(:testvm).uuid : false)
117       Rails.configuration.auto_setup_new_users_with_repository =
118         testcase[:cfg][:repo]
119
120       mock_auth_with(email: testcase[:email])
121       u = assigns(:user)
122       vm_links = Link.where('link_class=? and tail_uuid=? and head_uuid like ?',
123                             'permission', u.uuid,
124                             '%-' + VirtualMachine.uuid_prefix + '-%')
125       repo_links = Link.where('link_class=? and tail_uuid=? and head_uuid like ?',
126                               'permission', u.uuid,
127                               '%-' + Repository.uuid_prefix + '-%')
128       repos = Repository.where('uuid in (?)', repo_links.collect(&:head_uuid))
129       case u[:result]
130       when :nope
131         assert_equal false, u.is_invited, "should not have been set up"
132         assert_empty vm_links, "should not have VM login permission"
133         assert_empty repo_links, "should not have repo permission"
134       when :yup
135         assert_equal true, u.is_invited
136         if testcase[:cfg][:vm]
137           assert_equal 1, vm_links.count, "wrong number of VM perm links"
138         else
139           assert_empty vm_links, "should not have VM login permission"
140         end
141         if testcase[:cfg][:repo]
142           assert_equal 1, repo_links.count, "wrong number of repo perm links"
143           assert_equal 1, repos.count, "wrong number of repos"
144           assert_equal 'can_manage', repo_links.first.name, "wrong perm type"
145         else
146           assert_empty repo_links, "should not have repo permission"
147         end
148       end
149       if (prefix = testcase[:uniqprefix])
150         # This email address conflicts with a test fixture. Make sure
151         # every VM login and repository name got digits added to make
152         # it unique.
153         (repos.collect(&:name) +
154          vm_links.collect { |link| link.properties['username'] }
155          ).each do |name|
156           r = name.match(/^(.{#{prefix.length}})(\d+)$/)
157           assert_not_nil r, "#{name.inspect} does not match {prefix}\\d+"
158           assert_equal(prefix, r[1],
159                        "#{name.inspect} was not {#{prefix.inspect} plus digits}")
160         end
161       end
162     end
163   end
164 end