omniauth-auth0 1.4.2 → 2.0.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 (95) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +6 -1
  3. data/.rspec +3 -0
  4. data/.rubocop.yml +20 -0
  5. data/.travis.yml +4 -1
  6. data/CHANGELOG.md +18 -1
  7. data/Gemfile +25 -3
  8. data/Guardfile +5 -0
  9. data/README.md +42 -26
  10. data/Rakefile +24 -4
  11. data/examples/sinatra/app.rb +14 -0
  12. data/examples/sinatra/config.ru +3 -0
  13. data/lib/omniauth-auth0.rb +2 -2
  14. data/lib/omniauth-auth0/version.rb +1 -1
  15. data/lib/omniauth/strategies/auth0.rb +74 -64
  16. data/omniauth-auth0.gemspec +12 -17
  17. data/spec/omniauth/strategies/auth0_spec.rb +240 -128
  18. data/spec/spec_helper.rb +46 -9
  19. metadata +23 -190
  20. data/examples/ruby-on-rails-webapp/.gitignore +0 -17
  21. data/examples/ruby-on-rails-webapp/Gemfile +0 -51
  22. data/examples/ruby-on-rails-webapp/README.md +0 -22
  23. data/examples/ruby-on-rails-webapp/README.rdoc +0 -28
  24. data/examples/ruby-on-rails-webapp/Rakefile +0 -6
  25. data/examples/ruby-on-rails-webapp/app/assets/images/.keep +0 -0
  26. data/examples/ruby-on-rails-webapp/app/assets/javascripts/application.js +0 -13
  27. data/examples/ruby-on-rails-webapp/app/assets/javascripts/home.js.erb +0 -10
  28. data/examples/ruby-on-rails-webapp/app/assets/stylesheets/application.css +0 -114
  29. data/examples/ruby-on-rails-webapp/app/controllers/application_controller.rb +0 -5
  30. data/examples/ruby-on-rails-webapp/app/controllers/auth0_controller.rb +0 -14
  31. data/examples/ruby-on-rails-webapp/app/controllers/concerns/.keep +0 -0
  32. data/examples/ruby-on-rails-webapp/app/controllers/dashboard_controller.rb +0 -5
  33. data/examples/ruby-on-rails-webapp/app/controllers/home_controller.rb +0 -5
  34. data/examples/ruby-on-rails-webapp/app/controllers/secured_controller.rb +0 -13
  35. data/examples/ruby-on-rails-webapp/app/helpers/application_helper.rb +0 -2
  36. data/examples/ruby-on-rails-webapp/app/helpers/callback_helper.rb +0 -2
  37. data/examples/ruby-on-rails-webapp/app/helpers/dashboard_helper.rb +0 -2
  38. data/examples/ruby-on-rails-webapp/app/helpers/home_helper.rb +0 -2
  39. data/examples/ruby-on-rails-webapp/app/mailers/.keep +0 -0
  40. data/examples/ruby-on-rails-webapp/app/models/.keep +0 -0
  41. data/examples/ruby-on-rails-webapp/app/models/concerns/.keep +0 -0
  42. data/examples/ruby-on-rails-webapp/app/views/auth0/failure.html.erb +0 -4
  43. data/examples/ruby-on-rails-webapp/app/views/dashboard/show.html.erb +0 -12
  44. data/examples/ruby-on-rails-webapp/app/views/home/show.html.erb +0 -14
  45. data/examples/ruby-on-rails-webapp/app/views/layouts/application.html.erb +0 -22
  46. data/examples/ruby-on-rails-webapp/bin/bundle +0 -3
  47. data/examples/ruby-on-rails-webapp/bin/rails +0 -4
  48. data/examples/ruby-on-rails-webapp/bin/rake +0 -4
  49. data/examples/ruby-on-rails-webapp/bin/spring +0 -18
  50. data/examples/ruby-on-rails-webapp/config.ru +0 -4
  51. data/examples/ruby-on-rails-webapp/config/application.rb +0 -32
  52. data/examples/ruby-on-rails-webapp/config/boot.rb +0 -4
  53. data/examples/ruby-on-rails-webapp/config/database.yml +0 -20
  54. data/examples/ruby-on-rails-webapp/config/environment.rb +0 -5
  55. data/examples/ruby-on-rails-webapp/config/environments/development.rb +0 -39
  56. data/examples/ruby-on-rails-webapp/config/environments/production.rb +0 -85
  57. data/examples/ruby-on-rails-webapp/config/environments/test.rb +0 -39
  58. data/examples/ruby-on-rails-webapp/config/initializers/01_dotenv.rb +0 -4
  59. data/examples/ruby-on-rails-webapp/config/initializers/auth0.rb +0 -9
  60. data/examples/ruby-on-rails-webapp/config/initializers/backtrace_silencers.rb +0 -7
  61. data/examples/ruby-on-rails-webapp/config/initializers/cookies_serializer.rb +0 -3
  62. data/examples/ruby-on-rails-webapp/config/initializers/filter_parameter_logging.rb +0 -4
  63. data/examples/ruby-on-rails-webapp/config/initializers/fix_ssl.rb +0 -15
  64. data/examples/ruby-on-rails-webapp/config/initializers/inflections.rb +0 -16
  65. data/examples/ruby-on-rails-webapp/config/initializers/mime_types.rb +0 -4
  66. data/examples/ruby-on-rails-webapp/config/initializers/session_store.rb +0 -3
  67. data/examples/ruby-on-rails-webapp/config/initializers/wrap_parameters.rb +0 -14
  68. data/examples/ruby-on-rails-webapp/config/locales/en.yml +0 -23
  69. data/examples/ruby-on-rails-webapp/config/routes.rb +0 -66
  70. data/examples/ruby-on-rails-webapp/config/secrets.yml +0 -35
  71. data/examples/ruby-on-rails-webapp/db/seeds.rb +0 -7
  72. data/examples/ruby-on-rails-webapp/lib/assets/.keep +0 -0
  73. data/examples/ruby-on-rails-webapp/lib/ca-bundle.crt +0 -3893
  74. data/examples/ruby-on-rails-webapp/lib/tasks/.keep +0 -0
  75. data/examples/ruby-on-rails-webapp/log/.keep +0 -0
  76. data/examples/ruby-on-rails-webapp/public/404.html +0 -67
  77. data/examples/ruby-on-rails-webapp/public/422.html +0 -67
  78. data/examples/ruby-on-rails-webapp/public/500.html +0 -66
  79. data/examples/ruby-on-rails-webapp/public/favicon.ico +0 -0
  80. data/examples/ruby-on-rails-webapp/public/robots.txt +0 -5
  81. data/examples/ruby-on-rails-webapp/test/controllers/.keep +0 -0
  82. data/examples/ruby-on-rails-webapp/test/controllers/callback_controller_test.rb +0 -14
  83. data/examples/ruby-on-rails-webapp/test/controllers/dashboard_controller_test.rb +0 -9
  84. data/examples/ruby-on-rails-webapp/test/controllers/home_controller_test.rb +0 -9
  85. data/examples/ruby-on-rails-webapp/test/fixtures/.keep +0 -0
  86. data/examples/ruby-on-rails-webapp/test/helpers/.keep +0 -0
  87. data/examples/ruby-on-rails-webapp/test/helpers/callback_helper_test.rb +0 -4
  88. data/examples/ruby-on-rails-webapp/test/helpers/dashboard_helper_test.rb +0 -4
  89. data/examples/ruby-on-rails-webapp/test/helpers/home_helper_test.rb +0 -4
  90. data/examples/ruby-on-rails-webapp/test/integration/.keep +0 -0
  91. data/examples/ruby-on-rails-webapp/test/mailers/.keep +0 -0
  92. data/examples/ruby-on-rails-webapp/test/models/.keep +0 -0
  93. data/examples/ruby-on-rails-webapp/test/test_helper.rb +0 -13
  94. data/examples/ruby-on-rails-webapp/vendor/assets/javascripts/.keep +0 -0
  95. data/examples/ruby-on-rails-webapp/vendor/assets/stylesheets/.keep +0 -0
@@ -1,14 +1,14 @@
1
1
  # -*- encoding: utf-8 -*-
2
- $:.push File.expand_path("../lib", __FILE__)
3
- require "omniauth-auth0/version"
2
+ $LOAD_PATH.push File.expand_path('../lib', __FILE__)
3
+ require 'omniauth-auth0/version'
4
4
 
5
5
  Gem::Specification.new do |s|
6
- s.name = "omniauth-auth0"
6
+ s.name = 'omniauth-auth0'
7
7
  s.version = OmniAuth::Auth0::VERSION
8
- s.authors = ["Auth0", "Ezequiel Morito", "Jose Romaniello"]
9
- s.email = ["support@auth0.com"]
10
- s.homepage = "https://github.com/auth0/omniauth-auth0"
11
- s.summary = %q{Omniauth OAuth2 strategy for the Auth0 platform.}
8
+ s.authors = ['Auth0']
9
+ s.email = ['info@auth0.com']
10
+ s.homepage = 'https://github.com/auth0/omniauth-auth0'
11
+ s.summary = 'Omniauth OAuth2 strategy for the Auth0 platform.'
12
12
  s.description = %q{Auth0 is an authentication broker that supports social identity providers as well as enterprise identity providers such as Active Directory, LDAP, Google Apps, Salesforce.
13
13
 
14
14
  OmniAuth is a library that standardizes multi-provider authentication for web applications. It was created to be powerful, flexible, and do as little as possible.
@@ -16,21 +16,16 @@ OmniAuth is a library that standardizes multi-provider authentication for web ap
16
16
  omniauth-auth0 is the omniauth strategy for Auth0.
17
17
  }
18
18
 
19
- s.rubyforge_project = "omniauth-auth0"
19
+ s.rubyforge_project = 'omniauth-auth0'
20
20
 
21
21
  s.files = `git ls-files`.split("\n")
22
22
  s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
23
- s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
24
- s.require_paths = ["lib"]
23
+ s.executables = `git ls-files -- bin/*`.split('\n').map{ |f| File.basename(f) }
24
+ s.require_paths = ['lib']
25
25
 
26
- s.add_runtime_dependency 'omniauth-oauth2', '~> 1.1'
26
+ s.add_runtime_dependency 'omniauth-oauth2', '~> 1.4'
27
27
 
28
- s.add_development_dependency 'rspec', '~> 2.7'
29
- s.add_development_dependency 'rack-test', '~> 0.6', '>= 0.6.3'
30
- s.add_development_dependency 'simplecov', '~> 0.9', '>= 0.9.1'
31
- s.add_development_dependency 'webmock', '~> 1.20', '>= 1.20.4'
32
- s.add_development_dependency 'rake', '~> 10.3', '>= 10.3.2'
33
- s.add_development_dependency 'gem-release', '~> 0.7'
28
+ s.add_development_dependency 'bundler', '~> 1.9'
34
29
 
35
30
  s.license = 'MIT'
36
31
  end
@@ -1,177 +1,289 @@
1
- require "spec_helper"
1
+ require 'spec_helper'
2
2
 
3
- describe OmniAuth::Strategies::Auth0 do
4
- let(:app){ Rack::Builder.new do |b|
5
- b.use Rack::Session::Cookie, {:secret => "abc123"}
6
- b.run lambda{|env| [200, {}, ['Not Found']]}
7
- end.to_app }
8
-
9
- before :each do
10
- OmniAuth.config.test_mode = true
11
- @request = double('Request')
12
- allow(@request).to receive(:params)
13
- allow(@request).to receive(:cookies)
14
- allow(@request).to receive(:env)
15
-
16
- @session = double('Session')
17
- allow(@session).to receive(:delete).with('omniauth.state').and_return('state')
18
- end
19
-
20
- after do
21
- OmniAuth.config.test_mode = false
22
- end
3
+ RSpec.shared_examples 'site has valid domain url' do |url|
4
+ it { expect(subject.site).to eq(url) }
5
+ end
23
6
 
24
- subject do
25
- OmniAuth::Strategies::Auth0.new(app,
26
- "client_id", "client_secret", "tenny.auth0.com:3000").tap do |strategy|
27
- allow(strategy).to receive(:request) { @request }
7
+ describe OmniAuth::Strategies::Auth0 do
8
+ let(:client_id) { 'CLIENT_ID' }
9
+ let(:client_secret) { 'CLIENT_SECRET' }
10
+ let(:domain_url) { 'https://samples.auth0.com' }
11
+ let(:application) do
12
+ lambda do
13
+ [200, {}, ['Hello.']]
28
14
  end
29
15
  end
16
+ let(:auth0) do
17
+ OmniAuth::Strategies::Auth0.new(
18
+ application,
19
+ client_id,
20
+ client_secret,
21
+ domain_url
22
+ )
23
+ end
30
24
 
31
- context "initiation" do
32
- let(:base64_token) {
33
- Base64.urlsafe_encode64('{"name":"omniauth-auth0","version":"' + OmniAuth::Auth0::VERSION + '"}')
34
- }
25
+ describe 'client_options' do
26
+ let(:subject) { auth0.client }
35
27
 
36
- it "uses the correct site" do
37
- expect(subject.options.client_options.site).to eql "https://tenny.auth0.com:3000"
28
+ context 'domain with https' do
29
+ let(:domain_url) { 'https://samples.auth0.com' }
30
+ it_behaves_like 'site has valid domain url', 'https://samples.auth0.com'
38
31
  end
39
32
 
40
- it "uses the correct authorize_url" do
41
- expect(subject.options.client_options.authorize_url).
42
- to eql "https://tenny.auth0.com:3000/authorize?auth0Client=#{base64_token}"
33
+ context 'domain with http' do
34
+ let(:domain_url) { 'http://mydomain.com' }
35
+ it_behaves_like 'site has valid domain url', 'http://mydomain.com'
36
+ end
43
37
 
38
+ context 'domain with host only' do
39
+ let(:domain_url) { 'samples.auth0.com' }
40
+ it_behaves_like 'site has valid domain url', 'https://samples.auth0.com'
44
41
  end
45
42
 
46
- it "uses the correct token_url" do
47
- expect(subject.options.client_options.token_url).
48
- to eql "https://tenny.auth0.com:3000/oauth/token?auth0Client=#{base64_token}"
43
+ it 'should have correct authorize path' do
44
+ expect(subject.options[:authorize_url]).to eq('/authorize')
49
45
  end
50
46
 
51
- it "uses the correct userinfo url" do
52
- expect(subject.options.client_options.userinfo_url).
53
- to eql "https://tenny.auth0.com:3000/userinfo"
47
+ it 'should have the correct userinfo path' do
48
+ expect(subject.options[:userinfo_url]).to eq('/userinfo')
54
49
  end
55
50
 
56
- it "should raise an ArgumentError error if no namespace passed" do
57
- expect {
58
- OmniAuth::Strategies::Auth0.new(app, "client_id", "client_secret")
59
- }.to raise_error(ArgumentError)
51
+ it 'should have the correct token path' do
52
+ expect(subject.options[:token_url]).to eq('/oauth/token')
60
53
  end
61
54
  end
62
55
 
63
- context "request phase" do
64
- before(:each){ get '/auth/auth0' }
56
+ describe 'options' do
57
+ let(:subject) { auth0.options }
65
58
 
66
- it "authenticate" do
67
- expect(last_response.status).to eq(200)
59
+ it 'should have the correct client_id' do
60
+ expect(subject[:client_id]).to eq(client_id)
68
61
  end
69
62
 
70
- it "authorize params" do
71
- allow(subject).to receive(:request) { double('Request', {:params => {
72
- "connection" => "google-oauth2", "redirect_uri" => "redirect_uri" }, :env => {}}) }
73
- expect(subject.authorize_params).to include("connection")
74
- expect(subject.authorize_params).to include("state")
75
- expect(subject.authorize_params).to include("redirect_uri")
63
+ it 'should have the correct client secret' do
64
+ expect(subject[:client_secret]).to eq(client_secret)
65
+ end
66
+ it 'should have correct domain' do
67
+ expect(subject[:domain]).to eq(domain_url)
76
68
  end
77
69
  end
78
70
 
79
- describe "callback phase" do
80
- before :each do
81
- @raw_info = {
82
- "_id" => "165dabb5140ee2cc66b5137912ccd760",
83
- "email" => "user@mail.com",
84
- "family_name" => "LastName",
85
- "gender" => "male",
86
- "given_name" => "FirstName",
87
- "identities" => [
88
- {
89
- "access_token" => "ya29.AHES6ZRPK1Skc_rtB30Em_5RkZlKez3FkktcmJ_0RX5fIkCbkOCrXA",
90
- "provider" => "google-oauth2",
91
- "user_id" => "102835921788417079450",
92
- "connection" => "google-oauth2",
93
- "isSocial" => true
94
- }
95
- ],
96
- "locale" => "en",
97
- "name" => "FirstName LastName",
98
- "nickname" => "nick",
99
- "picture" => "pic",
100
- "user_id" => "google-oauth2|102835921788417079450"
101
- }
102
- allow(subject).to receive(:raw_info) { @raw_info }
103
- end
104
-
105
- context "info" do
106
- it 'returns the uid (required)' do
107
- expect(subject.uid).to eq('google-oauth2|102835921788417079450')
108
- end
71
+ describe 'oauth' do
72
+ it 'redirects to hosted login page' do
73
+ get 'auth/auth0'
74
+ expect(last_response.status).to eq(302)
75
+ redirect_url = last_response.headers['Location']
76
+ expect(redirect_url).to start_with('https://samples.auth0.com/authorize')
77
+ expect(redirect_url).to have_query('response_type', 'code')
78
+ expect(redirect_url).to have_query('state')
79
+ expect(redirect_url).to have_query('client_id')
80
+ expect(redirect_url).to have_query('redirect_uri')
81
+ end
109
82
 
110
- it 'returns the name (required)' do
111
- expect(subject.info[:name]).to eq('FirstName LastName')
83
+ describe 'callback' do
84
+ let(:access_token) { 'access token' }
85
+ let(:expires_in) { 2000 }
86
+ let(:token_type) { 'bearer' }
87
+ let(:refresh_token) { 'refresh token' }
88
+ let(:id_token) { 'id token' }
89
+
90
+ let(:user_id) { 'user identifier' }
91
+ let(:state) { SecureRandom.hex(8) }
92
+ let(:name) { 'John' }
93
+ let(:nickname) { 'J' }
94
+ let(:picture) { 'some picture url' }
95
+ let(:email) { 'mail@mail.com' }
96
+ let(:email_verified) { true }
97
+
98
+ let(:oauth_response) do
99
+ {
100
+ access_token: access_token,
101
+ expires_in: expires_in,
102
+ token_type: token_type
103
+ }
112
104
  end
113
105
 
114
- it 'returns the email' do
115
- expect(subject.info[:email]).to eq('user@mail.com')
106
+ let(:oidc_response) do
107
+ {
108
+ id_token: id_token,
109
+ access_token: access_token,
110
+ expires_in: expires_in,
111
+ token_type: token_type
112
+ }
116
113
  end
117
114
 
118
- it 'returns the nickname' do
119
- expect(subject.info[:nickname]).to eq('nick')
115
+ let(:basic_user_info) { { sub: user_id } }
116
+ let(:oidc_user_info) do
117
+ {
118
+ sub: user_id,
119
+ name: name,
120
+ nickname: nickname,
121
+ email: email,
122
+ picture: picture,
123
+ email_verified: email_verified
124
+ }
120
125
  end
121
126
 
122
- it 'returns the last name' do
123
- expect(subject.info[:last_name]).to eq('LastName')
127
+ def stub_auth(body)
128
+ stub_request(:post, 'https://samples.auth0.com/oauth/token')
129
+ .to_return(
130
+ headers: { 'Content-Type' => 'application/json' },
131
+ body: MultiJson.encode(body)
132
+ )
124
133
  end
125
134
 
126
- it 'returns the first name' do
127
- expect(subject.info[:first_name]).to eq('FirstName')
135
+ def stub_userinfo(body)
136
+ stub_request(:get, 'https://samples.auth0.com/userinfo')
137
+ .to_return(
138
+ headers: { 'Content-Type' => 'application/json' },
139
+ body: MultiJson.encode(body)
140
+ )
128
141
  end
129
142
 
130
- it 'returns the location' do
131
- expect(subject.info[:location]).to eq('en')
143
+ def trigger_callback
144
+ get '/auth/auth0/callback', { 'state' => state },
145
+ 'rack.session' => { 'omniauth.state' => state }
132
146
  end
133
147
 
134
- it 'returns the image' do
135
- expect(subject.info[:image]).to eq('pic')
148
+ before(:each) do
149
+ WebMock.reset!
136
150
  end
137
- end
138
151
 
139
- context "get token" do
140
- before :each do
141
- @access_token = double('OAuth2::AccessToken')
152
+ let(:subject) { MultiJson.decode(last_response.body) }
142
153
 
143
- allow(@access_token).to receive(:token)
144
- allow(@access_token).to receive(:expires?)
145
- allow(@access_token).to receive(:expires_at)
146
- allow(@access_token).to receive(:refresh_token)
147
- allow(@access_token).to receive(:params)
154
+ context 'basic oauth' do
155
+ before do
156
+ stub_auth(oauth_response)
157
+ stub_userinfo(basic_user_info)
158
+ trigger_callback
159
+ end
148
160
 
149
- allow(subject).to receive(:access_token) { @access_token }
150
- end
161
+ it 'to succeed' do
162
+ expect(last_response.status).to eq(200)
163
+ end
164
+
165
+ it 'has credentials' do
166
+ expect(subject['credentials']['token']).to eq(access_token)
167
+ expect(subject['credentials']['expires']).to be true
168
+ expect(subject['credentials']['expires_at']).to_not be_nil
169
+ end
151
170
 
152
- it 'returns a Hash' do
153
- expect(subject.credentials).to be_a(Hash)
171
+ it 'has basic values' do
172
+ expect(subject['provider']).to eq('auth0')
173
+ expect(subject['uid']).to eq(user_id)
174
+ expect(subject['info']['name']).to eq(user_id)
175
+ end
154
176
  end
155
177
 
156
- it 'returns the token' do
157
- allow(@access_token).to receive(:token) {
158
- {
159
- :access_token => "OTqSFa9zrh0VRGAZHH4QPJISCoynRwSy9FocUazuaU950EVcISsJo3pST11iTCiI",
160
- :token_type => "bearer"
161
- } }
162
- expect(subject.credentials['token'][:access_token]).to eq('OTqSFa9zrh0VRGAZHH4QPJISCoynRwSy9FocUazuaU950EVcISsJo3pST11iTCiI')
163
- expect(subject.credentials['token'][:token_type]).to eq('bearer')
178
+ context 'basic oauth w/refresh token' do
179
+ before do
180
+ stub_auth(oauth_response.merge(refresh_token: refresh_token))
181
+ stub_userinfo(basic_user_info)
182
+ trigger_callback
183
+ end
184
+
185
+ it 'to succeed' do
186
+ expect(last_response.status).to eq(200)
187
+ end
188
+
189
+ it 'has credentials' do
190
+ expect(subject['credentials']['token']).to eq(access_token)
191
+ expect(subject['credentials']['refresh_token']).to eq(refresh_token)
192
+ expect(subject['credentials']['expires']).to be true
193
+ expect(subject['credentials']['expires_at']).to_not be_nil
194
+ end
164
195
  end
165
-
166
- it 'returns the refresh token' do
167
- allow(@access_token).to receive(:refresh_token) { "your_refresh_token" }
168
- allow(@access_token).to receive(:params) {
169
- {
170
- 'id_token' => "your_id_token",
171
- 'token_type' => "your_token_type"
172
- } }
173
- expect(subject.credentials['refresh_token']).to eq('your_refresh_token')
196
+
197
+ context 'oidc' do
198
+ before do
199
+ stub_auth(oidc_response)
200
+ stub_userinfo(oidc_user_info)
201
+ trigger_callback
202
+ end
203
+
204
+ it 'to succeed' do
205
+ expect(last_response.status).to eq(200)
206
+ end
207
+
208
+ it 'has credentials' do
209
+ expect(subject['credentials']['token']).to eq(access_token)
210
+ expect(subject['credentials']['expires']).to be true
211
+ expect(subject['credentials']['expires_at']).to_not be_nil
212
+ expect(subject['credentials']['id_token']).to eq(id_token)
213
+ end
214
+
215
+ it 'has basic values' do
216
+ expect(subject['provider']).to eq('auth0')
217
+ expect(subject['uid']).to eq(user_id)
218
+ end
219
+
220
+ it 'has info' do
221
+ expect(subject['info']['name']).to eq(name)
222
+ expect(subject['info']['nickname']).to eq(nickname)
223
+ expect(subject['info']['image']).to eq(picture)
224
+ expect(subject['info']['email']).to eq(email)
225
+ end
226
+
227
+ it 'has extra' do
228
+ expect(subject['extra']['raw_info']['email_verified']).to be true
229
+ end
174
230
  end
175
231
  end
176
232
  end
233
+
234
+ describe 'error_handling' do
235
+ it 'fails when missing client_id' do
236
+ @app = make_application(client_id: nil)
237
+ get 'auth/auth0'
238
+ expect(last_response.status).to eq(302)
239
+ redirect_url = last_response.headers['Location']
240
+ expect(redirect_url).to fail_auth_with('missing_client_id')
241
+ end
242
+
243
+ it 'fails when missing client_secret' do
244
+ @app = make_application(client_secret: nil)
245
+ get 'auth/auth0'
246
+ expect(last_response.status).to eq(302)
247
+ redirect_url = last_response.headers['Location']
248
+ expect(redirect_url).to fail_auth_with('missing_client_secret')
249
+ end
250
+
251
+ it 'fails when missing domain' do
252
+ @app = make_application(domain: nil)
253
+ get 'auth/auth0'
254
+ expect(last_response.status).to eq(302)
255
+ redirect_url = last_response.headers['Location']
256
+ expect(redirect_url).to fail_auth_with('missing_domain')
257
+ end
258
+ end
259
+ end
260
+
261
+ RSpec::Matchers.define :fail_auth_with do |message|
262
+ match do |actual|
263
+ uri = URI(actual)
264
+ query = CGI.parse(uri.query)
265
+ (uri.path == '/auth/failure') &&
266
+ (query['message'] == [message]) &&
267
+ (query['strategy'] == ['auth0'])
268
+ end
269
+ end
270
+
271
+ RSpec::Matchers.define :have_query do |key, value|
272
+ match do |actual|
273
+ uri = redirect_uri(actual)
274
+ query = query(uri)
275
+ if value.nil?
276
+ query[key].length == 1
277
+ else
278
+ query[key] == [value]
279
+ end
280
+ end
281
+
282
+ def redirect_uri(string)
283
+ URI(string)
284
+ end
285
+
286
+ def query(uri)
287
+ CGI.parse(uri.query)
288
+ end
177
289
  end