googleauth 0.11.0 → 0.12.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +5 -0
- data/Gemfile +1 -0
- data/googleauth.gemspec +2 -2
- data/lib/googleauth/compute_engine.rb +13 -5
- data/lib/googleauth/credentials.rb +89 -22
- data/lib/googleauth/json_key_reader.rb +6 -2
- data/lib/googleauth/service_account.rb +13 -4
- data/lib/googleauth/signet.rb +3 -2
- data/lib/googleauth/version.rb +1 -1
- data/spec/googleauth/apply_auth_examples.rb +16 -5
- data/spec/googleauth/compute_engine_spec.rb +22 -13
- data/spec/googleauth/credentials_spec.rb +17 -6
- data/spec/googleauth/service_account_spec.rb +23 -16
- data/spec/googleauth/signet_spec.rb +15 -7
- data/spec/googleauth/user_refresh_spec.rb +1 -1
- metadata +5 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9f7661bafaadfe1aa8d9a574ace1bae7cb6d708dea4420e54097464d2b449eb0
|
4
|
+
data.tar.gz: 6ddd0f1591487041e8cce3d563381877ba27793454e0b8ce1f773186d2fd497e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 57006f2ea4dd1c5a097b51ae66fc451b2c8598ea8915a6ec74446f7c2d87b0033b0c28fd23b8eae978ce75e17d73ac54c86d7aa03601f3aa61dcee62e85c7cbd
|
7
|
+
data.tar.gz: 81306dc3b804115ef426925535b2153916bf37752f81a55e47a3631a77a5e976d40432351eabd452058ad918ff141da2db406128666f993dc64e40d605006a22
|
data/CHANGELOG.md
CHANGED
data/Gemfile
CHANGED
data/googleauth.gemspec
CHANGED
@@ -9,7 +9,7 @@ Gem::Specification.new do |gem|
|
|
9
9
|
gem.version = Google::Auth::VERSION
|
10
10
|
gem.authors = ["Tim Emiola"]
|
11
11
|
gem.email = "temiola@google.com"
|
12
|
-
gem.homepage = "https://github.com/
|
12
|
+
gem.homepage = "https://github.com/googleapis/google-auth-library-ruby"
|
13
13
|
gem.summary = "Google Auth Library for Ruby"
|
14
14
|
gem.license = "Apache-2.0"
|
15
15
|
gem.description = <<-DESCRIPTION
|
@@ -32,6 +32,6 @@ Gem::Specification.new do |gem|
|
|
32
32
|
gem.add_dependency "memoist", "~> 0.16"
|
33
33
|
gem.add_dependency "multi_json", "~> 1.11"
|
34
34
|
gem.add_dependency "os", ">= 0.9", "< 2.0"
|
35
|
-
gem.add_dependency "signet", "~> 0.
|
35
|
+
gem.add_dependency "signet", "~> 0.14"
|
36
36
|
gem.add_development_dependency "yard", "~> 0.9"
|
37
37
|
end
|
@@ -51,8 +51,10 @@ module Google
|
|
51
51
|
class GCECredentials < Signet::OAuth2::Client
|
52
52
|
# The IP Address is used in the URIs to speed up failures on non-GCE
|
53
53
|
# systems.
|
54
|
-
COMPUTE_AUTH_TOKEN_URI =
|
55
|
-
|
54
|
+
COMPUTE_AUTH_TOKEN_URI =
|
55
|
+
"http://169.254.169.254/computeMetadata/v1/instance/service-accounts/default/token".freeze
|
56
|
+
COMPUTE_ID_TOKEN_URI =
|
57
|
+
"http://169.254.169.254/computeMetadata/v1/instance/service-accounts/default/identity".freeze
|
56
58
|
COMPUTE_CHECK_URI = "http://169.254.169.254".freeze
|
57
59
|
|
58
60
|
class << self
|
@@ -82,12 +84,18 @@ module Google
|
|
82
84
|
def fetch_access_token options = {}
|
83
85
|
c = options[:connection] || Faraday.default_connection
|
84
86
|
retry_with_error do
|
87
|
+
uri = target_audience ? COMPUTE_ID_TOKEN_URI : COMPUTE_AUTH_TOKEN_URI
|
88
|
+
query = target_audience ? { "audience" => target_audience, "format" => "full" } : nil
|
85
89
|
headers = { "Metadata-Flavor" => "Google" }
|
86
|
-
resp = c.get
|
90
|
+
resp = c.get uri, query, headers
|
87
91
|
case resp.status
|
88
92
|
when 200
|
89
|
-
|
90
|
-
|
93
|
+
content_type = resp.headers["content-type"]
|
94
|
+
if content_type == "text/html"
|
95
|
+
{ (target_audience ? "id_token" : "access_token") => resp.body }
|
96
|
+
else
|
97
|
+
Signet::OAuth2.parse_credentials resp.body, content_type
|
98
|
+
end
|
91
99
|
when 404
|
92
100
|
raise Signet::AuthorizationError, NO_METADATA_SERVER_ERROR
|
93
101
|
else
|
@@ -47,6 +47,8 @@ module Google
|
|
47
47
|
# The default target audience ID to be used when none is provided during initialization.
|
48
48
|
AUDIENCE = "https://oauth2.googleapis.com/token".freeze
|
49
49
|
|
50
|
+
@audience = @scope = @target_audience = @env_vars = @paths = nil
|
51
|
+
|
50
52
|
##
|
51
53
|
# The default token credential URI to be used when none is provided during initialization.
|
52
54
|
# The URI is the authorization server's HTTP endpoint capable of issuing tokens and
|
@@ -97,20 +99,25 @@ module Google
|
|
97
99
|
# A scope is an access range defined by the authorization server.
|
98
100
|
# The scope can be a single value or a list of values.
|
99
101
|
#
|
102
|
+
# Either {#scope} or {#target_audience}, but not both, should be non-nil.
|
103
|
+
# If {#scope} is set, this credential will produce access tokens.
|
104
|
+
# If {#target_audience} is set, this credential will produce ID tokens.
|
105
|
+
#
|
100
106
|
# @return [String, Array<String>]
|
101
107
|
#
|
102
108
|
def self.scope
|
103
109
|
return @scope unless @scope.nil?
|
104
110
|
|
105
|
-
|
106
|
-
# Pull in values is the SCOPE constant exists.
|
107
|
-
tmp_scope << const_get(:SCOPE) if const_defined? :SCOPE
|
108
|
-
tmp_scope.flatten.uniq
|
111
|
+
Array(const_get(:SCOPE)).flatten.uniq if const_defined? :SCOPE
|
109
112
|
end
|
110
113
|
|
111
114
|
##
|
112
115
|
# Sets the default scope to be used when none is provided during initialization.
|
113
116
|
#
|
117
|
+
# Either {#scope} or {#target_audience}, but not both, should be non-nil.
|
118
|
+
# If {#scope} is set, this credential will produce access tokens.
|
119
|
+
# If {#target_audience} is set, this credential will produce ID tokens.
|
120
|
+
#
|
114
121
|
# @param [String, Array<String>] new_scope
|
115
122
|
# @return [String, Array<String>]
|
116
123
|
#
|
@@ -119,6 +126,34 @@ module Google
|
|
119
126
|
@scope = new_scope
|
120
127
|
end
|
121
128
|
|
129
|
+
##
|
130
|
+
# The default final target audience for ID tokens, to be used when none
|
131
|
+
# is provided during initialization.
|
132
|
+
#
|
133
|
+
# Either {#scope} or {#target_audience}, but not both, should be non-nil.
|
134
|
+
# If {#scope} is set, this credential will produce access tokens.
|
135
|
+
# If {#target_audience} is set, this credential will produce ID tokens.
|
136
|
+
#
|
137
|
+
# @return [String]
|
138
|
+
#
|
139
|
+
def self.target_audience
|
140
|
+
@target_audience
|
141
|
+
end
|
142
|
+
|
143
|
+
##
|
144
|
+
# Sets the default final target audience for ID tokens, to be used when none
|
145
|
+
# is provided during initialization.
|
146
|
+
#
|
147
|
+
# Either {#scope} or {#target_audience}, but not both, should be non-nil.
|
148
|
+
# If {#scope} is set, this credential will produce access tokens.
|
149
|
+
# If {#target_audience} is set, this credential will produce ID tokens.
|
150
|
+
#
|
151
|
+
# @param [String] new_target_audience
|
152
|
+
#
|
153
|
+
def self.target_audience= new_target_audience
|
154
|
+
@target_audience = new_target_audience
|
155
|
+
end
|
156
|
+
|
122
157
|
##
|
123
158
|
# The environment variables to search for credentials. Values can either be a file path to the
|
124
159
|
# credentials file, or the JSON contents of the credentials file.
|
@@ -185,6 +220,13 @@ module Google
|
|
185
220
|
#
|
186
221
|
attr_reader :project_id
|
187
222
|
|
223
|
+
##
|
224
|
+
# Identifier for a separate project used for billing/quota, if any.
|
225
|
+
#
|
226
|
+
# @return [String,nil]
|
227
|
+
#
|
228
|
+
attr_reader :quota_project_id
|
229
|
+
|
188
230
|
# @private Delegate client methods to the client object.
|
189
231
|
extend Forwardable
|
190
232
|
|
@@ -201,6 +243,9 @@ module Google
|
|
201
243
|
# @return [String, Array<String>] The scope for this client. A scope is an access range
|
202
244
|
# defined by the authorization server. The scope can be a single value or a list of values.
|
203
245
|
#
|
246
|
+
# @!attribute [r] target_audience
|
247
|
+
# @return [String] The final target audience for ID tokens returned by this credential.
|
248
|
+
#
|
204
249
|
# @!attribute [r] issuer
|
205
250
|
# @return [String] The issuer ID associated with this client.
|
206
251
|
#
|
@@ -213,9 +258,7 @@ module Google
|
|
213
258
|
#
|
214
259
|
def_delegators :@client,
|
215
260
|
:token_credential_uri, :audience,
|
216
|
-
:scope, :issuer, :signing_key, :updater_proc
|
217
|
-
|
218
|
-
# rubocop:disable Metrics/AbcSize
|
261
|
+
:scope, :issuer, :signing_key, :updater_proc, :target_audience
|
219
262
|
|
220
263
|
##
|
221
264
|
# Creates a new Credentials instance with the provided auth credentials, and with the default
|
@@ -236,23 +279,15 @@ module Google
|
|
236
279
|
# * +:default_connection+ - the default connection to use for the client
|
237
280
|
#
|
238
281
|
def initialize keyfile, options = {}
|
239
|
-
scope = options[:scope]
|
240
282
|
verify_keyfile_provided! keyfile
|
241
283
|
@project_id = options["project_id"] || options["project"]
|
284
|
+
@quota_project_id = options["quota_project_id"]
|
242
285
|
if keyfile.is_a? Signet::OAuth2::Client
|
243
|
-
|
244
|
-
@project_id ||= keyfile.project_id if keyfile.respond_to? :project_id
|
286
|
+
update_from_signet keyfile
|
245
287
|
elsif keyfile.is_a? Hash
|
246
|
-
|
247
|
-
hash["scope"] ||= scope
|
248
|
-
@client = init_client hash, options
|
249
|
-
@project_id ||= (hash["project_id"] || hash["project"])
|
288
|
+
update_from_hash keyfile, options
|
250
289
|
else
|
251
|
-
|
252
|
-
json = JSON.parse ::File.read(keyfile)
|
253
|
-
json["scope"] ||= scope
|
254
|
-
@project_id ||= (json["project_id"] || json["project"])
|
255
|
-
@client = init_client json, options
|
290
|
+
update_from_filepath keyfile, options
|
256
291
|
end
|
257
292
|
CredentialsLoader.warn_if_cloud_sdk_credentials @client.client_id
|
258
293
|
@project_id ||= CredentialsLoader.load_gcloud_project_id
|
@@ -261,7 +296,6 @@ module Google
|
|
261
296
|
@paths = nil
|
262
297
|
@scope = nil
|
263
298
|
end
|
264
|
-
# rubocop:enable Metrics/AbcSize
|
265
299
|
|
266
300
|
##
|
267
301
|
# Creates a new Credentials instance with auth credentials acquired by searching the
|
@@ -323,7 +357,8 @@ module Google
|
|
323
357
|
# @private Lookup Credentials using Google::Auth.get_application_default.
|
324
358
|
def self.from_application_default options
|
325
359
|
scope = options[:scope] || self.scope
|
326
|
-
|
360
|
+
auth_opts = { target_audience: options[:target_audience] || target_audience }
|
361
|
+
client = Google::Auth.get_application_default scope, auth_opts
|
327
362
|
new client, options
|
328
363
|
end
|
329
364
|
|
@@ -362,14 +397,46 @@ module Google
|
|
362
397
|
options["token_credential_uri"] ||= self.class.token_credential_uri
|
363
398
|
options["audience"] ||= self.class.audience
|
364
399
|
options["scope"] ||= self.class.scope
|
400
|
+
options["target_audience"] ||= self.class.target_audience
|
365
401
|
|
402
|
+
if !Array(options["scope"]).empty? && options["target_audience"]
|
403
|
+
raise ArgumentError, "Cannot specify both scope and target_audience"
|
404
|
+
end
|
405
|
+
|
406
|
+
needs_scope = options["target_audience"].nil?
|
366
407
|
# client options for initializing signet client
|
367
408
|
{ token_credential_uri: options["token_credential_uri"],
|
368
409
|
audience: options["audience"],
|
369
|
-
scope: Array(options["scope"]),
|
410
|
+
scope: (needs_scope ? Array(options["scope"]) : nil),
|
411
|
+
target_audience: options["target_audience"],
|
370
412
|
issuer: options["client_email"],
|
371
413
|
signing_key: OpenSSL::PKey::RSA.new(options["private_key"]) }
|
372
414
|
end
|
415
|
+
|
416
|
+
def update_from_signet client
|
417
|
+
@project_id ||= client.project_id if client.respond_to? :project_id
|
418
|
+
@quota_project_id ||= client.quota_project_id if client.respond_to? :quota_project_id
|
419
|
+
@client = client
|
420
|
+
end
|
421
|
+
|
422
|
+
def update_from_hash hash, options
|
423
|
+
hash = stringify_hash_keys hash
|
424
|
+
hash["scope"] ||= options[:scope]
|
425
|
+
hash["target_audience"] ||= options[:target_audience]
|
426
|
+
@project_id ||= (hash["project_id"] || hash["project"])
|
427
|
+
@quota_project_id ||= hash["quota_project_id"]
|
428
|
+
@client = init_client hash, options
|
429
|
+
end
|
430
|
+
|
431
|
+
def update_from_filepath path, options
|
432
|
+
verify_keyfile_exists! path
|
433
|
+
json = JSON.parse ::File.read(path)
|
434
|
+
json["scope"] ||= options[:scope]
|
435
|
+
json["target_audience"] ||= options[:target_audience]
|
436
|
+
@project_id ||= (json["project_id"] || json["project"])
|
437
|
+
@quota_project_id ||= json["quota_project_id"]
|
438
|
+
@client = init_client json, options
|
439
|
+
end
|
373
440
|
end
|
374
441
|
end
|
375
442
|
end
|
@@ -38,8 +38,12 @@ module Google
|
|
38
38
|
json_key = MultiJson.load json_key_io.read
|
39
39
|
raise "missing client_email" unless json_key.key? "client_email"
|
40
40
|
raise "missing private_key" unless json_key.key? "private_key"
|
41
|
-
|
42
|
-
|
41
|
+
[
|
42
|
+
json_key["private_key"],
|
43
|
+
json_key["client_email"],
|
44
|
+
json_key["project_id"],
|
45
|
+
json_key["quota_project_id"]
|
46
|
+
]
|
43
47
|
end
|
44
48
|
end
|
45
49
|
end
|
@@ -51,28 +51,34 @@ module Google
|
|
51
51
|
extend CredentialsLoader
|
52
52
|
extend JsonKeyReader
|
53
53
|
attr_reader :project_id
|
54
|
+
attr_reader :quota_project_id
|
54
55
|
|
55
56
|
# Creates a ServiceAccountCredentials.
|
56
57
|
#
|
57
58
|
# @param json_key_io [IO] an IO from which the JSON key can be read
|
58
59
|
# @param scope [string|array|nil] the scope(s) to access
|
59
60
|
def self.make_creds options = {}
|
60
|
-
json_key_io, scope = options.values_at :json_key_io, :scope
|
61
|
+
json_key_io, scope, target_audience = options.values_at :json_key_io, :scope, :target_audience
|
62
|
+
raise ArgumentError, "Cannot specify both scope and target_audience" if scope && target_audience
|
63
|
+
|
61
64
|
if json_key_io
|
62
|
-
private_key, client_email, project_id = read_json_key json_key_io
|
65
|
+
private_key, client_email, project_id, quota_project_id = read_json_key json_key_io
|
63
66
|
else
|
64
67
|
private_key = unescape ENV[CredentialsLoader::PRIVATE_KEY_VAR]
|
65
68
|
client_email = ENV[CredentialsLoader::CLIENT_EMAIL_VAR]
|
66
69
|
project_id = ENV[CredentialsLoader::PROJECT_ID_VAR]
|
70
|
+
quota_project_id = nil
|
67
71
|
end
|
68
72
|
project_id ||= CredentialsLoader.load_gcloud_project_id
|
69
73
|
|
70
74
|
new(token_credential_uri: TOKEN_CRED_URI,
|
71
75
|
audience: TOKEN_CRED_URI,
|
72
76
|
scope: scope,
|
77
|
+
target_audience: target_audience,
|
73
78
|
issuer: client_email,
|
74
79
|
signing_key: OpenSSL::PKey::RSA.new(private_key),
|
75
|
-
project_id: project_id
|
80
|
+
project_id: project_id,
|
81
|
+
quota_project_id: quota_project_id)
|
76
82
|
.configure_connection(options)
|
77
83
|
end
|
78
84
|
|
@@ -87,6 +93,7 @@ module Google
|
|
87
93
|
|
88
94
|
def initialize options = {}
|
89
95
|
@project_id = options[:project_id]
|
96
|
+
@quota_project_id = options[:quota_project_id]
|
90
97
|
super options
|
91
98
|
end
|
92
99
|
|
@@ -133,6 +140,7 @@ module Google
|
|
133
140
|
extend CredentialsLoader
|
134
141
|
extend JsonKeyReader
|
135
142
|
attr_reader :project_id
|
143
|
+
attr_reader :quota_project_id
|
136
144
|
|
137
145
|
# make_creds proxies the construction of a credentials instance
|
138
146
|
#
|
@@ -151,12 +159,13 @@ module Google
|
|
151
159
|
def initialize options = {}
|
152
160
|
json_key_io = options[:json_key_io]
|
153
161
|
if json_key_io
|
154
|
-
@private_key, @issuer, @project_id =
|
162
|
+
@private_key, @issuer, @project_id, @quota_project_id =
|
155
163
|
self.class.read_json_key json_key_io
|
156
164
|
else
|
157
165
|
@private_key = ENV[CredentialsLoader::PRIVATE_KEY_VAR]
|
158
166
|
@issuer = ENV[CredentialsLoader::CLIENT_EMAIL_VAR]
|
159
167
|
@project_id = ENV[CredentialsLoader::PROJECT_ID_VAR]
|
168
|
+
@quota_project_id = nil
|
160
169
|
end
|
161
170
|
@project_id ||= CredentialsLoader.load_gcloud_project_id
|
162
171
|
@signing_key = OpenSSL::PKey::RSA.new @private_key
|
data/lib/googleauth/signet.rb
CHANGED
@@ -48,8 +48,9 @@ module Signet
|
|
48
48
|
def apply! a_hash, opts = {}
|
49
49
|
# fetch the access token there is currently not one, or if the client
|
50
50
|
# has expired
|
51
|
-
|
52
|
-
|
51
|
+
token_type = target_audience ? :id_token : :access_token
|
52
|
+
fetch_access_token! opts if send(token_type).nil? || expires_within?(60)
|
53
|
+
a_hash[AUTH_METADATA_KEY] = "Bearer #{send token_type}"
|
53
54
|
end
|
54
55
|
|
55
56
|
# Returns a clone of a_hash updated with the authentication token
|
data/lib/googleauth/version.rb
CHANGED
@@ -45,26 +45,37 @@ shared_examples "apply/apply! are OK" do
|
|
45
45
|
# auth client
|
46
46
|
describe "#fetch_access_token" do
|
47
47
|
let(:token) { "1/abcdef1234567890" }
|
48
|
-
let :
|
48
|
+
let :access_stub do
|
49
49
|
make_auth_stubs access_token: token
|
50
50
|
end
|
51
|
+
let :id_stub do
|
52
|
+
make_auth_stubs id_token: token
|
53
|
+
end
|
51
54
|
|
52
55
|
it "should set access_token to the fetched value" do
|
53
|
-
|
56
|
+
access_stub
|
54
57
|
@client.fetch_access_token!
|
55
58
|
expect(@client.access_token).to eq(token)
|
56
|
-
expect(
|
59
|
+
expect(access_stub).to have_been_requested
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should set id_token to the fetched value" do
|
63
|
+
skip unless @id_client
|
64
|
+
id_stub
|
65
|
+
@id_client.fetch_access_token!
|
66
|
+
expect(@id_client.id_token).to eq(token)
|
67
|
+
expect(id_stub).to have_been_requested
|
57
68
|
end
|
58
69
|
|
59
70
|
it "should notify refresh listeners after updating" do
|
60
|
-
|
71
|
+
access_stub
|
61
72
|
expect do |b|
|
62
73
|
@client.on_refresh(&b)
|
63
74
|
@client.fetch_access_token!
|
64
75
|
end.to yield_with_args(have_attributes(
|
65
76
|
access_token: "1/abcdef1234567890"
|
66
77
|
))
|
67
|
-
expect(
|
78
|
+
expect(access_stub).to have_been_requested
|
68
79
|
end
|
69
80
|
end
|
70
81
|
|
@@ -37,23 +37,32 @@ require "googleauth/compute_engine"
|
|
37
37
|
require "spec_helper"
|
38
38
|
|
39
39
|
describe Google::Auth::GCECredentials do
|
40
|
-
|
40
|
+
MD_ACCESS_URI = "http://169.254.169.254/computeMetadata/v1/instance/service-accounts/default/token".freeze
|
41
|
+
MD_ID_URI = "http://169.254.169.254/computeMetadata/v1/instance/service-accounts/default/identity?audience=https://pubsub.googleapis.com/&format=full".freeze
|
41
42
|
GCECredentials = Google::Auth::GCECredentials
|
42
43
|
|
43
44
|
before :example do
|
44
45
|
@client = GCECredentials.new
|
46
|
+
@id_client = GCECredentials.new target_audience: "https://pubsub.googleapis.com/"
|
45
47
|
end
|
46
48
|
|
47
|
-
def make_auth_stubs opts
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
49
|
+
def make_auth_stubs opts
|
50
|
+
if opts[:access_token]
|
51
|
+
body = MultiJson.dump("access_token" => opts[:access_token],
|
52
|
+
"token_type" => "Bearer",
|
53
|
+
"expires_in" => 3600)
|
54
|
+
stub_request(:get, MD_ACCESS_URI)
|
55
|
+
.with(headers: { "Metadata-Flavor" => "Google" })
|
56
|
+
.to_return(body: body,
|
57
|
+
status: 200,
|
58
|
+
headers: { "Content-Type" => "application/json" })
|
59
|
+
elsif opts[:id_token]
|
60
|
+
stub_request(:get, MD_ID_URI)
|
61
|
+
.with(headers: { "Metadata-Flavor" => "Google" })
|
62
|
+
.to_return(body: opts[:id_token],
|
63
|
+
status: 200,
|
64
|
+
headers: { "Content-Type" => "text/html" })
|
65
|
+
end
|
57
66
|
end
|
58
67
|
|
59
68
|
it_behaves_like "apply/apply! are OK"
|
@@ -61,7 +70,7 @@ describe Google::Auth::GCECredentials do
|
|
61
70
|
context "metadata is unavailable" do
|
62
71
|
describe "#fetch_access_token" do
|
63
72
|
it "should fail if the metadata request returns a 404" do
|
64
|
-
stub = stub_request(:get,
|
73
|
+
stub = stub_request(:get, MD_ACCESS_URI)
|
65
74
|
.to_return(status: 404,
|
66
75
|
headers: { "Metadata-Flavor" => "Google" })
|
67
76
|
expect { @client.fetch_access_token! }
|
@@ -70,7 +79,7 @@ describe Google::Auth::GCECredentials do
|
|
70
79
|
end
|
71
80
|
|
72
81
|
it "should fail if the metadata request returns an unexpected code" do
|
73
|
-
stub = stub_request(:get,
|
82
|
+
stub = stub_request(:get, MD_ACCESS_URI)
|
74
83
|
.to_return(status: 503,
|
75
84
|
headers: { "Metadata-Flavor" => "Google" })
|
76
85
|
expect { @client.fetch_access_token! }
|
@@ -36,12 +36,13 @@ require "googleauth"
|
|
36
36
|
describe Google::Auth::Credentials, :private do
|
37
37
|
let :default_keyfile_hash do
|
38
38
|
{
|
39
|
-
"private_key_id"
|
40
|
-
"private_key"
|
41
|
-
"client_email"
|
42
|
-
"client_id"
|
43
|
-
"type"
|
44
|
-
"project_id"
|
39
|
+
"private_key_id" => "testabc1234567890xyz",
|
40
|
+
"private_key" => "-----BEGIN RSA PRIVATE KEY-----\nMIIBOwIBAAJBAOyi0Hy1l4Ym2m2o71Q0TF4O9E81isZEsX0bb+Bqz1SXEaSxLiXM\nUZE8wu0eEXivXuZg6QVCW/5l+f2+9UPrdNUCAwEAAQJAJkqubA/Chj3RSL92guy3\nktzeodarLyw8gF8pOmpuRGSiEo/OLTeRUMKKD1/kX4f9sxf3qDhB4e7dulXR1co/\nIQIhAPx8kMW4XTTL6lJYd2K5GrH8uBMp8qL5ya3/XHrBgw3dAiEA7+3Iw3ULTn2I\n1J34WlJ2D5fbzMzB4FAHUNEV7Ys3f1kCIQDtUahCMChrl7+H5t9QS+xrn77lRGhs\nB50pjvy95WXpgQIhAI2joW6JzTfz8fAapb+kiJ/h9Vcs1ZN3iyoRlNFb61JZAiA8\nNy5NyNrMVwtB/lfJf1dAK/p/Bwd8LZLtgM6PapRfgw==\n-----END RSA PRIVATE KEY-----\n",
|
41
|
+
"client_email" => "credz-testabc1234567890xyz@developer.gserviceaccount.com",
|
42
|
+
"client_id" => "credz-testabc1234567890xyz.apps.googleusercontent.com",
|
43
|
+
"type" => "service_account",
|
44
|
+
"project_id" => "a_project_id",
|
45
|
+
"quota_project_id" => "b_project_id"
|
45
46
|
}
|
46
47
|
end
|
47
48
|
|
@@ -118,6 +119,7 @@ describe Google::Auth::Credentials, :private do
|
|
118
119
|
expect(creds).to be_a_kind_of(TestCredentials1)
|
119
120
|
expect(creds.client).to eq(mocked_signet)
|
120
121
|
expect(creds.project_id).to eq(default_keyfile_hash["project_id"])
|
122
|
+
expect(creds.quota_project_id).to eq(default_keyfile_hash["quota_project_id"])
|
121
123
|
end
|
122
124
|
|
123
125
|
it "subclasses can use PATH_ENV_VARS to get keyfile path" do
|
@@ -153,6 +155,7 @@ describe Google::Auth::Credentials, :private do
|
|
153
155
|
expect(creds).to be_a_kind_of(TestCredentials2)
|
154
156
|
expect(creds.client).to eq(mocked_signet)
|
155
157
|
expect(creds.project_id).to eq(default_keyfile_hash["project_id"])
|
158
|
+
expect(creds.quota_project_id).to eq(default_keyfile_hash["quota_project_id"])
|
156
159
|
end
|
157
160
|
|
158
161
|
it "subclasses can use JSON_ENV_VARS to get keyfile contents" do
|
@@ -190,6 +193,7 @@ describe Google::Auth::Credentials, :private do
|
|
190
193
|
expect(creds).to be_a_kind_of(TestCredentials3)
|
191
194
|
expect(creds.client).to eq(mocked_signet)
|
192
195
|
expect(creds.project_id).to eq(default_keyfile_hash["project_id"])
|
196
|
+
expect(creds.quota_project_id).to eq(default_keyfile_hash["quota_project_id"])
|
193
197
|
end
|
194
198
|
|
195
199
|
it "subclasses can use DEFAULT_PATHS to get keyfile path" do
|
@@ -225,6 +229,7 @@ describe Google::Auth::Credentials, :private do
|
|
225
229
|
expect(creds).to be_a_kind_of(TestCredentials4)
|
226
230
|
expect(creds.client).to eq(mocked_signet)
|
227
231
|
expect(creds.project_id).to eq(default_keyfile_hash["project_id"])
|
232
|
+
expect(creds.quota_project_id).to eq(default_keyfile_hash["quota_project_id"])
|
228
233
|
end
|
229
234
|
|
230
235
|
it "subclasses that find no matches default to Google::Auth.get_application_default" do
|
@@ -266,6 +271,7 @@ describe Google::Auth::Credentials, :private do
|
|
266
271
|
expect(creds).to be_a_kind_of(TestCredentials5)
|
267
272
|
expect(creds.client).to eq(mocked_signet)
|
268
273
|
expect(creds.project_id).to eq(default_keyfile_hash["project_id"])
|
274
|
+
expect(creds.quota_project_id).to eq(default_keyfile_hash["quota_project_id"])
|
269
275
|
end
|
270
276
|
end
|
271
277
|
|
@@ -305,6 +311,7 @@ describe Google::Auth::Credentials, :private do
|
|
305
311
|
expect(creds).to be_a_kind_of(TestCredentials11)
|
306
312
|
expect(creds.client).to eq(mocked_signet)
|
307
313
|
expect(creds.project_id).to eq(default_keyfile_hash["project_id"])
|
314
|
+
expect(creds.quota_project_id).to eq(default_keyfile_hash["quota_project_id"])
|
308
315
|
end
|
309
316
|
|
310
317
|
it "subclasses can use PATH_ENV_VARS to get keyfile path" do
|
@@ -339,6 +346,7 @@ describe Google::Auth::Credentials, :private do
|
|
339
346
|
expect(creds).to be_a_kind_of(TestCredentials12)
|
340
347
|
expect(creds.client).to eq(mocked_signet)
|
341
348
|
expect(creds.project_id).to eq(default_keyfile_hash["project_id"])
|
349
|
+
expect(creds.quota_project_id).to eq(default_keyfile_hash["quota_project_id"])
|
342
350
|
end
|
343
351
|
|
344
352
|
it "subclasses can use JSON_ENV_VARS to get keyfile contents" do
|
@@ -375,6 +383,7 @@ describe Google::Auth::Credentials, :private do
|
|
375
383
|
expect(creds).to be_a_kind_of(TestCredentials13)
|
376
384
|
expect(creds.client).to eq(mocked_signet)
|
377
385
|
expect(creds.project_id).to eq(default_keyfile_hash["project_id"])
|
386
|
+
expect(creds.quota_project_id).to eq(default_keyfile_hash["quota_project_id"])
|
378
387
|
end
|
379
388
|
|
380
389
|
it "subclasses can use DEFAULT_PATHS to get keyfile path" do
|
@@ -409,6 +418,7 @@ describe Google::Auth::Credentials, :private do
|
|
409
418
|
expect(creds).to be_a_kind_of(TestCredentials14)
|
410
419
|
expect(creds.client).to eq(mocked_signet)
|
411
420
|
expect(creds.project_id).to eq(default_keyfile_hash["project_id"])
|
421
|
+
expect(creds.quota_project_id).to eq(default_keyfile_hash["quota_project_id"])
|
412
422
|
end
|
413
423
|
|
414
424
|
it "subclasses that find no matches default to Google::Auth.get_application_default" do
|
@@ -449,6 +459,7 @@ describe Google::Auth::Credentials, :private do
|
|
449
459
|
expect(creds).to be_a_kind_of(TestCredentials15)
|
450
460
|
expect(creds.client).to eq(mocked_signet)
|
451
461
|
expect(creds.project_id).to eq(default_keyfile_hash["project_id"])
|
462
|
+
expect(creds.quota_project_id).to eq(default_keyfile_hash["quota_project_id"])
|
452
463
|
end
|
453
464
|
end
|
454
465
|
|
@@ -112,12 +112,13 @@ describe Google::Auth::ServiceAccountCredentials do
|
|
112
112
|
let(:client_email) { "app@developer.gserviceaccount.com" }
|
113
113
|
let :cred_json do
|
114
114
|
{
|
115
|
-
private_key_id:
|
116
|
-
private_key:
|
117
|
-
client_email:
|
118
|
-
client_id:
|
119
|
-
type:
|
120
|
-
project_id:
|
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"
|
121
122
|
}
|
122
123
|
end
|
123
124
|
|
@@ -127,24 +128,28 @@ describe Google::Auth::ServiceAccountCredentials do
|
|
127
128
|
json_key_io: StringIO.new(cred_json_text),
|
128
129
|
scope: "https://www.googleapis.com/auth/userinfo.profile"
|
129
130
|
)
|
131
|
+
@id_client = ServiceAccountCredentials.make_creds(
|
132
|
+
json_key_io: StringIO.new(cred_json_text),
|
133
|
+
target_audience: "https://pubsub.googleapis.com/"
|
134
|
+
)
|
130
135
|
end
|
131
136
|
|
132
|
-
def make_auth_stubs opts
|
133
|
-
|
134
|
-
|
135
|
-
|
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
|
137
142
|
blk = proc do |request|
|
138
143
|
params = Addressable::URI.form_unencode request.body
|
139
|
-
|
140
|
-
|
141
|
-
|
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/"
|
142
148
|
end
|
143
149
|
stub_request(:post, "https://www.googleapis.com/oauth2/v4/token")
|
144
150
|
.with(body: hash_including(
|
145
151
|
"grant_type" => "urn:ietf:params:oauth:grant-type:jwt-bearer"
|
146
|
-
),
|
147
|
-
&blk)
|
152
|
+
), &blk)
|
148
153
|
.to_return(body: body,
|
149
154
|
status: 200,
|
150
155
|
headers: { "Content-Type" => "application/json" })
|
@@ -285,6 +290,7 @@ describe Google::Auth::ServiceAccountCredentials do
|
|
285
290
|
ENV["APPDATA"] = dir
|
286
291
|
credentials = @clz.from_well_known_path @scope
|
287
292
|
expect(credentials.project_id).to eq(cred_json[:project_id])
|
293
|
+
expect(credentials.quota_project_id).to eq(cred_json[:quota_project_id])
|
288
294
|
end
|
289
295
|
end
|
290
296
|
|
@@ -476,6 +482,7 @@ describe Google::Auth::ServiceAccountJwtHeaderCredentials do
|
|
476
482
|
ENV["APPDATA"] = dir
|
477
483
|
credentials = clz.from_well_known_path @scope
|
478
484
|
expect(credentials.project_id).to eq(cred_json[:project_id])
|
485
|
+
expect(credentials.quota_project_id).to be_nil
|
479
486
|
end
|
480
487
|
end
|
481
488
|
end
|
@@ -47,18 +47,26 @@ describe Signet::OAuth2::Client do
|
|
47
47
|
audience: "https://oauth2.googleapis.com/token",
|
48
48
|
signing_key: @key
|
49
49
|
)
|
50
|
+
@id_client = Signet::OAuth2::Client.new(
|
51
|
+
token_credential_uri: "https://oauth2.googleapis.com/token",
|
52
|
+
target_audience: "https://pubsub.googleapis.com/",
|
53
|
+
issuer: "app@example.com",
|
54
|
+
audience: "https://oauth2.googleapis.com/token",
|
55
|
+
signing_key: @key
|
56
|
+
)
|
50
57
|
end
|
51
58
|
|
52
59
|
def make_auth_stubs opts
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
60
|
+
body_fields = { "token_type" => "Bearer", "expires_in" => 3600 }
|
61
|
+
body_fields["access_token"] = opts[:access_token] if opts[:access_token]
|
62
|
+
body_fields["id_token"] = opts[:id_token] if opts[:id_token]
|
63
|
+
body = MultiJson.dump body_fields
|
57
64
|
blk = proc do |request|
|
58
65
|
params = Addressable::URI.form_unencode request.body
|
59
|
-
|
60
|
-
|
61
|
-
|
66
|
+
claim, _header = JWT.decode(params.assoc("assertion").last,
|
67
|
+
@key.public_key, true,
|
68
|
+
algorithm: "RS256")
|
69
|
+
!opts[:id_token] || claim["target_audience"] == "https://pubsub.googleapis.com/"
|
62
70
|
end
|
63
71
|
with_params = { body: hash_including(
|
64
72
|
"grant_type" => "urn:ietf:params:oauth:grant-type:jwt-bearer"
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: googleauth
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.12.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tim Emiola
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-04-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: faraday
|
@@ -104,14 +104,14 @@ dependencies:
|
|
104
104
|
requirements:
|
105
105
|
- - "~>"
|
106
106
|
- !ruby/object:Gem::Version
|
107
|
-
version: '0.
|
107
|
+
version: '0.14'
|
108
108
|
type: :runtime
|
109
109
|
prerelease: false
|
110
110
|
version_requirements: !ruby/object:Gem::Requirement
|
111
111
|
requirements:
|
112
112
|
- - "~>"
|
113
113
|
- !ruby/object:Gem::Version
|
114
|
-
version: '0.
|
114
|
+
version: '0.14'
|
115
115
|
- !ruby/object:Gem::Dependency
|
116
116
|
name: yard
|
117
117
|
requirement: !ruby/object:Gem::Requirement
|
@@ -203,7 +203,7 @@ files:
|
|
203
203
|
- spec/googleauth/user_refresh_spec.rb
|
204
204
|
- spec/googleauth/web_user_authorizer_spec.rb
|
205
205
|
- spec/spec_helper.rb
|
206
|
-
homepage: https://github.com/
|
206
|
+
homepage: https://github.com/googleapis/google-auth-library-ruby
|
207
207
|
licenses:
|
208
208
|
- Apache-2.0
|
209
209
|
metadata: {}
|