googleauth 0.5.1 → 0.11.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 (69) hide show
  1. checksums.yaml +5 -5
  2. data/{CONTRIBUTING.md → .github/CONTRIBUTING.md} +5 -4
  3. data/.github/ISSUE_TEMPLATE/bug_report.md +36 -0
  4. data/.github/ISSUE_TEMPLATE/feature_request.md +21 -0
  5. data/.github/ISSUE_TEMPLATE/support_request.md +7 -0
  6. data/.kokoro/build.bat +16 -0
  7. data/.kokoro/build.sh +4 -0
  8. data/.kokoro/continuous/common.cfg +24 -0
  9. data/.kokoro/continuous/linux.cfg +25 -0
  10. data/.kokoro/continuous/osx.cfg +8 -0
  11. data/.kokoro/continuous/post.cfg +30 -0
  12. data/.kokoro/continuous/windows.cfg +29 -0
  13. data/.kokoro/osx.sh +4 -0
  14. data/.kokoro/presubmit/common.cfg +24 -0
  15. data/.kokoro/presubmit/linux.cfg +24 -0
  16. data/.kokoro/presubmit/osx.cfg +8 -0
  17. data/.kokoro/presubmit/windows.cfg +29 -0
  18. data/.kokoro/release.cfg +94 -0
  19. data/.kokoro/trampoline.bat +10 -0
  20. data/.kokoro/trampoline.sh +4 -0
  21. data/.repo-metadata.json +5 -0
  22. data/.rubocop.yml +17 -1
  23. data/CHANGELOG.md +90 -19
  24. data/CODE_OF_CONDUCT.md +43 -0
  25. data/Gemfile +16 -13
  26. data/README.md +58 -18
  27. data/Rakefile +106 -10
  28. data/googleauth.gemspec +27 -25
  29. data/lib/googleauth/application_default.rb +81 -0
  30. data/lib/googleauth/client_id.rb +21 -19
  31. data/lib/googleauth/compute_engine.rb +40 -43
  32. data/lib/googleauth/credentials.rb +375 -0
  33. data/lib/googleauth/credentials_loader.rb +117 -43
  34. data/lib/googleauth/default_credentials.rb +93 -0
  35. data/lib/googleauth/iam.rb +11 -11
  36. data/lib/googleauth/json_key_reader.rb +46 -0
  37. data/lib/googleauth/scope_util.rb +12 -12
  38. data/lib/googleauth/service_account.rb +64 -62
  39. data/lib/googleauth/signet.rb +53 -12
  40. data/lib/googleauth/stores/file_token_store.rb +8 -8
  41. data/lib/googleauth/stores/redis_token_store.rb +22 -22
  42. data/lib/googleauth/token_store.rb +6 -6
  43. data/lib/googleauth/user_authorizer.rb +80 -68
  44. data/lib/googleauth/user_refresh.rb +44 -35
  45. data/lib/googleauth/version.rb +1 -1
  46. data/lib/googleauth/web_user_authorizer.rb +77 -68
  47. data/lib/googleauth.rb +6 -96
  48. data/rakelib/devsite_builder.rb +45 -0
  49. data/rakelib/link_checker.rb +64 -0
  50. data/rakelib/repo_metadata.rb +59 -0
  51. data/spec/googleauth/apply_auth_examples.rb +47 -46
  52. data/spec/googleauth/client_id_spec.rb +75 -55
  53. data/spec/googleauth/compute_engine_spec.rb +60 -43
  54. data/spec/googleauth/credentials_spec.rb +467 -0
  55. data/spec/googleauth/get_application_default_spec.rb +149 -111
  56. data/spec/googleauth/iam_spec.rb +25 -25
  57. data/spec/googleauth/scope_util_spec.rb +26 -24
  58. data/spec/googleauth/service_account_spec.rb +261 -143
  59. data/spec/googleauth/signet_spec.rb +93 -30
  60. data/spec/googleauth/stores/file_token_store_spec.rb +12 -13
  61. data/spec/googleauth/stores/redis_token_store_spec.rb +11 -11
  62. data/spec/googleauth/stores/store_examples.rb +16 -16
  63. data/spec/googleauth/user_authorizer_spec.rb +153 -124
  64. data/spec/googleauth/user_refresh_spec.rb +186 -121
  65. data/spec/googleauth/web_user_authorizer_spec.rb +82 -69
  66. data/spec/spec_helper.rb +21 -19
  67. metadata +75 -32
  68. data/.rubocop_todo.yml +0 -32
  69. data/.travis.yml +0 -37
@@ -27,9 +27,9 @@
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 provides classes that provide Google-specific authorization
@@ -37,31 +37,31 @@ module Google
37
37
  module Auth
38
38
  # Authenticates requests using IAM credentials.
39
39
  class IAMCredentials
40
- SELECTOR_KEY = 'x-goog-iam-authority-selector'
41
- TOKEN_KEY = 'x-goog-iam-authorization-token'
40
+ SELECTOR_KEY = "x-goog-iam-authority-selector".freeze
41
+ TOKEN_KEY = "x-goog-iam-authorization-token".freeze
42
42
 
43
43
  # Initializes an IAMCredentials.
44
44
  #
45
45
  # @param selector the IAM selector.
46
46
  # @param token the IAM token.
47
- def initialize(selector, token)
48
- fail TypeError unless selector.is_a? String
49
- fail TypeError unless token.is_a? String
47
+ def initialize selector, token
48
+ raise TypeError unless selector.is_a? String
49
+ raise TypeError unless token.is_a? String
50
50
  @selector = selector
51
51
  @token = token
52
52
  end
53
53
 
54
54
  # Adds the credential fields to the hash.
55
- def apply!(a_hash)
55
+ def apply! a_hash
56
56
  a_hash[SELECTOR_KEY] = @selector
57
57
  a_hash[TOKEN_KEY] = @token
58
58
  a_hash
59
59
  end
60
60
 
61
61
  # Returns a clone of a_hash updated with the authoriation header
62
- def apply(a_hash)
62
+ def apply a_hash
63
63
  a_copy = a_hash.clone
64
- apply!(a_copy)
64
+ apply! a_copy
65
65
  a_copy
66
66
  end
67
67
 
@@ -0,0 +1,46 @@
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
+ project_id = json_key["project_id"]
42
+ [json_key["private_key"], json_key["client_email"], project_id]
43
+ end
44
+ end
45
+ end
46
+ 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,49 @@ 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
51
54
 
52
55
  # Creates a ServiceAccountCredentials.
53
56
  #
54
57
  # @param json_key_io [IO] an IO from which the JSON key can be read
55
58
  # @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)
59
+ def self.make_creds options = {}
60
+ json_key_io, scope = options.values_at :json_key_io, :scope
58
61
  if json_key_io
59
- private_key, client_email = read_json_key(json_key_io)
62
+ private_key, client_email, project_id = read_json_key json_key_io
60
63
  else
61
- private_key = ENV[CredentialsLoader::PRIVATE_KEY_VAR]
64
+ private_key = unescape ENV[CredentialsLoader::PRIVATE_KEY_VAR]
62
65
  client_email = ENV[CredentialsLoader::CLIENT_EMAIL_VAR]
66
+ project_id = ENV[CredentialsLoader::PROJECT_ID_VAR]
63
67
  end
68
+ project_id ||= CredentialsLoader.load_gcloud_project_id
64
69
 
65
70
  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))
71
+ audience: TOKEN_CRED_URI,
72
+ scope: scope,
73
+ issuer: client_email,
74
+ signing_key: OpenSSL::PKey::RSA.new(private_key),
75
+ project_id: project_id)
76
+ .configure_connection(options)
70
77
  end
71
78
 
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']]
79
+ # Handles certain escape sequences that sometimes appear in input.
80
+ # Specifically, interprets the "\n" sequence for newline, and removes
81
+ # enclosing quotes.
82
+ def self.unescape str
83
+ str = str.gsub '\n', "\n"
84
+ str = str[1..-2] if str.start_with?('"') && str.end_with?('"')
85
+ str
79
86
  end
80
87
 
81
- def initialize(options = {})
82
- super(options)
88
+ def initialize options = {}
89
+ @project_id = options[:project_id]
90
+ super options
83
91
  end
84
92
 
85
93
  # Extends the base class.
@@ -87,7 +95,7 @@ module Google
87
95
  # If scope(s) is not set, it creates a transient
88
96
  # ServiceAccountJwtHeaderCredentials instance and uses that to
89
97
  # authenticate instead.
90
- def apply!(a_hash, opts = {})
98
+ def apply! a_hash, opts = {}
91
99
  # Use the base implementation if scopes are set
92
100
  unless scope.nil?
93
101
  super
@@ -97,13 +105,13 @@ module Google
97
105
  # Use the ServiceAccountJwtHeaderCredentials using the same cred values
98
106
  # if no scopes are set.
99
107
  cred_json = {
100
- private_key: @signing_key.to_s,
108
+ private_key: @signing_key.to_s,
101
109
  client_email: @issuer
102
110
  }
103
111
  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)
112
+ key_io = StringIO.new MultiJson.dump(cred_json)
113
+ alt = alt_clz.make_creds json_key_io: key_io
114
+ alt.apply! a_hash
107
115
  end
108
116
  end
109
117
 
@@ -115,14 +123,16 @@ module Google
115
123
  # console (via 'Generate new Json Key'). It is not part of any OAuth2
116
124
  # flow, rather it creates a JWT and sends that as a credential.
117
125
  #
118
- # cf [Application Default Credentials](http://goo.gl/mkAHpZ)
126
+ # cf [Application Default Credentials](https://cloud.google.com/docs/authentication/production)
119
127
  class ServiceAccountJwtHeaderCredentials
120
128
  JWT_AUD_URI_KEY = :jwt_aud_uri
121
129
  AUTH_METADATA_KEY = Signet::OAuth2::AUTH_METADATA_KEY
122
- TOKEN_CRED_URI = 'https://www.googleapis.com/oauth2/v3/token'
123
- SIGNING_ALGORITHM = 'RS256'
130
+ TOKEN_CRED_URI = "https://www.googleapis.com/oauth2/v4/token".freeze
131
+ SIGNING_ALGORITHM = "RS256".freeze
124
132
  EXPIRY = 60
125
133
  extend CredentialsLoader
134
+ extend JsonKeyReader
135
+ attr_reader :project_id
126
136
 
127
137
  # make_creds proxies the construction of a credentials instance
128
138
  #
@@ -131,51 +141,43 @@ module Google
131
141
  # By default, it calls #new with 2 args, the second one being an
132
142
  # optional scope. Here's the constructor only has one param, so
133
143
  # 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']]
144
+ def self.make_creds *args
145
+ new json_key_io: args[0][:json_key_io]
145
146
  end
146
147
 
147
148
  # Initializes a ServiceAccountJwtHeaderCredentials.
148
149
  #
149
150
  # @param json_key_io [IO] an IO from which the JSON key can be read
150
- def initialize(options = {})
151
+ def initialize options = {}
151
152
  json_key_io = options[:json_key_io]
152
153
  if json_key_io
153
- private_key, client_email = self.class.read_json_key(json_key_io)
154
+ @private_key, @issuer, @project_id =
155
+ self.class.read_json_key json_key_io
154
156
  else
155
- private_key = ENV[CredentialsLoader::PRIVATE_KEY_VAR]
156
- client_email = ENV[CredentialsLoader::CLIENT_EMAIL_VAR]
157
+ @private_key = ENV[CredentialsLoader::PRIVATE_KEY_VAR]
158
+ @issuer = ENV[CredentialsLoader::CLIENT_EMAIL_VAR]
159
+ @project_id = ENV[CredentialsLoader::PROJECT_ID_VAR]
157
160
  end
158
- @private_key = private_key
159
- @issuer = client_email
160
- @signing_key = OpenSSL::PKey::RSA.new(private_key)
161
+ @project_id ||= CredentialsLoader.load_gcloud_project_id
162
+ @signing_key = OpenSSL::PKey::RSA.new @private_key
161
163
  end
162
164
 
163
165
  # Construct a jwt token if the JWT_AUD_URI key is present in the input
164
166
  # hash.
165
167
  #
166
168
  # 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)
169
+ def apply! a_hash, opts = {}
170
+ jwt_aud_uri = a_hash.delete JWT_AUD_URI_KEY
169
171
  return a_hash if jwt_aud_uri.nil?
170
- jwt_token = new_jwt_token(jwt_aud_uri, opts)
172
+ jwt_token = new_jwt_token jwt_aud_uri, opts
171
173
  a_hash[AUTH_METADATA_KEY] = "Bearer #{jwt_token}"
172
174
  a_hash
173
175
  end
174
176
 
175
177
  # Returns a clone of a_hash updated with the authoriation header
176
- def apply(a_hash, opts = {})
178
+ def apply a_hash, opts = {}
177
179
  a_copy = a_hash.clone
178
- apply!(a_copy, opts)
180
+ apply! a_copy, opts
179
181
  a_copy
180
182
  end
181
183
 
@@ -188,17 +190,17 @@ module Google
188
190
  protected
189
191
 
190
192
  # Creates a jwt uri token.
191
- def new_jwt_token(jwt_aud_uri, options = {})
193
+ def new_jwt_token jwt_aud_uri, options = {}
192
194
  now = Time.new
193
195
  skew = options[:skew] || 60
194
196
  assertion = {
195
- 'iss' => @issuer,
196
- 'sub' => @issuer,
197
- 'aud' => jwt_aud_uri,
198
- 'exp' => (now + EXPIRY).to_i,
199
- 'iat' => (now - skew).to_i
197
+ "iss" => @issuer,
198
+ "sub" => @issuer,
199
+ "aud" => jwt_aud_uri,
200
+ "exp" => (now + EXPIRY).to_i,
201
+ "iat" => (now - skew).to_i
200
202
  }
201
- JWT.encode(assertion, @signing_key, SIGNING_ALGORITHM)
203
+ JWT.encode assertion, @signing_key, SIGNING_ALGORITHM
202
204
  end
203
205
  end
204
206
  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,24 @@ 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)
51
+ fetch_access_token! opts if access_token.nil? || expires_within?(60)
46
52
  a_hash[AUTH_METADATA_KEY] = "Bearer #{access_token}"
47
53
  end
48
54
 
49
55
  # Returns a clone of a_hash updated with the authentication token
50
- def apply(a_hash, opts = {})
56
+ def apply a_hash, opts = {}
51
57
  a_copy = a_hash.clone
52
- apply!(a_copy, opts)
58
+ apply! a_copy, opts
53
59
  a_copy
54
60
  end
55
61
 
@@ -59,22 +65,57 @@ module Signet
59
65
  lambda(&method(:apply))
60
66
  end
61
67
 
62
- def on_refresh(&block)
63
- @refresh_listeners ||= []
68
+ def on_refresh &block
69
+ @refresh_listeners = [] unless defined? @refresh_listeners
64
70
  @refresh_listeners << block
65
71
  end
66
72
 
67
- alias_method :orig_fetch_access_token!, :fetch_access_token!
68
- def fetch_access_token!(options = {})
69
- info = orig_fetch_access_token!(options)
73
+ alias orig_fetch_access_token! fetch_access_token!
74
+ def fetch_access_token! options = {}
75
+ unless options[:connection]
76
+ connection = build_default_connection
77
+ options = options.merge connection: connection if connection
78
+ end
79
+ info = retry_with_error do
80
+ orig_fetch_access_token! options
81
+ end
70
82
  notify_refresh_listeners
71
83
  info
72
84
  end
73
85
 
74
86
  def notify_refresh_listeners
75
- listeners = @refresh_listeners || []
87
+ listeners = defined?(@refresh_listeners) ? @refresh_listeners : []
76
88
  listeners.each do |block|
77
- block.call(self)
89
+ block.call self
90
+ end
91
+ end
92
+
93
+ def build_default_connection
94
+ if !defined?(@connection_info)
95
+ nil
96
+ elsif @connection_info.respond_to? :call
97
+ @connection_info.call
98
+ else
99
+ @connection_info
100
+ end
101
+ end
102
+
103
+ def retry_with_error max_retry_count = 5
104
+ retry_count = 0
105
+
106
+ begin
107
+ yield
108
+ rescue StandardError => e
109
+ raise e if e.is_a?(Signet::AuthorizationError) || e.is_a?(Signet::ParseError)
110
+
111
+ if retry_count < max_retry_count
112
+ retry_count += 1
113
+ sleep retry_count * 0.3
114
+ retry
115
+ else
116
+ msg = "Unexpected error: #{e.inspect}"
117
+ raise Signet::AuthorizationError, msg
118
+ end
78
119
  end
79
120
  end
80
121
  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
@@ -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 'redis'
31
- require 'googleauth/token_store'
30
+ require "redis"
31
+ require "googleauth/token_store"
32
32
 
33
33
  module Google
34
34
  module Auth
@@ -37,7 +37,7 @@ module Google
37
37
  # are stored as JSON using the supplied key, prefixed with
38
38
  # `g-user-token:`
39
39
  class RedisTokenStore < Google::Auth::TokenStore
40
- DEFAULT_KEY_PREFIX = 'g-user-token:'
40
+ DEFAULT_KEY_PREFIX = "g-user-token:".freeze
41
41
 
42
42
  # Create a new store with the supplied redis client.
43
43
  #
@@ -48,34 +48,34 @@ module Google
48
48
  # @note If no redis instance is provided, a new one is created and
49
49
  # the options passed through. You may include any other keys accepted
50
50
  # by `Redis.new`
51
- def initialize(options = {})
52
- redis = options.delete(:redis)
53
- prefix = options.delete(:prefix)
54
- case redis
55
- when Redis
56
- @redis = redis
57
- else
58
- @redis = Redis.new(options)
59
- end
51
+ def initialize options = {}
52
+ redis = options.delete :redis
53
+ prefix = options.delete :prefix
54
+ @redis = case redis
55
+ when Redis
56
+ redis
57
+ else
58
+ Redis.new options
59
+ end
60
60
  @prefix = prefix || DEFAULT_KEY_PREFIX
61
61
  end
62
62
 
63
63
  # (see Google::Auth::Stores::TokenStore#load)
64
- def load(id)
65
- key = key_for(id)
66
- @redis.get(key)
64
+ def load id
65
+ key = key_for id
66
+ @redis.get key
67
67
  end
68
68
 
69
69
  # (see Google::Auth::Stores::TokenStore#store)
70
- def store(id, token)
71
- key = key_for(id)
72
- @redis.set(key, token)
70
+ def store id, token
71
+ key = key_for id
72
+ @redis.set key, token
73
73
  end
74
74
 
75
75
  # (see Google::Auth::Stores::TokenStore#delete)
76
- def delete(id)
77
- key = key_for(id)
78
- @redis.del(key)
76
+ def delete id
77
+ key = key_for id
78
+ @redis.del key
79
79
  end
80
80
 
81
81
  private
@@ -86,7 +86,7 @@ module Google
86
86
  # ID of the token
87
87
  # @return [String]
88
88
  # Redis key
89
- def key_for(id)
89
+ def key_for id
90
90
  @prefix + id
91
91
  end
92
92
  end
@@ -43,8 +43,8 @@ module Google
43
43
  # ID of token data to load.
44
44
  # @return [String]
45
45
  # The loaded token data.
46
- def load(_id)
47
- fail 'Not implemented'
46
+ def load _id
47
+ raise "Not implemented"
48
48
  end
49
49
 
50
50
  # Put the token data into storage for the given ID.
@@ -53,16 +53,16 @@ module Google
53
53
  # ID of token data to store.
54
54
  # @param [String] token
55
55
  # The token data to store.
56
- def store(_id, _token)
57
- fail 'Not implemented'
56
+ def store _id, _token
57
+ raise "Not implemented"
58
58
  end
59
59
 
60
60
  # Remove the token data from storage for the given ID.
61
61
  #
62
62
  # @param [String] id
63
63
  # ID of the token data to delete
64
- def delete(_id)
65
- fail 'Not implemented'
64
+ def delete _id
65
+ raise "Not implemented"
66
66
  end
67
67
  end
68
68
  end