18004: Fixes a couple of race condition bugs related to caching remote users.
[arvados.git] / services / api / test / integration / api_client_authorizations_api_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 ApiClientAuthorizationsApiTest < ActionDispatch::IntegrationTest
8   include DbCurrentTime
9   extend DbCurrentTime
10   fixtures :all
11
12   test "create system auth" do
13     post "/arvados/v1/api_client_authorizations/create_system_auth",
14       params: {:format => :json, :scopes => ['test'].to_json},
15       headers: {'HTTP_AUTHORIZATION' => "OAuth2 #{api_client_authorizations(:admin_trustedclient).api_token}"}
16     assert_response :success
17   end
18
19   [:admin_trustedclient, :SystemRootToken].each do |tk|
20     test "create token for different user using #{tk}" do
21       if tk == :SystemRootToken
22         token = "xyzzy-SystemRootToken"
23         Rails.configuration.SystemRootToken = token
24       else
25         token = api_client_authorizations(tk).api_token
26       end
27
28       post "/arvados/v1/api_client_authorizations",
29            params: {
30              :format => :json,
31              :api_client_authorization => {
32                :owner_uuid => users(:spectator).uuid
33              }
34            },
35            headers: {'HTTP_AUTHORIZATION' => "OAuth2 #{token}"}
36       assert_response :success
37
38       get "/arvados/v1/users/current",
39           params: {:format => :json},
40           headers: {'HTTP_AUTHORIZATION' => "OAuth2 #{json_response['api_token']}"}
41       @json_response = nil
42       assert_equal json_response['uuid'], users(:spectator).uuid
43     end
44   end
45
46   test "System root token is system user" do
47     token = "xyzzy-SystemRootToken"
48     Rails.configuration.SystemRootToken = token
49     get "/arvados/v1/users/current",
50         params: {:format => :json},
51         headers: {'HTTP_AUTHORIZATION' => "OAuth2 #{token}"}
52     assert_equal json_response['uuid'], system_user_uuid
53   end
54
55   test "refuse to create token for different user if not trusted client" do
56     post "/arvados/v1/api_client_authorizations",
57       params: {
58         :format => :json,
59         :api_client_authorization => {
60           :owner_uuid => users(:spectator).uuid
61         }
62       },
63       headers: {'HTTP_AUTHORIZATION' => "OAuth2 #{api_client_authorizations(:admin).api_token}"}
64     assert_response 403
65   end
66
67   test "refuse to create token for different user if not admin" do
68     post "/arvados/v1/api_client_authorizations",
69       params: {
70         :format => :json,
71         :api_client_authorization => {
72           :owner_uuid => users(:spectator).uuid
73         }
74       },
75       headers: {'HTTP_AUTHORIZATION' => "OAuth2 #{api_client_authorizations(:active_trustedclient).api_token}"}
76     assert_response 403
77   end
78
79   [nil, db_current_time + 2.hours].each do |desired_expiration|
80     test "expires_at gets clamped on non-admins when API.MaxTokenLifetime is set and desired expires_at #{desired_expiration.nil? ? 'is not set' : 'exceeds the limit'}" do
81       Rails.configuration.API.MaxTokenLifetime = 1.hour
82
83       # Test token creation
84       start_t = db_current_time
85       post "/arvados/v1/api_client_authorizations",
86         params: {
87           :format => :json,
88           :api_client_authorization => {
89             :owner_uuid => users(:active).uuid,
90             :expires_at => desired_expiration,
91           }
92         },
93         headers: {'HTTP_AUTHORIZATION' => "OAuth2 #{api_client_authorizations(:active_trustedclient).api_token}"}
94       end_t = db_current_time
95       assert_response 200
96       expiration_t = json_response['expires_at'].to_time
97       assert_operator expiration_t.to_f, :>, (start_t + Rails.configuration.API.MaxTokenLifetime).to_f
98       if !desired_expiration.nil?
99         assert_operator expiration_t.to_f, :<, desired_expiration.to_f
100       else
101         assert_operator expiration_t.to_f, :<, (end_t + Rails.configuration.API.MaxTokenLifetime).to_f
102       end
103
104       # Test token update
105       previous_expiration = expiration_t
106       token_uuid = json_response["uuid"]
107       start_t = db_current_time
108       put "/arvados/v1/api_client_authorizations/#{token_uuid}",
109         params: {
110           :api_client_authorization => {
111             :expires_at => desired_expiration
112           }
113         },
114         headers: {'HTTP_AUTHORIZATION' => "OAuth2 #{api_client_authorizations(:active_trustedclient).api_token}"}
115       end_t = db_current_time
116       assert_response 200
117       expiration_t = json_response['expires_at'].to_time
118       assert_operator previous_expiration.to_f, :<, expiration_t.to_f
119       assert_operator expiration_t.to_f, :>, (start_t + Rails.configuration.API.MaxTokenLifetime).to_f
120       if !desired_expiration.nil?
121         assert_operator expiration_t.to_f, :<, desired_expiration.to_f
122       else
123         assert_operator expiration_t.to_f, :<, (end_t + Rails.configuration.API.MaxTokenLifetime).to_f
124       end
125     end
126
127     test "behavior when expires_at is set to #{desired_expiration.nil? ? 'nil' : 'exceed the limit'} by admins when API.MaxTokenLifetime is set" do
128       Rails.configuration.API.MaxTokenLifetime = 1.hour
129
130       # Test token creation
131       post "/arvados/v1/api_client_authorizations",
132         params: {
133           :format => :json,
134           :api_client_authorization => {
135             :owner_uuid => users(:admin).uuid,
136             :expires_at => desired_expiration,
137           }
138         },
139         headers: {'HTTP_AUTHORIZATION' => "OAuth2 #{api_client_authorizations(:admin_trustedclient).api_token}"}
140       assert_response 200
141       if desired_expiration.nil?
142         # When expires_at is nil, default to MaxTokenLifetime
143         assert_operator (json_response['expires_at'].to_time.to_i - (db_current_time + Rails.configuration.API.MaxTokenLifetime).to_i).abs, :<, 2
144       else
145         assert_equal json_response['expires_at'].to_time.to_i, desired_expiration.to_i
146       end
147
148       # Test token update (reverse the above behavior)
149       token_uuid = json_response['uuid']
150       if desired_expiration.nil?
151         submitted_updated_expiration = db_current_time + Rails.configuration.API.MaxTokenLifetime + 1.hour
152       else
153         submitted_updated_expiration = nil
154       end
155       put "/arvados/v1/api_client_authorizations/#{token_uuid}",
156         params: {
157           :api_client_authorization => {
158             :expires_at => submitted_updated_expiration,
159           }
160         },
161         headers: {'HTTP_AUTHORIZATION' => "OAuth2 #{api_client_authorizations(:admin_trustedclient).api_token}"}
162       assert_response 200
163       if submitted_updated_expiration.nil?
164         assert_operator (json_response['expires_at'].to_time.to_i - (db_current_time + Rails.configuration.API.MaxTokenLifetime).to_i).abs, :<, 2
165       else
166         assert_equal json_response['expires_at'].to_time.to_i, submitted_updated_expiration.to_i
167       end
168     end
169   end
170
171   test "get current token using salted token" do
172     salted = salt_token(fixture: :active, remote: 'abcde')
173     get('/arvados/v1/api_client_authorizations/current',
174         params: {remote: 'abcde'},
175         headers: {'HTTP_AUTHORIZATION' => "Bearer #{salted}"})
176     assert_response :success
177     assert_equal(json_response['uuid'], api_client_authorizations(:active).uuid)
178     assert_equal(json_response['scopes'], ['all'])
179     assert_not_nil(json_response['expires_at'])
180     assert_nil(json_response['api_token'])
181   end
182 end