googleauth 0.1.0 → 0.16.2
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 +5 -5
- data/.github/CODEOWNERS +7 -0
- data/.github/CONTRIBUTING.md +74 -0
- data/.github/ISSUE_TEMPLATE/bug_report.md +36 -0
- data/.github/ISSUE_TEMPLATE/feature_request.md +21 -0
- data/.github/ISSUE_TEMPLATE/support_request.md +7 -0
- data/.github/renovate.json +6 -0
- data/.github/sync-repo-settings.yaml +18 -0
- data/.github/workflows/ci.yml +55 -0
- data/.github/workflows/release-please.yml +39 -0
- data/.gitignore +3 -0
- data/.kokoro/populate-secrets.sh +76 -0
- data/.kokoro/release.cfg +52 -0
- data/.kokoro/release.sh +18 -0
- data/.kokoro/trampoline_v2.sh +489 -0
- data/.repo-metadata.json +5 -0
- data/.rubocop.yml +17 -0
- data/.toys/.toys.rb +45 -0
- data/.toys/ci.rb +43 -0
- data/.toys/kokoro/.toys.rb +66 -0
- data/.toys/kokoro/publish-docs.rb +67 -0
- data/.toys/kokoro/publish-gem.rb +53 -0
- data/.toys/linkinator.rb +43 -0
- data/.trampolinerc +48 -0
- data/CHANGELOG.md +199 -0
- data/CODE_OF_CONDUCT.md +43 -0
- data/Gemfile +22 -1
- data/{COPYING → LICENSE} +0 -0
- data/README.md +140 -17
- data/googleauth.gemspec +28 -28
- data/integration/helper.rb +31 -0
- data/integration/id_tokens/key_source_test.rb +74 -0
- data/lib/googleauth.rb +7 -37
- data/lib/googleauth/application_default.rb +81 -0
- data/lib/googleauth/client_id.rb +104 -0
- data/lib/googleauth/compute_engine.rb +73 -26
- data/lib/googleauth/credentials.rb +561 -0
- data/lib/googleauth/credentials_loader.rb +207 -0
- data/lib/googleauth/default_credentials.rb +93 -0
- data/lib/googleauth/iam.rb +75 -0
- data/lib/googleauth/id_tokens.rb +233 -0
- data/lib/googleauth/id_tokens/errors.rb +71 -0
- data/lib/googleauth/id_tokens/key_sources.rb +396 -0
- data/lib/googleauth/id_tokens/verifier.rb +142 -0
- data/lib/googleauth/json_key_reader.rb +50 -0
- data/lib/googleauth/scope_util.rb +61 -0
- data/lib/googleauth/service_account.rb +177 -67
- data/lib/googleauth/signet.rb +69 -8
- data/lib/googleauth/stores/file_token_store.rb +65 -0
- data/lib/googleauth/stores/redis_token_store.rb +96 -0
- data/lib/googleauth/token_store.rb +69 -0
- data/lib/googleauth/user_authorizer.rb +285 -0
- data/lib/googleauth/user_refresh.rb +129 -0
- data/lib/googleauth/version.rb +1 -1
- data/lib/googleauth/web_user_authorizer.rb +295 -0
- data/spec/googleauth/apply_auth_examples.rb +96 -94
- data/spec/googleauth/client_id_spec.rb +160 -0
- data/spec/googleauth/compute_engine_spec.rb +125 -55
- data/spec/googleauth/credentials_spec.rb +600 -0
- data/spec/googleauth/get_application_default_spec.rb +232 -80
- data/spec/googleauth/iam_spec.rb +80 -0
- data/spec/googleauth/scope_util_spec.rb +77 -0
- data/spec/googleauth/service_account_spec.rb +422 -68
- data/spec/googleauth/signet_spec.rb +101 -25
- data/spec/googleauth/stores/file_token_store_spec.rb +57 -0
- data/spec/googleauth/stores/redis_token_store_spec.rb +50 -0
- data/spec/googleauth/stores/store_examples.rb +58 -0
- data/spec/googleauth/user_authorizer_spec.rb +343 -0
- data/spec/googleauth/user_refresh_spec.rb +359 -0
- data/spec/googleauth/web_user_authorizer_spec.rb +172 -0
- data/spec/spec_helper.rb +51 -10
- data/test/helper.rb +33 -0
- data/test/id_tokens/key_sources_test.rb +240 -0
- data/test/id_tokens/verifier_test.rb +269 -0
- metadata +114 -75
- data/.travis.yml +0 -18
- data/CONTRIBUTING.md +0 -32
- data/Rakefile +0 -15
@@ -27,116 +27,470 @@
|
|
27
27
|
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
28
28
|
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
29
29
|
|
30
|
-
spec_dir = File.expand_path
|
31
|
-
$LOAD_PATH.unshift
|
30
|
+
spec_dir = File.expand_path File.join(File.dirname(__FILE__))
|
31
|
+
$LOAD_PATH.unshift spec_dir
|
32
32
|
$LOAD_PATH.uniq!
|
33
33
|
|
34
|
-
require
|
35
|
-
require
|
36
|
-
require
|
37
|
-
require
|
38
|
-
require
|
39
|
-
require
|
40
|
-
require
|
41
|
-
require
|
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
|
42
109
|
|
43
110
|
describe Google::Auth::ServiceAccountCredentials do
|
44
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
|
+
quota_project_id: "b_project_id"
|
122
|
+
}
|
123
|
+
end
|
45
124
|
|
46
|
-
before
|
47
|
-
@key = OpenSSL::PKey::RSA.new
|
48
|
-
@client = ServiceAccountCredentials.
|
49
|
-
|
50
|
-
|
125
|
+
before :example do
|
126
|
+
@key = OpenSSL::PKey::RSA.new 2048
|
127
|
+
@client = ServiceAccountCredentials.make_creds(
|
128
|
+
json_key_io: StringIO.new(cred_json_text),
|
129
|
+
scope: "https://www.googleapis.com/auth/userinfo.profile"
|
130
|
+
)
|
131
|
+
@id_client = ServiceAccountCredentials.make_creds(
|
132
|
+
json_key_io: StringIO.new(cred_json_text),
|
133
|
+
target_audience: "https://pubsub.googleapis.com/"
|
134
|
+
)
|
51
135
|
end
|
52
136
|
|
53
|
-
def make_auth_stubs
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
137
|
+
def make_auth_stubs opts
|
138
|
+
body_fields = { "token_type" => "Bearer", "expires_in" => 3600 }
|
139
|
+
body_fields["access_token"] = opts[:access_token] if opts[:access_token]
|
140
|
+
body_fields["id_token"] = opts[:id_token] if opts[:id_token]
|
141
|
+
body = MultiJson.dump body_fields
|
142
|
+
blk = proc do |request|
|
143
|
+
params = Addressable::URI.form_unencode request.body
|
144
|
+
claim, _header = JWT.decode(params.assoc("assertion").last,
|
145
|
+
@key.public_key, true,
|
146
|
+
algorithm: "RS256")
|
147
|
+
!opts[:id_token] || claim["target_audience"] == "https://pubsub.googleapis.com/"
|
63
148
|
end
|
149
|
+
stub_request(:post, "https://www.googleapis.com/oauth2/v4/token")
|
150
|
+
.with(body: hash_including(
|
151
|
+
"grant_type" => "urn:ietf:params:oauth:grant-type:jwt-bearer"
|
152
|
+
), &blk)
|
153
|
+
.to_return(body: body,
|
154
|
+
status: 200,
|
155
|
+
headers: { "Content-Type" => "application/json" })
|
64
156
|
end
|
65
157
|
|
66
158
|
def cred_json_text
|
67
|
-
cred_json
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
159
|
+
MultiJson.dump cred_json
|
160
|
+
end
|
161
|
+
|
162
|
+
it_behaves_like "apply/apply! are OK"
|
163
|
+
|
164
|
+
context "when scope is nil" do
|
165
|
+
before :example do
|
166
|
+
@client.scope = nil
|
167
|
+
end
|
168
|
+
|
169
|
+
it_behaves_like "jwt header auth"
|
170
|
+
end
|
171
|
+
|
172
|
+
context "when enable_self_signed_jwt is set" do
|
173
|
+
before :example do
|
174
|
+
@client.instance_variable_set(:@enable_self_signed_jwt, true)
|
175
|
+
end
|
176
|
+
|
177
|
+
it_behaves_like "jwt header auth"
|
75
178
|
end
|
76
179
|
|
77
|
-
|
180
|
+
describe "#from_env" do
|
181
|
+
before :example do
|
182
|
+
@var_name = ENV_VAR
|
183
|
+
@credential_vars = [
|
184
|
+
ENV_VAR, PRIVATE_KEY_VAR, CLIENT_EMAIL_VAR, ACCOUNT_TYPE_VAR
|
185
|
+
]
|
186
|
+
@original_env_vals = {}
|
187
|
+
@credential_vars.each { |var| @original_env_vals[var] = ENV[var] }
|
188
|
+
ENV[ACCOUNT_TYPE_VAR] = cred_json[:type]
|
78
189
|
|
79
|
-
|
80
|
-
|
81
|
-
@var_name = ServiceAccountCredentials::ENV_VAR
|
82
|
-
@orig = ENV[@var_name]
|
83
|
-
@scope = 'https://www.googleapis.com/auth/userinfo.profile'
|
190
|
+
@scope = "https://www.googleapis.com/auth/userinfo.profile"
|
191
|
+
@clz = ServiceAccountCredentials
|
84
192
|
end
|
85
193
|
|
86
|
-
after
|
87
|
-
ENV[
|
194
|
+
after :example do
|
195
|
+
@credential_vars.each { |var| ENV[var] = @original_env_vals[var] }
|
88
196
|
end
|
89
197
|
|
90
|
-
it
|
91
|
-
ENV.delete
|
198
|
+
it "returns nil if the GOOGLE_APPLICATION_CREDENTIALS is unset" do
|
199
|
+
ENV.delete @var_name unless ENV[@var_name].nil?
|
92
200
|
expect(ServiceAccountCredentials.from_env(@scope)).to be_nil
|
93
201
|
end
|
94
202
|
|
95
|
-
it
|
96
|
-
ENV
|
203
|
+
it "returns nil if the GOOGLE_APPLICATION_CREDENTIALS is empty" do
|
204
|
+
ENV[@var_name] = ""
|
205
|
+
expect(ServiceAccountCredentials.from_env(@scope)).to be_nil
|
206
|
+
end
|
207
|
+
|
208
|
+
it "fails if the GOOGLE_APPLICATION_CREDENTIALS path does not exist" do
|
209
|
+
ENV.delete @var_name unless ENV[@var_name].nil?
|
97
210
|
expect(ServiceAccountCredentials.from_env(@scope)).to be_nil
|
98
211
|
Dir.mktmpdir do |dir|
|
99
|
-
key_path = File.join
|
212
|
+
key_path = File.join dir, "does-not-exist"
|
100
213
|
ENV[@var_name] = key_path
|
101
|
-
expect {
|
214
|
+
expect { @clz.from_env @scope }.to raise_error RuntimeError
|
102
215
|
end
|
103
216
|
end
|
104
217
|
|
105
|
-
it
|
106
|
-
sac = ServiceAccountCredentials # shortens name
|
218
|
+
it "succeeds when the GOOGLE_APPLICATION_CREDENTIALS file is valid" do
|
107
219
|
Dir.mktmpdir do |dir|
|
108
|
-
key_path = File.join
|
109
|
-
FileUtils.mkdir_p
|
110
|
-
File.write
|
220
|
+
key_path = File.join dir, "my_cert_file"
|
221
|
+
FileUtils.mkdir_p File.dirname(key_path)
|
222
|
+
File.write key_path, cred_json_text
|
111
223
|
ENV[@var_name] = key_path
|
112
|
-
expect(
|
224
|
+
expect(@clz.from_env(@scope)).to_not be_nil
|
113
225
|
end
|
114
226
|
end
|
227
|
+
|
228
|
+
it "succeeds when GOOGLE_PRIVATE_KEY and GOOGLE_CLIENT_EMAIL env vars are"\
|
229
|
+
" valid" do
|
230
|
+
ENV[PRIVATE_KEY_VAR] = cred_json[:private_key]
|
231
|
+
ENV[CLIENT_EMAIL_VAR] = cred_json[:client_email]
|
232
|
+
expect(@clz.from_env(@scope)).to_not be_nil
|
233
|
+
end
|
234
|
+
|
235
|
+
it "sets project_id when the PROJECT_ID_VAR env var is set" do
|
236
|
+
ENV[PRIVATE_KEY_VAR] = cred_json[:private_key]
|
237
|
+
ENV[CLIENT_EMAIL_VAR] = cred_json[:client_email]
|
238
|
+
ENV[PROJECT_ID_VAR] = cred_json[:project_id]
|
239
|
+
ENV[ENV_VAR] = nil
|
240
|
+
credentials = @clz.from_env @scope
|
241
|
+
expect(credentials.project_id).to eq(cred_json[:project_id])
|
242
|
+
end
|
243
|
+
|
244
|
+
it "succeeds when GOOGLE_PRIVATE_KEY is escaped" do
|
245
|
+
escaped_key = cred_json[:private_key].gsub "\n", '\n'
|
246
|
+
ENV[PRIVATE_KEY_VAR] = "\"#{escaped_key}\""
|
247
|
+
ENV[CLIENT_EMAIL_VAR] = cred_json[:client_email]
|
248
|
+
expect(@clz.from_env(@scope)).to_not be_nil
|
249
|
+
end
|
250
|
+
|
251
|
+
it "propagates default_connection option" do
|
252
|
+
ENV[PRIVATE_KEY_VAR] = cred_json[:private_key]
|
253
|
+
ENV[CLIENT_EMAIL_VAR] = cred_json[:client_email]
|
254
|
+
connection = Faraday.new headers: { "User-Agent" => "hello" }
|
255
|
+
creds = @clz.from_env @scope, default_connection: connection
|
256
|
+
expect(creds.build_default_connection).to be connection
|
257
|
+
end
|
115
258
|
end
|
116
259
|
|
117
|
-
describe
|
118
|
-
before
|
119
|
-
@home = ENV[
|
120
|
-
@
|
260
|
+
describe "#from_well_known_path" do
|
261
|
+
before :example do
|
262
|
+
@home = ENV["HOME"]
|
263
|
+
@app_data = ENV["APPDATA"]
|
264
|
+
@scope = "https://www.googleapis.com/auth/userinfo.profile"
|
265
|
+
@known_path = WELL_KNOWN_PATH
|
266
|
+
@clz = ServiceAccountCredentials
|
121
267
|
end
|
122
268
|
|
123
|
-
after
|
124
|
-
ENV[
|
269
|
+
after :example do
|
270
|
+
ENV["HOME"] = @home unless @home == ENV["HOME"]
|
271
|
+
ENV["APPDATA"] = @app_data unless @app_data == ENV["APPDATA"]
|
125
272
|
end
|
126
273
|
|
127
|
-
it
|
128
|
-
ENV[
|
274
|
+
it "is nil if no file exists" do
|
275
|
+
ENV["HOME"] = File.dirname __FILE__
|
129
276
|
expect(ServiceAccountCredentials.from_well_known_path(@scope)).to be_nil
|
130
277
|
end
|
131
278
|
|
132
|
-
it
|
133
|
-
|
279
|
+
it "successfully loads the file when it is present" do
|
280
|
+
Dir.mktmpdir do |dir|
|
281
|
+
key_path = File.join dir, ".config", @known_path
|
282
|
+
key_path = File.join dir, WELL_KNOWN_PATH if OS.windows?
|
283
|
+
FileUtils.mkdir_p File.dirname(key_path)
|
284
|
+
File.write key_path, cred_json_text
|
285
|
+
ENV["HOME"] = dir
|
286
|
+
ENV["APPDATA"] = dir
|
287
|
+
expect(@clz.from_well_known_path(@scope)).to_not be_nil
|
288
|
+
end
|
289
|
+
end
|
290
|
+
|
291
|
+
it "successfully sets project_id when file is present" 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
|
+
credentials = @clz.from_well_known_path @scope
|
300
|
+
expect(credentials.project_id).to eq(cred_json[:project_id])
|
301
|
+
expect(credentials.quota_project_id).to eq(cred_json[:quota_project_id])
|
302
|
+
end
|
303
|
+
end
|
304
|
+
|
305
|
+
it "propagates default_connection option" do
|
306
|
+
Dir.mktmpdir do |dir|
|
307
|
+
key_path = File.join dir, ".config", @known_path
|
308
|
+
key_path = File.join dir, WELL_KNOWN_PATH if OS.windows?
|
309
|
+
FileUtils.mkdir_p File.dirname(key_path)
|
310
|
+
File.write key_path, cred_json_text
|
311
|
+
ENV["HOME"] = dir
|
312
|
+
ENV["APPDATA"] = dir
|
313
|
+
connection = Faraday.new headers: { "User-Agent" => "hello" }
|
314
|
+
creds = @clz.from_well_known_path @scope, default_connection: connection
|
315
|
+
expect(creds.build_default_connection).to be connection
|
316
|
+
end
|
317
|
+
end
|
318
|
+
end
|
319
|
+
|
320
|
+
describe "#from_system_default_path" do
|
321
|
+
before :example do
|
322
|
+
@scope = "https://www.googleapis.com/auth/userinfo.profile"
|
323
|
+
@program_data = ENV["ProgramData"]
|
324
|
+
@prefix = OS.windows? ? "/etc/Google/Auth/" : "/etc/google/auth/"
|
325
|
+
@path = File.join @prefix, CREDENTIALS_FILE_NAME
|
326
|
+
@clz = ServiceAccountCredentials
|
327
|
+
end
|
328
|
+
|
329
|
+
after :example do
|
330
|
+
ENV["ProgramData"] = @program_data
|
331
|
+
end
|
332
|
+
|
333
|
+
it "is nil if no file exists" do
|
334
|
+
FakeFS do
|
335
|
+
expect(ServiceAccountCredentials.from_system_default_path(@scope))
|
336
|
+
.to be_nil
|
337
|
+
end
|
338
|
+
end
|
339
|
+
|
340
|
+
it "successfully loads the file when it is present" do
|
341
|
+
FakeFS do
|
342
|
+
ENV["ProgramData"] = "/etc"
|
343
|
+
FileUtils.mkdir_p File.dirname(@path)
|
344
|
+
File.write @path, cred_json_text
|
345
|
+
expect(@clz.from_system_default_path(@scope)).to_not be_nil
|
346
|
+
File.delete @path
|
347
|
+
end
|
348
|
+
end
|
349
|
+
|
350
|
+
it "propagates default_connection option" do
|
351
|
+
FakeFS do
|
352
|
+
ENV["ProgramData"] = "/etc"
|
353
|
+
FileUtils.mkdir_p File.dirname(@path)
|
354
|
+
File.write @path, cred_json_text
|
355
|
+
connection = Faraday.new headers: { "User-Agent" => "hello" }
|
356
|
+
creds = @clz.from_system_default_path @scope, default_connection: connection
|
357
|
+
expect(creds.build_default_connection).to be connection
|
358
|
+
File.delete @path
|
359
|
+
end
|
360
|
+
end
|
361
|
+
end
|
362
|
+
end
|
363
|
+
|
364
|
+
describe Google::Auth::ServiceAccountJwtHeaderCredentials do
|
365
|
+
ServiceAccountJwtHeaderCredentials =
|
366
|
+
Google::Auth::ServiceAccountJwtHeaderCredentials
|
367
|
+
|
368
|
+
let(:client_email) { "app@developer.gserviceaccount.com" }
|
369
|
+
let(:clz) { Google::Auth::ServiceAccountJwtHeaderCredentials }
|
370
|
+
let :cred_json do
|
371
|
+
{
|
372
|
+
private_key_id: "a_private_key_id",
|
373
|
+
private_key: @key.to_pem,
|
374
|
+
client_email: client_email,
|
375
|
+
client_id: "app.apps.googleusercontent.com",
|
376
|
+
type: "service_account",
|
377
|
+
project_id: "a_project_id"
|
378
|
+
}
|
379
|
+
end
|
380
|
+
|
381
|
+
before :example do
|
382
|
+
@key = OpenSSL::PKey::RSA.new 2048
|
383
|
+
@client = clz.make_creds json_key_io: StringIO.new(cred_json_text)
|
384
|
+
end
|
385
|
+
|
386
|
+
def cred_json_text
|
387
|
+
MultiJson.dump cred_json
|
388
|
+
end
|
389
|
+
|
390
|
+
it_behaves_like "jwt header auth"
|
391
|
+
|
392
|
+
describe "#from_env" do
|
393
|
+
before :example do
|
394
|
+
@var_name = ENV_VAR
|
395
|
+
@credential_vars = [
|
396
|
+
ENV_VAR, PRIVATE_KEY_VAR, CLIENT_EMAIL_VAR, ACCOUNT_TYPE_VAR
|
397
|
+
]
|
398
|
+
@original_env_vals = {}
|
399
|
+
@credential_vars.each { |var| @original_env_vals[var] = ENV[var] }
|
400
|
+
ENV[ACCOUNT_TYPE_VAR] = cred_json[:type]
|
401
|
+
end
|
402
|
+
|
403
|
+
after :example do
|
404
|
+
@credential_vars.each { |var| ENV[var] = @original_env_vals[var] }
|
405
|
+
end
|
406
|
+
|
407
|
+
it "returns nil if the GOOGLE_APPLICATION_CREDENTIALS is unset" do
|
408
|
+
ENV.delete @var_name unless ENV[@var_name].nil?
|
409
|
+
expect(clz.from_env).to be_nil
|
410
|
+
end
|
411
|
+
|
412
|
+
it "returns nil if the GOOGLE_APPLICATION_CREDENTIALS is empty" do
|
413
|
+
ENV[@var_name] = ""
|
414
|
+
expect(clz.from_env).to be_nil
|
415
|
+
end
|
416
|
+
|
417
|
+
it "fails if the GOOGLE_APPLICATION_CREDENTIALS path does not exist" do
|
418
|
+
ENV.delete @var_name unless ENV[@var_name].nil?
|
419
|
+
expect(clz.from_env).to be_nil
|
420
|
+
Dir.mktmpdir do |dir|
|
421
|
+
key_path = File.join dir, "does-not-exist"
|
422
|
+
ENV[@var_name] = key_path
|
423
|
+
expect { clz.from_env }.to raise_error RuntimeError
|
424
|
+
end
|
425
|
+
end
|
426
|
+
|
427
|
+
it "succeeds when the GOOGLE_APPLICATION_CREDENTIALS file is valid" do
|
428
|
+
Dir.mktmpdir do |dir|
|
429
|
+
key_path = File.join dir, "my_cert_file"
|
430
|
+
FileUtils.mkdir_p File.dirname(key_path)
|
431
|
+
File.write key_path, cred_json_text
|
432
|
+
ENV[@var_name] = key_path
|
433
|
+
expect(clz.from_env).to_not be_nil
|
434
|
+
end
|
435
|
+
end
|
436
|
+
|
437
|
+
it "succeeds when GOOGLE_PRIVATE_KEY and GOOGLE_CLIENT_EMAIL env vars are"\
|
438
|
+
" valid" do
|
439
|
+
ENV[PRIVATE_KEY_VAR] = cred_json[:private_key]
|
440
|
+
ENV[CLIENT_EMAIL_VAR] = cred_json[:client_email]
|
441
|
+
expect(clz.from_env(@scope)).to_not be_nil
|
442
|
+
end
|
443
|
+
|
444
|
+
it "sets project_id when the PROJECT_ID_VAR env var is set" do
|
445
|
+
ENV[PRIVATE_KEY_VAR] = cred_json[:private_key]
|
446
|
+
ENV[CLIENT_EMAIL_VAR] = cred_json[:client_email]
|
447
|
+
ENV[PROJECT_ID_VAR] = cred_json[:project_id]
|
448
|
+
ENV[ENV_VAR] = nil
|
449
|
+
credentials = clz.from_env @scope
|
450
|
+
expect(credentials).to_not be_nil
|
451
|
+
expect(credentials.project_id).to eq(cred_json[:project_id])
|
452
|
+
end
|
453
|
+
end
|
454
|
+
|
455
|
+
describe "#from_well_known_path" do
|
456
|
+
before :example do
|
457
|
+
@home = ENV["HOME"]
|
458
|
+
@app_data = ENV["APPDATA"]
|
459
|
+
end
|
460
|
+
|
461
|
+
after :example do
|
462
|
+
ENV["HOME"] = @home unless @home == ENV["HOME"]
|
463
|
+
ENV["APPDATA"] = @app_data unless @app_data == ENV["APPDATA"]
|
464
|
+
end
|
465
|
+
|
466
|
+
it "is nil if no file exists" do
|
467
|
+
ENV["HOME"] = File.dirname __FILE__
|
468
|
+
expect(clz.from_well_known_path).to be_nil
|
469
|
+
end
|
470
|
+
|
471
|
+
it "successfully loads the file when it is present" do
|
472
|
+
Dir.mktmpdir do |dir|
|
473
|
+
key_path = File.join dir, ".config", WELL_KNOWN_PATH
|
474
|
+
key_path = File.join dir, WELL_KNOWN_PATH if OS.windows?
|
475
|
+
FileUtils.mkdir_p File.dirname(key_path)
|
476
|
+
File.write key_path, cred_json_text
|
477
|
+
ENV["HOME"] = dir
|
478
|
+
ENV["APPDATA"] = dir
|
479
|
+
expect(clz.from_well_known_path).to_not be_nil
|
480
|
+
end
|
481
|
+
end
|
482
|
+
|
483
|
+
it "successfully sets project_id when file is present" do
|
134
484
|
Dir.mktmpdir do |dir|
|
135
|
-
key_path = File.join
|
136
|
-
|
137
|
-
File.
|
138
|
-
|
139
|
-
|
485
|
+
key_path = File.join dir, ".config", WELL_KNOWN_PATH
|
486
|
+
key_path = File.join dir, WELL_KNOWN_PATH if OS.windows?
|
487
|
+
FileUtils.mkdir_p File.dirname(key_path)
|
488
|
+
File.write key_path, cred_json_text
|
489
|
+
ENV["HOME"] = dir
|
490
|
+
ENV["APPDATA"] = dir
|
491
|
+
credentials = clz.from_well_known_path @scope
|
492
|
+
expect(credentials.project_id).to eq(cred_json[:project_id])
|
493
|
+
expect(credentials.quota_project_id).to be_nil
|
140
494
|
end
|
141
495
|
end
|
142
496
|
end
|