omniauth-microsoft_graph 0.2.1 → 0.3.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.

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
-