doorkeeper 4.4.3 → 5.0.0

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

Potentially problematic release.


This version of doorkeeper might be problematic. Click here for more details.

Files changed (181) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.gitlab-ci.yml +16 -0
  4. data/.travis.yml +2 -0
  5. data/Appraisals +2 -2
  6. data/Gemfile +1 -1
  7. data/NEWS.md +61 -8
  8. data/README.md +92 -9
  9. data/Rakefile +6 -0
  10. data/UPGRADE.md +2 -0
  11. data/app/assets/stylesheets/doorkeeper/admin/application.css +2 -2
  12. data/app/controllers/doorkeeper/application_controller.rb +4 -3
  13. data/app/controllers/doorkeeper/application_metal_controller.rb +4 -0
  14. data/app/controllers/doorkeeper/applications_controller.rb +42 -22
  15. data/app/controllers/doorkeeper/authorizations_controller.rb +55 -12
  16. data/app/controllers/doorkeeper/authorized_applications_controller.rb +19 -2
  17. data/app/controllers/doorkeeper/tokens_controller.rb +2 -6
  18. data/app/helpers/doorkeeper/dashboard_helper.rb +7 -7
  19. data/app/validators/redirect_uri_validator.rb +3 -2
  20. data/app/views/doorkeeper/applications/_delete_form.html.erb +3 -1
  21. data/app/views/doorkeeper/applications/_form.html.erb +25 -24
  22. data/app/views/doorkeeper/applications/edit.html.erb +1 -1
  23. data/app/views/doorkeeper/applications/index.html.erb +17 -7
  24. data/app/views/doorkeeper/applications/new.html.erb +1 -1
  25. data/app/views/doorkeeper/applications/show.html.erb +6 -6
  26. data/app/views/doorkeeper/authorizations/error.html.erb +1 -1
  27. data/app/views/doorkeeper/authorizations/new.html.erb +4 -0
  28. data/app/views/layouts/doorkeeper/admin.html.erb +15 -15
  29. data/config/locales/en.yml +10 -1
  30. data/doorkeeper.gemspec +18 -20
  31. data/gemfiles/rails_5_2.gemfile +1 -1
  32. data/gemfiles/rails_master.gemfile +4 -1
  33. data/lib/doorkeeper/config.rb +75 -39
  34. data/lib/doorkeeper/engine.rb +4 -0
  35. data/lib/doorkeeper/errors.rb +2 -5
  36. data/lib/doorkeeper/grape/helpers.rb +1 -1
  37. data/lib/doorkeeper/helpers/controller.rb +7 -2
  38. data/lib/doorkeeper/models/access_grant_mixin.rb +71 -0
  39. data/lib/doorkeeper/models/access_token_mixin.rb +39 -22
  40. data/lib/doorkeeper/models/concerns/scopes.rb +1 -1
  41. data/lib/doorkeeper/oauth/authorization/code.rb +31 -8
  42. data/lib/doorkeeper/oauth/authorization/context.rb +15 -0
  43. data/lib/doorkeeper/oauth/authorization/token.rb +36 -14
  44. data/lib/doorkeeper/oauth/authorization_code_request.rb +27 -2
  45. data/lib/doorkeeper/oauth/base_request.rb +20 -9
  46. data/lib/doorkeeper/oauth/client/credentials.rb +1 -1
  47. data/lib/doorkeeper/oauth/client.rb +0 -2
  48. data/lib/doorkeeper/oauth/client_credentials/creator.rb +2 -1
  49. data/lib/doorkeeper/oauth/client_credentials/issuer.rb +6 -3
  50. data/lib/doorkeeper/oauth/client_credentials/validation.rb +4 -6
  51. data/lib/doorkeeper/oauth/client_credentials_request.rb +0 -4
  52. data/lib/doorkeeper/oauth/error_response.rb +11 -3
  53. data/lib/doorkeeper/oauth/helpers/scope_checker.rb +0 -8
  54. data/lib/doorkeeper/oauth/password_access_token_request.rb +7 -4
  55. data/lib/doorkeeper/oauth/pre_authorization.rb +41 -11
  56. data/lib/doorkeeper/oauth/refresh_token_request.rb +6 -1
  57. data/lib/doorkeeper/oauth/scopes.rb +1 -1
  58. data/lib/doorkeeper/oauth/token.rb +5 -2
  59. data/lib/doorkeeper/oauth/token_introspection.rb +2 -2
  60. data/lib/doorkeeper/oauth/token_response.rb +4 -2
  61. data/lib/doorkeeper/oauth.rb +13 -0
  62. data/lib/doorkeeper/orm/active_record/application.rb +22 -14
  63. data/lib/doorkeeper/orm/active_record/stale_records_cleaner.rb +26 -0
  64. data/lib/doorkeeper/orm/active_record.rb +2 -0
  65. data/lib/doorkeeper/rails/helpers.rb +2 -4
  66. data/lib/doorkeeper/rails/routes.rb +14 -6
  67. data/lib/doorkeeper/rake/db.rake +40 -0
  68. data/lib/doorkeeper/rake/setup.rake +6 -0
  69. data/lib/doorkeeper/rake.rb +14 -0
  70. data/lib/doorkeeper/request/authorization_code.rb +0 -2
  71. data/lib/doorkeeper/request/client_credentials.rb +0 -2
  72. data/lib/doorkeeper/request/code.rb +0 -2
  73. data/lib/doorkeeper/request/password.rb +0 -2
  74. data/lib/doorkeeper/request/refresh_token.rb +0 -2
  75. data/lib/doorkeeper/request/token.rb +0 -2
  76. data/lib/doorkeeper/request.rb +28 -35
  77. data/lib/doorkeeper/version.rb +5 -25
  78. data/lib/doorkeeper.rb +19 -17
  79. data/lib/generators/doorkeeper/application_owner_generator.rb +23 -18
  80. data/lib/generators/doorkeeper/confidential_applications_generator.rb +32 -0
  81. data/lib/generators/doorkeeper/install_generator.rb +17 -9
  82. data/lib/generators/doorkeeper/migration_generator.rb +23 -18
  83. data/lib/generators/doorkeeper/pkce_generator.rb +32 -0
  84. data/lib/generators/doorkeeper/previous_refresh_token_generator.rb +29 -24
  85. data/lib/generators/doorkeeper/templates/add_confidential_to_applications.rb.erb +13 -0
  86. data/lib/generators/doorkeeper/templates/enable_pkce_migration.rb.erb +6 -0
  87. data/lib/generators/doorkeeper/templates/initializer.rb +76 -11
  88. data/lib/generators/doorkeeper/views_generator.rb +3 -1
  89. data/spec/controllers/application_metal_controller_spec.rb +50 -0
  90. data/spec/controllers/applications_controller_spec.rb +126 -13
  91. data/spec/controllers/authorizations_controller_spec.rb +277 -47
  92. data/spec/controllers/protected_resources_controller_spec.rb +16 -16
  93. data/spec/controllers/token_info_controller_spec.rb +4 -12
  94. data/spec/controllers/tokens_controller_spec.rb +13 -15
  95. data/spec/dummy/app/assets/config/manifest.js +2 -0
  96. data/spec/dummy/config/environments/test.rb +4 -5
  97. data/spec/dummy/config/initializers/doorkeeper.rb +10 -5
  98. data/spec/dummy/config/initializers/new_framework_defaults.rb +4 -0
  99. data/spec/dummy/config/routes.rb +3 -42
  100. data/spec/dummy/db/migrate/20170822064514_enable_pkce.rb +6 -0
  101. data/spec/dummy/db/migrate/{20180210183654_add_confidential_to_application.rb → 20180210183654_add_confidential_to_applications.rb} +1 -1
  102. data/spec/dummy/db/schema.rb +36 -36
  103. data/spec/generators/application_owner_generator_spec.rb +1 -1
  104. data/spec/generators/confidential_applications_generator_spec.rb +45 -0
  105. data/spec/generators/install_generator_spec.rb +1 -1
  106. data/spec/generators/migration_generator_spec.rb +1 -1
  107. data/spec/generators/pkce_generator_spec.rb +43 -0
  108. data/spec/generators/previous_refresh_token_generator_spec.rb +1 -1
  109. data/spec/generators/views_generator_spec.rb +1 -1
  110. data/spec/grape/grape_integration_spec.rb +1 -1
  111. data/spec/helpers/doorkeeper/dashboard_helper_spec.rb +1 -1
  112. data/spec/lib/config_spec.rb +80 -31
  113. data/spec/lib/doorkeeper_spec.rb +1 -126
  114. data/spec/lib/models/expirable_spec.rb +0 -3
  115. data/spec/lib/models/revocable_spec.rb +0 -2
  116. data/spec/lib/models/scopes_spec.rb +0 -4
  117. data/spec/lib/oauth/authorization/uri_builder_spec.rb +0 -4
  118. data/spec/lib/oauth/authorization_code_request_spec.rb +9 -2
  119. data/spec/lib/oauth/base_request_spec.rb +40 -2
  120. data/spec/lib/oauth/base_response_spec.rb +1 -1
  121. data/spec/lib/oauth/client/credentials_spec.rb +1 -3
  122. data/spec/lib/oauth/client_credentials/creator_spec.rb +5 -1
  123. data/spec/lib/oauth/client_credentials/issuer_spec.rb +26 -7
  124. data/spec/lib/oauth/client_credentials/validation_spec.rb +2 -3
  125. data/spec/lib/oauth/client_credentials_integration_spec.rb +1 -1
  126. data/spec/lib/oauth/client_credentials_request_spec.rb +3 -5
  127. data/spec/lib/oauth/client_spec.rb +0 -3
  128. data/spec/lib/oauth/code_request_spec.rb +4 -2
  129. data/spec/lib/oauth/error_response_spec.rb +0 -3
  130. data/spec/lib/oauth/error_spec.rb +0 -2
  131. data/spec/lib/oauth/forbidden_token_response_spec.rb +1 -4
  132. data/spec/lib/oauth/helpers/scope_checker_spec.rb +0 -3
  133. data/spec/lib/oauth/helpers/unique_token_spec.rb +0 -1
  134. data/spec/lib/oauth/helpers/uri_checker_spec.rb +5 -7
  135. data/spec/lib/oauth/invalid_token_response_spec.rb +1 -4
  136. data/spec/lib/oauth/password_access_token_request_spec.rb +37 -2
  137. data/spec/lib/oauth/pre_authorization_spec.rb +33 -4
  138. data/spec/lib/oauth/refresh_token_request_spec.rb +11 -7
  139. data/spec/lib/oauth/scopes_spec.rb +0 -3
  140. data/spec/lib/oauth/token_request_spec.rb +4 -5
  141. data/spec/lib/oauth/token_response_spec.rb +0 -1
  142. data/spec/lib/oauth/token_spec.rb +37 -14
  143. data/spec/lib/orm/active_record/stale_records_cleaner_spec.rb +79 -0
  144. data/spec/lib/request/strategy_spec.rb +0 -1
  145. data/spec/lib/server_spec.rb +1 -1
  146. data/spec/models/doorkeeper/access_grant_spec.rb +44 -1
  147. data/spec/models/doorkeeper/access_token_spec.rb +66 -22
  148. data/spec/models/doorkeeper/application_spec.rb +14 -47
  149. data/spec/requests/applications/applications_request_spec.rb +134 -1
  150. data/spec/requests/applications/authorized_applications_spec.rb +1 -1
  151. data/spec/requests/endpoints/authorization_spec.rb +1 -1
  152. data/spec/requests/endpoints/token_spec.rb +7 -5
  153. data/spec/requests/flows/authorization_code_errors_spec.rb +1 -1
  154. data/spec/requests/flows/authorization_code_spec.rb +197 -1
  155. data/spec/requests/flows/client_credentials_spec.rb +46 -6
  156. data/spec/requests/flows/implicit_grant_errors_spec.rb +1 -1
  157. data/spec/requests/flows/implicit_grant_spec.rb +38 -11
  158. data/spec/requests/flows/password_spec.rb +56 -2
  159. data/spec/requests/flows/refresh_token_spec.rb +2 -2
  160. data/spec/requests/flows/revoke_token_spec.rb +11 -11
  161. data/spec/requests/flows/skip_authorization_spec.rb +16 -11
  162. data/spec/requests/protected_resources/metal_spec.rb +1 -1
  163. data/spec/requests/protected_resources/private_api_spec.rb +1 -1
  164. data/spec/routing/custom_controller_routes_spec.rb +59 -7
  165. data/spec/routing/default_routes_spec.rb +2 -2
  166. data/spec/routing/scoped_routes_spec.rb +16 -2
  167. data/spec/spec_helper.rb +54 -3
  168. data/spec/spec_helper_integration.rb +2 -74
  169. data/spec/support/dependencies/{factory_girl.rb → factory_bot.rb} +0 -0
  170. data/spec/support/doorkeeper_rspec.rb +19 -0
  171. data/spec/support/helpers/authorization_request_helper.rb +4 -4
  172. data/spec/support/helpers/request_spec_helper.rb +10 -2
  173. data/spec/support/helpers/url_helper.rb +7 -3
  174. data/spec/support/http_method_shim.rb +12 -16
  175. data/spec/validators/redirect_uri_validator_spec.rb +7 -1
  176. data/spec/version/version_spec.rb +3 -3
  177. data/vendor/assets/stylesheets/doorkeeper/bootstrap.min.css +4 -5
  178. metadata +37 -33
  179. data/lib/generators/doorkeeper/add_client_confidentiality_generator.rb +0 -31
  180. data/lib/generators/doorkeeper/templates/add_confidential_to_application_migration.rb.erb +0 -11
  181. data/spec/controllers/application_metal_controller.rb +0 -10
@@ -1,7 +1,99 @@
1
- require 'spec_helper_integration'
1
+ require 'spec_helper'
2
2
 
3
3
  module Doorkeeper
4
4
  describe ApplicationsController do
5
+ context 'JSON API' do
6
+ render_views
7
+
8
+ before do
9
+ allow(Doorkeeper.configuration).to receive(:api_only).and_return(true)
10
+ allow(Doorkeeper.configuration).to receive(:authenticate_admin).and_return(->(*) { true })
11
+ end
12
+
13
+ it 'creates an application' do
14
+ expect do
15
+ post :create, params: {
16
+ doorkeeper_application: {
17
+ name: 'Example',
18
+ redirect_uri: 'https://example.com'
19
+ }, format: :json
20
+ }
21
+ end.to change { Doorkeeper::Application.count }
22
+
23
+ expect(response).to be_successful
24
+
25
+ expect(json_response).to include('id', 'name', 'uid', 'secret', 'redirect_uri', 'scopes')
26
+
27
+ expect(json_response['name']).to eq('Example')
28
+ expect(json_response['redirect_uri']).to eq('https://example.com')
29
+ end
30
+
31
+ it 'returns validation errors on wrong create params' do
32
+ expect do
33
+ post :create, params: {
34
+ doorkeeper_application: {
35
+ name: 'Example'
36
+ }, format: :json
37
+ }
38
+ end.not_to change { Doorkeeper::Application.count }
39
+
40
+ expect(response).to have_http_status(422)
41
+
42
+ expect(json_response).to include('errors')
43
+ end
44
+
45
+ it 'returns application info' do
46
+ application = FactoryBot.create(:application, name: 'Change me')
47
+
48
+ get :show, params: { id: application.id, format: :json }
49
+
50
+ expect(response).to be_successful
51
+
52
+ expect(json_response).to include('id', 'name', 'uid', 'secret', 'redirect_uri', 'scopes')
53
+ end
54
+
55
+ it 'updates application' do
56
+ application = FactoryBot.create(:application, name: 'Change me')
57
+
58
+ put :update, params: {
59
+ id: application.id,
60
+ doorkeeper_application: {
61
+ name: 'Example App',
62
+ redirect_uri: 'https://example.com'
63
+ }, format: :json
64
+ }
65
+
66
+ expect(application.reload.name).to eq 'Example App'
67
+
68
+ expect(json_response).to include('id', 'name', 'uid', 'secret', 'redirect_uri', 'scopes')
69
+ end
70
+
71
+ it 'returns validation errors on wrong update params' do
72
+ application = FactoryBot.create(:application, name: 'Change me')
73
+
74
+ put :update, params: {
75
+ id: application.id,
76
+ doorkeeper_application: {
77
+ name: 'Example App',
78
+ redirect_uri: 'localhost:3000'
79
+ }, format: :json
80
+ }
81
+
82
+ expect(response).to have_http_status(422)
83
+
84
+ expect(json_response).to include('errors')
85
+ end
86
+
87
+ it 'destroys an application' do
88
+ application = FactoryBot.create(:application)
89
+
90
+ delete :destroy, params: { id: application.id, format: :json }
91
+
92
+ expect(response).to have_http_status(204)
93
+ expect(Application.count).to be_zero
94
+ end
95
+ end
96
+
5
97
  context 'when admin is not authenticated' do
6
98
  before do
7
99
  allow(Doorkeeper.configuration).to receive(:authenticate_admin).and_return(proc do
@@ -16,9 +108,13 @@ module Doorkeeper
16
108
 
17
109
  it 'does not create application' do
18
110
  expect do
19
- post :create, doorkeeper_application: {
20
- name: 'Example',
21
- redirect_uri: 'https://example.com' }
111
+ post :create,
112
+ params: {
113
+ doorkeeper_application: {
114
+ name: 'Example',
115
+ redirect_uri: 'https://example.com'
116
+ }
117
+ }
22
118
  end.not_to change { Doorkeeper::Application.count }
23
119
  end
24
120
  end
@@ -34,34 +130,51 @@ module Doorkeeper
34
130
  first_application = FactoryBot.create(:application)
35
131
  second_application = FactoryBot.create(:application)
36
132
  expect(Doorkeeper::Application).to receive(:ordered_by).and_call_original
133
+
37
134
  get :index
135
+
38
136
  expect(response.body).to have_selector("tbody tr:first-child#application_#{first_application.id}")
39
137
  expect(response.body).to have_selector("tbody tr:last-child#application_#{second_application.id}")
40
138
  end
41
139
 
42
140
  it 'creates application' do
43
141
  expect do
44
- post :create, doorkeeper_application: {
45
- name: 'Example',
46
- redirect_uri: 'https://example.com' }
142
+ post :create,
143
+ params: {
144
+ doorkeeper_application: {
145
+ name: 'Example',
146
+ redirect_uri: 'https://example.com'
147
+ }
148
+ }
47
149
  end.to change { Doorkeeper::Application.count }.by(1)
150
+
48
151
  expect(response).to be_redirect
49
152
  end
50
153
 
51
154
  it 'does not allow mass assignment of uid or secret' do
52
155
  application = FactoryBot.create(:application)
53
- put :update, id: application.id, doorkeeper_application: {
54
- uid: '1A2B3C4D',
55
- secret: '1A2B3C4D' }
156
+ put :update,
157
+ params: {
158
+ id: application.id,
159
+ doorkeeper_application: {
160
+ uid: '1A2B3C4D',
161
+ secret: '1A2B3C4D'
162
+ }
163
+ }
56
164
 
57
165
  expect(application.reload.uid).not_to eq '1A2B3C4D'
58
166
  end
59
167
 
60
168
  it 'updates application' do
61
169
  application = FactoryBot.create(:application)
62
- put :update, id: application.id, doorkeeper_application: {
63
- name: 'Example',
64
- redirect_uri: 'https://example.com' }
170
+ put :update,
171
+ params: {
172
+ id: application.id, doorkeeper_application: {
173
+ name: 'Example',
174
+ redirect_uri: 'https://example.com'
175
+ }
176
+ }
177
+
65
178
  expect(application.reload.name).to eq 'Example'
66
179
  end
67
180
  end
@@ -1,4 +1,4 @@
1
- require 'spec_helper_integration'
1
+ require 'spec_helper'
2
2
 
3
3
  describe Doorkeeper::AuthorizationsController, 'implicit grant flow' do
4
4
  include AuthorizationRequestHelper
@@ -6,7 +6,7 @@ describe Doorkeeper::AuthorizationsController, 'implicit grant flow' do
6
6
  if Rails::VERSION::MAJOR >= 5
7
7
  class ActionDispatch::TestResponse
8
8
  def query_params
9
- @_query_params ||= begin
9
+ @query_params ||= begin
10
10
  fragment = URI.parse(location).fragment
11
11
  Rack::Utils.parse_query(fragment)
12
12
  end
@@ -15,7 +15,7 @@ describe Doorkeeper::AuthorizationsController, 'implicit grant flow' do
15
15
  else
16
16
  class ActionController::TestResponse
17
17
  def query_params
18
- @_query_params ||= begin
18
+ @query_params ||= begin
19
19
  fragment = URI.parse(location).fragment
20
20
  Rack::Utils.parse_query(fragment)
21
21
  end
@@ -34,11 +34,14 @@ describe Doorkeeper::AuthorizationsController, 'implicit grant flow' do
34
34
  before do
35
35
  allow(Doorkeeper.configuration).to receive(:grant_flows).and_return(["implicit"])
36
36
  allow(controller).to receive(:current_resource_owner).and_return(user)
37
+ allow(Doorkeeper.configuration).to receive(:custom_access_token_expires_in).and_return(proc { |context|
38
+ context.grant_type == Doorkeeper::OAuth::IMPLICIT ? 1234 : nil
39
+ })
37
40
  end
38
41
 
39
42
  describe 'POST #create' do
40
43
  before do
41
- post :create, client_id: client.uid, response_type: 'token', redirect_uri: client.redirect_uri
44
+ post :create, params: { client_id: client.uid, response_type: 'token', redirect_uri: client.redirect_uri }
42
45
  end
43
46
 
44
47
  it 'redirects after authorization' do
@@ -58,7 +61,7 @@ describe Doorkeeper::AuthorizationsController, 'implicit grant flow' do
58
61
  end
59
62
 
60
63
  it 'includes token expiration in fragment' do
61
- expect(response.query_params['expires_in'].to_i).to eq(2.hours.to_i)
64
+ expect(response.query_params['expires_in'].to_i).to eq(1234)
62
65
  end
63
66
 
64
67
  it 'issues the token for the current client' do
@@ -70,10 +73,48 @@ describe Doorkeeper::AuthorizationsController, 'implicit grant flow' do
70
73
  end
71
74
  end
72
75
 
76
+ describe "POST #create in API mode" do
77
+ before do
78
+ allow(Doorkeeper.configuration).to receive(:api_only).and_return(true)
79
+ post :create, params: { client_id: client.uid, response_type: "token", redirect_uri: client.redirect_uri }
80
+ end
81
+
82
+ let(:response_json_body) { JSON.parse(response.body) }
83
+ let(:redirect_uri) { response_json_body["redirect_uri"] }
84
+
85
+ it "renders success after authorization" do
86
+ expect(response).to be_successful
87
+ end
88
+
89
+ it "renders correct redirect uri" do
90
+ expect(redirect_uri).to match(/^#{client.redirect_uri}/)
91
+ end
92
+
93
+ it "includes access token in fragment" do
94
+ expect(redirect_uri.match(/access_token=([a-f0-9]+)&?/)[1]).to eq(Doorkeeper::AccessToken.first.token)
95
+ end
96
+
97
+ it "includes token type in fragment" do
98
+ expect(redirect_uri.match(/token_type=(\w+)&?/)[1]).to eq "Bearer"
99
+ end
100
+
101
+ it "includes token expiration in fragment" do
102
+ expect(redirect_uri.match(/expires_in=(\d+)&?/)[1].to_i).to eq 1234
103
+ end
104
+
105
+ it "issues the token for the current client" do
106
+ expect(Doorkeeper::AccessToken.first.application_id).to eq(client.id)
107
+ end
108
+
109
+ it "issues the token for the current resource owner" do
110
+ expect(Doorkeeper::AccessToken.first.resource_owner_id).to eq(user.id)
111
+ end
112
+ end
113
+
73
114
  describe 'POST #create with errors' do
74
115
  before do
75
116
  default_scopes_exist :public
76
- post :create, client_id: client.uid, response_type: 'token', scope: 'invalid', redirect_uri: client.redirect_uri
117
+ post :create, params: { client_id: client.uid, response_type: 'token', scope: 'invalid', redirect_uri: client.redirect_uri }
77
118
  end
78
119
 
79
120
  it 'redirects after authorization' do
@@ -81,7 +122,7 @@ describe Doorkeeper::AuthorizationsController, 'implicit grant flow' do
81
122
  end
82
123
 
83
124
  it 'redirects to client redirect uri' do
84
- expect(response.location).to match(%r{^#{client.redirect_uri}})
125
+ expect(response.location).to match(/^#{client.redirect_uri}/)
85
126
  end
86
127
 
87
128
  it 'does not include access token in fragment' do
@@ -101,12 +142,47 @@ describe Doorkeeper::AuthorizationsController, 'implicit grant flow' do
101
142
  end
102
143
  end
103
144
 
145
+ describe 'POST #create in API mode with errors' do
146
+ before do
147
+ allow(Doorkeeper.configuration).to receive(:api_only).and_return(true)
148
+ default_scopes_exist :public
149
+ post :create, params: { client_id: client.uid, response_type: 'token', scope: 'invalid', redirect_uri: client.redirect_uri }
150
+ end
151
+
152
+ let(:response_json_body) { JSON.parse(response.body) }
153
+ let(:redirect_uri) { response_json_body['redirect_uri'] }
154
+
155
+ it 'renders 400 error' do
156
+ expect(response.status).to eq 401
157
+ end
158
+
159
+ it 'includes correct redirect URI' do
160
+ expect(redirect_uri).to match(/^#{client.redirect_uri}/)
161
+ end
162
+
163
+ it 'does not include access token in fragment' do
164
+ expect(redirect_uri.match(/access_token=([a-f0-9]+)&?/)).to be_nil
165
+ end
166
+
167
+ it 'includes error in redirect uri' do
168
+ expect(redirect_uri.match(/error=([a-z_]+)&?/)[1]).to eq 'invalid_scope'
169
+ end
170
+
171
+ it 'includes error description in redirect uri' do
172
+ expect(redirect_uri.match(/error_description=(.+)&?/)[1]).to_not be_nil
173
+ end
174
+
175
+ it 'does not issue any access token' do
176
+ expect(Doorkeeper::AccessToken.all).to be_empty
177
+ end
178
+ end
179
+
104
180
  describe 'POST #create with application already authorized' do
105
181
  before do
106
182
  allow(Doorkeeper.configuration).to receive(:reuse_access_token).and_return(true)
107
183
 
108
184
  access_token.save!
109
- post :create, client_id: client.uid, response_type: 'token', redirect_uri: client.redirect_uri
185
+ post :create, params: { client_id: client.uid, response_type: 'token', redirect_uri: client.redirect_uri }
110
186
  end
111
187
 
112
188
  it 'returns the existing access token in a fragment' do
@@ -118,13 +194,47 @@ describe Doorkeeper::AuthorizationsController, 'implicit grant flow' do
118
194
  end
119
195
  end
120
196
 
197
+ describe 'POST #create with callbacks' do
198
+ after do
199
+ client.update_attribute :redirect_uri, 'urn:ietf:wg:oauth:2.0:oob'
200
+ end
201
+
202
+ describe 'when successful' do
203
+ after do
204
+ post :create, params: { client_id: client.uid, response_type: 'token', redirect_uri: client.redirect_uri }
205
+ end
206
+
207
+ it 'should call :before_successful_authorization callback' do
208
+ expect(Doorkeeper.configuration).to receive_message_chain(:before_successful_authorization, :call).with(instance_of(described_class))
209
+ end
210
+
211
+ it 'should call :after_successful_authorization callback' do
212
+ expect(Doorkeeper.configuration).to receive_message_chain(:after_successful_authorization, :call).with(instance_of(described_class))
213
+ end
214
+ end
215
+
216
+ describe 'with errors' do
217
+ after do
218
+ post :create, params: { client_id: client.uid, response_type: 'token', redirect_uri: 'bad_uri' }
219
+ end
220
+
221
+ it 'should not call :before_successful_authorization callback' do
222
+ expect(Doorkeeper.configuration).not_to receive(:before_successful_authorization)
223
+ end
224
+
225
+ it 'should not call :after_successful_authorization callback' do
226
+ expect(Doorkeeper.configuration).not_to receive(:after_successful_authorization)
227
+ end
228
+ end
229
+ end
230
+
121
231
  describe 'GET #new token request with native url and skip_authorization true' do
122
232
  before do
123
233
  allow(Doorkeeper.configuration).to receive(:skip_authorization).and_return(proc do
124
234
  true
125
235
  end)
126
236
  client.update_attribute :redirect_uri, 'urn:ietf:wg:oauth:2.0:oob'
127
- get :new, client_id: client.uid, response_type: 'token', redirect_uri: client.redirect_uri
237
+ get :new, params: { client_id: client.uid, response_type: 'token', redirect_uri: client.redirect_uri }
128
238
  end
129
239
 
130
240
  it 'should redirect immediately' do
@@ -143,13 +253,12 @@ describe Doorkeeper::AuthorizationsController, 'implicit grant flow' do
143
253
 
144
254
  describe 'GET #new code request with native url and skip_authorization true' do
145
255
  before do
146
- allow(Doorkeeper.configuration).to receive(:grant_flows).
147
- and_return(%w[authorization_code])
256
+ allow(Doorkeeper.configuration).to receive(:grant_flows).and_return(%w[authorization_code])
148
257
  allow(Doorkeeper.configuration).to receive(:skip_authorization).and_return(proc do
149
258
  true
150
259
  end)
151
260
  client.update_attribute :redirect_uri, 'urn:ietf:wg:oauth:2.0:oob'
152
- get :new, client_id: client.uid, response_type: 'code', redirect_uri: client.redirect_uri
261
+ get :new, params: { client_id: client.uid, response_type: 'code', redirect_uri: client.redirect_uri }
153
262
  end
154
263
 
155
264
  it 'should redirect immediately' do
@@ -164,38 +273,6 @@ describe Doorkeeper::AuthorizationsController, 'implicit grant flow' do
164
273
  it 'should not issue a token' do
165
274
  expect(Doorkeeper::AccessToken.count).to be 0
166
275
  end
167
-
168
- context 'with opt_out_native_route_change' do
169
- around(:each) do |example|
170
- Doorkeeper.configure do
171
- orm DOORKEEPER_ORM
172
- opt_out_native_route_change
173
- end
174
-
175
- Rails.application.reload_routes!
176
-
177
- example.run
178
-
179
- Doorkeeper.configure do
180
- orm DOORKEEPER_ORM
181
- end
182
-
183
- Rails.application.reload_routes!
184
- end
185
-
186
- it 'should redirect immediately' do
187
- expect(response).to be_redirect
188
- expect(response.location).to match(/oauth\/authorize\/#{Doorkeeper::AccessGrant.first.token}/)
189
- end
190
-
191
- it 'should issue a grant' do
192
- expect(Doorkeeper::AccessGrant.count).to be 1
193
- end
194
-
195
- it 'should not issue a token' do
196
- expect(Doorkeeper::AccessToken.count).to be 0
197
- end
198
- end
199
276
  end
200
277
 
201
278
  describe 'GET #new with skip_authorization true' do
@@ -203,7 +280,7 @@ describe Doorkeeper::AuthorizationsController, 'implicit grant flow' do
203
280
  allow(Doorkeeper.configuration).to receive(:skip_authorization).and_return(proc do
204
281
  true
205
282
  end)
206
- get :new, client_id: client.uid, response_type: 'token', redirect_uri: client.redirect_uri
283
+ get :new, params: { client_id: client.uid, response_type: 'token', redirect_uri: client.redirect_uri }
207
284
  end
208
285
 
209
286
  it 'should redirect immediately' do
@@ -220,7 +297,7 @@ describe Doorkeeper::AuthorizationsController, 'implicit grant flow' do
220
297
  end
221
298
 
222
299
  it 'includes token expiration in fragment' do
223
- expect(response.query_params['expires_in'].to_i).to eq(2.hours.to_i)
300
+ expect(response.query_params['expires_in'].to_i).to eq(1234)
224
301
  end
225
302
 
226
303
  it 'issues the token for the current client' do
@@ -232,10 +309,72 @@ describe Doorkeeper::AuthorizationsController, 'implicit grant flow' do
232
309
  end
233
310
  end
234
311
 
312
+ describe 'GET #new in API mode' do
313
+ before do
314
+ allow(Doorkeeper.configuration).to receive(:api_only).and_return(true)
315
+ get :new, params: { client_id: client.uid, response_type: 'token', redirect_uri: client.redirect_uri }
316
+ end
317
+
318
+ it 'should render success' do
319
+ expect(response).to be_successful
320
+ end
321
+
322
+ it "sets status to pre-authorization" do
323
+ expect(json_response["status"]).to eq(I18n.t('doorkeeper.pre_authorization.status'))
324
+ end
325
+
326
+ it "sets correct values" do
327
+ expect(json_response['client_id']).to eq(client.uid)
328
+ expect(json_response['redirect_uri']).to eq(client.redirect_uri)
329
+ expect(json_response['state']).to be_nil
330
+ expect(json_response['response_type']).to eq('token')
331
+ expect(json_response['scope']).to eq('')
332
+ end
333
+ end
334
+
335
+ describe 'GET #new in API mode with skip_authorization true' do
336
+ before do
337
+ allow(Doorkeeper.configuration).to receive(:skip_authorization).and_return(proc { true })
338
+ allow(Doorkeeper.configuration).to receive(:api_only).and_return(true)
339
+
340
+ get :new, params: { client_id: client.uid, response_type: 'token', redirect_uri: client.redirect_uri }
341
+ end
342
+
343
+ it 'should render success' do
344
+ expect(response).to be_successful
345
+ end
346
+
347
+ it 'should issue a token' do
348
+ expect(Doorkeeper::AccessToken.count).to be 1
349
+ end
350
+
351
+ it "sets status to redirect" do
352
+ expect(JSON.parse(response.body)["status"]).to eq("redirect")
353
+ end
354
+
355
+ it "sets redirect_uri to correct value" do
356
+ redirect_uri = JSON.parse(response.body)["redirect_uri"]
357
+ expect(redirect_uri).to_not be_nil
358
+ expect(redirect_uri.match(/token_type=(\w+)&?/)[1]).to eq "Bearer"
359
+ expect(redirect_uri.match(/expires_in=(\d+)&?/)[1].to_i).to eq 1234
360
+ expect(
361
+ redirect_uri.match(/access_token=([a-f0-9]+)&?/)[1]
362
+ ).to eq Doorkeeper::AccessToken.first.token
363
+ end
364
+
365
+ it "issues the token for the current client" do
366
+ expect(Doorkeeper::AccessToken.first.application_id).to eq(client.id)
367
+ end
368
+
369
+ it "issues the token for the current resource owner" do
370
+ expect(Doorkeeper::AccessToken.first.resource_owner_id).to eq(user.id)
371
+ end
372
+ end
373
+
235
374
  describe 'GET #new with errors' do
236
375
  before do
237
376
  default_scopes_exist :public
238
- get :new, an_invalid: 'request'
377
+ get :new, params: { an_invalid: 'request' }
239
378
  end
240
379
 
241
380
  it 'does not redirect' do
@@ -247,4 +386,95 @@ describe Doorkeeper::AuthorizationsController, 'implicit grant flow' do
247
386
  expect(Doorkeeper::AccessToken.count).to eq 0
248
387
  end
249
388
  end
389
+
390
+ describe 'GET #new in API mode with errors' do
391
+ let(:response_json_body) { JSON.parse(response.body) }
392
+
393
+ before do
394
+ default_scopes_exist :public
395
+ allow(Doorkeeper.configuration).to receive(:api_only).and_return(true)
396
+ get :new, params: { an_invalid: 'request' }
397
+ end
398
+
399
+ it 'should render bad request' do
400
+ expect(response).to have_http_status(:bad_request)
401
+ end
402
+
403
+ it 'includes error in body' do
404
+ expect(response_json_body['error']).to eq('unsupported_response_type')
405
+ end
406
+
407
+ it 'includes error description in body' do
408
+ expect(response_json_body['error_description']).to eq(translated_error_message(:unsupported_response_type))
409
+ end
410
+
411
+ it 'does not issue any token' do
412
+ expect(Doorkeeper::AccessGrant.count).to eq 0
413
+ expect(Doorkeeper::AccessToken.count).to eq 0
414
+ end
415
+ end
416
+
417
+ describe 'GET #new with callbacks' do
418
+ after do
419
+ client.update_attribute :redirect_uri, 'urn:ietf:wg:oauth:2.0:oob'
420
+ get :new, params: { client_id: client.uid, response_type: 'token', redirect_uri: client.redirect_uri }
421
+ end
422
+
423
+ describe 'when authorizing' do
424
+ before do
425
+ allow(Doorkeeper.configuration).to receive(:skip_authorization).and_return(proc { true })
426
+ end
427
+
428
+ it 'should call :before_successful_authorization callback' do
429
+ expect(Doorkeeper.configuration).to receive_message_chain(:before_successful_authorization, :call).with(instance_of(described_class))
430
+ end
431
+
432
+ it 'should call :after_successful_authorization callback' do
433
+ expect(Doorkeeper.configuration).to receive_message_chain(:after_successful_authorization, :call).with(instance_of(described_class))
434
+ end
435
+ end
436
+
437
+ describe 'when not authorizing' do
438
+ before do
439
+ allow(Doorkeeper.configuration).to receive(:skip_authorization).and_return(proc { false })
440
+ end
441
+
442
+ it 'should not call :before_successful_authorization callback' do
443
+ expect(Doorkeeper.configuration).not_to receive(:before_successful_authorization)
444
+ end
445
+
446
+ it 'should not call :after_successful_authorization callback' do
447
+ expect(Doorkeeper.configuration).not_to receive(:after_successful_authorization)
448
+ end
449
+ end
450
+
451
+ describe 'when not authorizing in api mode' do
452
+ before do
453
+ allow(Doorkeeper.configuration).to receive(:skip_authorization).and_return(proc { false })
454
+ allow(Doorkeeper.configuration).to receive(:api_only).and_return(true)
455
+ end
456
+
457
+ it 'should not call :before_successful_authorization callback' do
458
+ expect(Doorkeeper.configuration).not_to receive(:before_successful_authorization)
459
+ end
460
+
461
+ it 'should not call :after_successful_authorization callback' do
462
+ expect(Doorkeeper.configuration).not_to receive(:after_successful_authorization)
463
+ end
464
+ end
465
+ end
466
+
467
+ describe 'authorize response memoization' do
468
+ it 'memoizes the result of the authorization' do
469
+ strategy = double(:strategy, authorize: true)
470
+ expect(strategy).to receive(:authorize).once
471
+ allow(controller).to receive(:strategy) { strategy }
472
+ allow(controller).to receive(:create) do
473
+ 2.times { controller.send :authorize_response }
474
+ controller.render json: {}, status: :ok
475
+ end
476
+
477
+ post :create
478
+ end
479
+ end
250
480
  end