omniauth-microsoft_graph 0.2.1 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of omniauth-microsoft_graph might be problematic. Click here for more details.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: bc7fe638d8adc7a7d35f5c16bdee73b203ac1692
4
- data.tar.gz: 61003e06a1329c5da156f151293af05d9b55c34c
3
+ metadata.gz: d5fb7e4f89d46058d18c857dbe0935cbf720c802
4
+ data.tar.gz: 29291329512d0d36bad6e0ff1a3917f842a4b83c
5
5
  SHA512:
6
- metadata.gz: 2a3d808f2b673c8400650aebf3e8ac942b34f378b4419f358ddbeaee3c2780081447118dc18555d9761c6d5e4ed34da687b79da685dc04deb4d9967549041bd4
7
- data.tar.gz: ffe7af4f24659f74743360a51b8f67bb4e4f367c9bf1f4fe32b29bd9ca5781b24e10f0046c3ba3073d68595f071d5360840ace5f377eec3c088f8f9053a57dd8
6
+ metadata.gz: 339872f74676b8269b0a92c46f56bdb8b350a6fe64df495bd23a8580ed45645b258bd181bbb82ab68faa362de0a9b1823bd25e71a0ba60a629d4e517fe33cbf5
7
+ data.tar.gz: b562fde6e3529990b1caa343c7044f7ae3dd02d66c41065aa6332c8282290397f21a310080f109581784dbd58b91f3ea2a5662518326705e47fac38727de4ef4
@@ -1,4 +1,5 @@
1
1
  language: ruby
2
2
  rvm:
3
- - 2.2
3
+ - 2.3
4
+ - 2.6
4
5
  - jruby
data/Rakefile CHANGED
@@ -1,10 +1,8 @@
1
- require "bundler/gem_tasks"
2
- require "rake/testtask"
1
+ # frozen_string_literal: true
3
2
 
4
- Rake::TestTask.new(:test) do |t|
5
- t.libs << "test"
6
- t.test_files = FileList['test/*_test.rb']
7
- end
3
+ require File.join('bundler', 'gem_tasks')
4
+ require File.join('rspec', 'core', 'rake_task')
8
5
 
9
- task :default => :test
6
+ RSpec::Core::RakeTask.new(:spec)
10
7
 
8
+ task default: :spec
@@ -1,5 +1,5 @@
1
1
  module Omniauth
2
2
  module MicrosoftGraph
3
- VERSION = "0.2.1"
3
+ VERSION = "0.3.0"
4
4
  end
5
5
  end
@@ -3,64 +3,123 @@ require 'omniauth-oauth2'
3
3
  module OmniAuth
4
4
  module Strategies
5
5
  class MicrosoftGraph < OmniAuth::Strategies::OAuth2
6
+ BASE_SCOPE_URL = 'https://graph.microsoft.com/'
7
+ BASE_SCOPES = %w[offline_access openid email profile].freeze
8
+ DEFAULT_SCOPE = 'openid email profile User.Read'.freeze
9
+
6
10
  option :name, :microsoft_graph
7
11
 
8
12
  option :client_options, {
9
- site: 'https://login.microsoftonline.com',
10
- token_url: '/common/oauth2/v2.0/token',
11
- authorize_url: '/common/oauth2/v2.0/authorize'
13
+ site: 'https://login.microsoftonline.com/',
14
+ token_url: 'common/oauth2/v2.0/token',
15
+ authorize_url: 'common/oauth2/v2.0/authorize'
16
+ }
17
+
18
+ option :authorize_options, %i[state callback_url access_type display score auth_type scope prompt login_hint domain_hint response_mode]
19
+
20
+ option :token_params, {
12
21
  }
13
22
 
14
- option :authorize_options, %i[display score auth_type scope prompt login_hint domain_hint response_mode]
23
+ option :scope, DEFAULT_SCOPE
24
+ option :authorized_client_ids, []
15
25
 
16
26
  uid { raw_info["id"] }
17
27
 
18
28
  info do
19
29
  {
20
- email: raw_info["mail"] || raw_info["userPrincipalName"],
21
- first_name: raw_info["givenName"],
22
- last_name: raw_info["surname"],
23
- name: full_name,
24
- nickname: raw_info["userPrincipalName"],
30
+ 'email' => raw_info["mail"],
31
+ 'first_name' => raw_info["givenName"],
32
+ 'last_name' => raw_info["surname"],
33
+ 'name' => [raw_info["givenName"], raw_info["surname"]].join(' '),
34
+ 'nickname' => raw_info["displayName"],
25
35
  }
26
36
  end
27
37
 
28
38
  extra do
29
39
  {
30
40
  'raw_info' => raw_info,
31
- 'params' => access_token.params
41
+ 'params' => access_token.params,
42
+ 'aud' => options.client_id
32
43
  }
33
44
  end
34
-
35
- def callback_url
36
- options[:redirect_uri] || (full_host + script_name + callback_path)
37
- end
38
-
39
- def raw_info
40
- @raw_info ||= access_token.get('https://graph.microsoft.com/v1.0/me').parsed
41
- end
42
45
 
43
46
  def authorize_params
44
47
  super.tap do |params|
45
- %w[display score auth_type].each do |v|
46
- if request.params[v]
47
- params[v.to_sym] = request.params[v]
48
- end
48
+ options[:authorize_options].each do |k|
49
+ params[k] = request.params[k.to_s] unless [nil, ''].include?(request.params[k.to_s])
49
50
  end
51
+
52
+ params[:scope] = get_scope(params)
53
+ params[:access_type] = 'offline' if params[:access_type].nil?
54
+
55
+ session['omniauth.state'] = params[:state] if params[:state]
50
56
  end
57
+ end
58
+
59
+ def raw_info
60
+ @raw_info ||= access_token.get('https://graph.microsoft.com/v1.0/me').parsed
51
61
  end
52
62
 
53
- def full_name
54
- raw_info["displayName"].presence || raw_info.values_at("givenName", "surname").compact.join(' ')
63
+ def callback_url
64
+ options[:callback_url] || full_host + script_name + callback_path
65
+ end
66
+
67
+ def custom_build_access_token
68
+ access_token = get_access_token(request)
69
+ access_token
55
70
  end
56
71
 
57
- def build_access_token
58
- if request.params['access_token']
72
+ alias build_access_token custom_build_access_token
73
+
74
+ private
75
+
76
+ def get_access_token(request)
77
+ verifier = request.params['code']
78
+ redirect_uri = request.params['redirect_uri'] || request.params['callback_url']
79
+ if verifier && request.xhr?
80
+ client_get_token(verifier, redirect_uri || '/auth/microsoft_graph/callback')
81
+ elsif verifier
82
+ client_get_token(verifier, redirect_uri || callback_url)
83
+ elsif verify_token(request.params['access_token'])
59
84
  ::OAuth2::AccessToken.from_hash(client, request.params.dup)
60
- else
61
- super
85
+ elsif request.content_type =~ /json/i
86
+ begin
87
+ body = JSON.parse(request.body.read)
88
+ request.body.rewind # rewind request body for downstream middlewares
89
+ verifier = body && body['code']
90
+ client_get_token(verifier, '/auth/microsoft_graph/callback') if verifier
91
+ rescue JSON::ParserError => e
92
+ warn "[omniauth google-oauth2] JSON parse error=#{e}"
93
+ end
62
94
  end
63
95
  end
96
+
97
+ def client_get_token(verifier, redirect_uri)
98
+ client.auth_code.get_token(verifier, get_token_options(redirect_uri), get_token_params)
99
+ end
100
+
101
+ def get_token_params
102
+ deep_symbolize(options.auth_token_params || {})
103
+ end
104
+
105
+ def get_token_options(redirect_uri = '')
106
+ { redirect_uri: redirect_uri }.merge(token_params.to_hash(symbolize_keys: true))
107
+ end
108
+
109
+ def get_scope(params)
110
+ raw_scope = params[:scope] || DEFAULT_SCOPE
111
+ scope_list = raw_scope.split(' ').map { |item| item.split(',') }.flatten
112
+ scope_list.map! { |s| s =~ %r{^https?://} || BASE_SCOPES.include?(s) ? s : "#{BASE_SCOPE_URL}#{s}" }
113
+ scope_list.join(' ')
114
+ end
115
+
116
+ def verify_token(access_token)
117
+ return false unless access_token
118
+ # access_token.get('https://graph.microsoft.com/v1.0/me').parsed
119
+ raw_response = client.request(:get, 'https://graph.microsoft.com/v1.0/me',
120
+ params: { access_token: access_token }).parsed
121
+ (raw_response['aud'] == options.client_id) || options.authorized_client_ids.include?(raw_response['aud'])
122
+ end
64
123
  end
65
124
  end
66
125
  end
@@ -18,10 +18,10 @@ Gem::Specification.new do |spec|
18
18
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
19
  spec.require_paths = ["lib"]
20
20
 
21
- spec.add_runtime_dependency "omniauth-oauth2"
22
-
23
- spec.add_development_dependency "sinatra"
24
- spec.add_development_dependency "rake"
25
- spec.add_development_dependency "minitest"
26
- spec.add_development_dependency "mocha"
21
+ spec.add_runtime_dependency 'omniauth', '~> 1.1', '>= 1.1.1'
22
+ spec.add_runtime_dependency 'omniauth-oauth2', '~> 1.6'
23
+ spec.add_development_dependency "sinatra", '~> 0'
24
+ spec.add_development_dependency "rake", '~> 0'
25
+ spec.add_development_dependency 'rspec', '~> 3.6'
26
+ spec.add_development_dependency "mocha", '~> 0'
27
27
  end
@@ -0,0 +1,443 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+ require 'json'
5
+ require 'omniauth_microsoft_graph'
6
+ require 'stringio'
7
+
8
+ describe OmniAuth::Strategies::MicrosoftGraph do
9
+ let(:request) { double('Request', params: {}, cookies: {}, env: {}) }
10
+ let(:app) do
11
+ lambda do
12
+ [200, {}, ['Hello.']]
13
+ end
14
+ end
15
+
16
+ subject do
17
+ OmniAuth::Strategies::MicrosoftGraph.new(app, 'appid', 'secret', @options || {}).tap do |strategy|
18
+ allow(strategy).to receive(:request) do
19
+ request
20
+ end
21
+ end
22
+ end
23
+
24
+ before do
25
+ OmniAuth.config.test_mode = true
26
+ end
27
+
28
+ after do
29
+ OmniAuth.config.test_mode = false
30
+ end
31
+
32
+ describe '#client_options' do
33
+ it 'has correct site' do
34
+ expect(subject.client.site).to eq('https://login.microsoftonline.com/')
35
+ end
36
+
37
+ it 'has correct authorize_url' do
38
+ expect(subject.client.options[:authorize_url]).to eq('common/oauth2/v2.0/authorize')
39
+ end
40
+
41
+ it 'has correct token_url' do
42
+ expect(subject.client.options[:token_url]).to eq('common/oauth2/v2.0/token')
43
+ end
44
+
45
+ describe 'overrides' do
46
+ context 'as strings' do
47
+ it 'should allow overriding the site' do
48
+ @options = { client_options: { 'site' => 'https://example.com' } }
49
+ expect(subject.client.site).to eq('https://example.com')
50
+ end
51
+
52
+ it 'should allow overriding the authorize_url' do
53
+ @options = { client_options: { 'authorize_url' => 'https://example.com' } }
54
+ expect(subject.client.options[:authorize_url]).to eq('https://example.com')
55
+ end
56
+
57
+ it 'should allow overriding the token_url' do
58
+ @options = { client_options: { 'token_url' => 'https://example.com' } }
59
+ expect(subject.client.options[:token_url]).to eq('https://example.com')
60
+ end
61
+ end
62
+
63
+ context 'as symbols' do
64
+ it 'should allow overriding the site' do
65
+ @options = { client_options: { site: 'https://example.com' } }
66
+ expect(subject.client.site).to eq('https://example.com')
67
+ end
68
+
69
+ it 'should allow overriding the authorize_url' do
70
+ @options = { client_options: { authorize_url: 'https://example.com' } }
71
+ expect(subject.client.options[:authorize_url]).to eq('https://example.com')
72
+ end
73
+
74
+ it 'should allow overriding the token_url' do
75
+ @options = { client_options: { token_url: 'https://example.com' } }
76
+ expect(subject.client.options[:token_url]).to eq('https://example.com')
77
+ end
78
+ end
79
+ end
80
+ end
81
+
82
+ describe '#authorize_options' do
83
+ %i[display score auth_type scope prompt login_hint domain_hint response_mode].each do |k|
84
+ it "should support #{k}" do
85
+ @options = { k => 'http://someval' }
86
+ expect(subject.authorize_params[k.to_s]).to eq('http://someval')
87
+ end
88
+ end
89
+
90
+ describe 'callback_url' do
91
+ it 'should default to nil' do
92
+ @options = {}
93
+ expect(subject.authorize_params['callback_url']).to eq(nil)
94
+ end
95
+
96
+ it 'should set the callback_url parameter if present' do
97
+ @options = { callback_url: 'https://example.com' }
98
+ expect(subject.authorize_params['callback_url']).to eq('https://example.com')
99
+ end
100
+ end
101
+
102
+ describe 'access_type' do
103
+ it 'should default to "offline"' do
104
+ @options = {}
105
+ expect(subject.authorize_params['access_type']).to eq('offline')
106
+ end
107
+
108
+ it 'should set the access_type parameter if present' do
109
+ @options = { access_type: 'online' }
110
+ expect(subject.authorize_params['access_type']).to eq('online')
111
+ end
112
+ end
113
+
114
+ describe 'login_hint' do
115
+ it 'should default to nil' do
116
+ expect(subject.authorize_params['login_hint']).to eq(nil)
117
+ end
118
+
119
+ it 'should set the login_hint parameter if present' do
120
+ @options = { login_hint: 'john@example.com' }
121
+ expect(subject.authorize_params['login_hint']).to eq('john@example.com')
122
+ end
123
+ end
124
+
125
+ describe 'prompt' do
126
+ it 'should default to nil' do
127
+ expect(subject.authorize_params['prompt']).to eq(nil)
128
+ end
129
+
130
+ it 'should set the prompt parameter if present' do
131
+ @options = { prompt: 'consent select_account' }
132
+ expect(subject.authorize_params['prompt']).to eq('consent select_account')
133
+ end
134
+ end
135
+
136
+ describe 'scope' do
137
+
138
+ it 'should leave base scopes as is' do
139
+ @options = { scope: 'profile' }
140
+ expect(subject.authorize_params['scope']).to eq('profile')
141
+ end
142
+
143
+ it 'should join scopes' do
144
+ @options = { scope: 'profile,email' }
145
+ expect(subject.authorize_params['scope']).to eq('profile email')
146
+ end
147
+
148
+ it 'should deal with whitespace when joining scopes' do
149
+ @options = { scope: 'profile, email' }
150
+ expect(subject.authorize_params['scope']).to eq('profile email')
151
+ end
152
+
153
+ it 'should set default scope to email,profile' do
154
+ expect(subject.authorize_params['scope']).to eq('openid email profile https://graph.microsoft.com/User.Read')
155
+ end
156
+
157
+ it 'should support space delimited scopes' do
158
+ @options = { scope: 'profile email' }
159
+ expect(subject.authorize_params['scope']).to eq('profile email')
160
+ end
161
+
162
+ it 'should support extremely badly formed scopes' do
163
+ @options = { scope: 'profile email,foo,steve yeah http://example.com' }
164
+ expect(subject.authorize_params['scope']).to eq('profile email https://graph.microsoft.com/foo https://graph.microsoft.com/steve https://graph.microsoft.com/yeah http://example.com')
165
+ end
166
+ end
167
+
168
+ describe 'state' do
169
+ it 'should set the state parameter' do
170
+ @options = { state: 'some_state' }
171
+ expect(subject.authorize_params['state']).to eq('some_state')
172
+ expect(subject.authorize_params[:state]).to eq('some_state')
173
+ expect(subject.session['omniauth.state']).to eq('some_state')
174
+ end
175
+
176
+ it 'should set the omniauth.state dynamically' do
177
+ allow(subject).to receive(:request) { double('Request', params: { 'state' => 'some_state' }, env: {}) }
178
+ expect(subject.authorize_params['state']).to eq('some_state')
179
+ expect(subject.authorize_params[:state]).to eq('some_state')
180
+ expect(subject.session['omniauth.state']).to eq('some_state')
181
+ end
182
+ end
183
+
184
+ describe 'overrides' do
185
+ it 'should include top-level options that are marked as :authorize_options' do
186
+ @options = { authorize_options: %i[scope foo request_visible_actions], scope: 'http://bar', foo: 'baz', hd: 'wow', request_visible_actions: 'something' }
187
+ expect(subject.authorize_params['scope']).to eq('http://bar')
188
+ expect(subject.authorize_params['foo']).to eq('baz')
189
+ expect(subject.authorize_params['hd']).to eq(nil)
190
+ expect(subject.authorize_params['request_visible_actions']).to eq('something')
191
+ end
192
+
193
+ describe 'request overrides' do
194
+ %i[access_type login_hint prompt scope state].each do |k|
195
+ context "authorize option #{k}" do
196
+ let(:request) { double('Request', params: { k.to_s => 'http://example.com' }, cookies: {}, env: {}) }
197
+
198
+ it "should set the #{k} authorize option dynamically in the request" do
199
+ @options = { k: '' }
200
+ expect(subject.authorize_params[k.to_s]).to eq('http://example.com')
201
+ end
202
+ end
203
+ end
204
+
205
+ describe 'custom authorize_options' do
206
+ let(:request) { double('Request', params: { 'foo' => 'something' }, cookies: {}, env: {}) }
207
+
208
+ it 'should support request overrides from custom authorize_options' do
209
+ @options = { authorize_options: [:foo], foo: '' }
210
+ expect(subject.authorize_params['foo']).to eq('something')
211
+ end
212
+ end
213
+ end
214
+ end
215
+ end
216
+
217
+ describe '#authorize_params' do
218
+ it 'should include any authorize params passed in the :authorize_params option' do
219
+ @options = { authorize_params: { request_visible_actions: 'something', foo: 'bar', baz: 'zip' }, hd: 'wow', bad: 'not_included' }
220
+ expect(subject.authorize_params['request_visible_actions']).to eq('something')
221
+ expect(subject.authorize_params['foo']).to eq('bar')
222
+ expect(subject.authorize_params['baz']).to eq('zip')
223
+ expect(subject.authorize_params['bad']).to eq(nil)
224
+ end
225
+ end
226
+
227
+ describe '#token_params' do
228
+ it 'should include any token params passed in the :token_params option' do
229
+ @options = { token_params: { foo: 'bar', baz: 'zip' } }
230
+ expect(subject.token_params['foo']).to eq('bar')
231
+ expect(subject.token_params['baz']).to eq('zip')
232
+ end
233
+ end
234
+
235
+ describe '#token_options' do
236
+ it 'should include top-level options that are marked as :token_options' do
237
+ @options = { token_options: %i[scope foo], scope: 'bar', foo: 'baz', bad: 'not_included' }
238
+ expect(subject.token_params['scope']).to eq('bar')
239
+ expect(subject.token_params['foo']).to eq('baz')
240
+ expect(subject.token_params['bad']).to eq(nil)
241
+ end
242
+ end
243
+
244
+ describe '#callback_path' do
245
+ it 'has the correct default callback path' do
246
+ expect(subject.callback_path).to eq('/auth/microsoft_graph/callback')
247
+ end
248
+
249
+ it 'should set the callback_path parameter if present' do
250
+ @options = { callback_path: '/auth/foo/callback' }
251
+ expect(subject.callback_path).to eq('/auth/foo/callback')
252
+ end
253
+ end
254
+
255
+ describe '#info' do
256
+ let(:client) do
257
+ OAuth2::Client.new('abc', 'def') do |builder|
258
+ builder.request :url_encoded
259
+ builder.adapter :test do |stub|
260
+ stub.get('/v1.0/me') { [200, { 'content-type' => 'application/json' }, response_hash.to_json] }
261
+ end
262
+ end
263
+ end
264
+ let(:access_token) { OAuth2::AccessToken.from_hash(client, {}) }
265
+ before { allow(subject).to receive(:access_token).and_return(access_token) }
266
+
267
+ context 'with verified email' do
268
+ let(:response_hash) do
269
+ { mail: 'something@domain.invalid' }
270
+ end
271
+
272
+ it 'should return equal email ' do
273
+ expect(subject.info['email']).to eq('something@domain.invalid')
274
+ end
275
+ end
276
+
277
+ end
278
+
279
+ describe '#extra' do
280
+ let(:client) do
281
+ OAuth2::Client.new('abc', 'def') do |builder|
282
+ builder.request :url_encoded
283
+ builder.adapter :test do |stub|
284
+ stub.get('/v1.0/me') { [200, { 'content-type' => 'application/json' }, '{"id": "12345"}'] }
285
+ end
286
+ end
287
+ end
288
+ let(:access_token) { OAuth2::AccessToken.from_hash(client, {}) }
289
+
290
+ before { allow(subject).to receive(:access_token).and_return(access_token) }
291
+
292
+ describe 'raw_info' do
293
+ it 'should include raw_info' do
294
+ expect(subject.extra['raw_info']).to eq('id' => '12345')
295
+ end
296
+ end
297
+ end
298
+
299
+ describe 'build_access_token' do
300
+ it 'should use a hybrid authorization request_uri if this is an AJAX request with a code parameter' do
301
+ allow(request).to receive(:scheme).and_return('https')
302
+ allow(request).to receive(:url).and_return('https://example.com')
303
+ allow(request).to receive(:xhr?).and_return(true)
304
+ allow(request).to receive(:params).and_return('code' => 'valid_code')
305
+
306
+ client = double(:client)
307
+ auth_code = double(:auth_code)
308
+ allow(client).to receive(:auth_code).and_return(auth_code)
309
+ expect(subject).to receive(:client).and_return(client)
310
+ expect(auth_code).to receive(:get_token).with('valid_code', { redirect_uri: '/auth/microsoft_graph/callback' }, {})
311
+
312
+ expect(subject).not_to receive(:orig_build_access_token)
313
+ subject.instance_variable_set("@env", {})
314
+ subject.send(:build_access_token)
315
+ end
316
+
317
+ it 'should use a hybrid authorization request_uri if this is an AJAX request (mobile) with a code parameter' do
318
+ allow(request).to receive(:scheme).and_return('https')
319
+ allow(request).to receive(:url).and_return('https://example.com')
320
+ allow(request).to receive(:xhr?).and_return(true)
321
+ allow(request).to receive(:params).and_return('code' => 'valid_code', 'callback_url' => 'localhost')
322
+
323
+ client = double(:client)
324
+ auth_code = double(:auth_code)
325
+ allow(client).to receive(:auth_code).and_return(auth_code)
326
+ expect(subject).to receive(:client).and_return(client)
327
+ expect(auth_code).to receive(:get_token).with('valid_code', { redirect_uri: 'localhost' }, {})
328
+
329
+ expect(subject).not_to receive(:orig_build_access_token)
330
+ subject.instance_variable_set("@env", {})
331
+ subject.send(:build_access_token)
332
+ end
333
+
334
+ it 'should use the request_uri from params if this not an AJAX request (request from installed app) with a code parameter' do
335
+ allow(request).to receive(:scheme).and_return('https')
336
+ allow(request).to receive(:url).and_return('https://example.com')
337
+ allow(request).to receive(:xhr?).and_return(false)
338
+ allow(request).to receive(:params).and_return('code' => 'valid_code', 'callback_url' => 'callback_url')
339
+
340
+ client = double(:client)
341
+ auth_code = double(:auth_code)
342
+ allow(client).to receive(:auth_code).and_return(auth_code)
343
+ expect(subject).to receive(:client).and_return(client)
344
+ expect(auth_code).to receive(:get_token).with('valid_code', { redirect_uri: 'callback_url' }, {})
345
+
346
+ expect(subject).not_to receive(:orig_build_access_token)
347
+ subject.send(:build_access_token)
348
+ end
349
+
350
+ it 'should read access_token from hash if this is not an AJAX request with a code parameter' do
351
+ allow(request).to receive(:scheme).and_return('https')
352
+ allow(request).to receive(:url).and_return('https://example.com')
353
+ allow(request).to receive(:xhr?).and_return(false)
354
+ allow(request).to receive(:params).and_return('access_token' => 'valid_access_token')
355
+ expect(subject).to receive(:verify_token).with('valid_access_token').and_return true
356
+ expect(subject).to receive(:client).and_return(:client)
357
+
358
+ token = subject.send(:build_access_token)
359
+ expect(token).to be_instance_of(::OAuth2::AccessToken)
360
+ expect(token.token).to eq('valid_access_token')
361
+ expect(token.client).to eq(:client)
362
+ end
363
+
364
+ it 'reads the code from a json request body' do
365
+ body = StringIO.new(%({"code":"json_access_token"}))
366
+ client = double(:client)
367
+ auth_code = double(:auth_code)
368
+
369
+ allow(request).to receive(:scheme).and_return('https')
370
+ allow(request).to receive(:url).and_return('https://example.com')
371
+ allow(request).to receive(:xhr?).and_return(false)
372
+ allow(request).to receive(:content_type).and_return('application/json')
373
+ allow(request).to receive(:body).and_return(body)
374
+ allow(client).to receive(:auth_code).and_return(auth_code)
375
+ expect(subject).to receive(:client).and_return(client)
376
+
377
+ expect(auth_code).to receive(:get_token).with('json_access_token', { redirect_uri: '/auth/microsoft_graph/callback' }, {})
378
+
379
+ subject.send(:build_access_token)
380
+ end
381
+
382
+ it 'should use callback_url without query_string if this is not an AJAX request' do
383
+ allow(request).to receive(:scheme).and_return('https')
384
+ allow(request).to receive(:url).and_return('https://example.com')
385
+ allow(request).to receive(:xhr?).and_return(false)
386
+ allow(request).to receive(:params).and_return('code' => 'valid_code')
387
+ allow(request).to receive(:content_type).and_return('application/x-www-form-urlencoded')
388
+
389
+ client = double(:client)
390
+ auth_code = double(:auth_code)
391
+ allow(client).to receive(:auth_code).and_return(auth_code)
392
+ allow(subject).to receive(:callback_url).and_return('callback_url_without_query_string')
393
+
394
+ expect(subject).to receive(:client).and_return(client)
395
+ expect(auth_code).to receive(:get_token).with('valid_code', { redirect_uri: 'callback_url_without_query_string' }, {})
396
+ subject.send(:build_access_token)
397
+ end
398
+ end
399
+
400
+ describe 'verify_token' do
401
+ before(:each) do
402
+ subject.options.client_options[:connection_build] = proc do |builder|
403
+ builder.request :url_encoded
404
+ builder.adapter :test do |stub|
405
+ stub.get('/v1.0/me?access_token=valid_access_token') do
406
+ [200, { 'Content-Type' => 'application/json; charset=UTF-8' }, JSON.dump(
407
+ aud: '000000000000.apps.googleusercontent.com',
408
+ id: '123456789',
409
+ email: 'example@example.com',
410
+ access_type: 'offline',
411
+ scope: 'profile email',
412
+ expires_in: 436
413
+ )]
414
+ end
415
+ stub.get('/v1.0/me?access_token=invalid_access_token') do
416
+ [400, { 'Content-Type' => 'application/json; charset=UTF-8' }, JSON.dump(error_description: 'Invalid Value')]
417
+ end
418
+ end
419
+ end
420
+ end
421
+
422
+ it 'should verify token if access_token is valid and app_id equals' do
423
+ subject.options.client_id = '000000000000.apps.googleusercontent.com'
424
+ expect(subject.send(:verify_token, 'valid_access_token')).to eq(true)
425
+ end
426
+
427
+ it 'should verify token if access_token is valid and app_id authorized' do
428
+ subject.options.authorized_client_ids = ['000000000000.apps.googleusercontent.com']
429
+ expect(subject.send(:verify_token, 'valid_access_token')).to eq(true)
430
+ end
431
+
432
+ it 'should not verify token if access_token is valid but app_id is false' do
433
+ expect(subject.send(:verify_token, 'valid_access_token')).to eq(false)
434
+ end
435
+
436
+ it 'should raise error if access_token is invalid' do
437
+ expect do
438
+ subject.send(:verify_token, 'invalid_access_token')
439
+ end.to raise_error(OAuth2::Error)
440
+ end
441
+ end
442
+
443
+ end
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ require File.join('bundler', 'setup')
4
+ require 'rspec'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: omniauth-microsoft_graph
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Peter Philips
@@ -9,76 +9,96 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2019-03-09 00:00:00.000000000 Z
12
+ date: 2020-03-17 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
- name: omniauth-oauth2
15
+ name: omniauth
16
16
  requirement: !ruby/object:Gem::Requirement
17
17
  requirements:
18
+ - - "~>"
19
+ - !ruby/object:Gem::Version
20
+ version: '1.1'
18
21
  - - ">="
19
22
  - !ruby/object:Gem::Version
20
- version: '0'
23
+ version: 1.1.1
21
24
  type: :runtime
22
25
  prerelease: false
23
26
  version_requirements: !ruby/object:Gem::Requirement
24
27
  requirements:
28
+ - - "~>"
29
+ - !ruby/object:Gem::Version
30
+ version: '1.1'
25
31
  - - ">="
26
32
  - !ruby/object:Gem::Version
27
- version: '0'
33
+ version: 1.1.1
34
+ - !ruby/object:Gem::Dependency
35
+ name: omniauth-oauth2
36
+ requirement: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.6'
41
+ type: :runtime
42
+ prerelease: false
43
+ version_requirements: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.6'
28
48
  - !ruby/object:Gem::Dependency
29
49
  name: sinatra
30
50
  requirement: !ruby/object:Gem::Requirement
31
51
  requirements:
32
- - - ">="
52
+ - - "~>"
33
53
  - !ruby/object:Gem::Version
34
54
  version: '0'
35
55
  type: :development
36
56
  prerelease: false
37
57
  version_requirements: !ruby/object:Gem::Requirement
38
58
  requirements:
39
- - - ">="
59
+ - - "~>"
40
60
  - !ruby/object:Gem::Version
41
61
  version: '0'
42
62
  - !ruby/object:Gem::Dependency
43
63
  name: rake
44
64
  requirement: !ruby/object:Gem::Requirement
45
65
  requirements:
46
- - - ">="
66
+ - - "~>"
47
67
  - !ruby/object:Gem::Version
48
68
  version: '0'
49
69
  type: :development
50
70
  prerelease: false
51
71
  version_requirements: !ruby/object:Gem::Requirement
52
72
  requirements:
53
- - - ">="
73
+ - - "~>"
54
74
  - !ruby/object:Gem::Version
55
75
  version: '0'
56
76
  - !ruby/object:Gem::Dependency
57
- name: minitest
77
+ name: rspec
58
78
  requirement: !ruby/object:Gem::Requirement
59
79
  requirements:
60
- - - ">="
80
+ - - "~>"
61
81
  - !ruby/object:Gem::Version
62
- version: '0'
82
+ version: '3.6'
63
83
  type: :development
64
84
  prerelease: false
65
85
  version_requirements: !ruby/object:Gem::Requirement
66
86
  requirements:
67
- - - ">="
87
+ - - "~>"
68
88
  - !ruby/object:Gem::Version
69
- version: '0'
89
+ version: '3.6'
70
90
  - !ruby/object:Gem::Dependency
71
91
  name: mocha
72
92
  requirement: !ruby/object:Gem::Requirement
73
93
  requirements:
74
- - - ">="
94
+ - - "~>"
75
95
  - !ruby/object:Gem::Version
76
96
  version: '0'
77
97
  type: :development
78
98
  prerelease: false
79
99
  version_requirements: !ruby/object:Gem::Requirement
80
100
  requirements:
81
- - - ">="
101
+ - - "~>"
82
102
  - !ruby/object:Gem::Version
83
103
  version: '0'
84
104
  description: omniauth provider for new Microsoft Graph API
@@ -101,8 +121,8 @@ files:
101
121
  - lib/omniauth/strategies/microsoft_graph.rb
102
122
  - lib/omniauth_microsoft_graph.rb
103
123
  - omniauth-microsoft_graph.gemspec
104
- - test/strategy_test.rb
105
- - test/test_helper.rb
124
+ - spec/omniauth/strategies/microsoft_graph_oauth2_spec.rb
125
+ - spec/spec_helper.rb
106
126
  homepage: https://github.com/synth/omniauth-microsoft_graph
107
127
  licenses:
108
128
  - MIT
@@ -123,10 +143,10 @@ required_rubygems_version: !ruby/object:Gem::Requirement
123
143
  version: '0'
124
144
  requirements: []
125
145
  rubyforge_project:
126
- rubygems_version: 2.5.2.3
146
+ rubygems_version: 2.5.2
127
147
  signing_key:
128
148
  specification_version: 4
129
149
  summary: omniauth provider for Microsoft Graph
130
150
  test_files:
131
- - test/strategy_test.rb
132
- - test/test_helper.rb
151
+ - spec/omniauth/strategies/microsoft_graph_oauth2_spec.rb
152
+ - spec/spec_helper.rb
@@ -1,26 +0,0 @@
1
- require 'test_helper'
2
-
3
- class UidTest < StrategyTestCase
4
- def setup
5
- super
6
- strategy.stubs(:raw_info).returns({ 'id' => '123' })
7
- end
8
-
9
- def test_return_id_from_raw_info
10
- assert_equal '123', strategy.uid
11
- end
12
- end
13
-
14
- class AccessTokenTest < StrategyTestCase
15
- def setup
16
- super
17
- @request.stubs(:params).returns({ 'access_token' => 'valid_access_token' })
18
- strategy.stubs(:client).returns(:client)
19
- end
20
-
21
- def test_build_access_token
22
- token = strategy.build_access_token
23
- assert_equal token.token, 'valid_access_token'
24
- assert_equal token.client, :client
25
- end
26
- end
@@ -1,31 +0,0 @@
1
- require 'bundler/setup'
2
- require 'minitest/autorun'
3
- require 'mocha/setup'
4
- require 'omniauth/strategies/microsoft_graph'
5
-
6
- OmniAuth.config.test_mode = true
7
-
8
- class StrategyTestCase < Minitest::Test
9
- def setup
10
- @request = stub('Request')
11
- @request.stubs(:params).returns({})
12
- @request.stubs(:cookies).returns({})
13
- @request.stubs(:env).returns({})
14
- @request.stubs(:scheme).returns({})
15
- @request.stubs(:ssl?).returns(false)
16
-
17
- @client_id = '123'
18
- @client_secret = '53cr3tz'
19
- @options = {}
20
- end
21
-
22
- def strategy
23
- @strategy ||= begin
24
- args = [@client_id, @client_secret, @options].compact
25
- OmniAuth::Strategies::MicrosoftGraph.new(nil, *args).tap do |strategy|
26
- strategy.stubs(:request).returns(@request)
27
- end
28
- end
29
- end
30
- end
31
-