googleauth 0.9.0 → 0.17.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.yardopts +11 -0
- data/CHANGELOG.md +113 -21
- data/README.md +13 -15
- data/SECURITY.md +7 -0
- data/lib/googleauth/application_default.rb +9 -9
- data/lib/googleauth/compute_engine.rb +55 -30
- data/lib/googleauth/credentials.rb +253 -64
- data/lib/googleauth/credentials_loader.rb +15 -16
- data/lib/googleauth/iam.rb +1 -1
- data/{spec/googleauth/stores/store_examples.rb → lib/googleauth/id_tokens/errors.rb} +36 -23
- data/lib/googleauth/id_tokens/key_sources.rb +396 -0
- data/lib/googleauth/id_tokens/verifier.rb +142 -0
- data/lib/googleauth/id_tokens.rb +233 -0
- data/lib/googleauth/json_key_reader.rb +6 -2
- data/lib/googleauth/scope_util.rb +1 -1
- data/lib/googleauth/service_account.rb +61 -36
- data/lib/googleauth/signet.rb +9 -7
- data/lib/googleauth/stores/file_token_store.rb +1 -0
- data/lib/googleauth/stores/redis_token_store.rb +1 -0
- data/lib/googleauth/user_authorizer.rb +8 -3
- data/lib/googleauth/user_refresh.rb +1 -1
- data/lib/googleauth/version.rb +1 -1
- data/lib/googleauth/web_user_authorizer.rb +5 -8
- data/lib/googleauth.rb +1 -0
- metadata +33 -76
- data/.github/CONTRIBUTING.md +0 -74
- data/.github/ISSUE_TEMPLATE/bug_report.md +0 -36
- data/.github/ISSUE_TEMPLATE/feature_request.md +0 -21
- data/.github/ISSUE_TEMPLATE/support_request.md +0 -7
- data/.gitignore +0 -36
- data/.kokoro/build.bat +0 -16
- data/.kokoro/build.sh +0 -4
- data/.kokoro/continuous/common.cfg +0 -24
- data/.kokoro/continuous/linux.cfg +0 -15
- data/.kokoro/continuous/osx.cfg +0 -3
- data/.kokoro/continuous/windows.cfg +0 -19
- data/.kokoro/osx.sh +0 -4
- data/.kokoro/presubmit/common.cfg +0 -24
- data/.kokoro/presubmit/linux.cfg +0 -14
- data/.kokoro/presubmit/osx.cfg +0 -3
- data/.kokoro/presubmit/windows.cfg +0 -19
- data/.kokoro/release.cfg +0 -53
- data/.kokoro/trampoline.bat +0 -10
- data/.kokoro/trampoline.sh +0 -4
- data/.rspec +0 -2
- data/.rubocop.yml +0 -42
- data/Gemfile +0 -25
- data/Rakefile +0 -89
- data/googleauth.gemspec +0 -35
- data/spec/googleauth/apply_auth_examples.rb +0 -148
- data/spec/googleauth/client_id_spec.rb +0 -160
- data/spec/googleauth/compute_engine_spec.rb +0 -122
- data/spec/googleauth/credentials_spec.rb +0 -459
- data/spec/googleauth/get_application_default_spec.rb +0 -286
- data/spec/googleauth/iam_spec.rb +0 -80
- data/spec/googleauth/scope_util_spec.rb +0 -77
- data/spec/googleauth/service_account_spec.rb +0 -482
- data/spec/googleauth/signet_spec.rb +0 -134
- data/spec/googleauth/stores/file_token_store_spec.rb +0 -57
- data/spec/googleauth/stores/redis_token_store_spec.rb +0 -50
- data/spec/googleauth/user_authorizer_spec.rb +0 -323
- data/spec/googleauth/user_refresh_spec.rb +0 -359
- data/spec/googleauth/web_user_authorizer_spec.rb +0 -172
- data/spec/spec_helper.rb +0 -92
- /data/{COPYING → LICENSE} +0 -0
@@ -1,482 +0,0 @@
|
|
1
|
-
# Copyright 2015, Google Inc.
|
2
|
-
# All rights reserved.
|
3
|
-
#
|
4
|
-
# Redistribution and use in source and binary forms, with or without
|
5
|
-
# modification, are permitted provided that the following conditions are
|
6
|
-
# met:
|
7
|
-
#
|
8
|
-
# * Redistributions of source code must retain the above copyright
|
9
|
-
# notice, this list of conditions and the following disclaimer.
|
10
|
-
# * Redistributions in binary form must reproduce the above
|
11
|
-
# copyright notice, this list of conditions and the following disclaimer
|
12
|
-
# in the documentation and/or other materials provided with the
|
13
|
-
# distribution.
|
14
|
-
# * Neither the name of Google Inc. nor the names of its
|
15
|
-
# contributors may be used to endorse or promote products derived from
|
16
|
-
# this software without specific prior written permission.
|
17
|
-
#
|
18
|
-
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
19
|
-
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
20
|
-
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
21
|
-
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
22
|
-
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
23
|
-
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
24
|
-
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
25
|
-
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
26
|
-
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
27
|
-
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
28
|
-
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
29
|
-
|
30
|
-
spec_dir = File.expand_path File.join(File.dirname(__FILE__))
|
31
|
-
$LOAD_PATH.unshift spec_dir
|
32
|
-
$LOAD_PATH.uniq!
|
33
|
-
|
34
|
-
require "apply_auth_examples"
|
35
|
-
require "fakefs/safe"
|
36
|
-
require "fileutils"
|
37
|
-
require "googleauth/service_account"
|
38
|
-
require "jwt"
|
39
|
-
require "multi_json"
|
40
|
-
require "openssl"
|
41
|
-
require "spec_helper"
|
42
|
-
require "tmpdir"
|
43
|
-
require "os"
|
44
|
-
|
45
|
-
include Google::Auth::CredentialsLoader
|
46
|
-
|
47
|
-
shared_examples "jwt header auth" do
|
48
|
-
context "when jwt_aud_uri is present" do
|
49
|
-
let(:test_uri) { "https://www.googleapis.com/myservice" }
|
50
|
-
let(:auth_prefix) { "Bearer " }
|
51
|
-
let(:auth_key) { ServiceAccountJwtHeaderCredentials::AUTH_METADATA_KEY }
|
52
|
-
let(:jwt_uri_key) { ServiceAccountJwtHeaderCredentials::JWT_AUD_URI_KEY }
|
53
|
-
|
54
|
-
def expect_is_encoded_jwt hdr
|
55
|
-
expect(hdr).to_not be_nil
|
56
|
-
expect(hdr.start_with?(auth_prefix)).to be true
|
57
|
-
authorization = hdr[auth_prefix.length..-1]
|
58
|
-
payload, = JWT.decode authorization, @key.public_key, true, algorithm: "RS256"
|
59
|
-
expect(payload["aud"]).to eq(test_uri)
|
60
|
-
expect(payload["iss"]).to eq(client_email)
|
61
|
-
end
|
62
|
-
|
63
|
-
describe "#apply!" do
|
64
|
-
it "should update the target hash with a jwt token" do
|
65
|
-
md = { foo: "bar" }
|
66
|
-
md[jwt_uri_key] = test_uri
|
67
|
-
@client.apply! md
|
68
|
-
auth_header = md[auth_key]
|
69
|
-
expect_is_encoded_jwt auth_header
|
70
|
-
expect(md[jwt_uri_key]).to be_nil
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
|
-
describe "updater_proc" do
|
75
|
-
it "should provide a proc that updates a hash with a jwt token" do
|
76
|
-
md = { foo: "bar" }
|
77
|
-
md[jwt_uri_key] = test_uri
|
78
|
-
the_proc = @client.updater_proc
|
79
|
-
got = the_proc.call md
|
80
|
-
auth_header = got[auth_key]
|
81
|
-
expect_is_encoded_jwt auth_header
|
82
|
-
expect(got[jwt_uri_key]).to be_nil
|
83
|
-
expect(md[jwt_uri_key]).to_not be_nil
|
84
|
-
end
|
85
|
-
end
|
86
|
-
|
87
|
-
describe "#apply" do
|
88
|
-
it "should not update the original hash with a jwt token" do
|
89
|
-
md = { foo: "bar" }
|
90
|
-
md[jwt_uri_key] = test_uri
|
91
|
-
the_proc = @client.updater_proc
|
92
|
-
got = the_proc.call md
|
93
|
-
auth_header = md[auth_key]
|
94
|
-
expect(auth_header).to be_nil
|
95
|
-
expect(got[jwt_uri_key]).to be_nil
|
96
|
-
expect(md[jwt_uri_key]).to_not be_nil
|
97
|
-
end
|
98
|
-
|
99
|
-
it "should add a jwt token to the returned hash" do
|
100
|
-
md = { foo: "bar" }
|
101
|
-
md[jwt_uri_key] = test_uri
|
102
|
-
got = @client.apply md
|
103
|
-
auth_header = got[auth_key]
|
104
|
-
expect_is_encoded_jwt auth_header
|
105
|
-
end
|
106
|
-
end
|
107
|
-
end
|
108
|
-
end
|
109
|
-
|
110
|
-
describe Google::Auth::ServiceAccountCredentials do
|
111
|
-
ServiceAccountCredentials = Google::Auth::ServiceAccountCredentials
|
112
|
-
let(:client_email) { "app@developer.gserviceaccount.com" }
|
113
|
-
let :cred_json do
|
114
|
-
{
|
115
|
-
private_key_id: "a_private_key_id",
|
116
|
-
private_key: @key.to_pem,
|
117
|
-
client_email: client_email,
|
118
|
-
client_id: "app.apps.googleusercontent.com",
|
119
|
-
type: "service_account",
|
120
|
-
project_id: "a_project_id"
|
121
|
-
}
|
122
|
-
end
|
123
|
-
|
124
|
-
before :example do
|
125
|
-
@key = OpenSSL::PKey::RSA.new 2048
|
126
|
-
@client = ServiceAccountCredentials.make_creds(
|
127
|
-
json_key_io: StringIO.new(cred_json_text),
|
128
|
-
scope: "https://www.googleapis.com/auth/userinfo.profile"
|
129
|
-
)
|
130
|
-
end
|
131
|
-
|
132
|
-
def make_auth_stubs opts = {}
|
133
|
-
access_token = opts[:access_token] || ""
|
134
|
-
body = MultiJson.dump("access_token" => access_token,
|
135
|
-
"token_type" => "Bearer",
|
136
|
-
"expires_in" => 3600)
|
137
|
-
blk = proc do |request|
|
138
|
-
params = Addressable::URI.form_unencode request.body
|
139
|
-
_claim, _header = JWT.decode(params.assoc("assertion").last,
|
140
|
-
@key.public_key, true,
|
141
|
-
algorithm: "RS256")
|
142
|
-
end
|
143
|
-
stub_request(:post, "https://www.googleapis.com/oauth2/v4/token")
|
144
|
-
.with(body: hash_including(
|
145
|
-
"grant_type" => "urn:ietf:params:oauth:grant-type:jwt-bearer"
|
146
|
-
),
|
147
|
-
&blk)
|
148
|
-
.to_return(body: body,
|
149
|
-
status: 200,
|
150
|
-
headers: { "Content-Type" => "application/json" })
|
151
|
-
end
|
152
|
-
|
153
|
-
def cred_json_text
|
154
|
-
MultiJson.dump cred_json
|
155
|
-
end
|
156
|
-
|
157
|
-
it_behaves_like "apply/apply! are OK"
|
158
|
-
|
159
|
-
context "when scope is nil" do
|
160
|
-
before :example do
|
161
|
-
@client.scope = nil
|
162
|
-
end
|
163
|
-
|
164
|
-
it_behaves_like "jwt header auth"
|
165
|
-
end
|
166
|
-
|
167
|
-
describe "#from_env" do
|
168
|
-
before :example do
|
169
|
-
@var_name = ENV_VAR
|
170
|
-
@credential_vars = [
|
171
|
-
ENV_VAR, PRIVATE_KEY_VAR, CLIENT_EMAIL_VAR, ACCOUNT_TYPE_VAR
|
172
|
-
]
|
173
|
-
@original_env_vals = {}
|
174
|
-
@credential_vars.each { |var| @original_env_vals[var] = ENV[var] }
|
175
|
-
ENV[ACCOUNT_TYPE_VAR] = cred_json[:type]
|
176
|
-
|
177
|
-
@scope = "https://www.googleapis.com/auth/userinfo.profile"
|
178
|
-
@clz = ServiceAccountCredentials
|
179
|
-
end
|
180
|
-
|
181
|
-
after :example do
|
182
|
-
@credential_vars.each { |var| ENV[var] = @original_env_vals[var] }
|
183
|
-
end
|
184
|
-
|
185
|
-
it "returns nil if the GOOGLE_APPLICATION_CREDENTIALS is unset" do
|
186
|
-
ENV.delete @var_name unless ENV[@var_name].nil?
|
187
|
-
expect(ServiceAccountCredentials.from_env(@scope)).to be_nil
|
188
|
-
end
|
189
|
-
|
190
|
-
it "returns nil if the GOOGLE_APPLICATION_CREDENTIALS is empty" do
|
191
|
-
ENV[@var_name] = ""
|
192
|
-
expect(ServiceAccountCredentials.from_env(@scope)).to be_nil
|
193
|
-
end
|
194
|
-
|
195
|
-
it "fails if the GOOGLE_APPLICATION_CREDENTIALS path does not exist" do
|
196
|
-
ENV.delete @var_name unless ENV[@var_name].nil?
|
197
|
-
expect(ServiceAccountCredentials.from_env(@scope)).to be_nil
|
198
|
-
Dir.mktmpdir do |dir|
|
199
|
-
key_path = File.join dir, "does-not-exist"
|
200
|
-
ENV[@var_name] = key_path
|
201
|
-
expect { @clz.from_env @scope }.to raise_error RuntimeError
|
202
|
-
end
|
203
|
-
end
|
204
|
-
|
205
|
-
it "succeeds when the GOOGLE_APPLICATION_CREDENTIALS file is valid" do
|
206
|
-
Dir.mktmpdir do |dir|
|
207
|
-
key_path = File.join dir, "my_cert_file"
|
208
|
-
FileUtils.mkdir_p File.dirname(key_path)
|
209
|
-
File.write key_path, cred_json_text
|
210
|
-
ENV[@var_name] = key_path
|
211
|
-
expect(@clz.from_env(@scope)).to_not be_nil
|
212
|
-
end
|
213
|
-
end
|
214
|
-
|
215
|
-
it "succeeds when GOOGLE_PRIVATE_KEY and GOOGLE_CLIENT_EMAIL env vars are"\
|
216
|
-
" valid" do
|
217
|
-
ENV[PRIVATE_KEY_VAR] = cred_json[:private_key]
|
218
|
-
ENV[CLIENT_EMAIL_VAR] = cred_json[:client_email]
|
219
|
-
expect(@clz.from_env(@scope)).to_not be_nil
|
220
|
-
end
|
221
|
-
|
222
|
-
it "sets project_id when the PROJECT_ID_VAR env var is set" do
|
223
|
-
ENV[PRIVATE_KEY_VAR] = cred_json[:private_key]
|
224
|
-
ENV[CLIENT_EMAIL_VAR] = cred_json[:client_email]
|
225
|
-
ENV[PROJECT_ID_VAR] = cred_json[:project_id]
|
226
|
-
ENV[ENV_VAR] = nil
|
227
|
-
credentials = @clz.from_env @scope
|
228
|
-
expect(credentials.project_id).to eq(cred_json[:project_id])
|
229
|
-
end
|
230
|
-
|
231
|
-
it "succeeds when GOOGLE_PRIVATE_KEY is escaped" do
|
232
|
-
escaped_key = cred_json[:private_key].gsub "\n", '\n'
|
233
|
-
ENV[PRIVATE_KEY_VAR] = "\"#{escaped_key}\""
|
234
|
-
ENV[CLIENT_EMAIL_VAR] = cred_json[:client_email]
|
235
|
-
expect(@clz.from_env(@scope)).to_not be_nil
|
236
|
-
end
|
237
|
-
|
238
|
-
it "propagates default_connection option" do
|
239
|
-
ENV[PRIVATE_KEY_VAR] = cred_json[:private_key]
|
240
|
-
ENV[CLIENT_EMAIL_VAR] = cred_json[:client_email]
|
241
|
-
connection = Faraday.new headers: { "User-Agent" => "hello" }
|
242
|
-
creds = @clz.from_env @scope, default_connection: connection
|
243
|
-
expect(creds.build_default_connection).to be connection
|
244
|
-
end
|
245
|
-
end
|
246
|
-
|
247
|
-
describe "#from_well_known_path" do
|
248
|
-
before :example do
|
249
|
-
@home = ENV["HOME"]
|
250
|
-
@app_data = ENV["APPDATA"]
|
251
|
-
@scope = "https://www.googleapis.com/auth/userinfo.profile"
|
252
|
-
@known_path = WELL_KNOWN_PATH
|
253
|
-
@clz = ServiceAccountCredentials
|
254
|
-
end
|
255
|
-
|
256
|
-
after :example do
|
257
|
-
ENV["HOME"] = @home unless @home == ENV["HOME"]
|
258
|
-
ENV["APPDATA"] = @app_data unless @app_data == ENV["APPDATA"]
|
259
|
-
end
|
260
|
-
|
261
|
-
it "is nil if no file exists" do
|
262
|
-
ENV["HOME"] = File.dirname __FILE__
|
263
|
-
expect(ServiceAccountCredentials.from_well_known_path(@scope)).to be_nil
|
264
|
-
end
|
265
|
-
|
266
|
-
it "successfully loads the file when it is present" do
|
267
|
-
Dir.mktmpdir do |dir|
|
268
|
-
key_path = File.join dir, ".config", @known_path
|
269
|
-
key_path = File.join dir, WELL_KNOWN_PATH if OS.windows?
|
270
|
-
FileUtils.mkdir_p File.dirname(key_path)
|
271
|
-
File.write key_path, cred_json_text
|
272
|
-
ENV["HOME"] = dir
|
273
|
-
ENV["APPDATA"] = dir
|
274
|
-
expect(@clz.from_well_known_path(@scope)).to_not be_nil
|
275
|
-
end
|
276
|
-
end
|
277
|
-
|
278
|
-
it "successfully sets project_id when file is present" do
|
279
|
-
Dir.mktmpdir do |dir|
|
280
|
-
key_path = File.join dir, ".config", @known_path
|
281
|
-
key_path = File.join dir, WELL_KNOWN_PATH if OS.windows?
|
282
|
-
FileUtils.mkdir_p File.dirname(key_path)
|
283
|
-
File.write key_path, cred_json_text
|
284
|
-
ENV["HOME"] = dir
|
285
|
-
ENV["APPDATA"] = dir
|
286
|
-
credentials = @clz.from_well_known_path @scope
|
287
|
-
expect(credentials.project_id).to eq(cred_json[:project_id])
|
288
|
-
end
|
289
|
-
end
|
290
|
-
|
291
|
-
it "propagates default_connection option" do
|
292
|
-
Dir.mktmpdir do |dir|
|
293
|
-
key_path = File.join dir, ".config", @known_path
|
294
|
-
key_path = File.join dir, WELL_KNOWN_PATH if OS.windows?
|
295
|
-
FileUtils.mkdir_p File.dirname(key_path)
|
296
|
-
File.write key_path, cred_json_text
|
297
|
-
ENV["HOME"] = dir
|
298
|
-
ENV["APPDATA"] = dir
|
299
|
-
connection = Faraday.new headers: { "User-Agent" => "hello" }
|
300
|
-
creds = @clz.from_well_known_path @scope, default_connection: connection
|
301
|
-
expect(creds.build_default_connection).to be connection
|
302
|
-
end
|
303
|
-
end
|
304
|
-
end
|
305
|
-
|
306
|
-
describe "#from_system_default_path" do
|
307
|
-
before :example do
|
308
|
-
@scope = "https://www.googleapis.com/auth/userinfo.profile"
|
309
|
-
@program_data = ENV["ProgramData"]
|
310
|
-
@prefix = OS.windows? ? "/etc/Google/Auth/" : "/etc/google/auth/"
|
311
|
-
@path = File.join @prefix, CREDENTIALS_FILE_NAME
|
312
|
-
@clz = ServiceAccountCredentials
|
313
|
-
end
|
314
|
-
|
315
|
-
after :example do
|
316
|
-
ENV["ProgramData"] = @program_data
|
317
|
-
end
|
318
|
-
|
319
|
-
it "is nil if no file exists" do
|
320
|
-
FakeFS do
|
321
|
-
expect(ServiceAccountCredentials.from_system_default_path(@scope))
|
322
|
-
.to be_nil
|
323
|
-
end
|
324
|
-
end
|
325
|
-
|
326
|
-
it "successfully loads the file when it is present" do
|
327
|
-
FakeFS do
|
328
|
-
ENV["ProgramData"] = "/etc"
|
329
|
-
FileUtils.mkdir_p File.dirname(@path)
|
330
|
-
File.write @path, cred_json_text
|
331
|
-
expect(@clz.from_system_default_path(@scope)).to_not be_nil
|
332
|
-
File.delete @path
|
333
|
-
end
|
334
|
-
end
|
335
|
-
|
336
|
-
it "propagates default_connection option" do
|
337
|
-
FakeFS do
|
338
|
-
ENV["ProgramData"] = "/etc"
|
339
|
-
FileUtils.mkdir_p File.dirname(@path)
|
340
|
-
File.write @path, cred_json_text
|
341
|
-
connection = Faraday.new headers: { "User-Agent" => "hello" }
|
342
|
-
creds = @clz.from_system_default_path @scope, default_connection: connection
|
343
|
-
expect(creds.build_default_connection).to be connection
|
344
|
-
File.delete @path
|
345
|
-
end
|
346
|
-
end
|
347
|
-
end
|
348
|
-
end
|
349
|
-
|
350
|
-
describe Google::Auth::ServiceAccountJwtHeaderCredentials do
|
351
|
-
ServiceAccountJwtHeaderCredentials =
|
352
|
-
Google::Auth::ServiceAccountJwtHeaderCredentials
|
353
|
-
|
354
|
-
let(:client_email) { "app@developer.gserviceaccount.com" }
|
355
|
-
let(:clz) { Google::Auth::ServiceAccountJwtHeaderCredentials }
|
356
|
-
let :cred_json do
|
357
|
-
{
|
358
|
-
private_key_id: "a_private_key_id",
|
359
|
-
private_key: @key.to_pem,
|
360
|
-
client_email: client_email,
|
361
|
-
client_id: "app.apps.googleusercontent.com",
|
362
|
-
type: "service_account",
|
363
|
-
project_id: "a_project_id"
|
364
|
-
}
|
365
|
-
end
|
366
|
-
|
367
|
-
before :example do
|
368
|
-
@key = OpenSSL::PKey::RSA.new 2048
|
369
|
-
@client = clz.make_creds json_key_io: StringIO.new(cred_json_text)
|
370
|
-
end
|
371
|
-
|
372
|
-
def cred_json_text
|
373
|
-
MultiJson.dump cred_json
|
374
|
-
end
|
375
|
-
|
376
|
-
it_behaves_like "jwt header auth"
|
377
|
-
|
378
|
-
describe "#from_env" do
|
379
|
-
before :example do
|
380
|
-
@var_name = ENV_VAR
|
381
|
-
@credential_vars = [
|
382
|
-
ENV_VAR, PRIVATE_KEY_VAR, CLIENT_EMAIL_VAR, ACCOUNT_TYPE_VAR
|
383
|
-
]
|
384
|
-
@original_env_vals = {}
|
385
|
-
@credential_vars.each { |var| @original_env_vals[var] = ENV[var] }
|
386
|
-
ENV[ACCOUNT_TYPE_VAR] = cred_json[:type]
|
387
|
-
end
|
388
|
-
|
389
|
-
after :example do
|
390
|
-
@credential_vars.each { |var| ENV[var] = @original_env_vals[var] }
|
391
|
-
end
|
392
|
-
|
393
|
-
it "returns nil if the GOOGLE_APPLICATION_CREDENTIALS is unset" do
|
394
|
-
ENV.delete @var_name unless ENV[@var_name].nil?
|
395
|
-
expect(clz.from_env).to be_nil
|
396
|
-
end
|
397
|
-
|
398
|
-
it "returns nil if the GOOGLE_APPLICATION_CREDENTIALS is empty" do
|
399
|
-
ENV[@var_name] = ""
|
400
|
-
expect(clz.from_env).to be_nil
|
401
|
-
end
|
402
|
-
|
403
|
-
it "fails if the GOOGLE_APPLICATION_CREDENTIALS path does not exist" do
|
404
|
-
ENV.delete @var_name unless ENV[@var_name].nil?
|
405
|
-
expect(clz.from_env).to be_nil
|
406
|
-
Dir.mktmpdir do |dir|
|
407
|
-
key_path = File.join dir, "does-not-exist"
|
408
|
-
ENV[@var_name] = key_path
|
409
|
-
expect { clz.from_env }.to raise_error RuntimeError
|
410
|
-
end
|
411
|
-
end
|
412
|
-
|
413
|
-
it "succeeds when the GOOGLE_APPLICATION_CREDENTIALS file is valid" do
|
414
|
-
Dir.mktmpdir do |dir|
|
415
|
-
key_path = File.join dir, "my_cert_file"
|
416
|
-
FileUtils.mkdir_p File.dirname(key_path)
|
417
|
-
File.write key_path, cred_json_text
|
418
|
-
ENV[@var_name] = key_path
|
419
|
-
expect(clz.from_env).to_not be_nil
|
420
|
-
end
|
421
|
-
end
|
422
|
-
|
423
|
-
it "succeeds when GOOGLE_PRIVATE_KEY and GOOGLE_CLIENT_EMAIL env vars are"\
|
424
|
-
" valid" do
|
425
|
-
ENV[PRIVATE_KEY_VAR] = cred_json[:private_key]
|
426
|
-
ENV[CLIENT_EMAIL_VAR] = cred_json[:client_email]
|
427
|
-
expect(clz.from_env(@scope)).to_not be_nil
|
428
|
-
end
|
429
|
-
|
430
|
-
it "sets project_id when the PROJECT_ID_VAR env var is set" do
|
431
|
-
ENV[PRIVATE_KEY_VAR] = cred_json[:private_key]
|
432
|
-
ENV[CLIENT_EMAIL_VAR] = cred_json[:client_email]
|
433
|
-
ENV[PROJECT_ID_VAR] = cred_json[:project_id]
|
434
|
-
ENV[ENV_VAR] = nil
|
435
|
-
credentials = clz.from_env @scope
|
436
|
-
expect(credentials).to_not be_nil
|
437
|
-
expect(credentials.project_id).to eq(cred_json[:project_id])
|
438
|
-
end
|
439
|
-
end
|
440
|
-
|
441
|
-
describe "#from_well_known_path" do
|
442
|
-
before :example do
|
443
|
-
@home = ENV["HOME"]
|
444
|
-
@app_data = ENV["APPDATA"]
|
445
|
-
end
|
446
|
-
|
447
|
-
after :example do
|
448
|
-
ENV["HOME"] = @home unless @home == ENV["HOME"]
|
449
|
-
ENV["APPDATA"] = @app_data unless @app_data == ENV["APPDATA"]
|
450
|
-
end
|
451
|
-
|
452
|
-
it "is nil if no file exists" do
|
453
|
-
ENV["HOME"] = File.dirname __FILE__
|
454
|
-
expect(clz.from_well_known_path).to be_nil
|
455
|
-
end
|
456
|
-
|
457
|
-
it "successfully loads the file when it is present" do
|
458
|
-
Dir.mktmpdir do |dir|
|
459
|
-
key_path = File.join dir, ".config", WELL_KNOWN_PATH
|
460
|
-
key_path = File.join dir, WELL_KNOWN_PATH if OS.windows?
|
461
|
-
FileUtils.mkdir_p File.dirname(key_path)
|
462
|
-
File.write key_path, cred_json_text
|
463
|
-
ENV["HOME"] = dir
|
464
|
-
ENV["APPDATA"] = dir
|
465
|
-
expect(clz.from_well_known_path).to_not be_nil
|
466
|
-
end
|
467
|
-
end
|
468
|
-
|
469
|
-
it "successfully sets project_id when file is present" do
|
470
|
-
Dir.mktmpdir do |dir|
|
471
|
-
key_path = File.join dir, ".config", WELL_KNOWN_PATH
|
472
|
-
key_path = File.join dir, WELL_KNOWN_PATH if OS.windows?
|
473
|
-
FileUtils.mkdir_p File.dirname(key_path)
|
474
|
-
File.write key_path, cred_json_text
|
475
|
-
ENV["HOME"] = dir
|
476
|
-
ENV["APPDATA"] = dir
|
477
|
-
credentials = clz.from_well_known_path @scope
|
478
|
-
expect(credentials.project_id).to eq(cred_json[:project_id])
|
479
|
-
end
|
480
|
-
end
|
481
|
-
end
|
482
|
-
end
|
@@ -1,134 +0,0 @@
|
|
1
|
-
# Copyright 2015, Google Inc.
|
2
|
-
# All rights reserved.
|
3
|
-
#
|
4
|
-
# Redistribution and use in source and binary forms, with or without
|
5
|
-
# modification, are permitted provided that the following conditions are
|
6
|
-
# met:
|
7
|
-
#
|
8
|
-
# * Redistributions of source code must retain the above copyright
|
9
|
-
# notice, this list of conditions and the following disclaimer.
|
10
|
-
# * Redistributions in binary form must reproduce the above
|
11
|
-
# copyright notice, this list of conditions and the following disclaimer
|
12
|
-
# in the documentation and/or other materials provided with the
|
13
|
-
# distribution.
|
14
|
-
# * Neither the name of Google Inc. nor the names of its
|
15
|
-
# contributors may be used to endorse or promote products derived from
|
16
|
-
# this software without specific prior written permission.
|
17
|
-
#
|
18
|
-
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
19
|
-
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
20
|
-
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
21
|
-
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
22
|
-
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
23
|
-
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
24
|
-
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
25
|
-
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
26
|
-
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
27
|
-
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
28
|
-
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
29
|
-
|
30
|
-
spec_dir = File.expand_path File.join(File.dirname(__FILE__))
|
31
|
-
$LOAD_PATH.unshift spec_dir
|
32
|
-
$LOAD_PATH.uniq!
|
33
|
-
|
34
|
-
require "apply_auth_examples"
|
35
|
-
require "googleauth/signet"
|
36
|
-
require "jwt"
|
37
|
-
require "openssl"
|
38
|
-
require "spec_helper"
|
39
|
-
|
40
|
-
describe Signet::OAuth2::Client do
|
41
|
-
before :example do
|
42
|
-
@key = OpenSSL::PKey::RSA.new 2048
|
43
|
-
@client = Signet::OAuth2::Client.new(
|
44
|
-
token_credential_uri: "https://oauth2.googleapis.com/token",
|
45
|
-
scope: "https://www.googleapis.com/auth/userinfo.profile",
|
46
|
-
issuer: "app@example.com",
|
47
|
-
audience: "https://oauth2.googleapis.com/token",
|
48
|
-
signing_key: @key
|
49
|
-
)
|
50
|
-
end
|
51
|
-
|
52
|
-
def make_auth_stubs opts
|
53
|
-
access_token = opts[:access_token] || ""
|
54
|
-
body = MultiJson.dump("access_token" => access_token,
|
55
|
-
"token_type" => "Bearer",
|
56
|
-
"expires_in" => 3600)
|
57
|
-
blk = proc do |request|
|
58
|
-
params = Addressable::URI.form_unencode request.body
|
59
|
-
_claim, _header = JWT.decode(params.assoc("assertion").last,
|
60
|
-
@key.public_key, true,
|
61
|
-
algorithm: "RS256")
|
62
|
-
end
|
63
|
-
with_params = { body: hash_including(
|
64
|
-
"grant_type" => "urn:ietf:params:oauth:grant-type:jwt-bearer"
|
65
|
-
) }
|
66
|
-
with_params[:headers] = { "User-Agent" => opts[:user_agent] } if opts[:user_agent]
|
67
|
-
stub_request(:post, "https://oauth2.googleapis.com/token")
|
68
|
-
.with(with_params, &blk)
|
69
|
-
.to_return(body: body,
|
70
|
-
status: 200,
|
71
|
-
headers: { "Content-Type" => "application/json" })
|
72
|
-
end
|
73
|
-
|
74
|
-
it_behaves_like "apply/apply! are OK"
|
75
|
-
|
76
|
-
describe "#configure_connection" do
|
77
|
-
it "honors default_connection" do
|
78
|
-
token = "1/abcdef1234567890"
|
79
|
-
stub = make_auth_stubs access_token: token, user_agent: "RubyRocks/1.0"
|
80
|
-
conn = Faraday.new headers: { "User-Agent" => "RubyRocks/1.0" }
|
81
|
-
@client.configure_connection default_connection: conn
|
82
|
-
md = { foo: "bar" }
|
83
|
-
@client.apply! md
|
84
|
-
want = { foo: "bar", authorization: "Bearer #{token}" }
|
85
|
-
expect(md).to eq(want)
|
86
|
-
expect(stub).to have_been_requested
|
87
|
-
end
|
88
|
-
|
89
|
-
it "honors connection_builder" do
|
90
|
-
token = "1/abcdef1234567890"
|
91
|
-
stub = make_auth_stubs access_token: token, user_agent: "RubyRocks/2.0"
|
92
|
-
connection_builder = proc do
|
93
|
-
Faraday.new headers: { "User-Agent" => "RubyRocks/2.0" }
|
94
|
-
end
|
95
|
-
@client.configure_connection connection_builder: connection_builder
|
96
|
-
md = { foo: "bar" }
|
97
|
-
@client.apply! md
|
98
|
-
want = { foo: "bar", authorization: "Bearer #{token}" }
|
99
|
-
expect(md).to eq(want)
|
100
|
-
expect(stub).to have_been_requested
|
101
|
-
end
|
102
|
-
end
|
103
|
-
|
104
|
-
describe "#fetch_access_token!" do
|
105
|
-
it "retries when orig_fetch_access_token! raises Signet::RemoteServerError" do
|
106
|
-
mocked_responses = [:raise, :raise, "success"]
|
107
|
-
allow(@client).to receive(:orig_fetch_access_token!).exactly(3).times do
|
108
|
-
response = mocked_responses.shift
|
109
|
-
response == :raise ? raise(Signet::RemoteServerError) : response
|
110
|
-
end
|
111
|
-
expect(@client.fetch_access_token!).to eq("success")
|
112
|
-
end
|
113
|
-
|
114
|
-
it "raises when the max retry count is exceeded" do
|
115
|
-
mocked_responses = [:raise, :raise, :raise, :raise, :raise, :raise, "success"]
|
116
|
-
allow(@client).to receive(:orig_fetch_access_token!).exactly(6).times do
|
117
|
-
response = mocked_responses.shift
|
118
|
-
response == :raise ? raise(Signet::RemoteServerError) : response
|
119
|
-
end
|
120
|
-
expect { @client.fetch_access_token! }.to raise_error Signet::AuthorizationError
|
121
|
-
end
|
122
|
-
|
123
|
-
it "does not retry and raises right away if it encounters a Signet::AuthorizationError" do
|
124
|
-
allow(@client).to receive(:orig_fetch_access_token!).at_most(:once)
|
125
|
-
.and_raise(Signet::AuthorizationError.new("Some Message"))
|
126
|
-
expect { @client.fetch_access_token! }.to raise_error Signet::AuthorizationError
|
127
|
-
end
|
128
|
-
|
129
|
-
it "does not retry and raises right away if it encounters a Signet::ParseError" do
|
130
|
-
allow(@client).to receive(:orig_fetch_access_token!).at_most(:once).and_raise(Signet::ParseError)
|
131
|
-
expect { @client.fetch_access_token! }.to raise_error Signet::ParseError
|
132
|
-
end
|
133
|
-
end
|
134
|
-
end
|
@@ -1,57 +0,0 @@
|
|
1
|
-
# Copyright 2015, Google Inc.
|
2
|
-
# All rights reserved.
|
3
|
-
#
|
4
|
-
# Redistribution and use in source and binary forms, with or without
|
5
|
-
# modification, are permitted provided that the following conditions are
|
6
|
-
# met:
|
7
|
-
#
|
8
|
-
# * Redistributions of source code must retain the above copyright
|
9
|
-
# notice, this list of conditions and the following disclaimer.
|
10
|
-
# * Redistributions in binary form must reproduce the above
|
11
|
-
# copyright notice, this list of conditions and the following disclaimer
|
12
|
-
# in the documentation and/or other materials provided with the
|
13
|
-
# distribution.
|
14
|
-
# * Neither the name of Google Inc. nor the names of its
|
15
|
-
# contributors may be used to endorse or promote products derived from
|
16
|
-
# this software without specific prior written permission.
|
17
|
-
#
|
18
|
-
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
19
|
-
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
20
|
-
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
21
|
-
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
22
|
-
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
23
|
-
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
24
|
-
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
25
|
-
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
26
|
-
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
27
|
-
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
28
|
-
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
29
|
-
|
30
|
-
spec_dir = File.expand_path File.join(File.dirname(__FILE__))
|
31
|
-
$LOAD_PATH.unshift spec_dir
|
32
|
-
$LOAD_PATH.uniq!
|
33
|
-
|
34
|
-
require "googleauth"
|
35
|
-
require "googleauth/stores/file_token_store"
|
36
|
-
require "spec_helper"
|
37
|
-
require "fakefs/safe"
|
38
|
-
require "fakefs/spec_helpers"
|
39
|
-
require "googleauth/stores/store_examples"
|
40
|
-
|
41
|
-
module FakeFS
|
42
|
-
class File
|
43
|
-
# FakeFS doesn't implement. And since we don't need to actually lock,
|
44
|
-
# just stub out...
|
45
|
-
def flock *; end
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
describe Google::Auth::Stores::FileTokenStore do
|
50
|
-
include FakeFS::SpecHelpers
|
51
|
-
|
52
|
-
let :store do
|
53
|
-
Google::Auth::Stores::FileTokenStore.new file: "/tokens.yaml"
|
54
|
-
end
|
55
|
-
|
56
|
-
it_behaves_like "token store"
|
57
|
-
end
|