1 # Copyright (C) The Arvados Authors. All rights reserved.
3 # SPDX-License-Identifier: AGPL-3.0
7 class CredentialsApiTest < ActionDispatch::IntegrationTest
10 def credential_create_helper
11 post "/arvados/v1/credentials",
12 params: {:format => :json,
14 name: "test credential",
15 description: "the credential for test",
16 credential_class: "basic_auth",
17 credential_id: "my_username",
18 credential_secret: "my_password",
19 expires_at: Time.now+2.weeks
22 headers: auth(:active),
24 assert_response :success
28 test "credential create and query" do
29 jr = credential_create_helper
31 # fields other than secret is are returned by the API
32 assert_equal "test credential", jr["name"]
33 assert_equal "the credential for test", jr["description"]
34 assert_equal "basic_auth", jr["credential_class"]
35 assert_equal "my_username", jr["credential_id"]
36 assert_nil jr["credential_secret"]
38 # secret is not returned by the API
39 get "/arvados/v1/credentials/#{jr['uuid']}", headers: auth(:active)
40 assert_response :success
42 assert_equal "test credential", jr["name"]
43 assert_equal "the credential for test", jr["description"]
44 assert_equal "basic_auth", jr["credential_class"]
45 assert_equal "my_username", jr["credential_id"]
46 assert_nil jr["credential_secret"]
48 # can get credential from the database and it has the password
49 assert_equal "my_password", Credential.find_by_uuid(jr["uuid"]).credential_secret
51 # credential_secret cannot appear in queries
52 get "/arvados/v1/credentials",
53 params: {:format => :json,
54 :filters => [["credential_secret", "=", "my_password"]].to_json,
56 headers: auth(:active)
58 assert_match(/Cannot filter on credential_secret/, json_response["errors"][0])
60 get "/arvados/v1/credentials",
61 params: {:format => :json,
62 :where => {credential_secret: "my_password"}.to_json
64 headers: auth(:active)
66 assert_match(/Cannot use credential_secret in where clause/, json_response["errors"][0])
68 get "/arvados/v1/credentials",
69 params: {:format => :json,
70 :order => ["credential_secret"].to_json
72 headers: auth(:active)
74 assert_match(/Cannot order by credential_secret/, json_response["errors"][0])
77 test "credential fetch by container" do
78 jr = credential_create_helper
80 # cannot fetch secret using a regular token
81 get "/arvados/v1/credentials/#{jr['uuid']}/credential_secret", headers: auth(:active)
84 get "/arvados/v1/credentials/#{jr['uuid']}/credential_secret",
85 headers: {'HTTP_AUTHORIZATION' => "Bearer #{api_client_authorizations(:running_container_auth).token}/#{containers(:running).uuid}"}
86 assert_response :success
87 assert_equal "my_password", json_response["credential_secret"]
89 lg = Log.where(object_uuid: jr['uuid'], event_type: "credential_secret_access").first
90 assert_equal jr["name"], lg["properties"]["name"]
91 assert_equal jr["credential_class"], lg["properties"]["credential_class"]
92 assert_equal jr["credential_id"], lg["properties"]["credential_id"]
95 test "credential owned by admin" do
96 post "/arvados/v1/credentials",
97 params: {:format => :json,
99 name: "test credential",
100 description: "the credential for test",
101 credential_class: "basic_auth",
102 credential_id: "my_username",
103 credential_secret: "my_password",
104 expires_at: Time.now+2.weeks
107 headers: auth(:admin),
109 assert_response :success
112 # cannot fetch secret using a regular token, even by admin
113 get "/arvados/v1/credentials/#{jr['uuid']}/credential_secret", headers: auth(:admin)
116 # user 'active' can't see it
117 get "/arvados/v1/credentials/#{jr['uuid']}", headers: auth(:active)
120 # not readable by container run by 'active' user returns a 404
121 # here like the previous check because the credential itself isn't
122 # considered visible to the user
123 get "/arvados/v1/credentials/#{jr['uuid']}/credential_secret",
124 headers: {'HTTP_AUTHORIZATION' => "Bearer #{api_client_authorizations(:running_container_auth).token}/#{containers(:running).uuid}"}
128 test "credential sharing" do
129 post "/arvados/v1/credentials",
130 params: {:format => :json,
132 name: "test credential",
133 description: "the credential for test",
134 credential_class: "basic_auth",
135 credential_id: "my_username",
136 credential_secret: "my_password",
137 expires_at: Time.now+2.weeks
140 headers: auth(:admin),
142 assert_response :success
145 # user 'active' can't see it
146 get "/arvados/v1/credentials/#{jr['uuid']}", headers: auth(:active)
149 # not readable by container run by 'active' user returns a 404
150 # here like the previous check because the credential itself isn't
151 # considered visible to the user
152 get "/arvados/v1/credentials/#{jr['uuid']}/credential_secret",
153 headers: {'HTTP_AUTHORIZATION' => "Bearer #{api_client_authorizations(:running_container_auth).token}/#{containers(:running).uuid}"}
156 # active user can't share
157 post "/arvados/v1/links",
161 tail_uuid: users(:active).uuid,
162 link_class: 'permission',
164 head_uuid: jr["uuid"],
168 headers: auth(:active)
172 post "/arvados/v1/links",
176 tail_uuid: users(:active).uuid,
177 link_class: 'permission',
179 head_uuid: jr["uuid"],
183 headers: auth(:admin)
184 assert_response :success
186 # now the 'active' user can read it
187 get "/arvados/v1/credentials/#{jr['uuid']}/credential_secret",
188 headers: {'HTTP_AUTHORIZATION' => "Bearer #{api_client_authorizations(:running_container_auth).token}/#{containers(:running).uuid}"}
189 assert_response :success
192 test "credential expiration" do
193 post "/arvados/v1/credentials",
194 params: {:format => :json,
196 name: "test credential",
197 description: "the credential for test",
198 credential_class: "basic_auth",
199 credential_id: "my_username",
200 credential_secret: "my_password",
201 expires_at: Time.now+1.seconds
204 headers: auth(:active),
206 assert_response :success
209 get "/arvados/v1/credentials/#{jr['uuid']}/credential_secret",
210 headers: {'HTTP_AUTHORIZATION' => "Bearer #{api_client_authorizations(:running_container_auth).token}/#{containers(:running).uuid}"}
211 assert_response :success
212 assert_equal "my_username", json_response["credential_id"]
213 assert_equal "my_password", json_response["credential_secret"]
215 assert_equal "my_password", Credential.find_by_uuid(jr["uuid"]).credential_secret
219 get "/arvados/v1/credentials/#{jr['uuid']}/credential_secret",
220 headers: {'HTTP_AUTHORIZATION' => "Bearer #{api_client_authorizations(:running_container_auth).token}/#{containers(:running).uuid}"}
222 assert_match(/Credential has expired/, json_response["errors"][0])
224 post "/sys/trash_sweep",
225 headers: auth(:admin)
226 assert_response :success
228 assert_equal "", Credential.find_by_uuid(jr["uuid"]).credential_secret
231 test "credential names are unique" do
232 post "/arvados/v1/credentials",
233 params: {:format => :json,
235 name: "test credential",
236 description: "the credential for test",
237 credential_class: "basic_auth",
238 credential_id: "my_username",
239 credential_secret: "my_password",
240 expires_at: Time.now+2.weeks
243 headers: auth(:active),
245 assert_response :success
247 post "/arvados/v1/credentials",
248 params: {:format => :json,
250 name: "test credential",
251 description: "the credential for test",
252 credential_class: "basic_auth",
253 credential_id: "my_username",
254 credential_secret: "my_password",
255 expires_at: Time.now+2.weeks
258 headers: auth(:active),
261 assert_match(/RecordNotUnique/, json_response["errors"][0])
264 test "credential expires_at must be set" do
265 post "/arvados/v1/credentials",
266 params: {:format => :json,
268 name: "test credential",
269 description: "the credential for test",
270 credential_class: "basic_auth",
271 credential_id: "my_username",
272 credential_secret: "my_password"
275 headers: auth(:active),
278 assert_match(/NotNullViolation/, json_response["errors"][0])