googleauth 0.4.2 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -57,7 +57,7 @@ describe Google::Auth::UserRefreshCredentials do
57
57
 
58
58
  before(:example) do
59
59
  @key = OpenSSL::PKey::RSA.new(2048)
60
- @client = UserRefreshCredentials.new(
60
+ @client = UserRefreshCredentials.make_creds(
61
61
  json_key_io: StringIO.new(cred_json_text),
62
62
  scope: 'https://www.googleapis.com/auth/userinfo.profile'
63
63
  )
@@ -65,14 +65,14 @@ describe Google::Auth::UserRefreshCredentials do
65
65
 
66
66
  def make_auth_stubs(opts = {})
67
67
  access_token = opts[:access_token] || ''
68
- Faraday::Adapter::Test::Stubs.new do |stub|
69
- stub.post('/oauth2/v3/token') do |env|
70
- params = Addressable::URI.form_unencode(env[:body])
71
- want = %w(grant_type refresh_token)
72
- expect(params.assoc('grant_type')).to eq(want)
73
- build_access_token_json(access_token)
74
- end
75
- end
68
+ body = MultiJson.dump('access_token' => access_token,
69
+ 'token_type' => 'Bearer',
70
+ 'expires_in' => 3600)
71
+ stub_request(:post, 'https://www.googleapis.com/oauth2/v3/token')
72
+ .with(body: hash_including('grant_type' => 'refresh_token'))
73
+ .to_return(body: body,
74
+ status: 200,
75
+ headers: { 'Content-Type' => 'application/json' })
76
76
  end
77
77
 
78
78
  def cred_json_text(missing = nil)
@@ -142,10 +142,11 @@ describe Google::Auth::UserRefreshCredentials do
142
142
  ENV[CLIENT_SECRET_VAR] = cred_json[:client_secret]
143
143
  ENV[REFRESH_TOKEN_VAR] = cred_json[:refresh_token]
144
144
  ENV[ACCOUNT_TYPE_VAR] = cred_json[:type]
145
- expect(@clz.from_env(@scope)).to_not be_nil
146
- expect(subject.client_id).to eq(cred_json[:client_id])
147
- expect(subject.client_secret).to eq(cred_json[:client_secret])
148
- expect(subject.refresh_token).to eq(cred_json[:refresh_token])
145
+ creds = @clz.from_env(@scope)
146
+ expect(creds).to_not be_nil
147
+ expect(creds.client_id).to eq(cred_json[:client_id])
148
+ expect(creds.client_secret).to eq(cred_json[:client_secret])
149
+ expect(creds.refresh_token).to eq(cred_json[:refresh_token])
149
150
  end
150
151
  end
151
152
 
@@ -227,4 +228,67 @@ describe Google::Auth::UserRefreshCredentials do
227
228
  end
228
229
  end
229
230
  end
231
+
232
+ shared_examples 'revoked token' do
233
+ it 'should nil the refresh token' do
234
+ expect(@client.refresh_token).to be_nil
235
+ end
236
+
237
+ it 'should nil the access token' do
238
+ expect(@client.access_token).to be_nil
239
+ end
240
+
241
+ it 'should mark the token as expired' do
242
+ expect(@client.expired?).to be_truthy
243
+ end
244
+ end
245
+
246
+ describe 'when revoking a refresh token' do
247
+ let(:stub) do
248
+ stub_request(:get, 'https://accounts.google.com/o/oauth2/revoke' \
249
+ '?token=refreshtoken')
250
+ .to_return(status: 200,
251
+ headers: { 'Content-Type' => 'application/json' })
252
+ end
253
+
254
+ before(:example) do
255
+ stub
256
+ @client.revoke!
257
+ end
258
+
259
+ it_behaves_like 'revoked token'
260
+ end
261
+
262
+ describe 'when revoking an access token' do
263
+ let(:stub) do
264
+ stub_request(:get, 'https://accounts.google.com/o/oauth2/revoke' \
265
+ '?token=accesstoken')
266
+ .to_return(status: 200,
267
+ headers: { 'Content-Type' => 'application/json' })
268
+ end
269
+
270
+ before(:example) do
271
+ stub
272
+ @client.refresh_token = nil
273
+ @client.access_token = 'accesstoken'
274
+ @client.revoke!
275
+ end
276
+
277
+ it_behaves_like 'revoked token'
278
+ end
279
+
280
+ describe 'when revoking an invalid token' do
281
+ let(:stub) do
282
+ stub_request(:get, 'https://accounts.google.com/o/oauth2/revoke' \
283
+ '?token=refreshtoken')
284
+ .to_return(status: 400,
285
+ headers: { 'Content-Type' => 'application/json' })
286
+ end
287
+
288
+ it 'raises an authorization error' do
289
+ stub
290
+ expect { @client.revoke! }.to raise_error(
291
+ Signet::AuthorizationError)
292
+ end
293
+ end
230
294
  end
@@ -0,0 +1,159 @@
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
+ spec_dir = File.expand_path(File.join(File.dirname(__FILE__)))
31
+ $LOAD_PATH.unshift(spec_dir)
32
+ $LOAD_PATH.uniq!
33
+
34
+ require 'googleauth'
35
+ require 'googleauth/web_user_authorizer'
36
+ require 'uri'
37
+ require 'multi_json'
38
+ require 'spec_helper'
39
+ require 'rack'
40
+
41
+ describe Google::Auth::WebUserAuthorizer do
42
+ include TestHelpers
43
+
44
+ let(:client_id) { Google::Auth::ClientId.new('testclient', 'notasecret') }
45
+ let(:scope) { %w(email profile) }
46
+ let(:token_store) { DummyTokenStore.new }
47
+ let(:authorizer) do
48
+ Google::Auth::WebUserAuthorizer.new(client_id, scope, token_store)
49
+ end
50
+
51
+ describe '#get_authorization_url' do
52
+ let(:env) do
53
+ Rack::MockRequest.env_for(
54
+ 'http://example.com:8080/test',
55
+ 'REMOTE_ADDR' => '10.10.10.10')
56
+ end
57
+ let(:request) { Rack::Request.new(env) }
58
+ it 'should include current url in state' do
59
+ url = authorizer.get_authorization_url(request: request)
60
+ expect(url).to match(
61
+ %r{%22current_uri%22:%22http://example.com:8080/test%22})
62
+ end
63
+
64
+ it 'should include request forgery token in state' do
65
+ expect(SecureRandom).to receive(:base64).and_return('aGVsbG8=')
66
+ url = authorizer.get_authorization_url(request: request)
67
+ expect(url).to match(/%22session_id%22:%22aGVsbG8=%22/)
68
+ end
69
+
70
+ it 'should include request forgery token in session' do
71
+ expect(SecureRandom).to receive(:base64).and_return('aGVsbG8=')
72
+ authorizer.get_authorization_url(request: request)
73
+ expect(request.session['g-xsrf-token']).to eq 'aGVsbG8='
74
+ end
75
+
76
+ it 'should resolve callback against base URL' do
77
+ url = authorizer.get_authorization_url(request: request)
78
+ expect(url).to match(
79
+ %r{redirect_uri=http://example.com:8080/oauth2callback})
80
+ end
81
+
82
+ it 'should allow overriding the current URL' do
83
+ url = authorizer.get_authorization_url(
84
+ request: request,
85
+ redirect_to: '/foo')
86
+ expect(url).to match %r{%22current_uri%22:%22/foo%22}
87
+ end
88
+
89
+ it 'should pass through login hint' do
90
+ url = authorizer.get_authorization_url(
91
+ request: request,
92
+ login_hint: 'user@example.com')
93
+ expect(url).to match(/login_hint=user@example.com/)
94
+ end
95
+ end
96
+
97
+ shared_examples 'handles callback' do
98
+ let(:token_json) do
99
+ MultiJson.dump('access_token' => '1/abc123',
100
+ 'token_type' => 'Bearer',
101
+ 'expires_in' => 3600)
102
+ end
103
+
104
+ before(:example) do
105
+ stub_request(:post, 'https://www.googleapis.com/oauth2/v3/token')
106
+ .to_return(body: token_json,
107
+ status: 200,
108
+ headers: { 'Content-Type' => 'application/json' })
109
+ end
110
+
111
+ let(:env) do
112
+ Rack::MockRequest.env_for(
113
+ 'http://example.com:8080/oauth2callback?code=authcode&'\
114
+ 'state=%7B%22current_uri%22%3A%22%2Ffoo%22%2C%22'\
115
+ 'session_id%22%3A%22abc%22%7D',
116
+ 'REMOTE_ADDR' => '10.10.10.10')
117
+ end
118
+ let(:request) { Rack::Request.new(env) }
119
+
120
+ before(:example) do
121
+ request.session['g-xsrf-token'] = 'abc'
122
+ end
123
+
124
+ it 'should return credentials when valid code present' do
125
+ expect(credentials).to be_instance_of(
126
+ Google::Auth::UserRefreshCredentials)
127
+ end
128
+
129
+ it 'should return next URL to redirect to' do
130
+ expect(next_url).to eq '/foo'
131
+ end
132
+
133
+ it 'should fail if xrsf token in session and does not match request' do
134
+ request.session['g-xsrf-token'] = '123'
135
+ expect { credentials }.to raise_error(Signet::AuthorizationError)
136
+ end
137
+ end
138
+
139
+ describe '#handle_auth_callback' do
140
+ let(:result) { authorizer.handle_auth_callback('user1', request) }
141
+ let(:credentials) { result[0] }
142
+ let(:next_url) { result[1] }
143
+
144
+ it_behaves_like 'handles callback'
145
+ end
146
+
147
+ describe '#handle_auth_callback_deferred and #get_credentials' do
148
+ let(:next_url) do
149
+ Google::Auth::WebUserAuthorizer.handle_auth_callback_deferred(request)
150
+ end
151
+
152
+ let(:credentials) do
153
+ next_url
154
+ authorizer.get_credentials('user1', request)
155
+ end
156
+
157
+ it_behaves_like 'handles callback'
158
+ end
159
+ end
@@ -39,13 +39,21 @@ $LOAD_PATH.uniq!
39
39
  require 'simplecov'
40
40
  require 'coveralls'
41
41
 
42
- SimpleCov.formatter = Coveralls::SimpleCov::Formatter
42
+ SimpleCov.formatters = [
43
+ Coveralls::SimpleCov::Formatter,
44
+ SimpleCov::Formatter::HTMLFormatter
45
+ ]
43
46
  SimpleCov.start
44
47
 
45
48
  require 'faraday'
46
49
  require 'rspec'
47
50
  require 'logging'
48
51
  require 'rspec/logging_helper'
52
+ require 'webmock/rspec'
53
+ require 'multi_json'
54
+
55
+ # Preload adapter to work around Rubinius error with FakeFS
56
+ MultiJson.use(:json_gem)
49
57
 
50
58
  # Allow Faraday to support test stubs
51
59
  Faraday::Adapter.load_middleware(:test)
@@ -55,4 +63,28 @@ Faraday::Adapter.load_middleware(:test)
55
63
  RSpec.configure do |config|
56
64
  include RSpec::LoggingHelper
57
65
  config.capture_log_messages
66
+ config.include WebMock::API
67
+ end
68
+
69
+ module TestHelpers
70
+ include WebMock::API
71
+ include WebMock::Matchers
72
+ end
73
+
74
+ class DummyTokenStore
75
+ def initialize
76
+ @tokens = {}
77
+ end
78
+
79
+ def load(id)
80
+ @tokens[id]
81
+ end
82
+
83
+ def store(id, token)
84
+ @tokens[id] = token
85
+ end
86
+
87
+ def delete(id)
88
+ @tokens.delete(id)
89
+ end
58
90
  end
metadata CHANGED
@@ -1,197 +1,99 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: googleauth
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.2
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tim Emiola
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-08-06 00:00:00.000000000 Z
11
+ date: 2015-12-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- type: :runtime
15
14
  name: faraday
16
- prerelease: false
17
15
  requirement: !ruby/object:Gem::Requirement
18
16
  requirements:
19
17
  - - "~>"
20
18
  - !ruby/object:Gem::Version
21
19
  version: '0.9'
20
+ type: :runtime
21
+ prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0.9'
27
27
  - !ruby/object:Gem::Dependency
28
- type: :runtime
29
28
  name: logging
30
- prerelease: false
31
29
  requirement: !ruby/object:Gem::Requirement
32
30
  requirements:
33
31
  - - "~>"
34
32
  - !ruby/object:Gem::Version
35
33
  version: '2.0'
34
+ type: :runtime
35
+ prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: '2.0'
41
41
  - !ruby/object:Gem::Dependency
42
- type: :runtime
43
42
  name: jwt
44
- prerelease: false
45
43
  requirement: !ruby/object:Gem::Requirement
46
44
  requirements:
47
45
  - - "~>"
48
46
  - !ruby/object:Gem::Version
49
47
  version: '1.4'
48
+ type: :runtime
49
+ prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
54
  version: '1.4'
55
55
  - !ruby/object:Gem::Dependency
56
- type: :runtime
57
56
  name: memoist
58
- prerelease: false
59
57
  requirement: !ruby/object:Gem::Requirement
60
58
  requirements:
61
59
  - - "~>"
62
60
  - !ruby/object:Gem::Version
63
61
  version: '0.12'
62
+ type: :runtime
63
+ prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0.12'
69
69
  - !ruby/object:Gem::Dependency
70
- type: :runtime
71
70
  name: multi_json
72
- prerelease: false
73
71
  requirement: !ruby/object:Gem::Requirement
74
72
  requirements:
75
73
  - - "~>"
76
74
  - !ruby/object:Gem::Version
77
75
  version: '1.11'
78
- version_requirements: !ruby/object:Gem::Requirement
79
- requirements:
80
- - - "~>"
81
- - !ruby/object:Gem::Version
82
- version: '1.11'
83
- - !ruby/object:Gem::Dependency
84
76
  type: :runtime
85
- name: signet
86
- prerelease: false
87
- requirement: !ruby/object:Gem::Requirement
88
- requirements:
89
- - - "~>"
90
- - !ruby/object:Gem::Version
91
- version: '0.6'
92
- version_requirements: !ruby/object:Gem::Requirement
93
- requirements:
94
- - - "~>"
95
- - !ruby/object:Gem::Version
96
- version: '0.6'
97
- - !ruby/object:Gem::Dependency
98
- type: :development
99
- name: bundler
100
- prerelease: false
101
- requirement: !ruby/object:Gem::Requirement
102
- requirements:
103
- - - "~>"
104
- - !ruby/object:Gem::Version
105
- version: '1.9'
106
- version_requirements: !ruby/object:Gem::Requirement
107
- requirements:
108
- - - "~>"
109
- - !ruby/object:Gem::Version
110
- version: '1.9'
111
- - !ruby/object:Gem::Dependency
112
- type: :development
113
- name: simplecov
114
77
  prerelease: false
115
- requirement: !ruby/object:Gem::Requirement
116
- requirements:
117
- - - "~>"
118
- - !ruby/object:Gem::Version
119
- version: '0.9'
120
78
  version_requirements: !ruby/object:Gem::Requirement
121
79
  requirements:
122
80
  - - "~>"
123
81
  - !ruby/object:Gem::Version
124
- version: '0.9'
82
+ version: '1.11'
125
83
  - !ruby/object:Gem::Dependency
126
- type: :development
127
- name: coveralls
128
- prerelease: false
84
+ name: signet
129
85
  requirement: !ruby/object:Gem::Requirement
130
86
  requirements:
131
87
  - - "~>"
132
88
  - !ruby/object:Gem::Version
133
89
  version: '0.7'
134
- version_requirements: !ruby/object:Gem::Requirement
135
- requirements:
136
- - - "~>"
137
- - !ruby/object:Gem::Version
138
- version: '0.7'
139
- - !ruby/object:Gem::Dependency
140
- type: :development
141
- name: fakefs
142
- prerelease: false
143
- requirement: !ruby/object:Gem::Requirement
144
- requirements:
145
- - - "~>"
146
- - !ruby/object:Gem::Version
147
- version: '0.6'
148
- version_requirements: !ruby/object:Gem::Requirement
149
- requirements:
150
- - - "~>"
151
- - !ruby/object:Gem::Version
152
- version: '0.6'
153
- - !ruby/object:Gem::Dependency
154
- type: :development
155
- name: rake
156
- prerelease: false
157
- requirement: !ruby/object:Gem::Requirement
158
- requirements:
159
- - - "~>"
160
- - !ruby/object:Gem::Version
161
- version: '10.0'
162
- version_requirements: !ruby/object:Gem::Requirement
163
- requirements:
164
- - - "~>"
165
- - !ruby/object:Gem::Version
166
- version: '10.0'
167
- - !ruby/object:Gem::Dependency
168
- type: :development
169
- name: rubocop
170
- prerelease: false
171
- requirement: !ruby/object:Gem::Requirement
172
- requirements:
173
- - - "~>"
174
- - !ruby/object:Gem::Version
175
- version: '0.30'
176
- version_requirements: !ruby/object:Gem::Requirement
177
- requirements:
178
- - - "~>"
179
- - !ruby/object:Gem::Version
180
- version: '0.30'
181
- - !ruby/object:Gem::Dependency
182
- type: :development
183
- name: rspec
90
+ type: :runtime
184
91
  prerelease: false
185
- requirement: !ruby/object:Gem::Requirement
186
- requirements:
187
- - - "~>"
188
- - !ruby/object:Gem::Version
189
- version: '3.0'
190
92
  version_requirements: !ruby/object:Gem::Requirement
191
93
  requirements:
192
94
  - - "~>"
193
95
  - !ruby/object:Gem::Version
194
- version: '3.0'
96
+ version: '0.7'
195
97
  description: |2
196
98
  Allows simple authorization for accessing Google APIs.
197
99
  Provide support for Application Default Credentials, as described at
@@ -214,20 +116,34 @@ files:
214
116
  - Rakefile
215
117
  - googleauth.gemspec
216
118
  - lib/googleauth.rb
119
+ - lib/googleauth/client_id.rb
217
120
  - lib/googleauth/compute_engine.rb
218
121
  - lib/googleauth/credentials_loader.rb
219
122
  - lib/googleauth/iam.rb
123
+ - lib/googleauth/scope_util.rb
220
124
  - lib/googleauth/service_account.rb
221
125
  - lib/googleauth/signet.rb
126
+ - lib/googleauth/stores/file_token_store.rb
127
+ - lib/googleauth/stores/redis_token_store.rb
128
+ - lib/googleauth/token_store.rb
129
+ - lib/googleauth/user_authorizer.rb
222
130
  - lib/googleauth/user_refresh.rb
223
131
  - lib/googleauth/version.rb
132
+ - lib/googleauth/web_user_authorizer.rb
224
133
  - spec/googleauth/apply_auth_examples.rb
134
+ - spec/googleauth/client_id_spec.rb
225
135
  - spec/googleauth/compute_engine_spec.rb
226
136
  - spec/googleauth/get_application_default_spec.rb
227
137
  - spec/googleauth/iam_spec.rb
138
+ - spec/googleauth/scope_util_spec.rb
228
139
  - spec/googleauth/service_account_spec.rb
229
140
  - spec/googleauth/signet_spec.rb
141
+ - spec/googleauth/stores/file_token_store_spec.rb
142
+ - spec/googleauth/stores/redis_token_store_spec.rb
143
+ - spec/googleauth/stores/store_examples.rb
144
+ - spec/googleauth/user_authorizer_spec.rb
230
145
  - spec/googleauth/user_refresh_spec.rb
146
+ - spec/googleauth/web_user_authorizer_spec.rb
231
147
  - spec/spec_helper.rb
232
148
  homepage: https://github.com/google/google-auth-library-ruby
233
149
  licenses:
@@ -249,16 +165,24 @@ required_rubygems_version: !ruby/object:Gem::Requirement
249
165
  version: '0'
250
166
  requirements: []
251
167
  rubyforge_project:
252
- rubygems_version: 2.4.8
168
+ rubygems_version: 2.4.3
253
169
  signing_key:
254
170
  specification_version: 4
255
171
  summary: Google Auth Library for Ruby
256
172
  test_files:
257
173
  - spec/googleauth/apply_auth_examples.rb
174
+ - spec/googleauth/client_id_spec.rb
258
175
  - spec/googleauth/compute_engine_spec.rb
259
176
  - spec/googleauth/get_application_default_spec.rb
260
177
  - spec/googleauth/iam_spec.rb
178
+ - spec/googleauth/scope_util_spec.rb
261
179
  - spec/googleauth/service_account_spec.rb
262
180
  - spec/googleauth/signet_spec.rb
181
+ - spec/googleauth/stores/file_token_store_spec.rb
182
+ - spec/googleauth/stores/redis_token_store_spec.rb
183
+ - spec/googleauth/stores/store_examples.rb
184
+ - spec/googleauth/user_authorizer_spec.rb
263
185
  - spec/googleauth/user_refresh_spec.rb
186
+ - spec/googleauth/web_user_authorizer_spec.rb
264
187
  - spec/spec_helper.rb
188
+ has_rdoc: