googleauth 0.16.2 → 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.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +11 -0
  3. data/CHANGELOG.md +13 -0
  4. data/SECURITY.md +7 -0
  5. data/lib/googleauth/service_account.rb +16 -12
  6. data/lib/googleauth/version.rb +1 -1
  7. metadata +16 -89
  8. data/.github/CODEOWNERS +0 -7
  9. data/.github/CONTRIBUTING.md +0 -74
  10. data/.github/ISSUE_TEMPLATE/bug_report.md +0 -36
  11. data/.github/ISSUE_TEMPLATE/feature_request.md +0 -21
  12. data/.github/ISSUE_TEMPLATE/support_request.md +0 -7
  13. data/.github/renovate.json +0 -6
  14. data/.github/sync-repo-settings.yaml +0 -18
  15. data/.github/workflows/ci.yml +0 -55
  16. data/.github/workflows/release-please.yml +0 -39
  17. data/.gitignore +0 -39
  18. data/.kokoro/populate-secrets.sh +0 -76
  19. data/.kokoro/release.cfg +0 -52
  20. data/.kokoro/release.sh +0 -18
  21. data/.kokoro/trampoline_v2.sh +0 -489
  22. data/.repo-metadata.json +0 -5
  23. data/.rspec +0 -2
  24. data/.rubocop.yml +0 -17
  25. data/.toys/.toys.rb +0 -45
  26. data/.toys/ci.rb +0 -43
  27. data/.toys/kokoro/.toys.rb +0 -66
  28. data/.toys/kokoro/publish-docs.rb +0 -67
  29. data/.toys/kokoro/publish-gem.rb +0 -53
  30. data/.toys/linkinator.rb +0 -43
  31. data/.trampolinerc +0 -48
  32. data/Gemfile +0 -25
  33. data/googleauth.gemspec +0 -39
  34. data/integration/helper.rb +0 -31
  35. data/integration/id_tokens/key_source_test.rb +0 -74
  36. data/spec/googleauth/apply_auth_examples.rb +0 -171
  37. data/spec/googleauth/client_id_spec.rb +0 -160
  38. data/spec/googleauth/compute_engine_spec.rb +0 -178
  39. data/spec/googleauth/credentials_spec.rb +0 -600
  40. data/spec/googleauth/get_application_default_spec.rb +0 -286
  41. data/spec/googleauth/iam_spec.rb +0 -80
  42. data/spec/googleauth/scope_util_spec.rb +0 -77
  43. data/spec/googleauth/service_account_spec.rb +0 -497
  44. data/spec/googleauth/signet_spec.rb +0 -142
  45. data/spec/googleauth/stores/file_token_store_spec.rb +0 -57
  46. data/spec/googleauth/stores/redis_token_store_spec.rb +0 -50
  47. data/spec/googleauth/stores/store_examples.rb +0 -58
  48. data/spec/googleauth/user_authorizer_spec.rb +0 -343
  49. data/spec/googleauth/user_refresh_spec.rb +0 -359
  50. data/spec/googleauth/web_user_authorizer_spec.rb +0 -172
  51. data/spec/spec_helper.rb +0 -92
  52. data/test/helper.rb +0 -33
  53. data/test/id_tokens/key_sources_test.rb +0 -240
  54. data/test/id_tokens/verifier_test.rb +0 -269
@@ -1,286 +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 "faraday"
35
- require "fakefs/safe"
36
- require "googleauth"
37
- require "spec_helper"
38
- require "os"
39
-
40
- describe "#get_application_default" do
41
- # Pass unique options each time to bypass memoization
42
- let(:options) { |example| { dememoize: example } }
43
-
44
- before :example do
45
- @key = OpenSSL::PKey::RSA.new 2048
46
- @var_name = ENV_VAR
47
- @credential_vars = [
48
- ENV_VAR, PRIVATE_KEY_VAR, CLIENT_EMAIL_VAR, CLIENT_ID_VAR,
49
- CLIENT_SECRET_VAR, REFRESH_TOKEN_VAR, ACCOUNT_TYPE_VAR
50
- ]
51
- @original_env_vals = {}
52
- @credential_vars.each { |var| @original_env_vals[var] = ENV[var] }
53
- @home = ENV["HOME"]
54
- @app_data = ENV["APPDATA"]
55
- @program_data = ENV["ProgramData"]
56
- @scope = "https://www.googleapis.com/auth/userinfo.profile"
57
- end
58
-
59
- after :example do
60
- @credential_vars.each { |var| ENV[var] = @original_env_vals[var] }
61
- ENV["HOME"] = @home unless @home == ENV["HOME"]
62
- ENV["APPDATA"] = @app_data unless @app_data == ENV["APPDATA"]
63
- ENV["ProgramData"] = @program_data unless @program_data == ENV["ProgramData"]
64
- end
65
-
66
- shared_examples "it cannot load misconfigured credentials" do
67
- it "fails if the GOOGLE_APPLICATION_CREDENTIALS path does not exist" do
68
- Dir.mktmpdir do |dir|
69
- key_path = File.join dir, "does-not-exist"
70
- ENV[@var_name] = key_path
71
- expect { Google::Auth.get_application_default @scope, options }
72
- .to raise_error RuntimeError
73
- end
74
- end
75
-
76
- it "fails without default file or env if not on compute engine" do
77
- stub = stub_request(:get, "http://169.254.169.254")
78
- .to_return(status: 404,
79
- headers: { "Metadata-Flavor" => "NotGoogle" })
80
- Dir.mktmpdir do |dir|
81
- ENV.delete @var_name unless ENV[@var_name].nil? # no env var
82
- ENV["HOME"] = dir # no config present in this tmp dir
83
- expect do
84
- Google::Auth.get_application_default @scope, options
85
- end.to raise_error RuntimeError
86
- end
87
- expect(stub).to have_been_requested
88
- end
89
- end
90
-
91
- shared_examples "it can successfully load credentials" do
92
- it "succeeds if the GOOGLE_APPLICATION_CREDENTIALS file is valid" do
93
- Dir.mktmpdir do |dir|
94
- key_path = File.join dir, "my_cert_file"
95
- FileUtils.mkdir_p File.dirname(key_path)
96
- File.write key_path, cred_json_text
97
- ENV[@var_name] = key_path
98
- expect(Google::Auth.get_application_default(@scope, options))
99
- .to_not be_nil
100
- end
101
- end
102
-
103
- it "propagates default_connection option" do
104
- Dir.mktmpdir do |dir|
105
- key_path = File.join dir, "my_cert_file"
106
- FileUtils.mkdir_p File.dirname(key_path)
107
- File.write key_path, cred_json_text
108
- ENV[@var_name] = key_path
109
- connection = Faraday.new headers: { "User-Agent" => "hello" }
110
- opts = options.merge default_connection: connection
111
- creds = Google::Auth.get_application_default @scope, opts
112
- expect(creds.build_default_connection).to be connection
113
- end
114
- end
115
-
116
- it "succeeds with default file without GOOGLE_APPLICATION_CREDENTIALS" do
117
- ENV.delete @var_name unless ENV[@var_name].nil?
118
- Dir.mktmpdir do |dir|
119
- key_path = File.join dir, ".config", WELL_KNOWN_PATH
120
- key_path = File.join dir, WELL_KNOWN_PATH if OS.windows?
121
- FileUtils.mkdir_p File.dirname(key_path)
122
- File.write key_path, cred_json_text
123
- ENV["HOME"] = dir
124
- ENV["APPDATA"] = dir
125
- expect(Google::Auth.get_application_default(@scope, options))
126
- .to_not be_nil
127
- end
128
- end
129
-
130
- it "succeeds with default file without a scope" do
131
- ENV.delete @var_name unless ENV[@var_name].nil?
132
- Dir.mktmpdir do |dir|
133
- key_path = File.join dir, ".config", WELL_KNOWN_PATH
134
- key_path = File.join dir, WELL_KNOWN_PATH if OS.windows?
135
- FileUtils.mkdir_p File.dirname(key_path)
136
- File.write key_path, cred_json_text
137
- ENV["HOME"] = dir
138
- ENV["APPDATA"] = dir
139
- expect(Google::Auth.get_application_default(nil, options)).to_not be_nil
140
- end
141
- end
142
-
143
- it "succeeds without default file or env if on compute engine" do
144
- stub = stub_request(:get, "http://169.254.169.254")
145
- .to_return(status: 200,
146
- headers: { "Metadata-Flavor" => "Google" })
147
- Dir.mktmpdir do |dir|
148
- ENV.delete @var_name unless ENV[@var_name].nil? # no env var
149
- ENV["HOME"] = dir # no config present in this tmp dir
150
- creds = Google::Auth.get_application_default @scope, options
151
- expect(creds).to_not be_nil
152
- end
153
- expect(stub).to have_been_requested
154
- end
155
-
156
- it "succeeds with system default file" do
157
- ENV.delete @var_name unless ENV[@var_name].nil?
158
- FakeFS do
159
- ENV["ProgramData"] = "/etc"
160
- prefix = OS.windows? ? "/etc/Google/Auth/" : "/etc/google/auth/"
161
- key_path = File.join prefix, CREDENTIALS_FILE_NAME
162
- FileUtils.mkdir_p File.dirname(key_path)
163
- File.write key_path, cred_json_text
164
- expect(Google::Auth.get_application_default(@scope, options))
165
- .to_not be_nil
166
- File.delete key_path
167
- end
168
- end
169
-
170
- it "succeeds if environment vars are valid" do
171
- ENV.delete @var_name unless ENV[@var_name].nil? # no env var
172
- ENV[PRIVATE_KEY_VAR] = cred_json[:private_key]
173
- ENV[CLIENT_EMAIL_VAR] = cred_json[:client_email]
174
- ENV[CLIENT_ID_VAR] = cred_json[:client_id]
175
- ENV[CLIENT_SECRET_VAR] = cred_json[:client_secret]
176
- ENV[REFRESH_TOKEN_VAR] = cred_json[:refresh_token]
177
- ENV[ACCOUNT_TYPE_VAR] = cred_json[:type]
178
- expect(Google::Auth.get_application_default(@scope, options))
179
- .to_not be_nil
180
- end
181
-
182
- it "warns when using cloud sdk credentials" do
183
- ENV.delete @var_name unless ENV[@var_name].nil? # no env var
184
- ENV[PRIVATE_KEY_VAR] = cred_json[:private_key]
185
- ENV[CLIENT_EMAIL_VAR] = cred_json[:client_email]
186
- ENV[CLIENT_ID_VAR] = Google::Auth::CredentialsLoader::CLOUD_SDK_CLIENT_ID
187
- ENV[CLIENT_SECRET_VAR] = cred_json[:client_secret]
188
- ENV[REFRESH_TOKEN_VAR] = cred_json[:refresh_token]
189
- ENV[ACCOUNT_TYPE_VAR] = cred_json[:type]
190
- ENV[PROJECT_ID_VAR] = "a_project_id"
191
- expect { Google::Auth.get_application_default @scope, options }.to output(
192
- Google::Auth::CredentialsLoader::CLOUD_SDK_CREDENTIALS_WARNING + "\n"
193
- ).to_stderr
194
- end
195
- end
196
-
197
- describe "when credential type is service account" do
198
- let :cred_json do
199
- {
200
- private_key_id: "a_private_key_id",
201
- private_key: @key.to_pem,
202
- client_email: "app@developer.gserviceaccount.com",
203
- client_id: "app.apps.googleusercontent.com",
204
- type: "service_account"
205
- }
206
- end
207
-
208
- def cred_json_text
209
- MultiJson.dump cred_json
210
- end
211
-
212
- it_behaves_like "it can successfully load credentials"
213
- it_behaves_like "it cannot load misconfigured credentials"
214
- end
215
-
216
- describe "when credential type is authorized_user" do
217
- let :cred_json do
218
- {
219
- client_secret: "privatekey",
220
- refresh_token: "refreshtoken",
221
- client_id: "app.apps.googleusercontent.com",
222
- type: "authorized_user"
223
- }
224
- end
225
-
226
- def cred_json_text
227
- MultiJson.dump cred_json
228
- end
229
-
230
- it_behaves_like "it can successfully load credentials"
231
- it_behaves_like "it cannot load misconfigured credentials"
232
- end
233
-
234
- describe "when credential type is unknown" do
235
- let :cred_json do
236
- {
237
- client_secret: "privatekey",
238
- refresh_token: "refreshtoken",
239
- client_id: "app.apps.googleusercontent.com",
240
- private_key: @key.to_pem,
241
- client_email: "app@developer.gserviceaccount.com",
242
- type: "not_known_type"
243
- }
244
- end
245
-
246
- def cred_json_text
247
- MultiJson.dump cred_json
248
- end
249
-
250
- it "fails if the GOOGLE_APPLICATION_CREDENTIALS file contains the creds" do
251
- Dir.mktmpdir do |dir|
252
- key_path = File.join dir, "my_cert_file"
253
- FileUtils.mkdir_p File.dirname(key_path)
254
- File.write key_path, cred_json_text
255
- ENV[@var_name] = key_path
256
- expect do
257
- Google::Auth.get_application_default @scope, options
258
- end.to raise_error RuntimeError
259
- end
260
- end
261
-
262
- it "fails if the well known file contains the creds" do
263
- ENV.delete @var_name unless ENV[@var_name].nil?
264
- Dir.mktmpdir do |dir|
265
- key_path = File.join dir, ".config", WELL_KNOWN_PATH
266
- key_path = File.join dir, WELL_KNOWN_PATH if OS.windows?
267
- FileUtils.mkdir_p File.dirname(key_path)
268
- File.write key_path, cred_json_text
269
- ENV["HOME"] = dir
270
- ENV["APPDATA"] = dir
271
- expect do
272
- Google::Auth.get_application_default @scope, options
273
- end.to raise_error RuntimeError
274
- end
275
- end
276
-
277
- it "fails if env vars are set" do
278
- ENV[ENV_VAR] = nil
279
- ENV[PRIVATE_KEY_VAR] = cred_json[:private_key]
280
- ENV[CLIENT_EMAIL_VAR] = cred_json[:client_email]
281
- expect do
282
- Google::Auth.get_application_default @scope, options
283
- end.to raise_error RuntimeError
284
- end
285
- end
286
- end
@@ -1,80 +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/iam"
35
-
36
- describe Google::Auth::IAMCredentials do
37
- IAMCredentials = Google::Auth::IAMCredentials
38
- let(:test_selector) { "the-test-selector" }
39
- let(:test_token) { "the-test-token" }
40
- let(:test_creds) { IAMCredentials.new test_selector, test_token }
41
-
42
- describe "#apply!" do
43
- it "should update the target hash with the iam values" do
44
- md = { foo: "bar" }
45
- test_creds.apply! md
46
- expect(md[IAMCredentials::SELECTOR_KEY]).to eq test_selector
47
- expect(md[IAMCredentials::TOKEN_KEY]).to eq test_token
48
- expect(md[:foo]).to eq "bar"
49
- end
50
- end
51
-
52
- describe "updater_proc" do
53
- it "should provide a proc that updates a hash with the iam values" do
54
- md = { foo: "bar" }
55
- the_proc = test_creds.updater_proc
56
- got = the_proc.call md
57
- expect(got[IAMCredentials::SELECTOR_KEY]).to eq test_selector
58
- expect(got[IAMCredentials::TOKEN_KEY]).to eq test_token
59
- expect(got[:foo]).to eq "bar"
60
- end
61
- end
62
-
63
- describe "#apply" do
64
- it "should not update the original hash with the iam values" do
65
- md = { foo: "bar" }
66
- test_creds.apply md
67
- expect(md[IAMCredentials::SELECTOR_KEY]).to be_nil
68
- expect(md[IAMCredentials::TOKEN_KEY]).to be_nil
69
- expect(md[:foo]).to eq "bar"
70
- end
71
-
72
- it "should return a with the iam values" do
73
- md = { foo: "bar" }
74
- got = test_creds.apply md
75
- expect(got[IAMCredentials::SELECTOR_KEY]).to eq test_selector
76
- expect(got[IAMCredentials::TOKEN_KEY]).to eq test_token
77
- expect(got[:foo]).to eq "bar"
78
- end
79
- end
80
- end
@@ -1,77 +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/scope_util"
35
-
36
- describe Google::Auth::ScopeUtil do
37
- shared_examples "normalizes scopes" do
38
- let(:normalized) { Google::Auth::ScopeUtil.normalize source }
39
-
40
- it "normalizes the email scope" do
41
- expect(normalized).to include(
42
- "https://www.googleapis.com/auth/userinfo.email"
43
- )
44
- expect(normalized).to_not include "email"
45
- end
46
-
47
- it "normalizes the profile scope" do
48
- expect(normalized).to include(
49
- "https://www.googleapis.com/auth/userinfo.profile"
50
- )
51
- expect(normalized).to_not include "profile"
52
- end
53
-
54
- it "normalizes the openid scope" do
55
- expect(normalized).to include "https://www.googleapis.com/auth/plus.me"
56
- expect(normalized).to_not include "openid"
57
- end
58
-
59
- it "leaves other other scopes as-is" do
60
- expect(normalized).to include "https://www.googleapis.com/auth/drive"
61
- end
62
- end
63
-
64
- context "with scope as string" do
65
- let :source do
66
- "email profile openid https://www.googleapis.com/auth/drive"
67
- end
68
- it_behaves_like "normalizes scopes"
69
- end
70
-
71
- context "with scope as Array" do
72
- let :source do
73
- %w[email profile openid https://www.googleapis.com/auth/drive]
74
- end
75
- it_behaves_like "normalizes scopes"
76
- end
77
- end
@@ -1,497 +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
- quota_project_id: "b_project_id"
122
- }
123
- end
124
-
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
- )
135
- end
136
-
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/"
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" })
156
- end
157
-
158
- def cred_json_text
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"
178
- end
179
-
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]
189
-
190
- @scope = "https://www.googleapis.com/auth/userinfo.profile"
191
- @clz = ServiceAccountCredentials
192
- end
193
-
194
- after :example do
195
- @credential_vars.each { |var| ENV[var] = @original_env_vals[var] }
196
- end
197
-
198
- it "returns nil if the GOOGLE_APPLICATION_CREDENTIALS is unset" do
199
- ENV.delete @var_name unless ENV[@var_name].nil?
200
- expect(ServiceAccountCredentials.from_env(@scope)).to be_nil
201
- end
202
-
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?
210
- expect(ServiceAccountCredentials.from_env(@scope)).to be_nil
211
- Dir.mktmpdir do |dir|
212
- key_path = File.join dir, "does-not-exist"
213
- ENV[@var_name] = key_path
214
- expect { @clz.from_env @scope }.to raise_error RuntimeError
215
- end
216
- end
217
-
218
- it "succeeds when the GOOGLE_APPLICATION_CREDENTIALS file is valid" do
219
- Dir.mktmpdir do |dir|
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
223
- ENV[@var_name] = key_path
224
- expect(@clz.from_env(@scope)).to_not be_nil
225
- end
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
258
- end
259
-
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
267
- end
268
-
269
- after :example do
270
- ENV["HOME"] = @home unless @home == ENV["HOME"]
271
- ENV["APPDATA"] = @app_data unless @app_data == ENV["APPDATA"]
272
- end
273
-
274
- it "is nil if no file exists" do
275
- ENV["HOME"] = File.dirname __FILE__
276
- expect(ServiceAccountCredentials.from_well_known_path(@scope)).to be_nil
277
- end
278
-
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
484
- Dir.mktmpdir do |dir|
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
494
- end
495
- end
496
- end
497
- end