googleauth 0.9.0 → 0.17.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.yardopts +11 -0
- data/CHANGELOG.md +113 -21
- data/README.md +13 -15
- data/SECURITY.md +7 -0
- data/lib/googleauth/application_default.rb +9 -9
- data/lib/googleauth/compute_engine.rb +55 -30
- data/lib/googleauth/credentials.rb +253 -64
- data/lib/googleauth/credentials_loader.rb +15 -16
- data/lib/googleauth/iam.rb +1 -1
- data/{spec/googleauth/stores/store_examples.rb → lib/googleauth/id_tokens/errors.rb} +36 -23
- data/lib/googleauth/id_tokens/key_sources.rb +396 -0
- data/lib/googleauth/id_tokens/verifier.rb +142 -0
- data/lib/googleauth/id_tokens.rb +233 -0
- data/lib/googleauth/json_key_reader.rb +6 -2
- data/lib/googleauth/scope_util.rb +1 -1
- data/lib/googleauth/service_account.rb +61 -36
- data/lib/googleauth/signet.rb +9 -7
- data/lib/googleauth/stores/file_token_store.rb +1 -0
- data/lib/googleauth/stores/redis_token_store.rb +1 -0
- data/lib/googleauth/user_authorizer.rb +8 -3
- data/lib/googleauth/user_refresh.rb +1 -1
- data/lib/googleauth/version.rb +1 -1
- data/lib/googleauth/web_user_authorizer.rb +5 -8
- data/lib/googleauth.rb +1 -0
- metadata +33 -76
- data/.github/CONTRIBUTING.md +0 -74
- data/.github/ISSUE_TEMPLATE/bug_report.md +0 -36
- data/.github/ISSUE_TEMPLATE/feature_request.md +0 -21
- data/.github/ISSUE_TEMPLATE/support_request.md +0 -7
- data/.gitignore +0 -36
- data/.kokoro/build.bat +0 -16
- data/.kokoro/build.sh +0 -4
- data/.kokoro/continuous/common.cfg +0 -24
- data/.kokoro/continuous/linux.cfg +0 -15
- data/.kokoro/continuous/osx.cfg +0 -3
- data/.kokoro/continuous/windows.cfg +0 -19
- data/.kokoro/osx.sh +0 -4
- data/.kokoro/presubmit/common.cfg +0 -24
- data/.kokoro/presubmit/linux.cfg +0 -14
- data/.kokoro/presubmit/osx.cfg +0 -3
- data/.kokoro/presubmit/windows.cfg +0 -19
- data/.kokoro/release.cfg +0 -53
- data/.kokoro/trampoline.bat +0 -10
- data/.kokoro/trampoline.sh +0 -4
- data/.rspec +0 -2
- data/.rubocop.yml +0 -42
- data/Gemfile +0 -25
- data/Rakefile +0 -89
- data/googleauth.gemspec +0 -35
- data/spec/googleauth/apply_auth_examples.rb +0 -148
- data/spec/googleauth/client_id_spec.rb +0 -160
- data/spec/googleauth/compute_engine_spec.rb +0 -122
- data/spec/googleauth/credentials_spec.rb +0 -459
- data/spec/googleauth/get_application_default_spec.rb +0 -286
- data/spec/googleauth/iam_spec.rb +0 -80
- data/spec/googleauth/scope_util_spec.rb +0 -77
- data/spec/googleauth/service_account_spec.rb +0 -482
- data/spec/googleauth/signet_spec.rb +0 -134
- data/spec/googleauth/stores/file_token_store_spec.rb +0 -57
- data/spec/googleauth/stores/redis_token_store_spec.rb +0 -50
- data/spec/googleauth/user_authorizer_spec.rb +0 -323
- data/spec/googleauth/user_refresh_spec.rb +0 -359
- data/spec/googleauth/web_user_authorizer_spec.rb +0 -172
- data/spec/spec_helper.rb +0 -92
- /data/{COPYING → LICENSE} +0 -0
@@ -1,359 +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/user_refresh"
|
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
|
-
describe Google::Auth::UserRefreshCredentials do
|
48
|
-
UserRefreshCredentials = Google::Auth::UserRefreshCredentials
|
49
|
-
|
50
|
-
let :cred_json do
|
51
|
-
{
|
52
|
-
client_secret: "privatekey",
|
53
|
-
client_id: "client123",
|
54
|
-
refresh_token: "refreshtoken",
|
55
|
-
type: "authorized_user"
|
56
|
-
}
|
57
|
-
end
|
58
|
-
|
59
|
-
before :example do
|
60
|
-
@key = OpenSSL::PKey::RSA.new 2048
|
61
|
-
@client = UserRefreshCredentials.make_creds(
|
62
|
-
json_key_io: StringIO.new(cred_json_text),
|
63
|
-
scope: "https://www.googleapis.com/auth/userinfo.profile"
|
64
|
-
)
|
65
|
-
end
|
66
|
-
|
67
|
-
def make_auth_stubs opts = {}
|
68
|
-
access_token = opts[:access_token] || ""
|
69
|
-
body = MultiJson.dump("access_token" => access_token,
|
70
|
-
"token_type" => "Bearer",
|
71
|
-
"expires_in" => 3600)
|
72
|
-
stub_request(:post, "https://oauth2.googleapis.com/token")
|
73
|
-
.with(body: hash_including("grant_type" => "refresh_token"))
|
74
|
-
.to_return(body: body,
|
75
|
-
status: 200,
|
76
|
-
headers: { "Content-Type" => "application/json" })
|
77
|
-
end
|
78
|
-
|
79
|
-
def cred_json_text missing = nil
|
80
|
-
cred_json.delete missing.to_sym unless missing.nil?
|
81
|
-
MultiJson.dump cred_json
|
82
|
-
end
|
83
|
-
|
84
|
-
it_behaves_like "apply/apply! are OK"
|
85
|
-
|
86
|
-
describe "#from_env" do
|
87
|
-
before :example do
|
88
|
-
@var_name = ENV_VAR
|
89
|
-
@credential_vars = [
|
90
|
-
ENV_VAR, CLIENT_ID_VAR, CLIENT_SECRET_VAR, REFRESH_TOKEN_VAR,
|
91
|
-
ACCOUNT_TYPE_VAR
|
92
|
-
]
|
93
|
-
@original_env_vals = {}
|
94
|
-
@credential_vars.each { |var| @original_env_vals[var] = ENV[var] }
|
95
|
-
@scope = "https://www.googleapis.com/auth/userinfo.profile"
|
96
|
-
@clz = UserRefreshCredentials
|
97
|
-
@project_id = "a_project_id"
|
98
|
-
end
|
99
|
-
|
100
|
-
after :example do
|
101
|
-
@credential_vars.each { |var| ENV[var] = @original_env_vals[var] }
|
102
|
-
end
|
103
|
-
|
104
|
-
it "returns nil if the GOOGLE_APPLICATION_CREDENTIALS is unset" do
|
105
|
-
ENV.delete @var_name unless ENV[@var_name].nil?
|
106
|
-
expect(UserRefreshCredentials.from_env(@scope)).to be_nil
|
107
|
-
end
|
108
|
-
|
109
|
-
it "returns nil if the GOOGLE_APPLICATION_CREDENTIALS is empty" do
|
110
|
-
ENV[@var_name] = ""
|
111
|
-
expect(UserRefreshCredentials.from_env(@scope)).to be_nil
|
112
|
-
end
|
113
|
-
|
114
|
-
it "fails if the GOOGLE_APPLICATION_CREDENTIALS path does not exist" do
|
115
|
-
ENV.delete @var_name unless ENV[@var_name].nil?
|
116
|
-
expect(UserRefreshCredentials.from_env(@scope)).to be_nil
|
117
|
-
Dir.mktmpdir do |dir|
|
118
|
-
key_path = File.join dir, "does-not-exist"
|
119
|
-
ENV[@var_name] = key_path
|
120
|
-
expect { @clz.from_env @scope }.to raise_error RuntimeError
|
121
|
-
end
|
122
|
-
end
|
123
|
-
|
124
|
-
it "fails if the GOOGLE_APPLICATION_CREDENTIALS path file is invalid" do
|
125
|
-
needed = %w[client_id client_secret refresh_token]
|
126
|
-
needed.each do |missing|
|
127
|
-
Dir.mktmpdir do |dir|
|
128
|
-
key_path = File.join dir, "my_cert_file"
|
129
|
-
FileUtils.mkdir_p File.dirname(key_path)
|
130
|
-
File.write key_path, cred_json_text(missing)
|
131
|
-
ENV[@var_name] = key_path
|
132
|
-
expect { @clz.from_env @scope }.to raise_error RuntimeError
|
133
|
-
end
|
134
|
-
end
|
135
|
-
end
|
136
|
-
|
137
|
-
it "succeeds when the GOOGLE_APPLICATION_CREDENTIALS file is valid" do
|
138
|
-
Dir.mktmpdir do |dir|
|
139
|
-
key_path = File.join dir, "my_cert_file"
|
140
|
-
FileUtils.mkdir_p File.dirname(key_path)
|
141
|
-
File.write key_path, cred_json_text
|
142
|
-
ENV[@var_name] = key_path
|
143
|
-
expect(@clz.from_env(@scope)).to_not be_nil
|
144
|
-
end
|
145
|
-
end
|
146
|
-
|
147
|
-
it "succeeds when GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET, and "\
|
148
|
-
"GOOGLE_REFRESH_TOKEN env vars are valid" do
|
149
|
-
ENV[ENV_VAR] = nil
|
150
|
-
ENV[CLIENT_ID_VAR] = cred_json[:client_id]
|
151
|
-
ENV[CLIENT_SECRET_VAR] = cred_json[:client_secret]
|
152
|
-
ENV[REFRESH_TOKEN_VAR] = cred_json[:refresh_token]
|
153
|
-
ENV[ACCOUNT_TYPE_VAR] = cred_json[:type]
|
154
|
-
creds = @clz.from_env @scope
|
155
|
-
expect(creds).to_not be_nil
|
156
|
-
expect(creds.client_id).to eq(cred_json[:client_id])
|
157
|
-
expect(creds.client_secret).to eq(cred_json[:client_secret])
|
158
|
-
expect(creds.refresh_token).to eq(cred_json[:refresh_token])
|
159
|
-
end
|
160
|
-
|
161
|
-
it "sets project_id when the PROJECT_ID_VAR env var is set" do
|
162
|
-
ENV[ENV_VAR] = nil
|
163
|
-
ENV[CLIENT_ID_VAR] = cred_json[:client_id]
|
164
|
-
ENV[CLIENT_SECRET_VAR] = cred_json[:client_secret]
|
165
|
-
ENV[REFRESH_TOKEN_VAR] = cred_json[:refresh_token]
|
166
|
-
ENV[ACCOUNT_TYPE_VAR] = cred_json[:type]
|
167
|
-
ENV[PROJECT_ID_VAR] = @project_id
|
168
|
-
creds = @clz.from_env @scope
|
169
|
-
expect(creds.project_id).to eq(@project_id)
|
170
|
-
end
|
171
|
-
end
|
172
|
-
|
173
|
-
describe "#from_well_known_path" do
|
174
|
-
before :example do
|
175
|
-
@home = ENV["HOME"]
|
176
|
-
@app_data = ENV["APPDATA"]
|
177
|
-
@scope = "https://www.googleapis.com/auth/userinfo.profile"
|
178
|
-
@known_path = WELL_KNOWN_PATH
|
179
|
-
@clz = UserRefreshCredentials
|
180
|
-
end
|
181
|
-
|
182
|
-
after :example do
|
183
|
-
ENV["HOME"] = @home unless @home == ENV["HOME"]
|
184
|
-
ENV["APPDATA"] = @app_data unless @app_data == ENV["APPDATA"]
|
185
|
-
end
|
186
|
-
|
187
|
-
it "is nil if no file exists" do
|
188
|
-
ENV["HOME"] = File.dirname __FILE__
|
189
|
-
expect(UserRefreshCredentials.from_well_known_path(@scope)).to be_nil
|
190
|
-
end
|
191
|
-
|
192
|
-
it "fails if the file is invalid" do
|
193
|
-
needed = %w[client_id client_secret refresh_token]
|
194
|
-
needed.each do |missing|
|
195
|
-
Dir.mktmpdir do |dir|
|
196
|
-
key_path = File.join dir, ".config", @known_path
|
197
|
-
key_path = File.join dir, @known_path if OS.windows?
|
198
|
-
FileUtils.mkdir_p File.dirname(key_path)
|
199
|
-
File.write key_path, cred_json_text(missing)
|
200
|
-
ENV["HOME"] = dir
|
201
|
-
ENV["APPDATA"] = dir
|
202
|
-
expect { @clz.from_well_known_path @scope }
|
203
|
-
.to raise_error RuntimeError
|
204
|
-
end
|
205
|
-
end
|
206
|
-
end
|
207
|
-
|
208
|
-
it "successfully loads the file when it is present" do
|
209
|
-
Dir.mktmpdir do |dir|
|
210
|
-
key_path = File.join dir, ".config", @known_path
|
211
|
-
key_path = File.join dir, @known_path if OS.windows?
|
212
|
-
FileUtils.mkdir_p File.dirname(key_path)
|
213
|
-
File.write key_path, cred_json_text
|
214
|
-
ENV["HOME"] = dir
|
215
|
-
ENV["APPDATA"] = dir
|
216
|
-
expect(@clz.from_well_known_path(@scope)).to_not be_nil
|
217
|
-
end
|
218
|
-
end
|
219
|
-
|
220
|
-
it "checks gcloud config for project_id if none was provided" do
|
221
|
-
Dir.mktmpdir do |dir|
|
222
|
-
key_path = File.join dir, ".config", @known_path
|
223
|
-
key_path = File.join dir, @known_path if OS.windows?
|
224
|
-
FileUtils.mkdir_p File.dirname(key_path)
|
225
|
-
File.write key_path, cred_json_text
|
226
|
-
ENV["HOME"] = dir
|
227
|
-
ENV["APPDATA"] = dir
|
228
|
-
ENV[PROJECT_ID_VAR] = nil
|
229
|
-
expect(Google::Auth::CredentialsLoader).to receive(:load_gcloud_project_id).with(no_args)
|
230
|
-
@clz.from_well_known_path @scope
|
231
|
-
end
|
232
|
-
end
|
233
|
-
end
|
234
|
-
|
235
|
-
describe "#from_system_default_path" do
|
236
|
-
before :example do
|
237
|
-
@scope = "https://www.googleapis.com/auth/userinfo.profile"
|
238
|
-
@prefix = OS.windows? ? "/etc/Google/Auth/" : "/etc/google/auth/"
|
239
|
-
@path = File.join @prefix, CREDENTIALS_FILE_NAME
|
240
|
-
@program_data = ENV["ProgramData"]
|
241
|
-
@clz = UserRefreshCredentials
|
242
|
-
end
|
243
|
-
|
244
|
-
after :example do
|
245
|
-
ENV["ProgramData"] = @program_data
|
246
|
-
end
|
247
|
-
|
248
|
-
it "is nil if no file exists" do
|
249
|
-
FakeFS do
|
250
|
-
expect(UserRefreshCredentials.from_system_default_path(@scope))
|
251
|
-
.to be_nil
|
252
|
-
end
|
253
|
-
end
|
254
|
-
|
255
|
-
it "fails if the file is invalid" do
|
256
|
-
needed = %w[client_id client_secret refresh_token]
|
257
|
-
needed.each do |missing|
|
258
|
-
FakeFS do
|
259
|
-
ENV["ProgramData"] = "/etc"
|
260
|
-
FileUtils.mkdir_p File.dirname(@path)
|
261
|
-
File.write @path, cred_json_text(missing)
|
262
|
-
expect { @clz.from_system_default_path @scope }
|
263
|
-
.to raise_error RuntimeError
|
264
|
-
File.delete @path
|
265
|
-
end
|
266
|
-
end
|
267
|
-
end
|
268
|
-
|
269
|
-
it "successfully loads the file when it is present" do
|
270
|
-
FakeFS do
|
271
|
-
ENV["ProgramData"] = "/etc"
|
272
|
-
FileUtils.mkdir_p File.dirname(@path)
|
273
|
-
File.write @path, cred_json_text
|
274
|
-
expect(@clz.from_system_default_path(@scope)).to_not be_nil
|
275
|
-
File.delete @path
|
276
|
-
end
|
277
|
-
end
|
278
|
-
end
|
279
|
-
|
280
|
-
shared_examples "revoked token" do
|
281
|
-
it "should nil the refresh token" do
|
282
|
-
expect(@client.refresh_token).to be_nil
|
283
|
-
end
|
284
|
-
|
285
|
-
it "should nil the access token" do
|
286
|
-
expect(@client.access_token).to be_nil
|
287
|
-
end
|
288
|
-
|
289
|
-
it "should mark the token as expired" do
|
290
|
-
expect(@client.expired?).to be_truthy
|
291
|
-
end
|
292
|
-
end
|
293
|
-
|
294
|
-
describe "when revoking a refresh token" do
|
295
|
-
let :stub do
|
296
|
-
stub_request(:post, "https://oauth2.googleapis.com/revoke")
|
297
|
-
.with(body: hash_including("token" => "refreshtoken"))
|
298
|
-
.to_return(status: 200,
|
299
|
-
headers: { "Content-Type" => "application/json" })
|
300
|
-
end
|
301
|
-
|
302
|
-
before :example do
|
303
|
-
stub
|
304
|
-
@client.revoke!
|
305
|
-
end
|
306
|
-
|
307
|
-
it_behaves_like "revoked token"
|
308
|
-
end
|
309
|
-
|
310
|
-
describe "when revoking an access token" do
|
311
|
-
let :stub do
|
312
|
-
stub_request(:post, "https://oauth2.googleapis.com/revoke")
|
313
|
-
.with(body: hash_including("token" => "accesstoken"))
|
314
|
-
.to_return(status: 200,
|
315
|
-
headers: { "Content-Type" => "application/json" })
|
316
|
-
end
|
317
|
-
|
318
|
-
before :example do
|
319
|
-
stub
|
320
|
-
@client.refresh_token = nil
|
321
|
-
@client.access_token = "accesstoken"
|
322
|
-
@client.revoke!
|
323
|
-
end
|
324
|
-
|
325
|
-
it_behaves_like "revoked token"
|
326
|
-
end
|
327
|
-
|
328
|
-
describe "when revoking an invalid token" do
|
329
|
-
let :stub do
|
330
|
-
stub_request(:post, "https://oauth2.googleapis.com/revoke")
|
331
|
-
.with(body: hash_including("token" => "refreshtoken"))
|
332
|
-
.to_return(status: 400,
|
333
|
-
headers: { "Content-Type" => "application/json" })
|
334
|
-
end
|
335
|
-
|
336
|
-
it "raises an authorization error" do
|
337
|
-
stub
|
338
|
-
expect { @client.revoke! }.to raise_error(
|
339
|
-
Signet::AuthorizationError
|
340
|
-
)
|
341
|
-
end
|
342
|
-
end
|
343
|
-
|
344
|
-
describe "when errors occurred with request" do
|
345
|
-
it "should fail with Signet::AuthorizationError if request times out" do
|
346
|
-
allow_any_instance_of(Faraday::Connection).to receive(:post)
|
347
|
-
.and_raise(Faraday::TimeoutError)
|
348
|
-
expect { @client.revoke! }
|
349
|
-
.to raise_error Signet::AuthorizationError
|
350
|
-
end
|
351
|
-
|
352
|
-
it "should fail with Signet::AuthorizationError if request fails" do
|
353
|
-
allow_any_instance_of(Faraday::Connection).to receive(:post)
|
354
|
-
.and_raise(Faraday::ConnectionFailed, nil)
|
355
|
-
expect { @client.revoke! }
|
356
|
-
.to raise_error Signet::AuthorizationError
|
357
|
-
end
|
358
|
-
end
|
359
|
-
end
|
@@ -1,172 +0,0 @@
|
|
1
|
-
# Copyright 2015, Google Inc.
|
2
|
-
# All rights reserved.
|
3
|
-
#
|
4
|
-
# Redistribution and use in source and binary forms, with or without
|
5
|
-
# modification, are permitted provided that the following conditions are
|
6
|
-
# met:
|
7
|
-
#
|
8
|
-
# * Redistributions of source code must retain the above copyright
|
9
|
-
# notice, this list of conditions and the following disclaimer.
|
10
|
-
# * Redistributions in binary form must reproduce the above
|
11
|
-
# copyright notice, this list of conditions and the following disclaimer
|
12
|
-
# in the documentation and/or other materials provided with the
|
13
|
-
# distribution.
|
14
|
-
# * Neither the name of Google Inc. nor the names of its
|
15
|
-
# contributors may be used to endorse or promote products derived from
|
16
|
-
# this software without specific prior written permission.
|
17
|
-
#
|
18
|
-
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
19
|
-
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
20
|
-
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
21
|
-
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
22
|
-
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
23
|
-
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
24
|
-
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
25
|
-
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
26
|
-
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
27
|
-
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
28
|
-
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
29
|
-
|
30
|
-
spec_dir = File.expand_path File.join(File.dirname(__FILE__))
|
31
|
-
$LOAD_PATH.unshift spec_dir
|
32
|
-
$LOAD_PATH.uniq!
|
33
|
-
|
34
|
-
require "googleauth"
|
35
|
-
require "googleauth/web_user_authorizer"
|
36
|
-
require "uri"
|
37
|
-
require "multi_json"
|
38
|
-
require "spec_helper"
|
39
|
-
require "rack"
|
40
|
-
|
41
|
-
describe Google::Auth::WebUserAuthorizer do
|
42
|
-
include TestHelpers
|
43
|
-
|
44
|
-
let(:client_id) { Google::Auth::ClientId.new "testclient", "notasecret" }
|
45
|
-
let(:scope) { %w[email profile] }
|
46
|
-
let(:token_store) { DummyTokenStore.new }
|
47
|
-
let :authorizer do
|
48
|
-
Google::Auth::WebUserAuthorizer.new client_id, scope, token_store
|
49
|
-
end
|
50
|
-
|
51
|
-
describe "#get_authorization_url" do
|
52
|
-
let :env do
|
53
|
-
Rack::MockRequest.env_for(
|
54
|
-
"http://example.com:8080/test",
|
55
|
-
"REMOTE_ADDR" => "10.10.10.10"
|
56
|
-
)
|
57
|
-
end
|
58
|
-
let(:request) { Rack::Request.new env }
|
59
|
-
it "should include current url in state" do
|
60
|
-
url = authorizer.get_authorization_url request: request
|
61
|
-
expect(url).to match(
|
62
|
-
%r{%22current_uri%22:%22http://example.com:8080/test%22}
|
63
|
-
)
|
64
|
-
end
|
65
|
-
|
66
|
-
it "should allow adding custom state key-value pairs" do
|
67
|
-
url = authorizer.get_authorization_url request: request, state: { james: "bond", kind: 1 }
|
68
|
-
expect(url).to match(%r{%22james%22:%22bond%22})
|
69
|
-
expect(url).to match(%r{%22kind%22:1})
|
70
|
-
end
|
71
|
-
|
72
|
-
it "should include request forgery token in state" do
|
73
|
-
expect(SecureRandom).to receive(:base64).and_return("aGVsbG8=")
|
74
|
-
url = authorizer.get_authorization_url request: request
|
75
|
-
expect(url).to match(/%22session_id%22:%22aGVsbG8=%22/)
|
76
|
-
end
|
77
|
-
|
78
|
-
it "should include request forgery token in session" do
|
79
|
-
expect(SecureRandom).to receive(:base64).and_return("aGVsbG8=")
|
80
|
-
authorizer.get_authorization_url request: request
|
81
|
-
expect(request.session["g-xsrf-token"]).to eq "aGVsbG8="
|
82
|
-
end
|
83
|
-
|
84
|
-
it "should resolve callback against base URL" do
|
85
|
-
url = authorizer.get_authorization_url request: request
|
86
|
-
expect(url).to match(
|
87
|
-
%r{redirect_uri=http://example.com:8080/oauth2callback}
|
88
|
-
)
|
89
|
-
end
|
90
|
-
|
91
|
-
it "should allow overriding the current URL" do
|
92
|
-
url = authorizer.get_authorization_url(
|
93
|
-
request: request,
|
94
|
-
redirect_to: "/foo"
|
95
|
-
)
|
96
|
-
expect(url).to match %r{%22current_uri%22:%22/foo%22}
|
97
|
-
end
|
98
|
-
|
99
|
-
it "should pass through login hint" do
|
100
|
-
url = authorizer.get_authorization_url(
|
101
|
-
request: request,
|
102
|
-
login_hint: "user@example.com"
|
103
|
-
)
|
104
|
-
expect(url).to match(/login_hint=user@example.com/)
|
105
|
-
end
|
106
|
-
end
|
107
|
-
|
108
|
-
shared_examples "handles callback" do
|
109
|
-
let :token_json do
|
110
|
-
MultiJson.dump("access_token" => "1/abc123",
|
111
|
-
"token_type" => "Bearer",
|
112
|
-
"expires_in" => 3600)
|
113
|
-
end
|
114
|
-
|
115
|
-
before :example do
|
116
|
-
stub_request(:post, "https://oauth2.googleapis.com/token")
|
117
|
-
.to_return(body: token_json,
|
118
|
-
status: 200,
|
119
|
-
headers: { "Content-Type" => "application/json" })
|
120
|
-
end
|
121
|
-
|
122
|
-
let :env do
|
123
|
-
Rack::MockRequest.env_for(
|
124
|
-
"http://example.com:8080/oauth2callback?code=authcode&"\
|
125
|
-
"state=%7B%22current_uri%22%3A%22%2Ffoo%22%2C%22"\
|
126
|
-
"session_id%22%3A%22abc%22%7D",
|
127
|
-
"REMOTE_ADDR" => "10.10.10.10"
|
128
|
-
)
|
129
|
-
end
|
130
|
-
let(:request) { Rack::Request.new env }
|
131
|
-
|
132
|
-
before :example do
|
133
|
-
request.session["g-xsrf-token"] = "abc"
|
134
|
-
end
|
135
|
-
|
136
|
-
it "should return credentials when valid code present" do
|
137
|
-
expect(credentials).to be_instance_of(
|
138
|
-
Google::Auth::UserRefreshCredentials
|
139
|
-
)
|
140
|
-
end
|
141
|
-
|
142
|
-
it "should return next URL to redirect to" do
|
143
|
-
expect(next_url).to eq "/foo"
|
144
|
-
end
|
145
|
-
|
146
|
-
it "should fail if xrsf token in session and does not match request" do
|
147
|
-
request.session["g-xsrf-token"] = "123"
|
148
|
-
expect { credentials }.to raise_error(Signet::AuthorizationError)
|
149
|
-
end
|
150
|
-
end
|
151
|
-
|
152
|
-
describe "#handle_auth_callback" do
|
153
|
-
let(:result) { authorizer.handle_auth_callback "user1", request }
|
154
|
-
let(:credentials) { result[0] }
|
155
|
-
let(:next_url) { result[1] }
|
156
|
-
|
157
|
-
it_behaves_like "handles callback"
|
158
|
-
end
|
159
|
-
|
160
|
-
describe "#handle_auth_callback_deferred and #get_credentials" do
|
161
|
-
let :next_url do
|
162
|
-
Google::Auth::WebUserAuthorizer.handle_auth_callback_deferred request
|
163
|
-
end
|
164
|
-
|
165
|
-
let :credentials do
|
166
|
-
next_url
|
167
|
-
authorizer.get_credentials "user1", request
|
168
|
-
end
|
169
|
-
|
170
|
-
it_behaves_like "handles callback"
|
171
|
-
end
|
172
|
-
end
|
data/spec/spec_helper.rb
DELETED
@@ -1,92 +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 = __dir__
|
31
|
-
root_dir = File.expand_path File.join(spec_dir, "..")
|
32
|
-
lib_dir = File.expand_path File.join(root_dir, "lib")
|
33
|
-
|
34
|
-
$LOAD_PATH.unshift spec_dir
|
35
|
-
$LOAD_PATH.unshift lib_dir
|
36
|
-
$LOAD_PATH.uniq!
|
37
|
-
|
38
|
-
# set up coverage
|
39
|
-
require "simplecov"
|
40
|
-
require "coveralls"
|
41
|
-
|
42
|
-
SimpleCov.formatters = [
|
43
|
-
Coveralls::SimpleCov::Formatter,
|
44
|
-
SimpleCov::Formatter::HTMLFormatter
|
45
|
-
]
|
46
|
-
SimpleCov.start
|
47
|
-
|
48
|
-
require "faraday"
|
49
|
-
require "rspec"
|
50
|
-
require "logging"
|
51
|
-
require "rspec/logging_helper"
|
52
|
-
require "webmock/rspec"
|
53
|
-
require "multi_json"
|
54
|
-
|
55
|
-
# Preload adapter to work around Rubinius error with FakeFS
|
56
|
-
MultiJson.use :json_gem
|
57
|
-
|
58
|
-
# Allow Faraday to support test stubs
|
59
|
-
Faraday::Adapter.load_middleware :test
|
60
|
-
|
61
|
-
# Configure RSpec to capture log messages for each test. The output from the
|
62
|
-
# logs will be stored in the @log_output variable. It is a StringIO instance.
|
63
|
-
RSpec.configure do |config|
|
64
|
-
include RSpec::LoggingHelper
|
65
|
-
config.capture_log_messages
|
66
|
-
config.include WebMock::API
|
67
|
-
config.filter_run focus: true
|
68
|
-
config.run_all_when_everything_filtered = true
|
69
|
-
end
|
70
|
-
|
71
|
-
module TestHelpers
|
72
|
-
include WebMock::API
|
73
|
-
include WebMock::Matchers
|
74
|
-
end
|
75
|
-
|
76
|
-
class DummyTokenStore
|
77
|
-
def initialize
|
78
|
-
@tokens = {}
|
79
|
-
end
|
80
|
-
|
81
|
-
def load id
|
82
|
-
@tokens[id]
|
83
|
-
end
|
84
|
-
|
85
|
-
def store id, token
|
86
|
-
@tokens[id] = token
|
87
|
-
end
|
88
|
-
|
89
|
-
def delete id
|
90
|
-
@tokens.delete id
|
91
|
-
end
|
92
|
-
end
|
/data/{COPYING → LICENSE}
RENAMED
File without changes
|