googleauth 0.5.1 → 0.11.0

Sign up to get free protection for your applications and to get access to all the features.
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