googleauth 0.5.1 → 0.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/.github/CODEOWNERS +7 -0
- data/{CONTRIBUTING.md → .github/CONTRIBUTING.md} +5 -4
- data/.github/ISSUE_TEMPLATE/bug_report.md +36 -0
- data/.github/ISSUE_TEMPLATE/feature_request.md +21 -0
- data/.github/ISSUE_TEMPLATE/support_request.md +7 -0
- data/.kokoro/build.bat +16 -0
- data/.kokoro/build.sh +4 -0
- data/.kokoro/continuous/common.cfg +24 -0
- data/.kokoro/continuous/linux.cfg +25 -0
- data/.kokoro/continuous/osx.cfg +8 -0
- data/.kokoro/continuous/post.cfg +30 -0
- data/.kokoro/continuous/windows.cfg +29 -0
- data/.kokoro/osx.sh +4 -0
- data/.kokoro/presubmit/common.cfg +24 -0
- data/.kokoro/presubmit/linux.cfg +24 -0
- data/.kokoro/presubmit/osx.cfg +8 -0
- data/.kokoro/presubmit/windows.cfg +29 -0
- data/.kokoro/release.cfg +94 -0
- data/.kokoro/trampoline.bat +10 -0
- data/.kokoro/trampoline.sh +4 -0
- data/.repo-metadata.json +5 -0
- data/.rubocop.yml +19 -1
- data/CHANGELOG.md +112 -19
- data/CODE_OF_CONDUCT.md +43 -0
- data/Gemfile +19 -13
- data/{COPYING → LICENSE} +0 -0
- data/README.md +58 -18
- data/Rakefile +126 -9
- data/googleauth.gemspec +28 -25
- data/integration/helper.rb +31 -0
- data/integration/id_tokens/key_source_test.rb +74 -0
- data/lib/googleauth.rb +7 -96
- data/lib/googleauth/application_default.rb +81 -0
- data/lib/googleauth/client_id.rb +21 -19
- data/lib/googleauth/compute_engine.rb +70 -43
- data/lib/googleauth/credentials.rb +442 -0
- data/lib/googleauth/credentials_loader.rb +117 -43
- data/lib/googleauth/default_credentials.rb +93 -0
- data/lib/googleauth/iam.rb +11 -11
- data/lib/googleauth/id_tokens.rb +233 -0
- data/lib/googleauth/id_tokens/errors.rb +71 -0
- data/lib/googleauth/id_tokens/key_sources.rb +394 -0
- data/lib/googleauth/id_tokens/verifier.rb +144 -0
- data/lib/googleauth/json_key_reader.rb +50 -0
- data/lib/googleauth/scope_util.rb +12 -12
- data/lib/googleauth/service_account.rb +74 -63
- data/lib/googleauth/signet.rb +55 -13
- data/lib/googleauth/stores/file_token_store.rb +8 -8
- data/lib/googleauth/stores/redis_token_store.rb +22 -22
- data/lib/googleauth/token_store.rb +6 -6
- data/lib/googleauth/user_authorizer.rb +80 -68
- data/lib/googleauth/user_refresh.rb +44 -35
- data/lib/googleauth/version.rb +1 -1
- data/lib/googleauth/web_user_authorizer.rb +77 -68
- data/rakelib/devsite_builder.rb +45 -0
- data/rakelib/link_checker.rb +64 -0
- data/rakelib/repo_metadata.rb +59 -0
- data/spec/googleauth/apply_auth_examples.rb +74 -50
- data/spec/googleauth/client_id_spec.rb +75 -55
- data/spec/googleauth/compute_engine_spec.rb +98 -46
- data/spec/googleauth/credentials_spec.rb +478 -0
- data/spec/googleauth/get_application_default_spec.rb +149 -111
- data/spec/googleauth/iam_spec.rb +25 -25
- data/spec/googleauth/scope_util_spec.rb +26 -24
- data/spec/googleauth/service_account_spec.rb +269 -144
- data/spec/googleauth/signet_spec.rb +101 -30
- data/spec/googleauth/stores/file_token_store_spec.rb +12 -13
- data/spec/googleauth/stores/redis_token_store_spec.rb +11 -11
- data/spec/googleauth/stores/store_examples.rb +16 -16
- data/spec/googleauth/user_authorizer_spec.rb +153 -124
- data/spec/googleauth/user_refresh_spec.rb +186 -121
- data/spec/googleauth/web_user_authorizer_spec.rb +82 -69
- data/spec/spec_helper.rb +21 -19
- data/test/helper.rb +33 -0
- data/test/id_tokens/key_sources_test.rb +240 -0
- data/test/id_tokens/verifier_test.rb +269 -0
- metadata +87 -34
- data/.rubocop_todo.yml +0 -32
- data/.travis.yml +0 -37
@@ -0,0 +1,50 @@
|
|
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
|
+
module Google
|
31
|
+
# Module Auth provides classes that provide Google-specific authorization
|
32
|
+
# used to access Google APIs.
|
33
|
+
module Auth
|
34
|
+
# JsonKeyReader contains the behaviour used to read private key and
|
35
|
+
# client email fields from the service account
|
36
|
+
module JsonKeyReader
|
37
|
+
def read_json_key json_key_io
|
38
|
+
json_key = MultiJson.load json_key_io.read
|
39
|
+
raise "missing client_email" unless json_key.key? "client_email"
|
40
|
+
raise "missing private_key" unless json_key.key? "private_key"
|
41
|
+
[
|
42
|
+
json_key["private_key"],
|
43
|
+
json_key["client_email"],
|
44
|
+
json_key["project_id"],
|
45
|
+
json_key["quota_project_id"]
|
46
|
+
]
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -27,33 +27,33 @@
|
|
27
27
|
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
28
28
|
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
29
29
|
|
30
|
-
require
|
31
|
-
require
|
32
|
-
require
|
30
|
+
require "googleauth/signet"
|
31
|
+
require "googleauth/credentials_loader"
|
32
|
+
require "multi_json"
|
33
33
|
|
34
34
|
module Google
|
35
35
|
module Auth
|
36
36
|
# Small utility for normalizing scopes into canonical form
|
37
37
|
module ScopeUtil
|
38
38
|
ALIASES = {
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
}
|
39
|
+
"email" => "https://www.googleapis.com/auth/userinfo.email",
|
40
|
+
"profile" => "https://www.googleapis.com/auth/userinfo.profile",
|
41
|
+
"openid" => "https://www.googleapis.com/auth/plus.me"
|
42
|
+
}.freeze
|
43
43
|
|
44
|
-
def self.normalize
|
45
|
-
list = as_array
|
44
|
+
def self.normalize scope
|
45
|
+
list = as_array scope
|
46
46
|
list.map { |item| ALIASES[item] || item }
|
47
47
|
end
|
48
48
|
|
49
|
-
def self.as_array
|
49
|
+
def self.as_array scope
|
50
50
|
case scope
|
51
51
|
when Array
|
52
52
|
scope
|
53
53
|
when String
|
54
|
-
scope.split
|
54
|
+
scope.split " "
|
55
55
|
else
|
56
|
-
|
56
|
+
raise "Invalid scope value. Must be string or array"
|
57
57
|
end
|
58
58
|
end
|
59
59
|
end
|
@@ -27,11 +27,12 @@
|
|
27
27
|
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
28
28
|
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
29
29
|
|
30
|
-
require
|
31
|
-
require
|
32
|
-
require
|
33
|
-
require
|
34
|
-
require
|
30
|
+
require "googleauth/signet"
|
31
|
+
require "googleauth/credentials_loader"
|
32
|
+
require "googleauth/json_key_reader"
|
33
|
+
require "jwt"
|
34
|
+
require "multi_json"
|
35
|
+
require "stringio"
|
35
36
|
|
36
37
|
module Google
|
37
38
|
# Module Auth provides classes that provide Google-specific authorization
|
@@ -44,42 +45,56 @@ module Google
|
|
44
45
|
# from credentials from a json key file downloaded from the developer
|
45
46
|
# console (via 'Generate new Json Key').
|
46
47
|
#
|
47
|
-
# cf [Application Default Credentials](
|
48
|
+
# cf [Application Default Credentials](https://cloud.google.com/docs/authentication/production)
|
48
49
|
class ServiceAccountCredentials < Signet::OAuth2::Client
|
49
|
-
TOKEN_CRED_URI =
|
50
|
+
TOKEN_CRED_URI = "https://www.googleapis.com/oauth2/v4/token".freeze
|
50
51
|
extend CredentialsLoader
|
52
|
+
extend JsonKeyReader
|
53
|
+
attr_reader :project_id
|
54
|
+
attr_reader :quota_project_id
|
51
55
|
|
52
56
|
# Creates a ServiceAccountCredentials.
|
53
57
|
#
|
54
58
|
# @param json_key_io [IO] an IO from which the JSON key can be read
|
55
59
|
# @param scope [string|array|nil] the scope(s) to access
|
56
|
-
def self.make_creds
|
57
|
-
json_key_io, scope = options.values_at
|
60
|
+
def self.make_creds options = {}
|
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
|
+
|
58
64
|
if json_key_io
|
59
|
-
private_key, client_email = read_json_key
|
65
|
+
private_key, client_email, project_id, quota_project_id = read_json_key json_key_io
|
60
66
|
else
|
61
|
-
private_key = ENV[CredentialsLoader::PRIVATE_KEY_VAR]
|
67
|
+
private_key = unescape ENV[CredentialsLoader::PRIVATE_KEY_VAR]
|
62
68
|
client_email = ENV[CredentialsLoader::CLIENT_EMAIL_VAR]
|
69
|
+
project_id = ENV[CredentialsLoader::PROJECT_ID_VAR]
|
70
|
+
quota_project_id = nil
|
63
71
|
end
|
72
|
+
project_id ||= CredentialsLoader.load_gcloud_project_id
|
64
73
|
|
65
74
|
new(token_credential_uri: TOKEN_CRED_URI,
|
66
|
-
audience:
|
67
|
-
scope:
|
68
|
-
|
69
|
-
|
75
|
+
audience: TOKEN_CRED_URI,
|
76
|
+
scope: scope,
|
77
|
+
target_audience: target_audience,
|
78
|
+
issuer: client_email,
|
79
|
+
signing_key: OpenSSL::PKey::RSA.new(private_key),
|
80
|
+
project_id: project_id,
|
81
|
+
quota_project_id: quota_project_id)
|
82
|
+
.configure_connection(options)
|
70
83
|
end
|
71
84
|
|
72
|
-
#
|
73
|
-
#
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
85
|
+
# Handles certain escape sequences that sometimes appear in input.
|
86
|
+
# Specifically, interprets the "\n" sequence for newline, and removes
|
87
|
+
# enclosing quotes.
|
88
|
+
def self.unescape str
|
89
|
+
str = str.gsub '\n', "\n"
|
90
|
+
str = str[1..-2] if str.start_with?('"') && str.end_with?('"')
|
91
|
+
str
|
79
92
|
end
|
80
93
|
|
81
|
-
def initialize
|
82
|
-
|
94
|
+
def initialize options = {}
|
95
|
+
@project_id = options[:project_id]
|
96
|
+
@quota_project_id = options[:quota_project_id]
|
97
|
+
super options
|
83
98
|
end
|
84
99
|
|
85
100
|
# Extends the base class.
|
@@ -87,9 +102,9 @@ module Google
|
|
87
102
|
# If scope(s) is not set, it creates a transient
|
88
103
|
# ServiceAccountJwtHeaderCredentials instance and uses that to
|
89
104
|
# authenticate instead.
|
90
|
-
def apply!
|
105
|
+
def apply! a_hash, opts = {}
|
91
106
|
# Use the base implementation if scopes are set
|
92
|
-
unless scope.nil?
|
107
|
+
unless scope.nil? && target_audience.nil?
|
93
108
|
super
|
94
109
|
return
|
95
110
|
end
|
@@ -97,13 +112,13 @@ module Google
|
|
97
112
|
# Use the ServiceAccountJwtHeaderCredentials using the same cred values
|
98
113
|
# if no scopes are set.
|
99
114
|
cred_json = {
|
100
|
-
private_key:
|
115
|
+
private_key: @signing_key.to_s,
|
101
116
|
client_email: @issuer
|
102
117
|
}
|
103
118
|
alt_clz = ServiceAccountJwtHeaderCredentials
|
104
|
-
key_io = StringIO.new
|
105
|
-
alt = alt_clz.make_creds
|
106
|
-
alt.apply!
|
119
|
+
key_io = StringIO.new MultiJson.dump(cred_json)
|
120
|
+
alt = alt_clz.make_creds json_key_io: key_io
|
121
|
+
alt.apply! a_hash
|
107
122
|
end
|
108
123
|
end
|
109
124
|
|
@@ -115,14 +130,17 @@ module Google
|
|
115
130
|
# console (via 'Generate new Json Key'). It is not part of any OAuth2
|
116
131
|
# flow, rather it creates a JWT and sends that as a credential.
|
117
132
|
#
|
118
|
-
# cf [Application Default Credentials](
|
133
|
+
# cf [Application Default Credentials](https://cloud.google.com/docs/authentication/production)
|
119
134
|
class ServiceAccountJwtHeaderCredentials
|
120
135
|
JWT_AUD_URI_KEY = :jwt_aud_uri
|
121
136
|
AUTH_METADATA_KEY = Signet::OAuth2::AUTH_METADATA_KEY
|
122
|
-
TOKEN_CRED_URI =
|
123
|
-
SIGNING_ALGORITHM =
|
137
|
+
TOKEN_CRED_URI = "https://www.googleapis.com/oauth2/v4/token".freeze
|
138
|
+
SIGNING_ALGORITHM = "RS256".freeze
|
124
139
|
EXPIRY = 60
|
125
140
|
extend CredentialsLoader
|
141
|
+
extend JsonKeyReader
|
142
|
+
attr_reader :project_id
|
143
|
+
attr_reader :quota_project_id
|
126
144
|
|
127
145
|
# make_creds proxies the construction of a credentials instance
|
128
146
|
#
|
@@ -131,51 +149,44 @@ module Google
|
|
131
149
|
# By default, it calls #new with 2 args, the second one being an
|
132
150
|
# optional scope. Here's the constructor only has one param, so
|
133
151
|
# we modify make_creds to reflect this.
|
134
|
-
def self.make_creds
|
135
|
-
new
|
136
|
-
end
|
137
|
-
|
138
|
-
# Reads the private key and client email fields from the service account
|
139
|
-
# JSON key.
|
140
|
-
def self.read_json_key(json_key_io)
|
141
|
-
json_key = MultiJson.load(json_key_io.read)
|
142
|
-
fail 'missing client_email' unless json_key.key?('client_email')
|
143
|
-
fail 'missing private_key' unless json_key.key?('private_key')
|
144
|
-
[json_key['private_key'], json_key['client_email']]
|
152
|
+
def self.make_creds *args
|
153
|
+
new json_key_io: args[0][:json_key_io]
|
145
154
|
end
|
146
155
|
|
147
156
|
# Initializes a ServiceAccountJwtHeaderCredentials.
|
148
157
|
#
|
149
158
|
# @param json_key_io [IO] an IO from which the JSON key can be read
|
150
|
-
def initialize
|
159
|
+
def initialize options = {}
|
151
160
|
json_key_io = options[:json_key_io]
|
152
161
|
if json_key_io
|
153
|
-
private_key,
|
162
|
+
@private_key, @issuer, @project_id, @quota_project_id =
|
163
|
+
self.class.read_json_key json_key_io
|
154
164
|
else
|
155
|
-
private_key = ENV[CredentialsLoader::PRIVATE_KEY_VAR]
|
156
|
-
|
165
|
+
@private_key = ENV[CredentialsLoader::PRIVATE_KEY_VAR]
|
166
|
+
@issuer = ENV[CredentialsLoader::CLIENT_EMAIL_VAR]
|
167
|
+
@project_id = ENV[CredentialsLoader::PROJECT_ID_VAR]
|
168
|
+
@quota_project_id = nil
|
157
169
|
end
|
158
|
-
@
|
159
|
-
@
|
160
|
-
@signing_key = OpenSSL::PKey::RSA.new(private_key)
|
170
|
+
@project_id ||= CredentialsLoader.load_gcloud_project_id
|
171
|
+
@signing_key = OpenSSL::PKey::RSA.new @private_key
|
161
172
|
end
|
162
173
|
|
163
174
|
# Construct a jwt token if the JWT_AUD_URI key is present in the input
|
164
175
|
# hash.
|
165
176
|
#
|
166
177
|
# The jwt token is used as the value of a 'Bearer '.
|
167
|
-
def apply!
|
168
|
-
jwt_aud_uri = a_hash.delete
|
178
|
+
def apply! a_hash, opts = {}
|
179
|
+
jwt_aud_uri = a_hash.delete JWT_AUD_URI_KEY
|
169
180
|
return a_hash if jwt_aud_uri.nil?
|
170
|
-
jwt_token = new_jwt_token
|
181
|
+
jwt_token = new_jwt_token jwt_aud_uri, opts
|
171
182
|
a_hash[AUTH_METADATA_KEY] = "Bearer #{jwt_token}"
|
172
183
|
a_hash
|
173
184
|
end
|
174
185
|
|
175
186
|
# Returns a clone of a_hash updated with the authoriation header
|
176
|
-
def apply
|
187
|
+
def apply a_hash, opts = {}
|
177
188
|
a_copy = a_hash.clone
|
178
|
-
apply!
|
189
|
+
apply! a_copy, opts
|
179
190
|
a_copy
|
180
191
|
end
|
181
192
|
|
@@ -188,17 +199,17 @@ module Google
|
|
188
199
|
protected
|
189
200
|
|
190
201
|
# Creates a jwt uri token.
|
191
|
-
def new_jwt_token
|
202
|
+
def new_jwt_token jwt_aud_uri, options = {}
|
192
203
|
now = Time.new
|
193
204
|
skew = options[:skew] || 60
|
194
205
|
assertion = {
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
206
|
+
"iss" => @issuer,
|
207
|
+
"sub" => @issuer,
|
208
|
+
"aud" => jwt_aud_uri,
|
209
|
+
"exp" => (now + EXPIRY).to_i,
|
210
|
+
"iat" => (now - skew).to_i
|
200
211
|
}
|
201
|
-
JWT.encode
|
212
|
+
JWT.encode assertion, @signing_key, SIGNING_ALGORITHM
|
202
213
|
end
|
203
214
|
end
|
204
215
|
end
|
data/lib/googleauth/signet.rb
CHANGED
@@ -27,7 +27,7 @@
|
|
27
27
|
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
28
28
|
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
29
29
|
|
30
|
-
require
|
30
|
+
require "signet/oauth_2/client"
|
31
31
|
|
32
32
|
module Signet
|
33
33
|
# OAuth2 supports OAuth2 authentication.
|
@@ -38,18 +38,25 @@ module Signet
|
|
38
38
|
# This reopens Client to add #apply and #apply! methods which update a
|
39
39
|
# hash with the fetched authentication token.
|
40
40
|
class Client
|
41
|
+
def configure_connection options
|
42
|
+
@connection_info =
|
43
|
+
options[:connection_builder] || options[:default_connection]
|
44
|
+
self
|
45
|
+
end
|
46
|
+
|
41
47
|
# Updates a_hash updated with the authentication token
|
42
|
-
def apply!
|
48
|
+
def apply! a_hash, opts = {}
|
43
49
|
# fetch the access token there is currently not one, or if the client
|
44
50
|
# has expired
|
45
|
-
|
46
|
-
|
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}"
|
47
54
|
end
|
48
55
|
|
49
56
|
# Returns a clone of a_hash updated with the authentication token
|
50
|
-
def apply
|
57
|
+
def apply a_hash, opts = {}
|
51
58
|
a_copy = a_hash.clone
|
52
|
-
apply!
|
59
|
+
apply! a_copy, opts
|
53
60
|
a_copy
|
54
61
|
end
|
55
62
|
|
@@ -59,22 +66,57 @@ module Signet
|
|
59
66
|
lambda(&method(:apply))
|
60
67
|
end
|
61
68
|
|
62
|
-
def on_refresh
|
63
|
-
@refresh_listeners
|
69
|
+
def on_refresh &block
|
70
|
+
@refresh_listeners = [] unless defined? @refresh_listeners
|
64
71
|
@refresh_listeners << block
|
65
72
|
end
|
66
73
|
|
67
|
-
|
68
|
-
def fetch_access_token!
|
69
|
-
|
74
|
+
alias orig_fetch_access_token! fetch_access_token!
|
75
|
+
def fetch_access_token! options = {}
|
76
|
+
unless options[:connection]
|
77
|
+
connection = build_default_connection
|
78
|
+
options = options.merge connection: connection if connection
|
79
|
+
end
|
80
|
+
info = retry_with_error do
|
81
|
+
orig_fetch_access_token! options
|
82
|
+
end
|
70
83
|
notify_refresh_listeners
|
71
84
|
info
|
72
85
|
end
|
73
86
|
|
74
87
|
def notify_refresh_listeners
|
75
|
-
listeners = @refresh_listeners
|
88
|
+
listeners = defined?(@refresh_listeners) ? @refresh_listeners : []
|
76
89
|
listeners.each do |block|
|
77
|
-
block.call
|
90
|
+
block.call self
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def build_default_connection
|
95
|
+
if !defined?(@connection_info)
|
96
|
+
nil
|
97
|
+
elsif @connection_info.respond_to? :call
|
98
|
+
@connection_info.call
|
99
|
+
else
|
100
|
+
@connection_info
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def retry_with_error max_retry_count = 5
|
105
|
+
retry_count = 0
|
106
|
+
|
107
|
+
begin
|
108
|
+
yield
|
109
|
+
rescue StandardError => e
|
110
|
+
raise e if e.is_a?(Signet::AuthorizationError) || e.is_a?(Signet::ParseError)
|
111
|
+
|
112
|
+
if retry_count < max_retry_count
|
113
|
+
retry_count += 1
|
114
|
+
sleep retry_count * 0.3
|
115
|
+
retry
|
116
|
+
else
|
117
|
+
msg = "Unexpected error: #{e.inspect}"
|
118
|
+
raise Signet::AuthorizationError, msg
|
119
|
+
end
|
78
120
|
end
|
79
121
|
end
|
80
122
|
end
|
@@ -27,8 +27,8 @@
|
|
27
27
|
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
28
28
|
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
29
29
|
|
30
|
-
require
|
31
|
-
require
|
30
|
+
require "yaml/store"
|
31
|
+
require "googleauth/token_store"
|
32
32
|
|
33
33
|
module Google
|
34
34
|
module Auth
|
@@ -39,24 +39,24 @@ module Google
|
|
39
39
|
#
|
40
40
|
# @param [String, File] file
|
41
41
|
# Path to storage file
|
42
|
-
def initialize
|
42
|
+
def initialize options = {}
|
43
43
|
path = options[:file]
|
44
|
-
@store = YAML::Store.new
|
44
|
+
@store = YAML::Store.new path
|
45
45
|
end
|
46
46
|
|
47
47
|
# (see Google::Auth::Stores::TokenStore#load)
|
48
|
-
def load
|
48
|
+
def load id
|
49
49
|
@store.transaction { @store[id] }
|
50
50
|
end
|
51
51
|
|
52
52
|
# (see Google::Auth::Stores::TokenStore#store)
|
53
|
-
def store
|
53
|
+
def store id, token
|
54
54
|
@store.transaction { @store[id] = token }
|
55
55
|
end
|
56
56
|
|
57
57
|
# (see Google::Auth::Stores::TokenStore#delete)
|
58
|
-
def delete
|
59
|
-
@store.transaction { @store.delete
|
58
|
+
def delete id
|
59
|
+
@store.transaction { @store.delete id }
|
60
60
|
end
|
61
61
|
end
|
62
62
|
end
|