doorkeeper 4.2.0 → 5.5.2

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 (271) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +1038 -0
  3. data/README.md +110 -348
  4. data/app/assets/stylesheets/doorkeeper/admin/application.css +2 -2
  5. data/app/controllers/doorkeeper/application_controller.rb +6 -7
  6. data/app/controllers/doorkeeper/application_metal_controller.rb +7 -11
  7. data/app/controllers/doorkeeper/applications_controller.rb +65 -20
  8. data/app/controllers/doorkeeper/authorizations_controller.rb +97 -17
  9. data/app/controllers/doorkeeper/authorized_applications_controller.rb +22 -3
  10. data/app/controllers/doorkeeper/token_info_controller.rb +16 -4
  11. data/app/controllers/doorkeeper/tokens_controller.rb +112 -35
  12. data/app/helpers/doorkeeper/dashboard_helper.rb +10 -6
  13. data/app/views/doorkeeper/applications/_delete_form.html.erb +4 -3
  14. data/app/views/doorkeeper/applications/_form.html.erb +33 -21
  15. data/app/views/doorkeeper/applications/edit.html.erb +1 -1
  16. data/app/views/doorkeeper/applications/index.html.erb +18 -6
  17. data/app/views/doorkeeper/applications/new.html.erb +1 -1
  18. data/app/views/doorkeeper/applications/show.html.erb +40 -16
  19. data/app/views/doorkeeper/authorizations/error.html.erb +1 -1
  20. data/app/views/doorkeeper/authorizations/form_post.html.erb +15 -0
  21. data/app/views/doorkeeper/authorizations/new.html.erb +7 -1
  22. data/app/views/doorkeeper/authorized_applications/_delete_form.html.erb +1 -2
  23. data/app/views/doorkeeper/authorized_applications/index.html.erb +0 -1
  24. data/app/views/layouts/doorkeeper/admin.html.erb +16 -14
  25. data/config/locales/en.yml +33 -9
  26. data/lib/doorkeeper/config/abstract_builder.rb +28 -0
  27. data/lib/doorkeeper/config/option.rb +82 -0
  28. data/lib/doorkeeper/config/validations.rb +53 -0
  29. data/lib/doorkeeper/config.rb +545 -143
  30. data/lib/doorkeeper/engine.rb +11 -5
  31. data/lib/doorkeeper/errors.rb +37 -10
  32. data/lib/doorkeeper/grant_flow/fallback_flow.rb +15 -0
  33. data/lib/doorkeeper/grant_flow/flow.rb +44 -0
  34. data/lib/doorkeeper/grant_flow/registry.rb +50 -0
  35. data/lib/doorkeeper/grant_flow.rb +45 -0
  36. data/lib/doorkeeper/grape/authorization_decorator.rb +6 -4
  37. data/lib/doorkeeper/grape/helpers.rb +24 -12
  38. data/lib/doorkeeper/helpers/controller.rb +49 -27
  39. data/lib/doorkeeper/models/access_grant_mixin.rb +100 -21
  40. data/lib/doorkeeper/models/access_token_mixin.rb +379 -75
  41. data/lib/doorkeeper/models/application_mixin.rb +72 -25
  42. data/lib/doorkeeper/models/concerns/accessible.rb +6 -0
  43. data/lib/doorkeeper/models/concerns/expirable.rb +20 -6
  44. data/lib/doorkeeper/models/concerns/orderable.rb +15 -0
  45. data/lib/doorkeeper/models/concerns/ownership.rb +4 -7
  46. data/lib/doorkeeper/models/concerns/resource_ownerable.rb +47 -0
  47. data/lib/doorkeeper/models/concerns/reusable.rb +19 -0
  48. data/lib/doorkeeper/models/concerns/revocable.rb +12 -18
  49. data/lib/doorkeeper/models/concerns/scopes.rb +12 -2
  50. data/lib/doorkeeper/models/concerns/secret_storable.rb +106 -0
  51. data/lib/doorkeeper/oauth/authorization/code.rb +48 -12
  52. data/lib/doorkeeper/oauth/authorization/context.rb +17 -0
  53. data/lib/doorkeeper/oauth/authorization/token.rb +66 -28
  54. data/lib/doorkeeper/oauth/authorization/uri_builder.rb +22 -18
  55. data/lib/doorkeeper/oauth/authorization_code_request.rb +64 -14
  56. data/lib/doorkeeper/oauth/base_request.rb +66 -0
  57. data/lib/doorkeeper/oauth/base_response.rb +31 -0
  58. data/lib/doorkeeper/oauth/client/credentials.rb +23 -10
  59. data/lib/doorkeeper/oauth/client.rb +10 -12
  60. data/lib/doorkeeper/oauth/client_credentials/creator.rb +47 -4
  61. data/lib/doorkeeper/oauth/client_credentials/issuer.rb +16 -9
  62. data/lib/doorkeeper/oauth/client_credentials/validator.rb +56 -0
  63. data/lib/doorkeeper/oauth/client_credentials_request.rb +11 -15
  64. data/lib/doorkeeper/oauth/code_request.rb +8 -12
  65. data/lib/doorkeeper/oauth/code_response.rb +28 -15
  66. data/lib/doorkeeper/oauth/error.rb +5 -3
  67. data/lib/doorkeeper/oauth/error_response.rb +41 -20
  68. data/lib/doorkeeper/oauth/forbidden_token_response.rb +10 -3
  69. data/lib/doorkeeper/oauth/helpers/scope_checker.rb +23 -18
  70. data/lib/doorkeeper/oauth/helpers/unique_token.rb +20 -3
  71. data/lib/doorkeeper/oauth/helpers/uri_checker.rb +53 -3
  72. data/lib/doorkeeper/oauth/hooks/context.rb +21 -0
  73. data/lib/doorkeeper/oauth/invalid_request_response.rb +43 -0
  74. data/lib/doorkeeper/oauth/invalid_token_response.rb +31 -5
  75. data/lib/doorkeeper/oauth/nonstandard.rb +39 -0
  76. data/lib/doorkeeper/oauth/password_access_token_request.rb +45 -13
  77. data/lib/doorkeeper/oauth/pre_authorization.rb +135 -26
  78. data/lib/doorkeeper/oauth/refresh_token_request.rb +61 -36
  79. data/lib/doorkeeper/oauth/scopes.rb +26 -12
  80. data/lib/doorkeeper/oauth/token.rb +25 -23
  81. data/lib/doorkeeper/oauth/token_introspection.rb +202 -0
  82. data/lib/doorkeeper/oauth/token_request.rb +8 -21
  83. data/lib/doorkeeper/oauth/token_response.rb +14 -10
  84. data/lib/doorkeeper/oauth.rb +13 -0
  85. data/lib/doorkeeper/orm/active_record/access_grant.rb +6 -4
  86. data/lib/doorkeeper/orm/active_record/access_token.rb +5 -25
  87. data/lib/doorkeeper/orm/active_record/application.rb +6 -15
  88. data/lib/doorkeeper/orm/active_record/mixins/access_grant.rb +68 -0
  89. data/lib/doorkeeper/orm/active_record/mixins/access_token.rb +59 -0
  90. data/lib/doorkeeper/orm/active_record/mixins/application.rb +198 -0
  91. data/lib/doorkeeper/orm/active_record/redirect_uri_validator.rb +66 -0
  92. data/lib/doorkeeper/orm/active_record/stale_records_cleaner.rb +33 -0
  93. data/lib/doorkeeper/orm/active_record.rb +37 -8
  94. data/lib/doorkeeper/rails/helpers.rb +14 -15
  95. data/lib/doorkeeper/rails/routes/abstract_router.rb +35 -0
  96. data/lib/doorkeeper/rails/routes/mapper.rb +3 -1
  97. data/lib/doorkeeper/rails/routes/mapping.rb +10 -8
  98. data/lib/doorkeeper/rails/routes/registry.rb +45 -0
  99. data/lib/doorkeeper/rails/routes.rb +42 -30
  100. data/lib/doorkeeper/rake/db.rake +40 -0
  101. data/lib/doorkeeper/rake/setup.rake +11 -0
  102. data/lib/doorkeeper/rake.rb +14 -0
  103. data/lib/doorkeeper/request/authorization_code.rb +12 -4
  104. data/lib/doorkeeper/request/client_credentials.rb +3 -3
  105. data/lib/doorkeeper/request/code.rb +1 -1
  106. data/lib/doorkeeper/request/password.rb +5 -14
  107. data/lib/doorkeeper/request/refresh_token.rb +6 -5
  108. data/lib/doorkeeper/request/strategy.rb +4 -2
  109. data/lib/doorkeeper/request/token.rb +1 -1
  110. data/lib/doorkeeper/request.rb +62 -29
  111. data/lib/doorkeeper/secret_storing/base.rb +64 -0
  112. data/lib/doorkeeper/secret_storing/bcrypt.rb +60 -0
  113. data/lib/doorkeeper/secret_storing/plain.rb +33 -0
  114. data/lib/doorkeeper/secret_storing/sha256_hash.rb +26 -0
  115. data/lib/doorkeeper/server.rb +9 -19
  116. data/lib/doorkeeper/stale_records_cleaner.rb +24 -0
  117. data/lib/doorkeeper/validations.rb +5 -2
  118. data/lib/doorkeeper/version.rb +12 -1
  119. data/lib/doorkeeper.rb +111 -56
  120. data/lib/generators/doorkeeper/application_owner_generator.rb +28 -13
  121. data/lib/generators/doorkeeper/confidential_applications_generator.rb +33 -0
  122. data/lib/generators/doorkeeper/enable_polymorphic_resource_owner_generator.rb +39 -0
  123. data/lib/generators/doorkeeper/install_generator.rb +19 -9
  124. data/lib/generators/doorkeeper/migration_generator.rb +27 -10
  125. data/lib/generators/doorkeeper/pkce_generator.rb +33 -0
  126. data/lib/generators/doorkeeper/previous_refresh_token_generator.rb +31 -19
  127. data/lib/generators/doorkeeper/templates/add_confidential_to_applications.rb.erb +13 -0
  128. data/lib/generators/doorkeeper/templates/add_owner_to_application_migration.rb.erb +9 -0
  129. data/lib/generators/doorkeeper/templates/{add_previous_refresh_token_to_access_tokens.rb → add_previous_refresh_token_to_access_tokens.rb.erb} +3 -1
  130. data/lib/generators/doorkeeper/templates/enable_pkce_migration.rb.erb +8 -0
  131. data/lib/generators/doorkeeper/templates/enable_polymorphic_resource_owner_migration.rb.erb +17 -0
  132. data/lib/generators/doorkeeper/templates/initializer.rb +410 -31
  133. data/lib/generators/doorkeeper/templates/migration.rb.erb +88 -0
  134. data/lib/generators/doorkeeper/views_generator.rb +8 -4
  135. data/vendor/assets/stylesheets/doorkeeper/bootstrap.min.css +4 -5
  136. metadata +132 -286
  137. data/.gitignore +0 -14
  138. data/.hound.yml +0 -13
  139. data/.rspec +0 -1
  140. data/.travis.yml +0 -20
  141. data/CONTRIBUTING.md +0 -47
  142. data/Gemfile +0 -14
  143. data/NEWS.md +0 -593
  144. data/RELEASING.md +0 -17
  145. data/Rakefile +0 -20
  146. data/app/validators/redirect_uri_validator.rb +0 -34
  147. data/doorkeeper.gemspec +0 -28
  148. data/lib/doorkeeper/oauth/client/methods.rb +0 -18
  149. data/lib/doorkeeper/oauth/client_credentials/validation.rb +0 -45
  150. data/lib/doorkeeper/oauth/request_concern.rb +0 -48
  151. data/lib/generators/doorkeeper/templates/add_owner_to_application_migration.rb +0 -7
  152. data/lib/generators/doorkeeper/templates/migration.rb +0 -68
  153. data/spec/controllers/application_metal_controller.rb +0 -10
  154. data/spec/controllers/applications_controller_spec.rb +0 -58
  155. data/spec/controllers/authorizations_controller_spec.rb +0 -189
  156. data/spec/controllers/protected_resources_controller_spec.rb +0 -300
  157. data/spec/controllers/token_info_controller_spec.rb +0 -52
  158. data/spec/controllers/tokens_controller_spec.rb +0 -88
  159. data/spec/dummy/Rakefile +0 -7
  160. data/spec/dummy/app/controllers/application_controller.rb +0 -3
  161. data/spec/dummy/app/controllers/custom_authorizations_controller.rb +0 -7
  162. data/spec/dummy/app/controllers/full_protected_resources_controller.rb +0 -12
  163. data/spec/dummy/app/controllers/home_controller.rb +0 -17
  164. data/spec/dummy/app/controllers/metal_controller.rb +0 -11
  165. data/spec/dummy/app/controllers/semi_protected_resources_controller.rb +0 -11
  166. data/spec/dummy/app/helpers/application_helper.rb +0 -5
  167. data/spec/dummy/app/models/user.rb +0 -5
  168. data/spec/dummy/app/views/home/index.html.erb +0 -0
  169. data/spec/dummy/app/views/layouts/application.html.erb +0 -14
  170. data/spec/dummy/config/application.rb +0 -23
  171. data/spec/dummy/config/boot.rb +0 -9
  172. data/spec/dummy/config/database.yml +0 -15
  173. data/spec/dummy/config/environment.rb +0 -5
  174. data/spec/dummy/config/environments/development.rb +0 -29
  175. data/spec/dummy/config/environments/production.rb +0 -62
  176. data/spec/dummy/config/environments/test.rb +0 -44
  177. data/spec/dummy/config/initializers/active_record_belongs_to_required_by_default.rb +0 -6
  178. data/spec/dummy/config/initializers/backtrace_silencers.rb +0 -7
  179. data/spec/dummy/config/initializers/doorkeeper.rb +0 -96
  180. data/spec/dummy/config/initializers/secret_token.rb +0 -9
  181. data/spec/dummy/config/initializers/session_store.rb +0 -8
  182. data/spec/dummy/config/initializers/wrap_parameters.rb +0 -14
  183. data/spec/dummy/config/locales/doorkeeper.en.yml +0 -5
  184. data/spec/dummy/config/routes.rb +0 -52
  185. data/spec/dummy/config.ru +0 -4
  186. data/spec/dummy/db/migrate/20111122132257_create_users.rb +0 -9
  187. data/spec/dummy/db/migrate/20120312140401_add_password_to_users.rb +0 -5
  188. data/spec/dummy/db/migrate/20151223192035_create_doorkeeper_tables.rb +0 -60
  189. data/spec/dummy/db/migrate/20151223200000_add_owner_to_application.rb +0 -7
  190. data/spec/dummy/db/migrate/20160320211015_add_previous_refresh_token_to_access_tokens.rb +0 -11
  191. data/spec/dummy/db/schema.rb +0 -67
  192. data/spec/dummy/public/404.html +0 -26
  193. data/spec/dummy/public/422.html +0 -26
  194. data/spec/dummy/public/500.html +0 -26
  195. data/spec/dummy/public/favicon.ico +0 -0
  196. data/spec/dummy/script/rails +0 -6
  197. data/spec/factories.rb +0 -28
  198. data/spec/generators/application_owner_generator_spec.rb +0 -22
  199. data/spec/generators/install_generator_spec.rb +0 -31
  200. data/spec/generators/migration_generator_spec.rb +0 -20
  201. data/spec/generators/templates/routes.rb +0 -3
  202. data/spec/generators/views_generator_spec.rb +0 -27
  203. data/spec/helpers/doorkeeper/dashboard_helper_spec.rb +0 -24
  204. data/spec/lib/config_spec.rb +0 -334
  205. data/spec/lib/doorkeeper_spec.rb +0 -28
  206. data/spec/lib/models/expirable_spec.rb +0 -51
  207. data/spec/lib/models/revocable_spec.rb +0 -59
  208. data/spec/lib/models/scopes_spec.rb +0 -43
  209. data/spec/lib/oauth/authorization/uri_builder_spec.rb +0 -42
  210. data/spec/lib/oauth/authorization_code_request_spec.rb +0 -80
  211. data/spec/lib/oauth/client/credentials_spec.rb +0 -47
  212. data/spec/lib/oauth/client/methods_spec.rb +0 -54
  213. data/spec/lib/oauth/client_credentials/creator_spec.rb +0 -44
  214. data/spec/lib/oauth/client_credentials/issuer_spec.rb +0 -86
  215. data/spec/lib/oauth/client_credentials/validation_spec.rb +0 -54
  216. data/spec/lib/oauth/client_credentials_integration_spec.rb +0 -27
  217. data/spec/lib/oauth/client_credentials_request_spec.rb +0 -104
  218. data/spec/lib/oauth/client_spec.rb +0 -39
  219. data/spec/lib/oauth/code_request_spec.rb +0 -45
  220. data/spec/lib/oauth/code_response_spec.rb +0 -34
  221. data/spec/lib/oauth/error_response_spec.rb +0 -61
  222. data/spec/lib/oauth/error_spec.rb +0 -23
  223. data/spec/lib/oauth/forbidden_token_response_spec.rb +0 -23
  224. data/spec/lib/oauth/helpers/scope_checker_spec.rb +0 -64
  225. data/spec/lib/oauth/helpers/unique_token_spec.rb +0 -20
  226. data/spec/lib/oauth/helpers/uri_checker_spec.rb +0 -104
  227. data/spec/lib/oauth/invalid_token_response_spec.rb +0 -28
  228. data/spec/lib/oauth/password_access_token_request_spec.rb +0 -90
  229. data/spec/lib/oauth/pre_authorization_spec.rb +0 -155
  230. data/spec/lib/oauth/refresh_token_request_spec.rb +0 -154
  231. data/spec/lib/oauth/scopes_spec.rb +0 -122
  232. data/spec/lib/oauth/token_request_spec.rb +0 -98
  233. data/spec/lib/oauth/token_response_spec.rb +0 -85
  234. data/spec/lib/oauth/token_spec.rb +0 -116
  235. data/spec/lib/request/strategy_spec.rb +0 -53
  236. data/spec/lib/server_spec.rb +0 -52
  237. data/spec/models/doorkeeper/access_grant_spec.rb +0 -36
  238. data/spec/models/doorkeeper/access_token_spec.rb +0 -394
  239. data/spec/models/doorkeeper/application_spec.rb +0 -179
  240. data/spec/requests/applications/applications_request_spec.rb +0 -94
  241. data/spec/requests/applications/authorized_applications_spec.rb +0 -30
  242. data/spec/requests/endpoints/authorization_spec.rb +0 -72
  243. data/spec/requests/endpoints/token_spec.rb +0 -64
  244. data/spec/requests/flows/authorization_code_errors_spec.rb +0 -66
  245. data/spec/requests/flows/authorization_code_spec.rb +0 -156
  246. data/spec/requests/flows/client_credentials_spec.rb +0 -58
  247. data/spec/requests/flows/implicit_grant_errors_spec.rb +0 -32
  248. data/spec/requests/flows/implicit_grant_spec.rb +0 -61
  249. data/spec/requests/flows/password_spec.rb +0 -115
  250. data/spec/requests/flows/refresh_token_spec.rb +0 -174
  251. data/spec/requests/flows/revoke_token_spec.rb +0 -157
  252. data/spec/requests/flows/skip_authorization_spec.rb +0 -59
  253. data/spec/requests/protected_resources/metal_spec.rb +0 -14
  254. data/spec/requests/protected_resources/private_api_spec.rb +0 -81
  255. data/spec/routing/custom_controller_routes_spec.rb +0 -71
  256. data/spec/routing/default_routes_spec.rb +0 -35
  257. data/spec/routing/scoped_routes_spec.rb +0 -31
  258. data/spec/spec_helper.rb +0 -2
  259. data/spec/spec_helper_integration.rb +0 -59
  260. data/spec/support/dependencies/factory_girl.rb +0 -2
  261. data/spec/support/helpers/access_token_request_helper.rb +0 -11
  262. data/spec/support/helpers/authorization_request_helper.rb +0 -41
  263. data/spec/support/helpers/config_helper.rb +0 -9
  264. data/spec/support/helpers/model_helper.rb +0 -67
  265. data/spec/support/helpers/request_spec_helper.rb +0 -76
  266. data/spec/support/helpers/url_helper.rb +0 -55
  267. data/spec/support/http_method_shim.rb +0 -24
  268. data/spec/support/orm/active_record.rb +0 -3
  269. data/spec/support/shared/controllers_shared_context.rb +0 -69
  270. data/spec/support/shared/models_shared_examples.rb +0 -52
  271. data/spec/validators/redirect_uri_validator_spec.rb +0 -78
@@ -1,54 +1,99 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
2
4
  class ApplicationsController < Doorkeeper::ApplicationController
3
- layout 'doorkeeper/admin'
5
+ layout "doorkeeper/admin" unless Doorkeeper.configuration.api_only
4
6
 
5
7
  before_action :authenticate_admin!
6
- before_action :set_application, only: [:show, :edit, :update, :destroy]
8
+ before_action :set_application, only: %i[show edit update destroy]
7
9
 
8
10
  def index
9
- @applications = Application.all
11
+ @applications = Doorkeeper.config.application_model.ordered_by(:created_at)
12
+
13
+ respond_to do |format|
14
+ format.html
15
+ format.json { head :no_content }
16
+ end
17
+ end
18
+
19
+ def show
20
+ respond_to do |format|
21
+ format.html
22
+ format.json { render json: @application, as_owner: true }
23
+ end
10
24
  end
11
25
 
12
26
  def new
13
- @application = Application.new
27
+ @application = Doorkeeper.config.application_model.new
14
28
  end
15
29
 
16
30
  def create
17
- @application = Application.new(application_params)
31
+ @application = Doorkeeper.config.application_model.new(application_params)
32
+
18
33
  if @application.save
19
- flash[:notice] = I18n.t(:notice, scope: [:doorkeeper, :flash, :applications, :create])
20
- redirect_to oauth_application_url(@application)
34
+ flash[:notice] = I18n.t(:notice, scope: %i[doorkeeper flash applications create])
35
+ flash[:application_secret] = @application.plaintext_secret
36
+
37
+ respond_to do |format|
38
+ format.html { redirect_to oauth_application_url(@application) }
39
+ format.json { render json: @application, as_owner: true }
40
+ end
21
41
  else
22
- render :new
42
+ respond_to do |format|
43
+ format.html { render :new }
44
+ format.json do
45
+ errors = @application.errors.full_messages
46
+
47
+ render json: { errors: errors }, status: :unprocessable_entity
48
+ end
49
+ end
23
50
  end
24
51
  end
25
52
 
53
+ def edit; end
54
+
26
55
  def update
27
- if @application.update_attributes(application_params)
28
- flash[:notice] = I18n.t(:notice, scope: [:doorkeeper, :flash, :applications, :update])
29
- redirect_to oauth_application_url(@application)
56
+ if @application.update(application_params)
57
+ flash[:notice] = I18n.t(:notice, scope: i18n_scope(:update))
58
+
59
+ respond_to do |format|
60
+ format.html { redirect_to oauth_application_url(@application) }
61
+ format.json { render json: @application, as_owner: true }
62
+ end
30
63
  else
31
- render :edit
64
+ respond_to do |format|
65
+ format.html { render :edit }
66
+ format.json do
67
+ errors = @application.errors.full_messages
68
+
69
+ render json: { errors: errors }, status: :unprocessable_entity
70
+ end
71
+ end
32
72
  end
33
73
  end
34
74
 
35
75
  def destroy
36
- flash[:notice] = I18n.t(:notice, scope: [:doorkeeper, :flash, :applications, :destroy]) if @application.destroy
37
- redirect_to oauth_applications_url
76
+ flash[:notice] = I18n.t(:notice, scope: i18n_scope(:destroy)) if @application.destroy
77
+
78
+ respond_to do |format|
79
+ format.html { redirect_to oauth_applications_url }
80
+ format.json { head :no_content }
81
+ end
38
82
  end
39
83
 
40
84
  private
41
85
 
42
86
  def set_application
43
- @application = Application.find(params[:id])
87
+ @application = Doorkeeper.config.application_model.find(params[:id])
44
88
  end
45
89
 
46
90
  def application_params
47
- if params.respond_to?(:permit)
48
- params.require(:doorkeeper_application).permit(:name, :redirect_uri, :scopes)
49
- else
50
- params[:doorkeeper_application].slice(:name, :redirect_uri, :scopes) rescue nil
51
- end
91
+ params.require(:doorkeeper_application)
92
+ .permit(:name, :redirect_uri, :scopes, :confidential)
93
+ end
94
+
95
+ def i18n_scope(action)
96
+ %i[doorkeeper flash applications] << action
52
97
  end
53
98
  end
54
99
  end
@@ -1,23 +1,19 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
2
4
  class AuthorizationsController < Doorkeeper::ApplicationController
3
5
  before_action :authenticate_resource_owner!
4
6
 
5
7
  def new
6
8
  if pre_auth.authorizable?
7
- if skip_authorization? || matching_token?
8
- auth = authorization.authorize
9
- redirect_to auth.redirect_uri
10
- else
11
- render :new
12
- end
9
+ render_success
13
10
  else
14
- render :error
11
+ render_error
15
12
  end
16
13
  end
17
14
 
18
- # TODO: Handle raise invalid authorization
19
15
  def create
20
- redirect_or_render authorization.authorize
16
+ redirect_or_render authorize_response
21
17
  end
22
18
 
23
19
  def destroy
@@ -26,24 +22,80 @@ module Doorkeeper
26
22
 
27
23
  private
28
24
 
25
+ def render_success
26
+ if skip_authorization? || matching_token?
27
+ redirect_or_render authorize_response
28
+ elsif Doorkeeper.configuration.api_only
29
+ render json: pre_auth
30
+ else
31
+ render :new
32
+ end
33
+ end
34
+
35
+ def render_error
36
+ if Doorkeeper.configuration.api_only
37
+ render json: pre_auth.error_response.body,
38
+ status: :bad_request
39
+ else
40
+ render :error
41
+ end
42
+ end
43
+
29
44
  def matching_token?
30
- AccessToken.matching_token_for pre_auth.client,
31
- current_resource_owner.id,
32
- pre_auth.scopes
45
+ Doorkeeper.config.access_token_model.matching_token_for(
46
+ pre_auth.client,
47
+ current_resource_owner,
48
+ pre_auth.scopes,
49
+ )
33
50
  end
34
51
 
35
52
  def redirect_or_render(auth)
36
53
  if auth.redirectable?
37
- redirect_to auth.redirect_uri
54
+ if Doorkeeper.configuration.api_only
55
+ if pre_auth.form_post_response?
56
+ render(
57
+ json: { status: :post, redirect_uri: pre_auth.redirect_uri, body: auth.body },
58
+ status: auth.status,
59
+ )
60
+ else
61
+ render(
62
+ json: { status: :redirect, redirect_uri: auth.redirect_uri },
63
+ status: auth.status,
64
+ )
65
+ end
66
+ elsif pre_auth.form_post_response?
67
+ render :form_post
68
+ else
69
+ redirect_to auth.redirect_uri
70
+ end
38
71
  else
39
72
  render json: auth.body, status: auth.status
40
73
  end
41
74
  end
42
75
 
43
76
  def pre_auth
44
- @pre_auth ||= OAuth::PreAuthorization.new(Doorkeeper.configuration,
45
- server.client_via_uid,
46
- params)
77
+ @pre_auth ||= OAuth::PreAuthorization.new(
78
+ Doorkeeper.configuration,
79
+ pre_auth_params,
80
+ current_resource_owner,
81
+ )
82
+ end
83
+
84
+ def pre_auth_params
85
+ params.slice(*pre_auth_param_fields).permit(*pre_auth_param_fields)
86
+ end
87
+
88
+ def pre_auth_param_fields
89
+ %i[
90
+ client_id
91
+ code_challenge
92
+ code_challenge_method
93
+ response_type
94
+ response_mode
95
+ redirect_uri
96
+ scope
97
+ state
98
+ ]
47
99
  end
48
100
 
49
101
  def authorization
@@ -51,7 +103,35 @@ module Doorkeeper
51
103
  end
52
104
 
53
105
  def strategy
54
- @strategy ||= server.authorization_request pre_auth.response_type
106
+ @strategy ||= server.authorization_request(pre_auth.response_type)
107
+ end
108
+
109
+ def authorize_response
110
+ @authorize_response ||= begin
111
+ return pre_auth.error_response unless pre_auth.authorizable?
112
+
113
+ context = build_context(pre_auth: pre_auth)
114
+ before_successful_authorization(context)
115
+
116
+ auth = strategy.authorize
117
+
118
+ context = build_context(auth: auth)
119
+ after_successful_authorization(context)
120
+
121
+ auth
122
+ end
123
+ end
124
+
125
+ def build_context(**attributes)
126
+ Doorkeeper::OAuth::Hooks::Context.new(**attributes)
127
+ end
128
+
129
+ def before_successful_authorization(context = nil)
130
+ Doorkeeper.config.before_successful_authorization.call(self, context)
131
+ end
132
+
133
+ def after_successful_authorization(context)
134
+ Doorkeeper.config.after_successful_authorization.call(self, context)
55
135
  end
56
136
  end
57
137
  end
@@ -1,14 +1,33 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
2
4
  class AuthorizedApplicationsController < Doorkeeper::ApplicationController
3
5
  before_action :authenticate_resource_owner!
4
6
 
5
7
  def index
6
- @applications = Application.authorized_for(current_resource_owner)
8
+ @applications = Doorkeeper.config.application_model.authorized_for(current_resource_owner)
9
+
10
+ respond_to do |format|
11
+ format.html
12
+ format.json { render json: @applications, current_resource_owner: current_resource_owner }
13
+ end
7
14
  end
8
15
 
9
16
  def destroy
10
- AccessToken.revoke_all_for params[:id], current_resource_owner
11
- redirect_to oauth_authorized_applications_url, notice: I18n.t(:notice, scope: [:doorkeeper, :flash, :authorized_applications, :destroy])
17
+ Doorkeeper.config.application_model.revoke_tokens_and_grants_for(
18
+ params[:id],
19
+ current_resource_owner,
20
+ )
21
+
22
+ respond_to do |format|
23
+ format.html do
24
+ redirect_to oauth_authorized_applications_url, notice: I18n.t(
25
+ :notice, scope: %i[doorkeeper flash authorized_applications destroy],
26
+ )
27
+ end
28
+
29
+ format.json { head :no_content }
30
+ end
12
31
  end
13
32
  end
14
33
  end
@@ -1,13 +1,25 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
2
4
  class TokenInfoController < Doorkeeper::ApplicationMetalController
3
5
  def show
4
- if doorkeeper_token && doorkeeper_token.accessible?
5
- render json: doorkeeper_token, status: :ok
6
+ if doorkeeper_token&.accessible?
7
+ render json: doorkeeper_token_to_json, status: :ok
6
8
  else
7
- error = OAuth::ErrorResponse.new(name: :invalid_request)
9
+ error = OAuth::InvalidTokenResponse.new
8
10
  response.headers.merge!(error.headers)
9
- render json: error.body, status: error.status
11
+ render json: error_to_json(error), status: error.status
10
12
  end
11
13
  end
14
+
15
+ protected
16
+
17
+ def doorkeeper_token_to_json
18
+ doorkeeper_token
19
+ end
20
+
21
+ def error_to_json(error)
22
+ error.body
23
+ end
12
24
  end
13
25
  end
@@ -1,37 +1,88 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
2
4
  class TokensController < Doorkeeper::ApplicationMetalController
5
+ before_action :validate_presence_of_client, only: [:revoke]
6
+
3
7
  def create
4
- response = authorize_response
5
- headers.merge! response.headers
6
- self.response_body = response.body.to_json
7
- self.status = response.status
8
+ headers.merge!(authorize_response.headers)
9
+ render json: authorize_response.body,
10
+ status: authorize_response.status
8
11
  rescue Errors::DoorkeeperError => e
9
- handle_token_exception e
12
+ handle_token_exception(e)
10
13
  end
11
14
 
12
15
  # OAuth 2.0 Token Revocation - http://tools.ietf.org/html/rfc7009
13
16
  def revoke
14
- # The authorization server, if applicable, first authenticates the client
15
- # and checks its ownership of the provided token.
16
- #
17
- # Doorkeeper does not use the token_type_hint logic described in the
18
- # RFC 7009 due to the refresh token implementation that is a field in
19
- # the access token model.
20
- if authorized?
17
+ # The authorization server responds with HTTP status code 200 if the client
18
+ # submitted an invalid token or the token has been revoked successfully.
19
+ if token.blank?
20
+ render json: {}, status: 200
21
+ # The authorization server validates [...] and whether the token
22
+ # was issued to the client making the revocation request. If this
23
+ # validation fails, the request is refused and the client is informed
24
+ # of the error by the authorization server as described below.
25
+ elsif authorized?
21
26
  revoke_token
27
+ render json: {}, status: 200
28
+ else
29
+ render json: revocation_error_response, status: :forbidden
22
30
  end
31
+ end
23
32
 
24
- # The authorization server responds with HTTP status code 200 if the token
25
- # has been revoked successfully or if the client submitted an invalid
26
- # token
27
- render json: {}, status: 200
33
+ def introspect
34
+ introspection = OAuth::TokenIntrospection.new(server, token)
35
+
36
+ if introspection.authorized?
37
+ render json: introspection.to_json, status: 200
38
+ else
39
+ error = introspection.error_response
40
+ headers.merge!(error.headers)
41
+ render json: error.body, status: error.status
42
+ end
28
43
  end
29
44
 
30
45
  private
31
46
 
47
+ def validate_presence_of_client
48
+ return if Doorkeeper.config.skip_client_authentication_for_password_grant
49
+
50
+ # @see 2.1. Revocation Request
51
+ #
52
+ # The client constructs the request by including the following
53
+ # parameters using the "application/x-www-form-urlencoded" format in
54
+ # the HTTP request entity-body:
55
+ # token REQUIRED.
56
+ # token_type_hint OPTIONAL.
57
+ #
58
+ # The client also includes its authentication credentials as described
59
+ # in Section 2.3. of [RFC6749].
60
+ #
61
+ # The authorization server first validates the client credentials (in
62
+ # case of a confidential client) and then verifies whether the token
63
+ # was issued to the client making the revocation request.
64
+ return if server.client
65
+
66
+ # If this validation [client credentials / token ownership] fails, the request is
67
+ # refused and the client is informed of the error by the authorization server as
68
+ # described below.
69
+ #
70
+ # @see 2.2.1. Error Response
71
+ #
72
+ # The error presentation conforms to the definition in Section 5.2 of [RFC6749].
73
+ render json: revocation_error_response, status: :forbidden
74
+ end
75
+
32
76
  # OAuth 2.0 Section 2.1 defines two client types, "public" & "confidential".
33
- # Public clients (as per RFC 7009) do not require authentication whereas
34
- # confidential clients must be authenticated for their token revocation.
77
+ #
78
+ # RFC7009
79
+ # Section 5. Security Considerations
80
+ # A malicious client may attempt to guess valid tokens on this endpoint
81
+ # by making revocation requests against potential token strings.
82
+ # According to this specification, a client's request must contain a
83
+ # valid client_id, in the case of a public client, or valid client
84
+ # credentials, in the case of a confidential client. The token being
85
+ # revoked must also belong to the requesting client.
35
86
  #
36
87
  # Once a confidential client is authenticated, it must be authorized to
37
88
  # revoke the provided access or refresh token. This ensures one client
@@ -46,36 +97,62 @@ module Doorkeeper
46
97
  # https://tools.ietf.org/html/rfc6749#section-2.1
47
98
  # https://tools.ietf.org/html/rfc7009
48
99
  def authorized?
49
- if token.present?
50
- # Client is confidential, therefore client authentication & authorization
51
- # is required
52
- if token.application_id?
53
- # We authorize client by checking token's application
54
- server.client && server.client.application == token.application
55
- else
56
- # Client is public, authentication unnecessary
57
- true
58
- end
100
+ # Token belongs to specific client, so we need to check if
101
+ # authenticated client could access it.
102
+ if token.application_id? && token.application.confidential?
103
+ # We authorize client by checking token's application
104
+ server.client && server.client.application == token.application
105
+ else
106
+ # Token was issued without client, authorization unnecessary
107
+ true
59
108
  end
60
109
  end
61
110
 
62
111
  def revoke_token
63
- if token.accessible?
64
- token.revoke
65
- end
112
+ # The authorization server responds with HTTP status code 200 if the token
113
+ # has been revoked successfully or if the client submitted an invalid
114
+ # token
115
+ token.revoke if token&.accessible?
66
116
  end
67
117
 
118
+ # Doorkeeper does not use the token_type_hint logic described in the
119
+ # RFC 7009 due to the refresh token implementation that is a field in
120
+ # the access token model.
68
121
  def token
69
- @token ||= AccessToken.by_token(request.POST['token']) ||
70
- AccessToken.by_refresh_token(request.POST['token'])
122
+ @token ||= Doorkeeper.config.access_token_model.by_token(params["token"]) ||
123
+ Doorkeeper.config.access_token_model.by_refresh_token(params["token"])
71
124
  end
72
125
 
73
126
  def strategy
74
- @strategy ||= server.token_request params[:grant_type]
127
+ @strategy ||= server.token_request(params[:grant_type])
75
128
  end
76
129
 
77
130
  def authorize_response
78
- @authorize_response ||= strategy.authorize
131
+ @authorize_response ||= begin
132
+ before_successful_authorization
133
+ auth = strategy.authorize
134
+ context = build_context(auth: auth)
135
+ after_successful_authorization(context) unless auth.is_a?(Doorkeeper::OAuth::ErrorResponse)
136
+ auth
137
+ end
138
+ end
139
+
140
+ def build_context(**attributes)
141
+ Doorkeeper::OAuth::Hooks::Context.new(**attributes)
142
+ end
143
+
144
+ def before_successful_authorization(context = nil)
145
+ Doorkeeper.config.before_successful_authorization.call(self, context)
146
+ end
147
+
148
+ def after_successful_authorization(context)
149
+ Doorkeeper.config.after_successful_authorization.call(self, context)
150
+ end
151
+
152
+ def revocation_error_response
153
+ error_description = I18n.t(:unauthorized, scope: %i[doorkeeper errors messages revoke])
154
+
155
+ { error: :unauthorized_client, error_description: error_description }
79
156
  end
80
157
  end
81
158
  end
@@ -1,13 +1,17 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
2
4
  module DashboardHelper
3
5
  def doorkeeper_errors_for(object, method)
4
- if object.errors[method].present?
5
- object.errors[method].map do |msg|
6
- content_tag(:span, class: 'help-block') do
7
- msg.capitalize
8
- end
9
- end.join.html_safe
6
+ return if object.errors[method].blank?
7
+
8
+ output = object.errors[method].map do |msg|
9
+ content_tag(:span, class: "form-text") do
10
+ msg.capitalize
11
+ end
10
12
  end
13
+
14
+ safe_join(output)
11
15
  end
12
16
 
13
17
  def doorkeeper_submit_path(application)
@@ -1,5 +1,6 @@
1
1
  <%- submit_btn_css ||= 'btn btn-link' %>
2
- <%= form_tag oauth_application_path(application) do %>
3
- <input type="hidden" name="_method" value="delete">
4
- <%= submit_tag t('doorkeeper.applications.buttons.destroy'), onclick: "return confirm('#{ t('doorkeeper.applications.confirmations.destroy') }')", class: submit_btn_css %>
2
+ <%= form_tag oauth_application_path(application), method: :delete do %>
3
+ <%= submit_tag t('doorkeeper.applications.buttons.destroy'),
4
+ onclick: "return confirm('#{ t('doorkeeper.applications.confirmations.destroy') }')",
5
+ class: submit_btn_css %>
5
6
  <% end %>
@@ -1,47 +1,59 @@
1
- <%= form_for application, url: doorkeeper_submit_path(application), html: {class: 'form-horizontal', role: 'form'} do |f| %>
1
+ <%= form_for application, url: doorkeeper_submit_path(application), as: :doorkeeper_application, html: { role: 'form' } do |f| %>
2
2
  <% if application.errors.any? %>
3
3
  <div class="alert alert-danger" data-alert><p><%= t('doorkeeper.applications.form.error') %></p></div>
4
4
  <% end %>
5
5
 
6
- <%= content_tag :div, class: "form-group#{' has-error' if application.errors[:name].present?}" do %>
7
- <%= f.label :name, class: 'col-sm-2 control-label' %>
6
+ <div class="form-group row">
7
+ <%= f.label :name, class: 'col-sm-2 col-form-label font-weight-bold' %>
8
8
  <div class="col-sm-10">
9
- <%= f.text_field :name, class: 'form-control' %>
9
+ <%= f.text_field :name, class: "form-control #{ 'is-invalid' if application.errors[:name].present? }", required: true %>
10
10
  <%= doorkeeper_errors_for application, :name %>
11
11
  </div>
12
- <% end %>
12
+ </div>
13
13
 
14
- <%= content_tag :div, class: "form-group#{' has-error' if application.errors[:redirect_uri].present?}" do %>
15
- <%= f.label :redirect_uri, class: 'col-sm-2 control-label' %>
14
+ <div class="form-group row">
15
+ <%= f.label :redirect_uri, class: 'col-sm-2 col-form-label font-weight-bold' %>
16
16
  <div class="col-sm-10">
17
- <%= f.text_area :redirect_uri, class: 'form-control' %>
17
+ <%= f.text_area :redirect_uri, class: "form-control #{ 'is-invalid' if application.errors[:redirect_uri].present? }" %>
18
18
  <%= doorkeeper_errors_for application, :redirect_uri %>
19
- <span class="help-block">
19
+ <span class="form-text text-secondary">
20
20
  <%= t('doorkeeper.applications.help.redirect_uri') %>
21
21
  </span>
22
- <% if Doorkeeper.configuration.native_redirect_uri %>
23
- <span class="help-block">
24
- <%= raw t('doorkeeper.applications.help.native_redirect_uri', native_redirect_uri: "<code>#{ Doorkeeper.configuration.native_redirect_uri }</code>") %>
25
- </span>
22
+
23
+ <% if Doorkeeper.configuration.allow_blank_redirect_uri?(application) %>
24
+ <span class="form-text text-secondary">
25
+ <%= t('doorkeeper.applications.help.blank_redirect_uri') %>
26
+ </span>
26
27
  <% end %>
27
28
  </div>
28
- <% end %>
29
+ </div>
30
+
31
+ <div class="form-group row">
32
+ <%= f.label :confidential, class: 'col-sm-2 form-check-label font-weight-bold' %>
33
+ <div class="col-sm-10">
34
+ <%= f.check_box :confidential, class: "checkbox #{ 'is-invalid' if application.errors[:confidential].present? }" %>
35
+ <%= doorkeeper_errors_for application, :confidential %>
36
+ <span class="form-text text-secondary">
37
+ <%= t('doorkeeper.applications.help.confidential') %>
38
+ </span>
39
+ </div>
40
+ </div>
29
41
 
30
- <%= content_tag :div, class: "form-group#{' has-error' if application.errors[:scopes].present?}" do %>
31
- <%= f.label :scopes, class: 'col-sm-2 control-label' %>
42
+ <div class="form-group row">
43
+ <%= f.label :scopes, class: 'col-sm-2 col-form-label font-weight-bold' %>
32
44
  <div class="col-sm-10">
33
- <%= f.text_field :scopes, class: 'form-control' %>
45
+ <%= f.text_field :scopes, class: "form-control #{ 'has-error' if application.errors[:scopes].present? }" %>
34
46
  <%= doorkeeper_errors_for application, :scopes %>
35
- <span class="help-block">
47
+ <span class="form-text text-secondary">
36
48
  <%= t('doorkeeper.applications.help.scopes') %>
37
49
  </span>
38
50
  </div>
39
- <% end %>
51
+ </div>
40
52
 
41
53
  <div class="form-group">
42
54
  <div class="col-sm-offset-2 col-sm-10">
43
- <%= f.submit t('doorkeeper.applications.buttons.submit'), class: "btn btn-primary" %>
44
- <%= link_to t('doorkeeper.applications.buttons.cancel'), oauth_applications_path, :class => "btn btn-default" %>
55
+ <%= f.submit t('doorkeeper.applications.buttons.submit'), class: 'btn btn-primary' %>
56
+ <%= link_to t('doorkeeper.applications.buttons.cancel'), oauth_applications_path, class: 'btn btn-secondary' %>
45
57
  </div>
46
58
  </div>
47
59
  <% end %>
@@ -1,4 +1,4 @@
1
- <div class="page-header">
1
+ <div class="border-bottom mb-4">
2
2
  <h1><%= t('.title') %></h1>
3
3
  </div>
4
4