omniauth-auth0 1.4.2 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
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