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.
Files changed (80) hide show
  1. checksums.yaml +5 -5
  2. data/.github/CODEOWNERS +7 -0
  3. data/{CONTRIBUTING.md → .github/CONTRIBUTING.md} +5 -4
  4. data/.github/ISSUE_TEMPLATE/bug_report.md +36 -0
  5. data/.github/ISSUE_TEMPLATE/feature_request.md +21 -0
  6. data/.github/ISSUE_TEMPLATE/support_request.md +7 -0
  7. data/.kokoro/build.bat +16 -0
  8. data/.kokoro/build.sh +4 -0
  9. data/.kokoro/continuous/common.cfg +24 -0
  10. data/.kokoro/continuous/linux.cfg +25 -0
  11. data/.kokoro/continuous/osx.cfg +8 -0
  12. data/.kokoro/continuous/post.cfg +30 -0
  13. data/.kokoro/continuous/windows.cfg +29 -0
  14. data/.kokoro/osx.sh +4 -0
  15. data/.kokoro/presubmit/common.cfg +24 -0
  16. data/.kokoro/presubmit/linux.cfg +24 -0
  17. data/.kokoro/presubmit/osx.cfg +8 -0
  18. data/.kokoro/presubmit/windows.cfg +29 -0
  19. data/.kokoro/release.cfg +94 -0
  20. data/.kokoro/trampoline.bat +10 -0
  21. data/.kokoro/trampoline.sh +4 -0
  22. data/.repo-metadata.json +5 -0
  23. data/.rubocop.yml +19 -1
  24. data/CHANGELOG.md +112 -19
  25. data/CODE_OF_CONDUCT.md +43 -0
  26. data/Gemfile +19 -13
  27. data/{COPYING → LICENSE} +0 -0
  28. data/README.md +58 -18
  29. data/Rakefile +126 -9
  30. data/googleauth.gemspec +28 -25
  31. data/integration/helper.rb +31 -0
  32. data/integration/id_tokens/key_source_test.rb +74 -0
  33. data/lib/googleauth.rb +7 -96
  34. data/lib/googleauth/application_default.rb +81 -0
  35. data/lib/googleauth/client_id.rb +21 -19
  36. data/lib/googleauth/compute_engine.rb +70 -43
  37. data/lib/googleauth/credentials.rb +442 -0
  38. data/lib/googleauth/credentials_loader.rb +117 -43
  39. data/lib/googleauth/default_credentials.rb +93 -0
  40. data/lib/googleauth/iam.rb +11 -11
  41. data/lib/googleauth/id_tokens.rb +233 -0
  42. data/lib/googleauth/id_tokens/errors.rb +71 -0
  43. data/lib/googleauth/id_tokens/key_sources.rb +394 -0
  44. data/lib/googleauth/id_tokens/verifier.rb +144 -0
  45. data/lib/googleauth/json_key_reader.rb +50 -0
  46. data/lib/googleauth/scope_util.rb +12 -12
  47. data/lib/googleauth/service_account.rb +74 -63
  48. data/lib/googleauth/signet.rb +55 -13
  49. data/lib/googleauth/stores/file_token_store.rb +8 -8
  50. data/lib/googleauth/stores/redis_token_store.rb +22 -22
  51. data/lib/googleauth/token_store.rb +6 -6
  52. data/lib/googleauth/user_authorizer.rb +80 -68
  53. data/lib/googleauth/user_refresh.rb +44 -35
  54. data/lib/googleauth/version.rb +1 -1
  55. data/lib/googleauth/web_user_authorizer.rb +77 -68
  56. data/rakelib/devsite_builder.rb +45 -0
  57. data/rakelib/link_checker.rb +64 -0
  58. data/rakelib/repo_metadata.rb +59 -0
  59. data/spec/googleauth/apply_auth_examples.rb +74 -50
  60. data/spec/googleauth/client_id_spec.rb +75 -55
  61. data/spec/googleauth/compute_engine_spec.rb +98 -46
  62. data/spec/googleauth/credentials_spec.rb +478 -0
  63. data/spec/googleauth/get_application_default_spec.rb +149 -111
  64. data/spec/googleauth/iam_spec.rb +25 -25
  65. data/spec/googleauth/scope_util_spec.rb +26 -24
  66. data/spec/googleauth/service_account_spec.rb +269 -144
  67. data/spec/googleauth/signet_spec.rb +101 -30
  68. data/spec/googleauth/stores/file_token_store_spec.rb +12 -13
  69. data/spec/googleauth/stores/redis_token_store_spec.rb +11 -11
  70. data/spec/googleauth/stores/store_examples.rb +16 -16
  71. data/spec/googleauth/user_authorizer_spec.rb +153 -124
  72. data/spec/googleauth/user_refresh_spec.rb +186 -121
  73. data/spec/googleauth/web_user_authorizer_spec.rb +82 -69
  74. data/spec/spec_helper.rb +21 -19
  75. data/test/helper.rb +33 -0
  76. data/test/id_tokens/key_sources_test.rb +240 -0
  77. data/test/id_tokens/verifier_test.rb +269 -0
  78. metadata +87 -34
  79. data/.rubocop_todo.yml +0 -32
  80. 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 'googleauth/signet'
31
- require 'googleauth/credentials_loader'
32
- require 'multi_json'
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
- '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
- }
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(scope)
45
- list = as_array(scope)
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(scope)
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
- fail 'Invalid scope value. Must be string or array'
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 'googleauth/signet'
31
- require 'googleauth/credentials_loader'
32
- require 'jwt'
33
- require 'multi_json'
34
- require 'stringio'
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](http://goo.gl/mkAHpZ)
48
+ # cf [Application Default Credentials](https://cloud.google.com/docs/authentication/production)
48
49
  class ServiceAccountCredentials < Signet::OAuth2::Client
49
- TOKEN_CRED_URI = 'https://www.googleapis.com/oauth2/v3/token'
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(options = {})
57
- json_key_io, scope = options.values_at(:json_key_io, :scope)
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(json_key_io)
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: TOKEN_CRED_URI,
67
- scope: scope,
68
- issuer: client_email,
69
- signing_key: OpenSSL::PKey::RSA.new(private_key))
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
- # Reads the private key and client email fields from the service account
73
- # JSON key.
74
- def self.read_json_key(json_key_io)
75
- json_key = MultiJson.load(json_key_io.read)
76
- fail 'missing client_email' unless json_key.key?('client_email')
77
- fail 'missing private_key' unless json_key.key?('private_key')
78
- [json_key['private_key'], json_key['client_email']]
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(options = {})
82
- super(options)
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!(a_hash, opts = {})
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: @signing_key.to_s,
115
+ private_key: @signing_key.to_s,
101
116
  client_email: @issuer
102
117
  }
103
118
  alt_clz = ServiceAccountJwtHeaderCredentials
104
- key_io = StringIO.new(MultiJson.dump(cred_json))
105
- alt = alt_clz.make_creds(json_key_io: key_io)
106
- alt.apply!(a_hash)
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](http://goo.gl/mkAHpZ)
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 = 'https://www.googleapis.com/oauth2/v3/token'
123
- SIGNING_ALGORITHM = 'RS256'
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(*args)
135
- new(json_key_io: args[0][:json_key_io])
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(options = {})
159
+ def initialize options = {}
151
160
  json_key_io = options[:json_key_io]
152
161
  if json_key_io
153
- private_key, client_email = self.class.read_json_key(json_key_io)
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
- client_email = ENV[CredentialsLoader::CLIENT_EMAIL_VAR]
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
- @private_key = private_key
159
- @issuer = client_email
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!(a_hash, opts = {})
168
- jwt_aud_uri = a_hash.delete(JWT_AUD_URI_KEY)
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(jwt_aud_uri, opts)
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(a_hash, opts = {})
187
+ def apply a_hash, opts = {}
177
188
  a_copy = a_hash.clone
178
- apply!(a_copy, opts)
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(jwt_aud_uri, options = {})
202
+ def new_jwt_token jwt_aud_uri, options = {}
192
203
  now = Time.new
193
204
  skew = options[:skew] || 60
194
205
  assertion = {
195
- 'iss' => @issuer,
196
- 'sub' => @issuer,
197
- 'aud' => jwt_aud_uri,
198
- 'exp' => (now + EXPIRY).to_i,
199
- 'iat' => (now - skew).to_i
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(assertion, @signing_key, SIGNING_ALGORITHM)
212
+ JWT.encode assertion, @signing_key, SIGNING_ALGORITHM
202
213
  end
203
214
  end
204
215
  end
@@ -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 'signet/oauth_2/client'
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!(a_hash, opts = {})
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
- fetch_access_token!(opts) if access_token.nil? || expires_within?(60)
46
- a_hash[AUTH_METADATA_KEY] = "Bearer #{access_token}"
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(a_hash, opts = {})
57
+ def apply a_hash, opts = {}
51
58
  a_copy = a_hash.clone
52
- apply!(a_copy, opts)
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(&block)
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
- alias_method :orig_fetch_access_token!, :fetch_access_token!
68
- def fetch_access_token!(options = {})
69
- info = orig_fetch_access_token!(options)
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(self)
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 'yaml/store'
31
- require 'googleauth/token_store'
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(options = {})
42
+ def initialize options = {}
43
43
  path = options[:file]
44
- @store = YAML::Store.new(path)
44
+ @store = YAML::Store.new path
45
45
  end
46
46
 
47
47
  # (see Google::Auth::Stores::TokenStore#load)
48
- def load(id)
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(id, token)
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(id)
59
- @store.transaction { @store.delete(id) }
58
+ def delete id
59
+ @store.transaction { @store.delete id }
60
60
  end
61
61
  end
62
62
  end