21059: Remote user status WIP
[arvados.git] / services / api / test / integration / remote_user_test.rb
1 # Copyright (C) The Arvados Authors. All rights reserved.
2 #
3 # SPDX-License-Identifier: AGPL-3.0
4
5 require 'webrick'
6 require 'webrick/https'
7 require 'test_helper'
8 require 'helpers/users_test_helper'
9
10 class RemoteUsersTest < ActionDispatch::IntegrationTest
11   include DbCurrentTime
12
13   def salted_active_token(remote:)
14     salt_token(fixture: :active, remote: remote).sub('/zzzzz-', '/'+remote+'-')
15   end
16
17   def auth(remote:)
18     token = salted_active_token(remote: remote)
19     {"HTTP_AUTHORIZATION" => "Bearer #{token}"}
20   end
21
22   # For remote authentication tests, we bring up a simple stub server
23   # (on a port chosen by webrick) and configure the SUT so the stub is
24   # responsible for clusters "zbbbb" (a well-behaved cluster) and
25   # "zbork" (a misbehaving cluster).
26   #
27   # Test cases can override the stub's default response to
28   # .../users/current by changing @stub_status and @stub_content.
29   setup do
30     clnt = HTTPClient.new
31     clnt.ssl_config.verify_mode = OpenSSL::SSL::VERIFY_NONE
32     HTTPClient.stubs(:new).returns clnt
33
34     @controller = Arvados::V1::UsersController.new
35     ready = Thread::Queue.new
36
37     @remote_server = []
38     @remote_host = []
39
40     ['zbbbb', 'zbork'].each do |clusterid|
41       srv = WEBrick::HTTPServer.new(
42         Port: 0,
43         Logger: WEBrick::Log.new(
44           Rails.root.join("log", "webrick.log").to_s,
45           WEBrick::Log::INFO),
46         AccessLog: [[File.open(Rails.root.join(
47                                  "log", "webrick_access.log").to_s, 'a+'),
48                      WEBrick::AccessLog::COMBINED_LOG_FORMAT]],
49         SSLEnable: true,
50         SSLVerifyClient: OpenSSL::SSL::VERIFY_NONE,
51         SSLPrivateKey: OpenSSL::PKey::RSA.new(
52           File.open(Rails.root.join("tmp", "self-signed.key")).read),
53         SSLCertificate: OpenSSL::X509::Certificate.new(
54           File.open(Rails.root.join("tmp", "self-signed.pem")).read),
55         SSLCertName: [["CN", WEBrick::Utils::getservername]],
56         StartCallback: lambda { ready.push(true) })
57       srv.mount_proc '/discovery/v1/apis/arvados/v1/rest' do |req, res|
58         res.body = Arvados::V1::SchemaController.new.send(:discovery_doc).to_json
59       end
60       srv.mount_proc '/arvados/v1/users/current' do |req, res|
61         if clusterid == 'zbbbb' and req.header['authorization'][0][10..14] == 'zbork'
62           # asking zbbbb about zbork should yield an error, zbbbb doesn't trust zbork
63           res.status = 401
64           return
65         end
66         res.status = @stub_status
67         res.body = @stub_content.is_a?(String) ? @stub_content : @stub_content.to_json
68       end
69       srv.mount_proc '/arvados/v1/api_client_authorizations/current' do |req, res|
70         if clusterid == 'zbbbb' and req.header['authorization'][0][10..14] == 'zbork'
71           # asking zbbbb about zbork should yield an error, zbbbb doesn't trust zbork
72           res.status = 401
73           return
74         end
75         res.status = @stub_token_status
76         if res.status == 200
77           body = {
78             uuid: api_client_authorizations(:active).uuid.sub('zzzzz', clusterid),
79             owner_uuid: "#{clusterid}-tpzed-00000000000000z",
80             scopes: @stub_token_scopes,
81           }
82           if @stub_content.is_a?(Hash) and owner_uuid = @stub_content[:uuid]
83             body[:owner_uuid] = owner_uuid
84           end
85           res.body = body.to_json
86         end
87       end
88       Thread.new do
89         srv.start
90       end
91       ready.pop
92       @remote_server << srv
93       @remote_host << "127.0.0.1:#{srv.config[:Port]}"
94     end
95     Rails.configuration.RemoteClusters = Rails.configuration.RemoteClusters.merge({zbbbb: ActiveSupport::InheritableOptions.new({Host: @remote_host[0]}),
96                                                                                    zbork: ActiveSupport::InheritableOptions.new({Host: @remote_host[1]})})
97     Arvados::V1::SchemaController.any_instance.stubs(:root_url).returns "https://#{@remote_host[0]}"
98     @stub_status = 200
99     @stub_content = {
100       uuid: 'zbbbb-tpzed-000000000000001',
101       email: 'foo@example.com',
102       username: 'barney',
103       first_name: "Barney",
104       last_name: "Foo",
105       is_admin: true,
106       is_active: true,
107       is_invited: true,
108     }
109     @stub_token_status = 200
110     @stub_token_scopes = ["all"]
111     ActionMailer::Base.deliveries = []
112   end
113
114   teardown do
115     @remote_server.each do |srv|
116       srv.stop
117     end
118   end
119
120   def uncache_token(src)
121     if match = src.match(/\b(?:[a-z0-9]{5}-){2}[a-z0-9]{15}\b/)
122       tokens = ApiClientAuthorization.where(uuid: match[0])
123     else
124       tokens = ApiClientAuthorization.where("uuid like ?", "#{src}-%")
125     end
126     tokens.update_all(expires_at: "1995-05-15T01:02:03Z")
127   end
128
129   test 'authenticate with remote token that has limited scope' do
130     get '/arvados/v1/collections',
131         params: {format: 'json'},
132         headers: auth(remote: 'zbbbb')
133     assert_response :success
134
135     @stub_token_scopes = ["GET /arvados/v1/users/current"]
136
137     # re-authorize before cache expires
138     get '/arvados/v1/collections',
139         params: {format: 'json'},
140         headers: auth(remote: 'zbbbb')
141     assert_response :success
142
143     uncache_token('zbbbb')
144     # re-authorize after cache expires
145     get '/arvados/v1/collections',
146         params: {format: 'json'},
147         headers: auth(remote: 'zbbbb')
148     assert_response 403
149   end
150
151   test "authenticate with remote token with limited initial scope" do
152     @stub_token_scopes = ["GET /arvados/v1/users/"]
153     get "/arvados/v1/users/#{@stub_content[:uuid]}",
154         params: {format: "json"},
155         headers: auth(remote: "zbbbb")
156     assert_response :success
157   end
158
159   test 'authenticate with remote token' do
160     get '/arvados/v1/users/current',
161       params: {format: 'json'},
162       headers: auth(remote: 'zbbbb')
163     assert_response :success
164     assert_equal 'zbbbb-tpzed-000000000000001', json_response['uuid']
165     assert_equal false, json_response['is_admin']
166     assert_equal false, json_response['is_active']
167     assert_equal 'foo@example.com', json_response['email']
168     assert_equal 'barney', json_response['username']
169
170     # revoke original token
171     @stub_token_status = 401
172
173     # re-authorize before cache expires
174     get '/arvados/v1/users/current',
175       params: {format: 'json'},
176       headers: auth(remote: 'zbbbb')
177     assert_response :success
178
179     uncache_token('zbbbb')
180     # re-authorize after cache expires
181     get '/arvados/v1/users/current',
182       params: {format: 'json'},
183       headers: auth(remote: 'zbbbb')
184     assert_response 401
185
186     # simulate cached token indicating wrong user (e.g., local user
187     # entry was migrated out of the way taking the cached token with
188     # it, or authorizing cluster reassigned auth to a different user)
189     ApiClientAuthorization.where(
190       uuid: salted_active_token(remote: 'zbbbb').split('/')[1]).
191       update_all(user_id: users(:active).id)
192
193     # revive original token and re-authorize
194     @stub_token_status = 200
195     @stub_content[:username] = 'blarney'
196     @stub_content[:email] = 'blarney@example.com'
197     get '/arvados/v1/users/current',
198       params: {format: 'json'},
199       headers: auth(remote: 'zbbbb')
200     assert_response :success
201     assert_equal 'barney', json_response['username'], 'local username should not change once assigned'
202     assert_equal 'blarney@example.com', json_response['email']
203   end
204
205   test 'remote user is deactivated' do
206     Rails.configuration.RemoteClusters['zbbbb'].ActivateUsers = true
207     get '/arvados/v1/users/current',
208       params: {format: 'json'},
209       headers: auth(remote: 'zbbbb')
210     assert_response :success
211     assert_equal true, json_response['is_active']
212
213     # revoke original token
214     @stub_content[:is_active] = false
215     @stub_content[:is_invited] = false
216
217     uncache_token('zbbbb')
218     # re-authorize after cache expires
219     get '/arvados/v1/users/current',
220       params: {format: 'json'},
221       headers: auth(remote: 'zbbbb')
222     assert_equal false, json_response['is_active']
223
224   end
225
226   test 'authenticate with remote token, remote username conflicts with local' do
227     @stub_content[:username] = 'active'
228     get '/arvados/v1/users/current',
229       params: {format: 'json'},
230       headers: auth(remote: 'zbbbb')
231     assert_response :success
232     assert_equal 'active2', json_response['username']
233   end
234
235   test 'authenticate with remote token, remote username is nil' do
236     @stub_content.delete :username
237     get '/arvados/v1/users/current',
238       params: {format: 'json'},
239       headers: auth(remote: 'zbbbb')
240     assert_response :success
241     assert_equal 'foo', json_response['username']
242   end
243
244   test 'authenticate with remote token from misbehaving remote cluster' do
245     get '/arvados/v1/users/current',
246       params: {format: 'json'},
247       headers: auth(remote: 'zbork')
248     assert_response 401
249   end
250
251   test 'authenticate with remote token that fails validate' do
252     @stub_status = 401
253     @stub_content = {
254       error: 'not authorized',
255     }
256     get '/arvados/v1/users/current',
257       params: {format: 'json'},
258       headers: auth(remote: 'zbbbb')
259     assert_response 401
260   end
261
262   ['v2',
263    'v2/',
264    'v2//',
265    'v2///',
266    "v2/'; delete from users where 1=1; commit; select '/lol",
267    'v2/foo/bar',
268    'v2/zzzzz-gj3su-077z32aux8dg2s1',
269    'v2/zzzzz-gj3su-077z32aux8dg2s1/',
270    'v2/3kg6k6lzmp9kj5cpkcoxie963cmvjahbt2fod9zru30k1jqdmi',
271    'v2/3kg6k6lzmp9kj5cpkcoxie963cmvjahbt2fod9zru30k1jqdmi/zzzzz-gj3su-077z32aux8dg2s1',
272    'v2//3kg6k6lzmp9kj5cpkcoxie963cmvjahbt2fod9zru30k1jqdmi',
273    'v8/zzzzz-gj3su-077z32aux8dg2s1/3kg6k6lzmp9kj5cpkcoxie963cmvjahbt2fod9zru30k1jqdmi',
274    '/zzzzz-gj3su-077z32aux8dg2s1/3kg6k6lzmp9kj5cpkcoxie963cmvjahbt2fod9zru30k1jqdmi',
275    '"v2/zzzzz-gj3su-077z32aux8dg2s1/3kg6k6lzmp9kj5cpkcoxie963cmvjahbt2fod9zru30k1jqdmi"',
276    '/',
277    '//',
278    '///',
279   ].each do |token|
280     test "authenticate with malformed remote token #{token}" do
281       get '/arvados/v1/users/current',
282         params: {format: 'json'},
283         headers: {"HTTP_AUTHORIZATION" => "Bearer #{token}"}
284       assert_response 401
285     end
286   end
287
288   test "ignore extra fields in remote token" do
289     token = salted_active_token(remote: 'zbbbb') + '/foo/bar/baz/*'
290     get '/arvados/v1/users/current',
291       params: {format: 'json'},
292       headers: {"HTTP_AUTHORIZATION" => "Bearer #{token}"}
293     assert_response :success
294   end
295
296   test 'remote api server is not an api server' do
297     @stub_status = 200
298     @stub_content = '<html>bad</html>'
299     get '/arvados/v1/users/current',
300       params: {format: 'json'},
301       headers: auth(remote: 'zbbbb')
302     assert_response 401
303   end
304
305   ['zbbbb', 'z0000'].each do |token_valid_for|
306     test "validate #{token_valid_for}-salted token for remote cluster zbbbb" do
307       salted_token = salt_token(fixture: :active, remote: token_valid_for)
308       get '/arvados/v1/users/current',
309         params: {format: 'json', remote: 'zbbbb'},
310         headers: {"HTTP_AUTHORIZATION" => "Bearer #{salted_token}"}
311       if token_valid_for == 'zbbbb'
312         assert_response 200
313         assert_equal(users(:active).uuid, json_response['uuid'])
314       else
315         assert_response 401
316       end
317     end
318   end
319
320   test "list readable groups with salted token" do
321     Rails.configuration.Users.RoleGroupsVisibleToAll = false
322     salted_token = salt_token(fixture: :active, remote: 'zbbbb')
323     get '/arvados/v1/groups',
324       params: {
325         format: 'json',
326         remote: 'zbbbb',
327         limit: 10000,
328       },
329       headers: {"HTTP_AUTHORIZATION" => "Bearer #{salted_token}"}
330     assert_response 200
331     group_uuids = json_response['items'].collect { |i| i['uuid'] }
332     assert_includes(group_uuids, 'zzzzz-j7d0g-fffffffffffffff')
333     refute_includes(group_uuids, 'zzzzz-j7d0g-000000000000000')
334     assert_includes(group_uuids, groups(:aproject).uuid)
335     refute_includes(group_uuids, groups(:trashed_project).uuid)
336     refute_includes(group_uuids, groups(:testusergroup_admins).uuid)
337   end
338
339   test 'do not auto-activate user from untrusted cluster' do
340     Rails.configuration.RemoteClusters['zbbbb'].AutoSetupNewUsers = false
341     Rails.configuration.RemoteClusters['zbbbb'].ActivateUsers = false
342     get '/arvados/v1/users/current',
343       params: {format: 'json'},
344       headers: auth(remote: 'zbbbb')
345     assert_response :success
346     assert_equal 'zbbbb-tpzed-000000000000001', json_response['uuid']
347     assert_equal false, json_response['is_admin']
348     assert_equal false, json_response['is_active']
349     assert_equal 'foo@example.com', json_response['email']
350     assert_equal 'barney', json_response['username']
351     post '/arvados/v1/users/zbbbb-tpzed-000000000000001/activate',
352       params: {format: 'json'},
353       headers: auth(remote: 'zbbbb')
354     assert_response 422
355   end
356
357   test 'auto-activate user from trusted cluster' do
358     Rails.configuration.RemoteClusters['zbbbb'].ActivateUsers = true
359     get '/arvados/v1/users/current',
360       params: {format: 'json'},
361       headers: auth(remote: 'zbbbb')
362     assert_response :success
363     assert_equal 'zbbbb-tpzed-000000000000001', json_response['uuid']
364     assert_equal false, json_response['is_admin']
365     assert_equal true, json_response['is_active']
366     assert_equal 'foo@example.com', json_response['email']
367     assert_equal 'barney', json_response['username']
368   end
369
370   test 'get user from Login cluster' do
371     Rails.configuration.Login.LoginCluster = 'zbbbb'
372     email_dest = ActiveSupport::OrderedOptions.new
373     email_dest[:'arvados-admin@example.com'] = ActiveSupport::OrderedOptions.new
374     Rails.configuration.Users.UserNotifierEmailBcc = email_dest
375     Rails.configuration.Users.NewUserNotificationRecipients = email_dest
376     Rails.configuration.Users.NewInactiveUserNotificationRecipients = email_dest
377
378     get '/arvados/v1/users/current',
379       params: {format: 'json'},
380       headers: auth(remote: 'zbbbb')
381     assert_response :success
382     assert_equal 'zbbbb-tpzed-000000000000001', json_response['uuid']
383     assert_equal true, json_response['is_admin']
384     assert_equal true, json_response['is_active']
385     assert_equal 'foo@example.com', json_response['email']
386     assert_equal 'barney', json_response['username']
387
388     # ActionMailer::Base.deliveries.each do |d|
389     #   puts "--- delivery #{d.inspect} #{d.body}"
390     # end
391
392     assert_equal 2, ActionMailer::Base.deliveries.length
393     assert_equal "Welcome to Arvados - account enabled", ActionMailer::Base.deliveries[0].subject
394     assert_equal "[ARVADOS] New user created notification", ActionMailer::Base.deliveries[1].subject
395   end
396
397   [true, false].each do |trusted|
398     [true, false].each do |logincluster|
399       [true, false, nil].each do |admin|
400         [true, false, nil].each do |active|
401           [true, false].each do |autosetup|
402             [true, false, nil].each do |invited|
403               test "get invited=#{invited}, active=#{active}, admin=#{admin} user from #{if logincluster then "Login" else "peer" end} cluster when AutoSetupNewUsers=#{autosetup} ActivateUsers=#{trusted}" do
404                 Rails.configuration.Login.LoginCluster = 'zbbbb' if logincluster
405                 Rails.configuration.RemoteClusters['zbbbb'].ActivateUsers = trusted
406                 Rails.configuration.Users.AutoSetupNewUsers = autosetup
407                 @stub_content = {
408                   uuid: 'zbbbb-tpzed-000000000000001',
409                   email: 'foo@example.com',
410                   username: 'barney',
411                   is_admin: admin,
412                   is_active: active,
413                   is_invited: invited,
414                 }
415                 get '/arvados/v1/users/current',
416                     params: {format: 'json'},
417                     headers: auth(remote: 'zbbbb')
418                 assert_response :success
419                 assert_equal 'zbbbb-tpzed-000000000000001', json_response['uuid']
420                 assert_equal (logincluster && !!admin && (invited != false) && !!active), json_response['is_admin']
421                 assert_equal ((invited == true || (invited == nil && !!active)) && (logincluster || trusted || autosetup)), json_response['is_invited']
422                 assert_equal ((invited != false) && (logincluster || trusted) && !!active), json_response['is_active']
423                 assert_equal 'foo@example.com', json_response['email']
424                 assert_equal 'barney', json_response['username']
425               end
426             end
427           end
428         end
429       end
430     end
431   end
432
433   test 'get active user from Login cluster when AutoSetupNewUsers is set' do
434     Rails.configuration.Login.LoginCluster = 'zbbbb'
435     Rails.configuration.Users.AutoSetupNewUsers = true
436     @stub_content = {
437       uuid: 'zbbbb-tpzed-000000000000001',
438       email: 'foo@example.com',
439       username: 'barney',
440       is_admin: false,
441       is_active: true,
442       is_invited: true,
443     }
444     get '/arvados/v1/users/current',
445       params: {format: 'json'},
446       headers: auth(remote: 'zbbbb')
447     assert_response :success
448     assert_equal 'zbbbb-tpzed-000000000000001', json_response['uuid']
449     assert_equal false, json_response['is_admin']
450     assert_equal true, json_response['is_active']
451     assert_equal true, json_response['is_invited']
452     assert_equal 'foo@example.com', json_response['email']
453     assert_equal 'barney', json_response['username']
454
455     @stub_content = {
456       uuid: 'zbbbb-tpzed-000000000000001',
457       email: 'foo@example.com',
458       username: 'barney',
459       is_admin: false,
460       is_active: false,
461       is_invited: false,
462     }
463
464     # Use cached value.  User will still be active because we haven't
465     # re-queried the upstream cluster.
466     get '/arvados/v1/users/current',
467       params: {format: 'json'},
468       headers: auth(remote: 'zbbbb')
469     assert_response :success
470     assert_equal 'zbbbb-tpzed-000000000000001', json_response['uuid']
471     assert_equal false, json_response['is_admin']
472     assert_equal true, json_response['is_active']
473     assert_equal true, json_response['is_invited']
474     assert_equal 'foo@example.com', json_response['email']
475     assert_equal 'barney', json_response['username']
476
477     uncache_token('zbbbb')
478     # User should be inactive now.
479     get '/arvados/v1/users/current',
480       params: {format: 'json'},
481       headers: auth(remote: 'zbbbb')
482     assert_response :success
483     assert_equal 'zbbbb-tpzed-000000000000001', json_response['uuid']
484     assert_equal false, json_response['is_admin']
485     assert_equal false, json_response['is_active']
486     assert_equal false, json_response['is_invited']
487     assert_equal 'foo@example.com', json_response['email']
488     assert_equal 'barney', json_response['username']
489
490   end
491
492   test 'pre-activate remote user' do
493     @stub_content = {
494       uuid: 'zbbbb-tpzed-000000000001234',
495       email: 'foo@example.com',
496       username: 'barney',
497       is_admin: true,
498       is_active: true,
499       is_invited: true,
500     }
501
502     post '/arvados/v1/users',
503       params: {
504         "user" => {
505           "uuid" => "zbbbb-tpzed-000000000001234",
506           "email" => 'foo@example.com',
507           "username" => 'barney',
508           "is_active" => true,
509           "is_admin" => false
510         }
511       },
512       headers: {'HTTP_AUTHORIZATION' => "OAuth2 #{api_token(:admin)}"}
513     assert_response :success
514
515     get '/arvados/v1/users/current',
516       params: {format: 'json'},
517       headers: auth(remote: 'zbbbb')
518     assert_response :success
519     assert_equal 'zbbbb-tpzed-000000000001234', json_response['uuid']
520     assert_equal false, json_response['is_admin']
521     assert_equal true, json_response['is_active']
522     assert_equal 'foo@example.com', json_response['email']
523     assert_equal 'barney', json_response['username']
524   end
525
526
527   test 'remote user inactive without pre-activation' do
528     @stub_content = {
529       uuid: 'zbbbb-tpzed-000000000001234',
530       email: 'foo@example.com',
531       username: 'barney',
532       is_admin: true,
533       is_active: true,
534       is_invited: true,
535     }
536
537     get '/arvados/v1/users/current',
538       params: {format: 'json'},
539       headers: auth(remote: 'zbbbb')
540     assert_response :success
541     assert_equal 'zbbbb-tpzed-000000000001234', json_response['uuid']
542     assert_equal false, json_response['is_admin']
543     assert_equal false, json_response['is_active']
544     assert_equal 'foo@example.com', json_response['email']
545     assert_equal 'barney', json_response['username']
546   end
547
548   test "validate unsalted v2 token for remote cluster zbbbb" do
549     auth = api_client_authorizations(:active)
550     token = "v2/#{auth.uuid}/#{auth.api_token}"
551     get '/arvados/v1/users/current',
552       params: {format: 'json', remote: 'zbbbb'},
553       headers: {"HTTP_AUTHORIZATION" => "Bearer #{token}"}
554     assert_response :success
555     assert_equal(users(:active).uuid, json_response['uuid'])
556   end
557
558   test 'container request with runtime_token' do
559     [["valid local", "v2/#{api_client_authorizations(:active).uuid}/#{api_client_authorizations(:active).api_token}"],
560      ["valid remote", "v2/zbbbb-gj3su-000000000000000/abc"],
561      ["invalid local", "v2/#{api_client_authorizations(:active).uuid}/fakefakefake"],
562      ["invalid remote", "v2/zbork-gj3su-000000000000000/abc"],
563     ].each do |label, runtime_token|
564       post '/arvados/v1/container_requests',
565         params: {
566           "container_request" => {
567             "command" => ["echo"],
568             "container_image" => "xyz",
569             "output_path" => "/",
570             "cwd" => "/",
571             "runtime_token" => runtime_token
572           }
573         },
574         headers: {"HTTP_AUTHORIZATION" => "Bearer #{api_client_authorizations(:active).api_token}"}
575       if label.include? "invalid"
576         assert_response 422
577       else
578         assert_response :success
579       end
580     end
581   end
582
583   test 'authenticate with remote token, remote user is system user' do
584     @stub_content[:uuid] = 'zbbbb-tpzed-000000000000000'
585     get '/arvados/v1/users/current',
586       params: {format: 'json'},
587       headers: auth(remote: 'zbbbb')
588     assert_equal 'from cluster zbbbb', json_response['last_name']
589   end
590
591   test 'authenticate with remote token, remote user is anonymous user' do
592     @stub_content[:uuid] = 'zbbbb-tpzed-anonymouspublic'
593     get '/arvados/v1/users/current',
594       params: {format: 'json'},
595       headers: auth(remote: 'zbbbb')
596     assert_response :success
597     assert_equal 'zzzzz-tpzed-anonymouspublic', json_response['uuid']
598   end
599
600   [401, 403, 422, 500, 502, 503].each do |status|
601     test "propagate #{status} response from getting remote token" do
602       @stub_token_status = status
603       get "/arvados/v1/users/#{@stub_content[:uuid]}",
604           params: {format: "json"},
605           headers: auth(remote: "zbbbb")
606       assert_response status
607     end
608
609     test "propagate #{status} response from getting uncached user" do
610       @stub_status = status
611       get "/arvados/v1/users/#{@stub_content[:uuid]}",
612           params: {format: "json"},
613           headers: auth(remote: "zbbbb")
614       assert_response status
615     end
616
617     test "use cached user after getting #{status} response" do
618       url_path = "/arvados/v1/users/#{@stub_content[:uuid]}"
619       params = {format: "json"}
620       headers = auth(remote: "zbbbb")
621
622       get url_path, params: params, headers: headers
623       assert_response :success
624
625       uncache_token(headers["HTTP_AUTHORIZATION"])
626       expect_email = @stub_content[:email]
627       @stub_content[:email] = "new#{expect_email}"
628       @stub_status = status
629       get url_path, params: params, headers: headers
630       assert_response :success
631       user = User.find_by_uuid(@stub_content[:uuid])
632       assert_not_nil user
633       assert_equal expect_email, user.email
634     end
635   end
636 end