doorkeeper 4.2.5 → 5.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 (215) hide show
  1. checksums.yaml +4 -4
  2. data/.github/ISSUE_TEMPLATE.md +25 -0
  3. data/.github/PULL_REQUEST_TEMPLATE.md +17 -0
  4. data/.gitignore +2 -1
  5. data/.gitlab-ci.yml +16 -0
  6. data/.hound.yml +2 -13
  7. data/.rubocop.yml +17 -0
  8. data/.travis.yml +19 -4
  9. data/Appraisals +8 -4
  10. data/CODE_OF_CONDUCT.md +46 -0
  11. data/Gemfile +1 -1
  12. data/NEWS.md +115 -0
  13. data/README.md +175 -39
  14. data/RELEASING.md +5 -12
  15. data/Rakefile +6 -0
  16. data/SECURITY.md +15 -0
  17. data/UPGRADE.md +2 -0
  18. data/app/assets/stylesheets/doorkeeper/admin/application.css +2 -2
  19. data/app/controllers/doorkeeper/application_controller.rb +2 -5
  20. data/app/controllers/doorkeeper/application_metal_controller.rb +4 -0
  21. data/app/controllers/doorkeeper/applications_controller.rb +47 -13
  22. data/app/controllers/doorkeeper/authorizations_controller.rb +55 -12
  23. data/app/controllers/doorkeeper/authorized_applications_controller.rb +19 -2
  24. data/app/controllers/doorkeeper/tokens_controller.rb +24 -17
  25. data/app/helpers/doorkeeper/dashboard_helper.rb +8 -6
  26. data/app/validators/redirect_uri_validator.rb +13 -2
  27. data/app/views/doorkeeper/applications/_delete_form.html.erb +3 -1
  28. data/app/views/doorkeeper/applications/_form.html.erb +31 -19
  29. data/app/views/doorkeeper/applications/edit.html.erb +1 -1
  30. data/app/views/doorkeeper/applications/index.html.erb +18 -6
  31. data/app/views/doorkeeper/applications/new.html.erb +1 -1
  32. data/app/views/doorkeeper/applications/show.html.erb +8 -5
  33. data/app/views/doorkeeper/authorizations/error.html.erb +1 -1
  34. data/app/views/doorkeeper/authorizations/new.html.erb +5 -1
  35. data/app/views/doorkeeper/authorized_applications/index.html.erb +0 -1
  36. data/app/views/layouts/doorkeeper/admin.html.erb +15 -15
  37. data/config/locales/en.yml +19 -6
  38. data/doorkeeper.gemspec +20 -20
  39. data/gemfiles/rails_4_2.gemfile +6 -4
  40. data/gemfiles/rails_5_0.gemfile +4 -4
  41. data/gemfiles/rails_5_1.gemfile +6 -7
  42. data/gemfiles/rails_5_2.gemfile +12 -0
  43. data/gemfiles/rails_master.gemfile +17 -0
  44. data/lib/doorkeeper/config.rb +123 -71
  45. data/lib/doorkeeper/engine.rb +7 -3
  46. data/lib/doorkeeper/errors.rb +20 -5
  47. data/lib/doorkeeper/grape/helpers.rb +14 -9
  48. data/lib/doorkeeper/helpers/controller.rb +16 -22
  49. data/lib/doorkeeper/models/access_grant_mixin.rb +67 -23
  50. data/lib/doorkeeper/models/access_token_mixin.rb +54 -55
  51. data/lib/doorkeeper/models/application_mixin.rb +16 -30
  52. data/lib/doorkeeper/models/concerns/expirable.rb +7 -5
  53. data/lib/doorkeeper/models/concerns/orderable.rb +13 -0
  54. data/lib/doorkeeper/models/concerns/scopes.rb +1 -1
  55. data/lib/doorkeeper/oauth/authorization/code.rb +31 -8
  56. data/lib/doorkeeper/oauth/authorization/context.rb +15 -0
  57. data/lib/doorkeeper/oauth/authorization/token.rb +46 -20
  58. data/lib/doorkeeper/oauth/authorization_code_request.rb +33 -3
  59. data/lib/doorkeeper/oauth/base_request.rb +23 -7
  60. data/lib/doorkeeper/oauth/client/credentials.rb +6 -4
  61. data/lib/doorkeeper/oauth/client.rb +2 -4
  62. data/lib/doorkeeper/oauth/client_credentials/creator.rb +2 -1
  63. data/lib/doorkeeper/oauth/client_credentials/issuer.rb +6 -3
  64. data/lib/doorkeeper/oauth/client_credentials/validation.rb +4 -6
  65. data/lib/doorkeeper/oauth/client_credentials_request.rb +0 -4
  66. data/lib/doorkeeper/oauth/error.rb +2 -2
  67. data/lib/doorkeeper/oauth/error_response.rb +11 -4
  68. data/lib/doorkeeper/oauth/forbidden_token_response.rb +1 -1
  69. data/lib/doorkeeper/oauth/helpers/scope_checker.rb +0 -8
  70. data/lib/doorkeeper/oauth/helpers/uri_checker.rb +15 -0
  71. data/lib/doorkeeper/oauth/invalid_token_response.rb +3 -4
  72. data/lib/doorkeeper/oauth/password_access_token_request.rb +8 -4
  73. data/lib/doorkeeper/oauth/pre_authorization.rb +45 -13
  74. data/lib/doorkeeper/oauth/refresh_token_request.rb +7 -1
  75. data/lib/doorkeeper/oauth/scopes.rb +19 -9
  76. data/lib/doorkeeper/oauth/token.rb +6 -3
  77. data/lib/doorkeeper/oauth/token_introspection.rb +128 -0
  78. data/lib/doorkeeper/oauth/token_response.rb +4 -2
  79. data/lib/doorkeeper/oauth.rb +13 -0
  80. data/lib/doorkeeper/orm/active_record/access_grant.rb +27 -0
  81. data/lib/doorkeeper/orm/active_record/access_token.rb +21 -20
  82. data/lib/doorkeeper/orm/active_record/application.rb +45 -0
  83. data/lib/doorkeeper/orm/active_record/stale_records_cleaner.rb +26 -0
  84. data/lib/doorkeeper/orm/active_record.rb +21 -8
  85. data/lib/doorkeeper/rails/helpers.rb +7 -10
  86. data/lib/doorkeeper/rails/routes.rb +21 -7
  87. data/lib/doorkeeper/rake/db.rake +40 -0
  88. data/lib/doorkeeper/rake/setup.rake +6 -0
  89. data/lib/doorkeeper/rake.rb +14 -0
  90. data/lib/doorkeeper/request/authorization_code.rb +0 -2
  91. data/lib/doorkeeper/request/client_credentials.rb +0 -2
  92. data/lib/doorkeeper/request/code.rb +0 -2
  93. data/lib/doorkeeper/request/password.rb +1 -13
  94. data/lib/doorkeeper/request/refresh_token.rb +0 -2
  95. data/lib/doorkeeper/request/token.rb +0 -2
  96. data/lib/doorkeeper/request.rb +29 -30
  97. data/lib/doorkeeper/validations.rb +3 -2
  98. data/lib/doorkeeper/version.rb +14 -1
  99. data/lib/doorkeeper.rb +21 -17
  100. data/lib/generators/doorkeeper/application_owner_generator.rb +26 -12
  101. data/lib/generators/doorkeeper/confidential_applications_generator.rb +32 -0
  102. data/lib/generators/doorkeeper/install_generator.rb +17 -9
  103. data/lib/generators/doorkeeper/migration_generator.rb +26 -9
  104. data/lib/generators/doorkeeper/pkce_generator.rb +32 -0
  105. data/lib/generators/doorkeeper/previous_refresh_token_generator.rb +31 -20
  106. data/lib/generators/doorkeeper/templates/add_confidential_to_applications.rb.erb +13 -0
  107. data/lib/generators/doorkeeper/templates/{add_owner_to_application_migration.rb → add_owner_to_application_migration.rb.erb} +1 -1
  108. data/lib/generators/doorkeeper/templates/{add_previous_refresh_token_to_access_tokens.rb → add_previous_refresh_token_to_access_tokens.rb.erb} +1 -1
  109. data/lib/generators/doorkeeper/templates/enable_pkce_migration.rb.erb +6 -0
  110. data/lib/generators/doorkeeper/templates/initializer.rb +104 -12
  111. data/lib/generators/doorkeeper/templates/{migration.rb → migration.rb.erb} +2 -1
  112. data/lib/generators/doorkeeper/views_generator.rb +3 -1
  113. data/spec/controllers/application_metal_controller_spec.rb +50 -0
  114. data/spec/controllers/applications_controller_spec.rb +141 -17
  115. data/spec/controllers/authorizations_controller_spec.rb +304 -27
  116. data/spec/controllers/protected_resources_controller_spec.rb +44 -35
  117. data/spec/controllers/token_info_controller_spec.rb +17 -21
  118. data/spec/controllers/tokens_controller_spec.rb +201 -17
  119. data/spec/dummy/app/assets/config/manifest.js +2 -0
  120. data/spec/dummy/config/environments/test.rb +4 -5
  121. data/spec/dummy/config/initializers/doorkeeper.rb +23 -2
  122. data/spec/dummy/config/initializers/{active_record_belongs_to_required_by_default.rb → new_framework_defaults.rb} +5 -1
  123. data/spec/dummy/config/initializers/secret_token.rb +0 -1
  124. data/spec/dummy/config/routes.rb +3 -42
  125. data/spec/dummy/db/migrate/20111122132257_create_users.rb +3 -1
  126. data/spec/dummy/db/migrate/20120312140401_add_password_to_users.rb +3 -1
  127. data/spec/dummy/db/migrate/20151223192035_create_doorkeeper_tables.rb +3 -1
  128. data/spec/dummy/db/migrate/20151223200000_add_owner_to_application.rb +3 -1
  129. data/spec/dummy/db/migrate/20160320211015_add_previous_refresh_token_to_access_tokens.rb +3 -1
  130. data/spec/dummy/db/migrate/20170822064514_enable_pkce.rb +6 -0
  131. data/spec/dummy/db/migrate/20180210183654_add_confidential_to_applications.rb +13 -0
  132. data/spec/dummy/db/schema.rb +38 -37
  133. data/spec/factories.rb +1 -1
  134. data/spec/generators/application_owner_generator_spec.rb +25 -6
  135. data/spec/generators/confidential_applications_generator_spec.rb +45 -0
  136. data/spec/generators/install_generator_spec.rb +1 -1
  137. data/spec/generators/migration_generator_spec.rb +25 -4
  138. data/spec/generators/pkce_generator_spec.rb +43 -0
  139. data/spec/generators/previous_refresh_token_generator_spec.rb +57 -0
  140. data/spec/generators/views_generator_spec.rb +1 -1
  141. data/spec/grape/grape_integration_spec.rb +135 -0
  142. data/spec/helpers/doorkeeper/dashboard_helper_spec.rb +2 -2
  143. data/spec/lib/config_spec.rb +199 -22
  144. data/spec/lib/doorkeeper_spec.rb +1 -126
  145. data/spec/lib/models/expirable_spec.rb +0 -4
  146. data/spec/lib/models/revocable_spec.rb +2 -4
  147. data/spec/lib/models/scopes_spec.rb +0 -4
  148. data/spec/lib/oauth/authorization/uri_builder_spec.rb +0 -4
  149. data/spec/lib/oauth/authorization_code_request_spec.rb +63 -13
  150. data/spec/lib/oauth/base_request_spec.rb +43 -10
  151. data/spec/lib/oauth/base_response_spec.rb +1 -1
  152. data/spec/lib/oauth/client/credentials_spec.rb +5 -5
  153. data/spec/lib/oauth/client_credentials/creator_spec.rb +6 -2
  154. data/spec/lib/oauth/client_credentials/issuer_spec.rb +26 -7
  155. data/spec/lib/oauth/client_credentials/validation_spec.rb +2 -3
  156. data/spec/lib/oauth/client_credentials_integration_spec.rb +2 -2
  157. data/spec/lib/oauth/client_credentials_request_spec.rb +4 -5
  158. data/spec/lib/oauth/client_spec.rb +0 -3
  159. data/spec/lib/oauth/code_request_spec.rb +5 -5
  160. data/spec/lib/oauth/error_response_spec.rb +0 -3
  161. data/spec/lib/oauth/error_spec.rb +1 -3
  162. data/spec/lib/oauth/forbidden_token_response_spec.rb +1 -4
  163. data/spec/lib/oauth/helpers/scope_checker_spec.rb +0 -3
  164. data/spec/lib/oauth/helpers/unique_token_spec.rb +0 -1
  165. data/spec/lib/oauth/helpers/uri_checker_spec.rb +115 -3
  166. data/spec/lib/oauth/invalid_token_response_spec.rb +2 -5
  167. data/spec/lib/oauth/password_access_token_request_spec.rb +46 -5
  168. data/spec/lib/oauth/pre_authorization_spec.rb +40 -6
  169. data/spec/lib/oauth/refresh_token_request_spec.rb +30 -14
  170. data/spec/lib/oauth/scopes_spec.rb +28 -4
  171. data/spec/lib/oauth/token_request_spec.rb +10 -13
  172. data/spec/lib/oauth/token_response_spec.rb +0 -1
  173. data/spec/lib/oauth/token_spec.rb +37 -14
  174. data/spec/lib/orm/active_record/stale_records_cleaner_spec.rb +79 -0
  175. data/spec/lib/request/strategy_spec.rb +0 -1
  176. data/spec/lib/server_spec.rb +10 -0
  177. data/spec/models/doorkeeper/access_grant_spec.rb +45 -2
  178. data/spec/models/doorkeeper/access_token_spec.rb +132 -64
  179. data/spec/models/doorkeeper/application_spec.rb +114 -23
  180. data/spec/requests/applications/applications_request_spec.rb +139 -6
  181. data/spec/requests/applications/authorized_applications_spec.rb +1 -1
  182. data/spec/requests/endpoints/authorization_spec.rb +1 -1
  183. data/spec/requests/endpoints/token_spec.rb +15 -6
  184. data/spec/requests/flows/authorization_code_errors_spec.rb +12 -2
  185. data/spec/requests/flows/authorization_code_spec.rb +199 -2
  186. data/spec/requests/flows/client_credentials_spec.rb +73 -5
  187. data/spec/requests/flows/implicit_grant_errors_spec.rb +3 -3
  188. data/spec/requests/flows/implicit_grant_spec.rb +38 -11
  189. data/spec/requests/flows/password_spec.rb +160 -24
  190. data/spec/requests/flows/refresh_token_spec.rb +6 -6
  191. data/spec/requests/flows/revoke_token_spec.rb +26 -26
  192. data/spec/requests/flows/skip_authorization_spec.rb +16 -11
  193. data/spec/requests/protected_resources/metal_spec.rb +2 -2
  194. data/spec/requests/protected_resources/private_api_spec.rb +2 -2
  195. data/spec/routing/custom_controller_routes_spec.rb +63 -7
  196. data/spec/routing/default_routes_spec.rb +6 -2
  197. data/spec/routing/scoped_routes_spec.rb +16 -2
  198. data/spec/spec_helper.rb +54 -3
  199. data/spec/spec_helper_integration.rb +2 -64
  200. data/spec/support/dependencies/factory_bot.rb +2 -0
  201. data/spec/support/doorkeeper_rspec.rb +19 -0
  202. data/spec/support/helpers/access_token_request_helper.rb +1 -1
  203. data/spec/support/helpers/authorization_request_helper.rb +4 -4
  204. data/spec/support/helpers/model_helper.rb +9 -4
  205. data/spec/support/helpers/request_spec_helper.rb +18 -6
  206. data/spec/support/helpers/url_helper.rb +15 -10
  207. data/spec/support/http_method_shim.rb +12 -16
  208. data/spec/support/shared/controllers_shared_context.rb +2 -6
  209. data/spec/support/shared/models_shared_examples.rb +4 -4
  210. data/spec/validators/redirect_uri_validator_spec.rb +58 -7
  211. data/spec/version/version_spec.rb +15 -0
  212. data/vendor/assets/stylesheets/doorkeeper/bootstrap.min.css +4 -5
  213. metadata +75 -33
  214. data/spec/controllers/application_metal_controller.rb +0 -10
  215. data/spec/support/dependencies/factory_girl.rb +0 -2
@@ -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,41 +108,73 @@ 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' }
22
- end.to_not change { Doorkeeper::Application.count }
111
+ post :create,
112
+ params: {
113
+ doorkeeper_application: {
114
+ name: 'Example',
115
+ redirect_uri: 'https://example.com'
116
+ }
117
+ }
118
+ end.not_to change { Doorkeeper::Application.count }
23
119
  end
24
120
  end
25
121
 
26
122
  context 'when admin is authenticated' do
123
+ render_views
124
+
27
125
  before do
28
- allow(Doorkeeper.configuration).to receive(:authenticate_admin).and_return(->(arg) { true })
126
+ allow(Doorkeeper.configuration).to receive(:authenticate_admin).and_return(->(*) { true })
127
+ end
128
+
129
+ it 'sorts applications by created_at' do
130
+ first_application = FactoryBot.create(:application)
131
+ second_application = FactoryBot.create(:application)
132
+ expect(Doorkeeper::Application).to receive(:ordered_by).and_call_original
133
+
134
+ get :index
135
+
136
+ expect(response.body).to have_selector("tbody tr:first-child#application_#{first_application.id}")
137
+ expect(response.body).to have_selector("tbody tr:last-child#application_#{second_application.id}")
29
138
  end
30
139
 
31
140
  it 'creates application' do
32
141
  expect do
33
- post :create, doorkeeper_application: {
34
- name: 'Example',
35
- redirect_uri: 'https://example.com' }
142
+ post :create,
143
+ params: {
144
+ doorkeeper_application: {
145
+ name: 'Example',
146
+ redirect_uri: 'https://example.com'
147
+ }
148
+ }
36
149
  end.to change { Doorkeeper::Application.count }.by(1)
150
+
37
151
  expect(response).to be_redirect
38
152
  end
39
153
 
40
154
  it 'does not allow mass assignment of uid or secret' do
41
- application = FactoryGirl.create(:application)
42
- put :update, id: application.id, doorkeeper_application: {
43
- uid: '1A2B3C4D',
44
- secret: '1A2B3C4D' }
155
+ application = FactoryBot.create(:application)
156
+ put :update,
157
+ params: {
158
+ id: application.id,
159
+ doorkeeper_application: {
160
+ uid: '1A2B3C4D',
161
+ secret: '1A2B3C4D'
162
+ }
163
+ }
45
164
 
46
165
  expect(application.reload.uid).not_to eq '1A2B3C4D'
47
166
  end
48
167
 
49
168
  it 'updates application' do
50
- application = FactoryGirl.create(:application)
51
- put :update, id: application.id, doorkeeper_application: {
52
- name: 'Example',
53
- redirect_uri: 'https://example.com' }
169
+ application = FactoryBot.create(:application)
170
+ put :update,
171
+ params: {
172
+ id: application.id, doorkeeper_application: {
173
+ name: 'Example',
174
+ redirect_uri: 'https://example.com'
175
+ }
176
+ }
177
+
54
178
  expect(application.reload.name).to eq 'Example'
55
179
  end
56
180
  end
@@ -1,29 +1,47 @@
1
- require 'spec_helper_integration'
1
+ require 'spec_helper'
2
2
 
3
3
  describe Doorkeeper::AuthorizationsController, 'implicit grant flow' do
4
4
  include AuthorizationRequestHelper
5
5
 
6
- def fragments(param)
7
- fragment = URI.parse(response.location).fragment
8
- Rack::Utils.parse_query(fragment)[param]
6
+ if Rails::VERSION::MAJOR >= 5
7
+ class ActionDispatch::TestResponse
8
+ def query_params
9
+ @query_params ||= begin
10
+ fragment = URI.parse(location).fragment
11
+ Rack::Utils.parse_query(fragment)
12
+ end
13
+ end
14
+ end
15
+ else
16
+ class ActionController::TestResponse
17
+ def query_params
18
+ @query_params ||= begin
19
+ fragment = URI.parse(location).fragment
20
+ Rack::Utils.parse_query(fragment)
21
+ end
22
+ end
23
+ end
9
24
  end
10
25
 
11
26
  def translated_error_message(key)
12
- I18n.translate key, scope: [:doorkeeper, :errors, :messages]
27
+ I18n.translate key, scope: %i[doorkeeper errors messages]
13
28
  end
14
29
 
15
- let(:client) { FactoryGirl.create :application }
30
+ let(:client) { FactoryBot.create :application }
16
31
  let(:user) { User.create!(name: 'Joe', password: 'sekret') }
17
- let(:access_token) { FactoryGirl.build :access_token, resource_owner_id: user.id, application_id: client.id }
32
+ let(:access_token) { FactoryBot.build :access_token, resource_owner_id: user.id, application_id: client.id }
18
33
 
19
34
  before do
20
35
  allow(Doorkeeper.configuration).to receive(:grant_flows).and_return(["implicit"])
21
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
+ })
22
40
  end
23
41
 
24
42
  describe 'POST #create' do
25
43
  before do
26
- 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 }
27
45
  end
28
46
 
29
47
  it 'redirects after authorization' do
@@ -35,15 +53,15 @@ describe Doorkeeper::AuthorizationsController, 'implicit grant flow' do
35
53
  end
36
54
 
37
55
  it 'includes access token in fragment' do
38
- expect(fragments('access_token')).to eq(Doorkeeper::AccessToken.first.token)
56
+ expect(response.query_params['access_token']).to eq(Doorkeeper::AccessToken.first.token)
39
57
  end
40
58
 
41
59
  it 'includes token type in fragment' do
42
- expect(fragments('token_type')).to eq('bearer')
60
+ expect(response.query_params['token_type']).to eq('Bearer')
43
61
  end
44
62
 
45
63
  it 'includes token expiration in fragment' do
46
- expect(fragments('expires_in').to_i).to eq(2.hours.to_i)
64
+ expect(response.query_params['expires_in'].to_i).to eq(1234)
47
65
  end
48
66
 
49
67
  it 'issues the token for the current client' do
@@ -55,10 +73,48 @@ describe Doorkeeper::AuthorizationsController, 'implicit grant flow' do
55
73
  end
56
74
  end
57
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
+
58
114
  describe 'POST #create with errors' do
59
115
  before do
60
116
  default_scopes_exist :public
61
- 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 }
62
118
  end
63
119
 
64
120
  it 'redirects after authorization' do
@@ -66,19 +122,54 @@ describe Doorkeeper::AuthorizationsController, 'implicit grant flow' do
66
122
  end
67
123
 
68
124
  it 'redirects to client redirect uri' do
69
- expect(response.location).to match(%r{^#{client.redirect_uri}})
125
+ expect(response.location).to match(/^#{client.redirect_uri}/)
70
126
  end
71
127
 
72
128
  it 'does not include access token in fragment' do
73
- expect(fragments('access_token')).to be_nil
129
+ expect(response.query_params['access_token']).to be_nil
74
130
  end
75
131
 
76
132
  it 'includes error in fragment' do
77
- expect(fragments('error')).to eq('invalid_scope')
133
+ expect(response.query_params['error']).to eq('invalid_scope')
78
134
  end
79
135
 
80
136
  it 'includes error description in fragment' do
81
- expect(fragments('error_description')).to eq(translated_error_message(:invalid_scope))
137
+ expect(response.query_params['error_description']).to eq(translated_error_message(:invalid_scope))
138
+ end
139
+
140
+ it 'does not issue any access token' do
141
+ expect(Doorkeeper::AccessToken.all).to be_empty
142
+ end
143
+ end
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
82
173
  end
83
174
 
84
175
  it 'does not issue any access token' do
@@ -91,11 +182,11 @@ describe Doorkeeper::AuthorizationsController, 'implicit grant flow' do
91
182
  allow(Doorkeeper.configuration).to receive(:reuse_access_token).and_return(true)
92
183
 
93
184
  access_token.save!
94
- 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 }
95
186
  end
96
187
 
97
188
  it 'returns the existing access token in a fragment' do
98
- expect(fragments('access_token')).to eq(access_token.token)
189
+ expect(response.query_params['access_token']).to eq(access_token.token)
99
190
  end
100
191
 
101
192
  it 'does not creates a new access token' do
@@ -103,13 +194,47 @@ describe Doorkeeper::AuthorizationsController, 'implicit grant flow' do
103
194
  end
104
195
  end
105
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
+
106
231
  describe 'GET #new token request with native url and skip_authorization true' do
107
232
  before do
108
233
  allow(Doorkeeper.configuration).to receive(:skip_authorization).and_return(proc do
109
234
  true
110
235
  end)
111
236
  client.update_attribute :redirect_uri, 'urn:ietf:wg:oauth:2.0:oob'
112
- 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 }
113
238
  end
114
239
 
115
240
  it 'should redirect immediately' do
@@ -128,18 +253,17 @@ describe Doorkeeper::AuthorizationsController, 'implicit grant flow' do
128
253
 
129
254
  describe 'GET #new code request with native url and skip_authorization true' do
130
255
  before do
131
- allow(Doorkeeper.configuration).to receive(:grant_flows).
132
- and_return(%w(authorization_code))
256
+ allow(Doorkeeper.configuration).to receive(:grant_flows).and_return(%w[authorization_code])
133
257
  allow(Doorkeeper.configuration).to receive(:skip_authorization).and_return(proc do
134
258
  true
135
259
  end)
136
260
  client.update_attribute :redirect_uri, 'urn:ietf:wg:oauth:2.0:oob'
137
- 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 }
138
262
  end
139
263
 
140
264
  it 'should redirect immediately' do
141
265
  expect(response).to be_redirect
142
- expect(response.location).to match(/oauth\/authorize\//)
266
+ expect(response.location).to match(/oauth\/authorize\/native\?code=#{Doorkeeper::AccessGrant.first.token}/)
143
267
  end
144
268
 
145
269
  it 'should issue a grant' do
@@ -156,7 +280,7 @@ describe Doorkeeper::AuthorizationsController, 'implicit grant flow' do
156
280
  allow(Doorkeeper.configuration).to receive(:skip_authorization).and_return(proc do
157
281
  true
158
282
  end)
159
- 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 }
160
284
  end
161
285
 
162
286
  it 'should redirect immediately' do
@@ -169,11 +293,11 @@ describe Doorkeeper::AuthorizationsController, 'implicit grant flow' do
169
293
  end
170
294
 
171
295
  it 'includes token type in fragment' do
172
- expect(fragments('token_type')).to eq('bearer')
296
+ expect(response.query_params['token_type']).to eq('Bearer')
173
297
  end
174
298
 
175
299
  it 'includes token expiration in fragment' do
176
- expect(fragments('expires_in').to_i).to eq(2.hours.to_i)
300
+ expect(response.query_params['expires_in'].to_i).to eq(1234)
177
301
  end
178
302
 
179
303
  it 'issues the token for the current client' do
@@ -185,10 +309,72 @@ describe Doorkeeper::AuthorizationsController, 'implicit grant flow' do
185
309
  end
186
310
  end
187
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
+
188
374
  describe 'GET #new with errors' do
189
375
  before do
190
376
  default_scopes_exist :public
191
- get :new, an_invalid: 'request'
377
+ get :new, params: { an_invalid: 'request' }
192
378
  end
193
379
 
194
380
  it 'does not redirect' do
@@ -200,4 +386,95 @@ describe Doorkeeper::AuthorizationsController, 'implicit grant flow' do
200
386
  expect(Doorkeeper::AccessToken.count).to eq 0
201
387
  end
202
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
203
480
  end