doorkeeper 3.1.0 → 5.6.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 (270) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +1079 -0
  3. data/README.md +114 -326
  4. data/app/assets/stylesheets/doorkeeper/admin/application.css +2 -2
  5. data/app/controllers/doorkeeper/application_controller.rb +7 -6
  6. data/app/controllers/doorkeeper/application_metal_controller.rb +9 -12
  7. data/app/controllers/doorkeeper/applications_controller.rb +66 -21
  8. data/app/controllers/doorkeeper/authorizations_controller.rb +100 -18
  9. data/app/controllers/doorkeeper/authorized_applications_controller.rb +23 -4
  10. data/app/controllers/doorkeeper/token_info_controller.rb +16 -4
  11. data/app/controllers/doorkeeper/tokens_controller.rb +138 -22
  12. data/app/helpers/doorkeeper/dashboard_helper.rb +15 -9
  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 +17 -11
  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 +37 -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 +602 -142
  30. data/lib/doorkeeper/engine.rb +22 -7
  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 +99 -16
  40. data/lib/doorkeeper/models/access_token_mixin.rb +386 -77
  41. data/lib/doorkeeper/models/application_mixin.rb +73 -30
  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/expiration_time_sql_math.rb +88 -0
  45. data/lib/doorkeeper/models/concerns/orderable.rb +15 -0
  46. data/lib/doorkeeper/models/concerns/ownership.rb +4 -2
  47. data/lib/doorkeeper/models/concerns/resource_ownerable.rb +47 -0
  48. data/lib/doorkeeper/models/concerns/reusable.rb +19 -0
  49. data/lib/doorkeeper/models/concerns/revocable.rb +13 -2
  50. data/lib/doorkeeper/models/concerns/scopes.rb +12 -2
  51. data/lib/doorkeeper/models/concerns/secret_storable.rb +106 -0
  52. data/lib/doorkeeper/oauth/authorization/code.rb +48 -12
  53. data/lib/doorkeeper/oauth/authorization/context.rb +17 -0
  54. data/lib/doorkeeper/oauth/authorization/token.rb +72 -28
  55. data/lib/doorkeeper/oauth/authorization/uri_builder.rb +22 -18
  56. data/lib/doorkeeper/oauth/authorization_code_request.rb +64 -14
  57. data/lib/doorkeeper/oauth/base_request.rb +66 -0
  58. data/lib/doorkeeper/oauth/base_response.rb +31 -0
  59. data/lib/doorkeeper/oauth/client/credentials.rb +23 -10
  60. data/lib/doorkeeper/oauth/client.rb +10 -12
  61. data/lib/doorkeeper/oauth/client_credentials/creator.rb +48 -4
  62. data/lib/doorkeeper/oauth/client_credentials/issuer.rb +17 -9
  63. data/lib/doorkeeper/oauth/client_credentials/validator.rb +55 -0
  64. data/lib/doorkeeper/oauth/client_credentials_request.rb +14 -15
  65. data/lib/doorkeeper/oauth/code_request.rb +8 -12
  66. data/lib/doorkeeper/oauth/code_response.rb +31 -19
  67. data/lib/doorkeeper/oauth/error.rb +5 -3
  68. data/lib/doorkeeper/oauth/error_response.rb +41 -20
  69. data/lib/doorkeeper/oauth/forbidden_token_response.rb +11 -3
  70. data/lib/doorkeeper/oauth/helpers/scope_checker.rb +24 -19
  71. data/lib/doorkeeper/oauth/helpers/unique_token.rb +20 -3
  72. data/lib/doorkeeper/oauth/helpers/uri_checker.rb +55 -4
  73. data/lib/doorkeeper/oauth/hooks/context.rb +21 -0
  74. data/lib/doorkeeper/oauth/invalid_request_response.rb +43 -0
  75. data/lib/doorkeeper/oauth/invalid_token_response.rb +31 -5
  76. data/lib/doorkeeper/oauth/nonstandard.rb +39 -0
  77. data/lib/doorkeeper/oauth/password_access_token_request.rb +46 -18
  78. data/lib/doorkeeper/oauth/pre_authorization.rb +135 -26
  79. data/lib/doorkeeper/oauth/refresh_token_request.rb +67 -30
  80. data/lib/doorkeeper/oauth/scopes.rb +26 -12
  81. data/lib/doorkeeper/oauth/token.rb +28 -25
  82. data/lib/doorkeeper/oauth/token_introspection.rb +202 -0
  83. data/lib/doorkeeper/oauth/token_request.rb +8 -21
  84. data/lib/doorkeeper/oauth/token_response.rb +14 -10
  85. data/lib/doorkeeper/oauth.rb +13 -0
  86. data/lib/doorkeeper/orm/active_record/access_grant.rb +6 -4
  87. data/lib/doorkeeper/orm/active_record/access_token.rb +5 -17
  88. data/lib/doorkeeper/orm/active_record/application.rb +6 -20
  89. data/lib/doorkeeper/orm/active_record/mixins/access_grant.rb +69 -0
  90. data/lib/doorkeeper/orm/active_record/mixins/access_token.rb +81 -0
  91. data/lib/doorkeeper/orm/active_record/mixins/application.rb +214 -0
  92. data/lib/doorkeeper/orm/active_record/redirect_uri_validator.rb +66 -0
  93. data/lib/doorkeeper/orm/active_record/stale_records_cleaner.rb +33 -0
  94. data/lib/doorkeeper/orm/active_record.rb +36 -26
  95. data/lib/doorkeeper/rails/helpers.rb +14 -15
  96. data/lib/doorkeeper/rails/routes/abstract_router.rb +35 -0
  97. data/lib/doorkeeper/rails/routes/mapper.rb +4 -2
  98. data/lib/doorkeeper/rails/routes/mapping.rb +10 -8
  99. data/lib/doorkeeper/rails/routes/registry.rb +45 -0
  100. data/lib/doorkeeper/rails/routes.rb +45 -28
  101. data/lib/doorkeeper/rake/db.rake +40 -0
  102. data/lib/doorkeeper/rake/setup.rake +6 -0
  103. data/lib/doorkeeper/rake.rb +14 -0
  104. data/lib/doorkeeper/request/authorization_code.rb +12 -4
  105. data/lib/doorkeeper/request/client_credentials.rb +3 -3
  106. data/lib/doorkeeper/request/code.rb +1 -1
  107. data/lib/doorkeeper/request/password.rb +5 -4
  108. data/lib/doorkeeper/request/refresh_token.rb +6 -5
  109. data/lib/doorkeeper/request/strategy.rb +4 -2
  110. data/lib/doorkeeper/request/token.rb +1 -1
  111. data/lib/doorkeeper/request.rb +62 -29
  112. data/lib/doorkeeper/secret_storing/base.rb +64 -0
  113. data/lib/doorkeeper/secret_storing/bcrypt.rb +60 -0
  114. data/lib/doorkeeper/secret_storing/plain.rb +33 -0
  115. data/lib/doorkeeper/secret_storing/sha256_hash.rb +26 -0
  116. data/lib/doorkeeper/server.rb +9 -19
  117. data/lib/doorkeeper/stale_records_cleaner.rb +24 -0
  118. data/lib/doorkeeper/validations.rb +5 -2
  119. data/lib/doorkeeper/version.rb +12 -1
  120. data/lib/doorkeeper.rb +112 -56
  121. data/lib/generators/doorkeeper/application_owner_generator.rb +28 -13
  122. data/lib/generators/doorkeeper/confidential_applications_generator.rb +33 -0
  123. data/lib/generators/doorkeeper/enable_polymorphic_resource_owner_generator.rb +39 -0
  124. data/lib/generators/doorkeeper/install_generator.rb +19 -9
  125. data/lib/generators/doorkeeper/migration_generator.rb +27 -10
  126. data/lib/generators/doorkeeper/pkce_generator.rb +33 -0
  127. data/lib/generators/doorkeeper/previous_refresh_token_generator.rb +41 -0
  128. data/lib/generators/doorkeeper/templates/add_confidential_to_applications.rb.erb +13 -0
  129. data/lib/generators/doorkeeper/templates/add_owner_to_application_migration.rb.erb +9 -0
  130. data/lib/generators/doorkeeper/templates/add_previous_refresh_token_to_access_tokens.rb.erb +13 -0
  131. data/lib/generators/doorkeeper/templates/enable_pkce_migration.rb.erb +8 -0
  132. data/lib/generators/doorkeeper/templates/enable_polymorphic_resource_owner_migration.rb.erb +17 -0
  133. data/lib/generators/doorkeeper/templates/initializer.rb +417 -32
  134. data/lib/generators/doorkeeper/templates/migration.rb.erb +88 -0
  135. data/lib/generators/doorkeeper/views_generator.rb +8 -4
  136. data/vendor/assets/stylesheets/doorkeeper/bootstrap.min.css +4 -5
  137. metadata +163 -280
  138. data/.gitignore +0 -14
  139. data/.hound.yml +0 -13
  140. data/.rspec +0 -1
  141. data/.travis.yml +0 -22
  142. data/CONTRIBUTING.md +0 -45
  143. data/Gemfile +0 -10
  144. data/NEWS.md +0 -525
  145. data/RELEASING.md +0 -17
  146. data/Rakefile +0 -20
  147. data/app/validators/redirect_uri_validator.rb +0 -34
  148. data/doorkeeper.gemspec +0 -27
  149. data/lib/doorkeeper/oauth/client/methods.rb +0 -18
  150. data/lib/doorkeeper/oauth/client_credentials/validation.rb +0 -45
  151. data/lib/doorkeeper/oauth/request_concern.rb +0 -48
  152. data/lib/generators/doorkeeper/application_scopes_generator.rb +0 -34
  153. data/lib/generators/doorkeeper/templates/add_owner_to_application_migration.rb +0 -7
  154. data/lib/generators/doorkeeper/templates/add_scopes_to_oauth_applications.rb +0 -5
  155. data/lib/generators/doorkeeper/templates/migration.rb +0 -50
  156. data/spec/controllers/applications_controller_spec.rb +0 -58
  157. data/spec/controllers/authorizations_controller_spec.rb +0 -203
  158. data/spec/controllers/protected_resources_controller_spec.rb +0 -271
  159. data/spec/controllers/token_info_controller_spec.rb +0 -52
  160. data/spec/controllers/tokens_controller_spec.rb +0 -88
  161. data/spec/dummy/Rakefile +0 -7
  162. data/spec/dummy/app/controllers/application_controller.rb +0 -3
  163. data/spec/dummy/app/controllers/custom_authorizations_controller.rb +0 -7
  164. data/spec/dummy/app/controllers/full_protected_resources_controller.rb +0 -12
  165. data/spec/dummy/app/controllers/home_controller.rb +0 -17
  166. data/spec/dummy/app/controllers/metal_controller.rb +0 -11
  167. data/spec/dummy/app/controllers/semi_protected_resources_controller.rb +0 -11
  168. data/spec/dummy/app/helpers/application_helper.rb +0 -5
  169. data/spec/dummy/app/models/user.rb +0 -9
  170. data/spec/dummy/app/views/home/index.html.erb +0 -0
  171. data/spec/dummy/app/views/layouts/application.html.erb +0 -14
  172. data/spec/dummy/config/application.rb +0 -57
  173. data/spec/dummy/config/boot.rb +0 -9
  174. data/spec/dummy/config/database.yml +0 -15
  175. data/spec/dummy/config/environment.rb +0 -5
  176. data/spec/dummy/config/environments/development.rb +0 -29
  177. data/spec/dummy/config/environments/production.rb +0 -62
  178. data/spec/dummy/config/environments/test.rb +0 -55
  179. data/spec/dummy/config/initializers/backtrace_silencers.rb +0 -7
  180. data/spec/dummy/config/initializers/doorkeeper.rb +0 -96
  181. data/spec/dummy/config/initializers/secret_token.rb +0 -9
  182. data/spec/dummy/config/initializers/session_store.rb +0 -8
  183. data/spec/dummy/config/initializers/wrap_parameters.rb +0 -14
  184. data/spec/dummy/config/locales/doorkeeper.en.yml +0 -5
  185. data/spec/dummy/config/routes.rb +0 -52
  186. data/spec/dummy/config.ru +0 -4
  187. data/spec/dummy/db/migrate/20111122132257_create_users.rb +0 -9
  188. data/spec/dummy/db/migrate/20120312140401_add_password_to_users.rb +0 -5
  189. data/spec/dummy/db/migrate/20130902165751_create_doorkeeper_tables.rb +0 -41
  190. data/spec/dummy/db/migrate/20130902175349_add_owner_to_application.rb +0 -7
  191. data/spec/dummy/db/migrate/20141209001746_add_scopes_to_oauth_applications.rb +0 -5
  192. data/spec/dummy/db/schema.rb +0 -66
  193. data/spec/dummy/public/404.html +0 -26
  194. data/spec/dummy/public/422.html +0 -26
  195. data/spec/dummy/public/500.html +0 -26
  196. data/spec/dummy/public/favicon.ico +0 -0
  197. data/spec/dummy/script/rails +0 -6
  198. data/spec/factories.rb +0 -26
  199. data/spec/generators/application_owner_generator_spec.rb +0 -22
  200. data/spec/generators/install_generator_spec.rb +0 -31
  201. data/spec/generators/migration_generator_spec.rb +0 -20
  202. data/spec/generators/templates/routes.rb +0 -3
  203. data/spec/generators/views_generator_spec.rb +0 -27
  204. data/spec/helpers/doorkeeper/dashboard_helper_spec.rb +0 -24
  205. data/spec/lib/config_spec.rb +0 -317
  206. data/spec/lib/doorkeeper_spec.rb +0 -28
  207. data/spec/lib/models/expirable_spec.rb +0 -51
  208. data/spec/lib/models/revocable_spec.rb +0 -36
  209. data/spec/lib/models/scopes_spec.rb +0 -43
  210. data/spec/lib/oauth/authorization/uri_builder_spec.rb +0 -42
  211. data/spec/lib/oauth/authorization_code_request_spec.rb +0 -80
  212. data/spec/lib/oauth/client/credentials_spec.rb +0 -47
  213. data/spec/lib/oauth/client/methods_spec.rb +0 -54
  214. data/spec/lib/oauth/client_credentials/creator_spec.rb +0 -44
  215. data/spec/lib/oauth/client_credentials/issuer_spec.rb +0 -86
  216. data/spec/lib/oauth/client_credentials/validation_spec.rb +0 -54
  217. data/spec/lib/oauth/client_credentials_integration_spec.rb +0 -27
  218. data/spec/lib/oauth/client_credentials_request_spec.rb +0 -104
  219. data/spec/lib/oauth/client_spec.rb +0 -39
  220. data/spec/lib/oauth/code_request_spec.rb +0 -45
  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 -123
  231. data/spec/lib/oauth/scopes_spec.rb +0 -123
  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 -109
  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 -350
  239. data/spec/models/doorkeeper/application_spec.rb +0 -187
  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 -94
  250. data/spec/requests/flows/refresh_token_spec.rb +0 -104
  251. data/spec/requests/flows/revoke_token_spec.rb +0 -143
  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 -56
  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 -45
  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/orm/active_record.rb +0 -3
  268. data/spec/support/shared/controllers_shared_context.rb +0 -60
  269. data/spec/support/shared/models_shared_examples.rb +0 -52
  270. 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
- before_filter :authenticate_admin!
6
- before_filter :set_application, only: [:show, :edit, :update, :destroy]
7
+ before_action :authenticate_admin!
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
- before_filter :authenticate_resource_owner!
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,82 @@ 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
+
44
+ # Active access token issued for the same client and resource owner with
45
+ # the same set of the scopes exists?
29
46
  def matching_token?
30
- AccessToken.matching_token_for pre_auth.client,
31
- current_resource_owner.id,
32
- pre_auth.scopes
47
+ Doorkeeper.config.access_token_model.matching_token_for(
48
+ pre_auth.client,
49
+ current_resource_owner,
50
+ pre_auth.scopes,
51
+ )
33
52
  end
34
53
 
35
54
  def redirect_or_render(auth)
36
55
  if auth.redirectable?
37
- redirect_to auth.redirect_uri
56
+ if Doorkeeper.configuration.api_only
57
+ if pre_auth.form_post_response?
58
+ render(
59
+ json: { status: :post, redirect_uri: pre_auth.redirect_uri, body: auth.body },
60
+ status: auth.status,
61
+ )
62
+ else
63
+ render(
64
+ json: { status: :redirect, redirect_uri: auth.redirect_uri },
65
+ status: auth.status,
66
+ )
67
+ end
68
+ elsif pre_auth.form_post_response?
69
+ render :form_post
70
+ else
71
+ redirect_to auth.redirect_uri, allow_other_host: true
72
+ end
38
73
  else
39
74
  render json: auth.body, status: auth.status
40
75
  end
41
76
  end
42
77
 
43
78
  def pre_auth
44
- @pre_auth ||= OAuth::PreAuthorization.new(Doorkeeper.configuration,
45
- server.client_via_uid,
46
- params)
79
+ @pre_auth ||= OAuth::PreAuthorization.new(
80
+ Doorkeeper.configuration,
81
+ pre_auth_params,
82
+ current_resource_owner,
83
+ )
84
+ end
85
+
86
+ def pre_auth_params
87
+ params.slice(*pre_auth_param_fields).permit(*pre_auth_param_fields)
88
+ end
89
+
90
+ def pre_auth_param_fields
91
+ %i[
92
+ client_id
93
+ code_challenge
94
+ code_challenge_method
95
+ response_type
96
+ response_mode
97
+ redirect_uri
98
+ scope
99
+ state
100
+ ]
47
101
  end
48
102
 
49
103
  def authorization
@@ -51,7 +105,35 @@ module Doorkeeper
51
105
  end
52
106
 
53
107
  def strategy
54
- @strategy ||= server.authorization_request pre_auth.response_type
108
+ @strategy ||= server.authorization_request(pre_auth.response_type)
109
+ end
110
+
111
+ def authorize_response
112
+ @authorize_response ||= begin
113
+ return pre_auth.error_response unless pre_auth.authorizable?
114
+
115
+ context = build_context(pre_auth: pre_auth)
116
+ before_successful_authorization(context)
117
+
118
+ auth = strategy.authorize
119
+
120
+ context = build_context(auth: auth)
121
+ after_successful_authorization(context)
122
+
123
+ auth
124
+ end
125
+ end
126
+
127
+ def build_context(**attributes)
128
+ Doorkeeper::OAuth::Hooks::Context.new(**attributes)
129
+ end
130
+
131
+ def before_successful_authorization(context = nil)
132
+ Doorkeeper.config.before_successful_authorization.call(self, context)
133
+ end
134
+
135
+ def after_successful_authorization(context)
136
+ Doorkeeper.config.after_successful_authorization.call(self, context)
55
137
  end
56
138
  end
57
139
  end
@@ -1,14 +1,33 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
2
4
  class AuthorizedApplicationsController < Doorkeeper::ApplicationController
3
- before_filter :authenticate_resource_owner!
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,45 +1,161 @@
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
- self.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
- # OAuth 2.0 Token Revocation - http://tools.ietf.org/html/rfc7009
15
+ # OAuth 2.0 Token Revocation - https://datatracker.ietf.org/doc/html/rfc7009
13
16
  def revoke
14
- # The authorization server first validates the client credentials
15
- if doorkeeper_token && doorkeeper_token.accessible?
16
- # Doorkeeper does not use the token_type_hint logic described in the RFC 7009
17
- # due to the refresh token implementation that is a field in the access token model.
18
- revoke_token(request.POST['token']) if request.POST['token']
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?
26
+ revoke_token
27
+ render json: {}, status: 200
28
+ else
29
+ render json: revocation_error_response, status: :forbidden
30
+ end
31
+ end
32
+
33
+ # OAuth 2.0 Token Introspection - https://datatracker.ietf.org/doc/html/rfc7662
34
+ def introspect
35
+ introspection = OAuth::TokenIntrospection.new(server, token)
36
+
37
+ if introspection.authorized?
38
+ render json: introspection.to_json, status: 200
39
+ else
40
+ error = introspection.error_response
41
+ headers.merge!(error.headers)
42
+ render json: error.body, status: error.status
19
43
  end
20
- # The authorization server responds with HTTP status code 200 if the
21
- # token has been revoked successfully or if the client submitted an invalid token
22
- render json: {}, status: 200
23
44
  end
24
45
 
25
46
  private
26
47
 
27
- def revoke_token(token)
28
- token = AccessToken.by_token(token) || AccessToken.by_refresh_token(token)
29
- if token && doorkeeper_token.same_credential?(token)
30
- token.revoke
31
- true
48
+ def validate_presence_of_client
49
+ return if Doorkeeper.config.skip_client_authentication_for_password_grant
50
+
51
+ # @see 2.1. Revocation Request
52
+ #
53
+ # The client constructs the request by including the following
54
+ # parameters using the "application/x-www-form-urlencoded" format in
55
+ # the HTTP request entity-body:
56
+ # token REQUIRED.
57
+ # token_type_hint OPTIONAL.
58
+ #
59
+ # The client also includes its authentication credentials as described
60
+ # in Section 2.3. of [RFC6749].
61
+ #
62
+ # The authorization server first validates the client credentials (in
63
+ # case of a confidential client) and then verifies whether the token
64
+ # was issued to the client making the revocation request.
65
+ return if server.client
66
+
67
+ # If this validation [client credentials / token ownership] fails, the request is
68
+ # refused and the client is informed of the error by the authorization server as
69
+ # described below.
70
+ #
71
+ # @see 2.2.1. Error Response
72
+ #
73
+ # The error presentation conforms to the definition in Section 5.2 of [RFC6749].
74
+ render json: revocation_error_response, status: :forbidden
75
+ end
76
+
77
+ # OAuth 2.0 Section 2.1 defines two client types, "public" & "confidential".
78
+ #
79
+ # RFC7009
80
+ # Section 5. Security Considerations
81
+ # A malicious client may attempt to guess valid tokens on this endpoint
82
+ # by making revocation requests against potential token strings.
83
+ # According to this specification, a client's request must contain a
84
+ # valid client_id, in the case of a public client, or valid client
85
+ # credentials, in the case of a confidential client. The token being
86
+ # revoked must also belong to the requesting client.
87
+ #
88
+ # Once a confidential client is authenticated, it must be authorized to
89
+ # revoke the provided access or refresh token. This ensures one client
90
+ # cannot revoke another's tokens.
91
+ #
92
+ # Doorkeeper determines the client type implicitly via the presence of the
93
+ # OAuth client associated with a given access or refresh token. Since public
94
+ # clients authenticate the resource owner via "password" or "implicit" grant
95
+ # types, they set the application_id as null (since the claim cannot be
96
+ # verified).
97
+ #
98
+ # https://datatracker.ietf.org/doc/html/rfc6749#section-2.1
99
+ # https://datatracker.ietf.org/doc/html/rfc7009
100
+ def authorized?
101
+ # Token belongs to specific client, so we need to check if
102
+ # authenticated client could access it.
103
+ if token.application_id? && token.application.confidential?
104
+ # We authorize client by checking token's application
105
+ server.client && server.client.application == token.application
32
106
  else
33
- false
107
+ # Token was issued without client, authorization unnecessary
108
+ true
34
109
  end
35
110
  end
36
111
 
112
+ def revoke_token
113
+ # The authorization server responds with HTTP status code 200 if the token
114
+ # has been revoked successfully or if the client submitted an invalid
115
+ # token
116
+ token.revoke if token&.accessible?
117
+ end
118
+
119
+ def token
120
+ @token ||=
121
+ if params[:token_type_hint] == "refresh_token"
122
+ Doorkeeper.config.access_token_model.by_refresh_token(params["token"])
123
+ else
124
+ Doorkeeper.config.access_token_model.by_token(params["token"]) ||
125
+ Doorkeeper.config.access_token_model.by_refresh_token(params["token"])
126
+ end
127
+ end
128
+
37
129
  def strategy
38
- @strategy ||= server.token_request params[:grant_type]
130
+ @strategy ||= server.token_request(params[:grant_type])
39
131
  end
40
132
 
41
133
  def authorize_response
42
- @authorize_response ||= strategy.authorize
134
+ @authorize_response ||= begin
135
+ before_successful_authorization
136
+ auth = strategy.authorize
137
+ context = build_context(auth: auth)
138
+ after_successful_authorization(context) unless auth.is_a?(Doorkeeper::OAuth::ErrorResponse)
139
+ auth
140
+ end
141
+ end
142
+
143
+ def build_context(**attributes)
144
+ Doorkeeper::OAuth::Hooks::Context.new(**attributes)
145
+ end
146
+
147
+ def before_successful_authorization(context = nil)
148
+ Doorkeeper.config.before_successful_authorization.call(self, context)
149
+ end
150
+
151
+ def after_successful_authorization(context)
152
+ Doorkeeper.config.after_successful_authorization.call(self, context)
153
+ end
154
+
155
+ def revocation_error_response
156
+ error_description = I18n.t(:unauthorized, scope: %i[doorkeeper errors messages revoke])
157
+
158
+ { error: :unauthorized_client, error_description: error_description }
43
159
  end
44
160
  end
45
161
  end
@@ -1,15 +1,21 @@
1
- module Doorkeeper::DashboardHelper
2
- def doorkeeper_errors_for(object, method)
3
- if object.errors[method].present?
4
- object.errors[method].map do |msg|
5
- content_tag(:span, class: 'help-block') do
1
+ # frozen_string_literal: true
2
+
3
+ module Doorkeeper
4
+ module DashboardHelper
5
+ def doorkeeper_errors_for(object, method)
6
+ return if object.errors[method].blank?
7
+
8
+ output = object.errors[method].map do |msg|
9
+ content_tag(:span, class: "invalid-feedback") do
6
10
  msg.capitalize
7
11
  end
8
- end.join.html_safe
12
+ end
13
+
14
+ safe_join(output)
9
15
  end
10
- end
11
16
 
12
- def doorkeeper_submit_path(application)
13
- application.persisted? ? oauth_application_path(application) : oauth_applications_path
17
+ def doorkeeper_submit_path(application)
18
+ application.persisted? ? oauth_application_path(application) : oauth_applications_path
19
+ end
14
20
  end
15
21
  end
@@ -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