googleauth 0.17.0 → 0.17.1

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