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
@@ -31,6 +31,6 @@ module Google
31
31
  # Module Auth provides classes that provide Google-specific authorization
32
32
  # used to access Google APIs.
33
33
  module Auth
34
- VERSION = '0.5.1'
34
+ VERSION = "0.14.0".freeze
35
35
  end
36
36
  end
@@ -27,11 +27,11 @@
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 'multi_json'
31
- require 'googleauth/signet'
32
- require 'googleauth/user_authorizer'
33
- require 'googleauth/user_refresh'
34
- require 'securerandom'
30
+ require "multi_json"
31
+ require "googleauth/signet"
32
+ require "googleauth/user_authorizer"
33
+ require "googleauth/user_refresh"
34
+ require "securerandom"
35
35
 
36
36
  module Google
37
37
  module Auth
@@ -66,20 +66,21 @@ module Google
66
66
  # @see {Google::Auth::ControllerHelpers}
67
67
  # @note Requires sessions are enabled
68
68
  class WebUserAuthorizer < Google::Auth::UserAuthorizer
69
- STATE_PARAM = 'state'
70
- AUTH_CODE_KEY = 'code'
71
- ERROR_CODE_KEY = 'error'
72
- SESSION_ID_KEY = 'session_id'
73
- CALLBACK_STATE_KEY = 'g-auth-callback'
74
- CURRENT_URI_KEY = 'current_uri'
75
- XSRF_KEY = 'g-xsrf-token'
76
- SCOPE_KEY = 'scope'
69
+ STATE_PARAM = "state".freeze
70
+ AUTH_CODE_KEY = "code".freeze
71
+ ERROR_CODE_KEY = "error".freeze
72
+ SESSION_ID_KEY = "session_id".freeze
73
+ CALLBACK_STATE_KEY = "g-auth-callback".freeze
74
+ CURRENT_URI_KEY = "current_uri".freeze
75
+ XSRF_KEY = "g-xsrf-token".freeze
76
+ SCOPE_KEY = "scope".freeze
77
77
 
78
- NIL_REQUEST_ERROR = 'Request is required.'
79
- NIL_SESSION_ERROR = 'Sessions must be enabled'
80
- MISSING_AUTH_CODE_ERROR = 'Missing authorization code in request'
81
- AUTHORIZATION_ERROR = 'Authorization error: %s'
82
- INVALID_STATE_TOKEN_ERROR = 'State token does not match expected value'
78
+ NIL_REQUEST_ERROR = "Request is required.".freeze
79
+ NIL_SESSION_ERROR = "Sessions must be enabled".freeze
80
+ MISSING_AUTH_CODE_ERROR = "Missing authorization code in request".freeze
81
+ AUTHORIZATION_ERROR = "Authorization error: %s".freeze
82
+ INVALID_STATE_TOKEN_ERROR =
83
+ "State token does not match expected value".freeze
83
84
 
84
85
  class << self
85
86
  attr_accessor :default
@@ -96,9 +97,9 @@ module Google
96
97
  #
97
98
  # @param [Rack::Request] request
98
99
  # Current request
99
- def self.handle_auth_callback_deferred(request)
100
- callback_state, redirect_uri = extract_callback_state(request)
101
- request.session[CALLBACK_STATE_KEY] = MultiJson.dump(callback_state)
100
+ def self.handle_auth_callback_deferred request
101
+ callback_state, redirect_uri = extract_callback_state request
102
+ request.session[CALLBACK_STATE_KEY] = MultiJson.dump callback_state
102
103
  redirect_uri
103
104
  end
104
105
 
@@ -113,8 +114,8 @@ module Google
113
114
  # @param [String] callback_uri
114
115
  # URL (either absolute or relative) of the auth callback. Defaults
115
116
  # to '/oauth2callback'
116
- def initialize(client_id, scope, token_store, callback_uri = nil)
117
- super(client_id, scope, token_store, callback_uri)
117
+ def initialize client_id, scope, token_store, callback_uri = nil
118
+ super client_id, scope, token_store, callback_uri
118
119
  end
119
120
 
120
121
  # Handle the result of the oauth callback. Exchanges the authorization
@@ -126,15 +127,17 @@ module Google
126
127
  # Current request
127
128
  # @return (Google::Auth::UserRefreshCredentials, String)
128
129
  # credentials & next URL to redirect to
129
- def handle_auth_callback(user_id, request)
130
+ def handle_auth_callback user_id, request
130
131
  callback_state, redirect_uri = WebUserAuthorizer.extract_callback_state(
131
- request)
132
- WebUserAuthorizer.validate_callback_state(callback_state, request)
132
+ request
133
+ )
134
+ WebUserAuthorizer.validate_callback_state callback_state, request
133
135
  credentials = get_and_store_credentials_from_code(
134
- user_id: user_id,
135
- code: callback_state[AUTH_CODE_KEY],
136
- scope: callback_state[SCOPE_KEY],
137
- base_url: request.url)
136
+ user_id: user_id,
137
+ code: callback_state[AUTH_CODE_KEY],
138
+ scope: callback_state[SCOPE_KEY],
139
+ base_url: request.url
140
+ )
138
141
  [credentials, redirect_uri]
139
142
  end
140
143
 
@@ -151,29 +154,35 @@ module Google
151
154
  # @param [String, Array<String>] scope
152
155
  # Authorization scope to request. Overrides the instance scopes if
153
156
  # not nil.
157
+ # @param [Hash] state
158
+ # Optional key-values to be returned to the oauth callback.
154
159
  # @return [String]
155
160
  # Authorization url
156
- def get_authorization_url(options = {})
161
+ def get_authorization_url options = {}
157
162
  options = options.dup
158
163
  request = options[:request]
159
- fail NIL_REQUEST_ERROR if request.nil?
160
- fail NIL_SESSION_ERROR if request.session.nil?
164
+ raise NIL_REQUEST_ERROR if request.nil?
165
+ raise NIL_SESSION_ERROR if request.session.nil?
166
+
167
+ state = options[:state] || {}
161
168
 
162
169
  redirect_to = options[:redirect_to] || request.url
163
170
  request.session[XSRF_KEY] = SecureRandom.base64
164
- options[:state] = MultiJson.dump(
165
- SESSION_ID_KEY => request.session[XSRF_KEY],
166
- CURRENT_URI_KEY => redirect_to)
171
+ options[:state] = MultiJson.dump(state.merge(
172
+ SESSION_ID_KEY => request.session[XSRF_KEY],
173
+ CURRENT_URI_KEY => redirect_to
174
+ ))
167
175
  options[:base_url] = request.url
168
- super(options)
176
+ super options
169
177
  end
170
178
 
171
- # Fetch stored credentials for the user.
179
+ # Fetch stored credentials for the user from the given request session.
172
180
  #
173
181
  # @param [String] user_id
174
182
  # Unique ID of the user for loading/storing credentials.
175
183
  # @param [Rack::Request] request
176
- # Current request
184
+ # Current request. Optional. If omitted, this will attempt to fall back
185
+ # on the base class behavior of reading from the token store.
177
186
  # @param [Array<String>, String] scope
178
187
  # If specified, only returns credentials that have all the \
179
188
  # requested scopes
@@ -182,31 +191,32 @@ module Google
182
191
  # @raise [Signet::AuthorizationError]
183
192
  # May raise an error if an authorization code is present in the session
184
193
  # and exchange of the code fails
185
- def get_credentials(user_id, request, scope = nil)
186
- if request.session.key?(CALLBACK_STATE_KEY)
194
+ def get_credentials user_id, request = nil, scope = nil
195
+ if request && request.session.key?(CALLBACK_STATE_KEY)
187
196
  # Note - in theory, no need to check required scope as this is
188
197
  # expected to be called immediately after a return from authorization
189
- state_json = request.session.delete(CALLBACK_STATE_KEY)
190
- callback_state = MultiJson.load(state_json)
191
- WebUserAuthorizer.validate_callback_state(callback_state, request)
198
+ state_json = request.session.delete CALLBACK_STATE_KEY
199
+ callback_state = MultiJson.load state_json
200
+ WebUserAuthorizer.validate_callback_state callback_state, request
192
201
  get_and_store_credentials_from_code(
193
- user_id: user_id,
194
- code: callback_state[AUTH_CODE_KEY],
195
- scope: callback_state[SCOPE_KEY],
196
- base_url: request.url)
202
+ user_id: user_id,
203
+ code: callback_state[AUTH_CODE_KEY],
204
+ scope: callback_state[SCOPE_KEY],
205
+ base_url: request.url
206
+ )
197
207
  else
198
- super(user_id, scope)
208
+ super user_id, scope
199
209
  end
200
210
  end
201
211
 
202
- def self.extract_callback_state(request)
203
- state = MultiJson.load(request[STATE_PARAM] || '{}')
212
+ def self.extract_callback_state request
213
+ state = MultiJson.load(request[STATE_PARAM] || "{}")
204
214
  redirect_uri = state[CURRENT_URI_KEY]
205
215
  callback_state = {
206
- AUTH_CODE_KEY => request[AUTH_CODE_KEY],
207
- ERROR_CODE_KEY => request[ERROR_CODE_KEY],
216
+ AUTH_CODE_KEY => request[AUTH_CODE_KEY],
217
+ ERROR_CODE_KEY => request[ERROR_CODE_KEY],
208
218
  SESSION_ID_KEY => state[SESSION_ID_KEY],
209
- SCOPE_KEY => request[SCOPE_KEY]
219
+ SCOPE_KEY => request[SCOPE_KEY]
210
220
  }
211
221
  [callback_state, redirect_uri]
212
222
  end
@@ -221,14 +231,13 @@ module Google
221
231
  # Error message if failed
222
232
  # @param [Rack::Request] request
223
233
  # Current request
224
- def self.validate_callback_state(state, request)
225
- if state[AUTH_CODE_KEY].nil?
226
- fail Signet::AuthorizationError, MISSING_AUTH_CODE_ERROR
227
- elsif state[ERROR_CODE_KEY]
228
- fail Signet::AuthorizationError,
229
- sprintf(AUTHORIZATION_ERROR, state[ERROR_CODE_KEY])
234
+ def self.validate_callback_state state, request
235
+ raise Signet::AuthorizationError, MISSING_AUTH_CODE_ERROR if state[AUTH_CODE_KEY].nil?
236
+ if state[ERROR_CODE_KEY]
237
+ raise Signet::AuthorizationError,
238
+ format(AUTHORIZATION_ERROR, state[ERROR_CODE_KEY])
230
239
  elsif request.session[XSRF_KEY] != state[SESSION_ID_KEY]
231
- fail Signet::AuthorizationError, INVALID_STATE_TOKEN_ERROR
240
+ raise Signet::AuthorizationError, INVALID_STATE_TOKEN_ERROR
232
241
  end
233
242
  end
234
243
 
@@ -254,7 +263,7 @@ module Google
254
263
  #
255
264
  # @see {Google::Auth::WebUserAuthorizer}
256
265
  class CallbackApp
257
- LOCATION_HEADER = 'Location'
266
+ LOCATION_HEADER = "Location".freeze
258
267
  REDIR_STATUS = 302
259
268
  ERROR_STATUS = 500
260
269
 
@@ -270,18 +279,18 @@ module Google
270
279
  # Rack environment
271
280
  # @return [Array]
272
281
  # HTTP response
273
- def self.call(env)
274
- request = Rack::Request.new(env)
275
- return_url = WebUserAuthorizer.handle_auth_callback_deferred(request)
282
+ def self.call env
283
+ request = Rack::Request.new env
284
+ return_url = WebUserAuthorizer.handle_auth_callback_deferred request
276
285
  if return_url
277
286
  [REDIR_STATUS, { LOCATION_HEADER => return_url }, []]
278
287
  else
279
- [ERROR_STATUS, {}, ['No return URL is present in the request.']]
288
+ [ERROR_STATUS, {}, ["No return URL is present in the request."]]
280
289
  end
281
290
  end
282
291
 
283
- def call(env)
284
- self.class.call(env)
292
+ def call env
293
+ self.class.call env
285
294
  end
286
295
  end
287
296
  end
@@ -0,0 +1,45 @@
1
+ require "pathname"
2
+
3
+ require_relative "repo_metadata.rb"
4
+
5
+ class DevsiteBuilder
6
+ def initialize master_dir = "."
7
+ @master_dir = Pathname.new master_dir
8
+ @output_dir = "doc"
9
+ @metadata = RepoMetadata.from_source "#{master_dir}/.repo-metadata.json"
10
+ end
11
+
12
+ def build
13
+ FileUtils.remove_dir @output_dir if Dir.exist? @output_dir
14
+ markup = "--markup markdown"
15
+
16
+ Dir.chdir @master_dir do
17
+ cmds = ["-o #{@output_dir}", markup]
18
+ cmd "yard --verbose #{cmds.join ' '}"
19
+ end
20
+ @metadata.build @master_dir + @output_dir
21
+ end
22
+
23
+ def upload
24
+ Dir.chdir @output_dir do
25
+ opts = [
26
+ "--credentials=#{ENV['KOKORO_KEYSTORE_DIR']}/73713_docuploader_service_account",
27
+ "--staging-bucket=#{ENV.fetch 'STAGING_BUCKET', 'docs-staging'}",
28
+ "--metadata-file=./docs.metadata"
29
+ ]
30
+ cmd "python3 -m docuploader upload . #{opts.join ' '}"
31
+ end
32
+ end
33
+
34
+ def publish
35
+ build
36
+ upload
37
+ end
38
+
39
+ def cmd line
40
+ puts line
41
+ output = `#{line}`
42
+ puts output
43
+ output
44
+ end
45
+ end
@@ -0,0 +1,64 @@
1
+ require "open3"
2
+
3
+ class LinkChecker
4
+ def initialize
5
+ @failed = false
6
+ end
7
+
8
+ def run
9
+ job_info
10
+ git_commit = ENV.fetch "KOKORO_GITHUB_COMMIT", "master"
11
+
12
+ markdown_files = Dir.glob "**/*.md"
13
+ broken_markdown_links = check_links markdown_files,
14
+ "https://github.com/googleapis/google-auth-library-ruby/tree/#{git_commit}",
15
+ " --skip '^(?!(\\Wruby.*google|.*google.*\\Wruby|.*cloud\\.google\\.com))'"
16
+
17
+ broken_devsite_links = check_links ["googleauth"],
18
+ "https://googleapis.dev/ruby",
19
+ "/latest/ --recurse --skip https:.*github.*"
20
+
21
+ puts_broken_links broken_markdown_links
22
+ puts_broken_links broken_devsite_links
23
+ end
24
+
25
+ def check_links location_list, base, tail
26
+ broken_links = Hash.new { |h, k| h[k] = [] }
27
+ location_list.each do |location|
28
+ out, err, st = Open3.capture3 "npx linkinator #{base}/#{location}#{tail}"
29
+ puts out
30
+ unless st.to_i.zero?
31
+ @failed = true
32
+ puts err
33
+ end
34
+ checked_links = out.split "\n"
35
+ checked_links.select! { |link| link =~ /\[\d+\]/ && !link.include?("[200]") }
36
+ unless checked_links.empty?
37
+ @failed = true
38
+ broken_links[location] += checked_links
39
+ end
40
+ end
41
+ broken_links
42
+ end
43
+
44
+ def puts_broken_links link_hash
45
+ link_hash.each do |location, links|
46
+ puts "#{location} contains the following broken links:"
47
+ links.each { |link| puts " #{link}" }
48
+ puts ""
49
+ end
50
+ end
51
+
52
+ def job_info
53
+ line_length = "Using Ruby - #{RUBY_VERSION}".length + 8
54
+ puts ""
55
+ puts "#" * line_length
56
+ puts "### Using Ruby - #{RUBY_VERSION} ###"
57
+ puts "#" * line_length
58
+ puts ""
59
+ end
60
+
61
+ def exit_status
62
+ @failed ? 1 : 0
63
+ end
64
+ end
@@ -0,0 +1,59 @@
1
+ require "json"
2
+
3
+ class RepoMetadata
4
+ attr_reader :data
5
+
6
+ def initialize data
7
+ @data = data
8
+ normalize_data!
9
+ end
10
+
11
+ def allowed_fields
12
+ [
13
+ "name", "version", "language", "distribution-name",
14
+ "product-page", "github-repository", "issue-tracker"
15
+ ]
16
+ end
17
+
18
+ def build output_directory
19
+ fields = @data.to_a.map { |kv| "--#{kv[0]} #{kv[1]}" }
20
+ Dir.chdir output_directory do
21
+ cmd "python3 -m docuploader create-metadata #{fields.join ' '}"
22
+ end
23
+ end
24
+
25
+ def normalize_data!
26
+ require_relative "../lib/googleauth/version.rb"
27
+
28
+ @data.delete_if { |k, _| !allowed_fields.include?(k) }
29
+ @data["version"] = "v#{Google::Auth::VERSION}"
30
+ end
31
+
32
+ def [] key
33
+ data[key]
34
+ end
35
+
36
+ def []= key, value
37
+ @data[key] = value
38
+ end
39
+
40
+ def cmd line
41
+ puts line
42
+ output = `#{line}`
43
+ puts output
44
+ output
45
+ end
46
+
47
+ def self.from_source source
48
+ if source.is_a? RepoMetadata
49
+ data = source.data
50
+ elsif source.is_a? Hash
51
+ data = source
52
+ elsif File.file? source
53
+ data = JSON.parse File.read(source)
54
+ else
55
+ raise "Source must be a path, hash, or RepoMetadata instance"
56
+ end
57
+ RepoMetadata.new data
58
+ end
59
+ end
@@ -27,14 +27,14 @@
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
- spec_dir = File.expand_path(File.join(File.dirname(__FILE__)))
31
- $LOAD_PATH.unshift(spec_dir)
30
+ spec_dir = File.expand_path File.join(File.dirname(__FILE__))
31
+ $LOAD_PATH.unshift spec_dir
32
32
  $LOAD_PATH.uniq!
33
33
 
34
- require 'faraday'
35
- require 'spec_helper'
34
+ require "faraday"
35
+ require "spec_helper"
36
36
 
37
- shared_examples 'apply/apply! are OK' do
37
+ shared_examples "apply/apply! are OK" do
38
38
  let(:auth_key) { :authorization }
39
39
 
40
40
  # tests that use these examples need to define
@@ -43,102 +43,126 @@ shared_examples 'apply/apply! are OK' do
43
43
  #
44
44
  # @make_auth_stubs, which should stub out the expected http behaviour of the
45
45
  # auth client
46
- describe '#fetch_access_token' do
47
- let(:token) { '1/abcdef1234567890' }
48
- let(:stub) do
46
+ describe "#fetch_access_token" do
47
+ let(:token) { "1/abcdef1234567890" }
48
+ let :access_stub do
49
49
  make_auth_stubs access_token: token
50
50
  end
51
+ let :id_stub do
52
+ make_auth_stubs id_token: token
53
+ end
51
54
 
52
- it 'should set access_token to the fetched value' do
53
- stub
55
+ it "should set access_token to the fetched value" do
56
+ access_stub
54
57
  @client.fetch_access_token!
55
58
  expect(@client.access_token).to eq(token)
56
- expect(stub).to have_been_requested
59
+ expect(access_stub).to have_been_requested
57
60
  end
58
61
 
59
- it 'should notify refresh listeners after updating' do
60
- stub
62
+ it "should set id_token to the fetched value" do
63
+ skip unless @id_client
64
+ id_stub
65
+ @id_client.fetch_access_token!
66
+ expect(@id_client.id_token).to eq(token)
67
+ expect(id_stub).to have_been_requested
68
+ end
69
+
70
+ it "should notify refresh listeners after updating" do
71
+ access_stub
61
72
  expect do |b|
62
73
  @client.on_refresh(&b)
63
74
  @client.fetch_access_token!
64
75
  end.to yield_with_args(have_attributes(
65
- access_token: '1/abcdef1234567890'))
66
- expect(stub).to have_been_requested
76
+ access_token: "1/abcdef1234567890"
77
+ ))
78
+ expect(access_stub).to have_been_requested
67
79
  end
68
80
  end
69
81
 
70
- describe '#apply!' do
71
- it 'should update the target hash with fetched access token' do
72
- token = '1/abcdef1234567890'
82
+ describe "#apply!" do
83
+ it "should update the target hash with fetched access token" do
84
+ token = "1/abcdef1234567890"
73
85
  stub = make_auth_stubs access_token: token
74
86
 
75
- md = { foo: 'bar' }
76
- @client.apply!(md)
77
- want = { :foo => 'bar', auth_key => "Bearer #{token}" }
87
+ md = { foo: "bar" }
88
+ @client.apply! md
89
+ want = { :foo => "bar", auth_key => "Bearer #{token}" }
90
+ expect(md).to eq(want)
91
+ expect(stub).to have_been_requested
92
+ end
93
+
94
+ it "should update the target hash with fetched ID token" do
95
+ skip unless @id_client
96
+ token = "1/abcdef1234567890"
97
+ stub = make_auth_stubs id_token: token
98
+
99
+ md = { foo: "bar" }
100
+ @id_client.apply! md
101
+ want = { :foo => "bar", auth_key => "Bearer #{token}" }
78
102
  expect(md).to eq(want)
79
103
  expect(stub).to have_been_requested
80
104
  end
81
105
  end
82
106
 
83
- describe 'updater_proc' do
84
- it 'should provide a proc that updates a hash with the access token' do
85
- token = '1/abcdef1234567890'
107
+ describe "updater_proc" do
108
+ it "should provide a proc that updates a hash with the access token" do
109
+ token = "1/abcdef1234567890"
86
110
  stub = make_auth_stubs access_token: token
87
- md = { foo: 'bar' }
111
+ md = { foo: "bar" }
88
112
  the_proc = @client.updater_proc
89
- got = the_proc.call(md)
90
- want = { :foo => 'bar', auth_key => "Bearer #{token}" }
113
+ got = the_proc.call md
114
+ want = { :foo => "bar", auth_key => "Bearer #{token}" }
91
115
  expect(got).to eq(want)
92
116
  expect(stub).to have_been_requested
93
117
  end
94
118
  end
95
119
 
96
- describe '#apply' do
97
- it 'should not update the original hash with the access token' do
98
- token = '1/abcdef1234567890'
120
+ describe "#apply" do
121
+ it "should not update the original hash with the access token" do
122
+ token = "1/abcdef1234567890"
99
123
  stub = make_auth_stubs access_token: token
100
124
 
101
- md = { foo: 'bar' }
102
- @client.apply(md)
103
- want = { foo: 'bar' }
125
+ md = { foo: "bar" }
126
+ @client.apply md
127
+ want = { foo: "bar" }
104
128
  expect(md).to eq(want)
105
129
  expect(stub).to have_been_requested
106
130
  end
107
131
 
108
- it 'should add the token to the returned hash' do
109
- token = '1/abcdef1234567890'
132
+ it "should add the token to the returned hash" do
133
+ token = "1/abcdef1234567890"
110
134
  stub = make_auth_stubs access_token: token
111
135
 
112
- md = { foo: 'bar' }
113
- got = @client.apply(md)
114
- want = { :foo => 'bar', auth_key => "Bearer #{token}" }
136
+ md = { foo: "bar" }
137
+ got = @client.apply md
138
+ want = { :foo => "bar", auth_key => "Bearer #{token}" }
115
139
  expect(got).to eq(want)
116
140
  expect(stub).to have_been_requested
117
141
  end
118
142
 
119
- it 'should not fetch a new token if the current is not expired' do
120
- token = '1/abcdef1234567890'
143
+ it "should not fetch a new token if the current is not expired" do
144
+ token = "1/abcdef1234567890"
121
145
  stub = make_auth_stubs access_token: token
122
146
 
123
147
  n = 5 # arbitrary
124
148
  n.times do |_t|
125
- md = { foo: 'bar' }
126
- got = @client.apply(md)
127
- want = { :foo => 'bar', auth_key => "Bearer #{token}" }
149
+ md = { foo: "bar" }
150
+ got = @client.apply md
151
+ want = { :foo => "bar", auth_key => "Bearer #{token}" }
128
152
  expect(got).to eq(want)
129
153
  end
130
154
  expect(stub).to have_been_requested
131
155
  end
132
156
 
133
- it 'should fetch a new token if the current one is expired' do
134
- token_1 = '1/abcdef1234567890'
135
- token_2 = '2/abcdef1234567891'
157
+ it "should fetch a new token if the current one is expired" do
158
+ token1 = "1/abcdef1234567890"
159
+ token2 = "2/abcdef1234567891"
136
160
 
137
- [token_1, token_2].each do |t|
161
+ [token1, token2].each do |t|
138
162
  make_auth_stubs access_token: t
139
- md = { foo: 'bar' }
140
- got = @client.apply(md)
141
- want = { :foo => 'bar', auth_key => "Bearer #{t}" }
163
+ md = { foo: "bar" }
164
+ got = @client.apply md
165
+ want = { :foo => "bar", auth_key => "Bearer #{t}" }
142
166
  expect(got).to eq(want)
143
167
  @client.expires_at -= 3601 # default is to expire in 1hr
144
168
  end