doorkeeper 4.2.6 → 5.0.0.rc1

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 (205) 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/.hound.yml +2 -13
  6. data/.rubocop.yml +17 -0
  7. data/.travis.yml +19 -5
  8. data/Appraisals +8 -4
  9. data/CODE_OF_CONDUCT.md +46 -0
  10. data/Gemfile +1 -1
  11. data/NEWS.md +77 -0
  12. data/README.md +169 -34
  13. data/Rakefile +6 -0
  14. data/SECURITY.md +15 -0
  15. data/app/assets/stylesheets/doorkeeper/admin/application.css +2 -2
  16. data/app/controllers/doorkeeper/application_controller.rb +2 -5
  17. data/app/controllers/doorkeeper/application_metal_controller.rb +4 -0
  18. data/app/controllers/doorkeeper/applications_controller.rb +47 -13
  19. data/app/controllers/doorkeeper/authorizations_controller.rb +55 -12
  20. data/app/controllers/doorkeeper/authorized_applications_controller.rb +15 -1
  21. data/app/controllers/doorkeeper/tokens_controller.rb +15 -7
  22. data/app/helpers/doorkeeper/dashboard_helper.rb +8 -6
  23. data/app/validators/redirect_uri_validator.rb +13 -2
  24. data/app/views/doorkeeper/applications/_delete_form.html.erb +3 -1
  25. data/app/views/doorkeeper/applications/_form.html.erb +31 -19
  26. data/app/views/doorkeeper/applications/edit.html.erb +1 -1
  27. data/app/views/doorkeeper/applications/index.html.erb +18 -6
  28. data/app/views/doorkeeper/applications/new.html.erb +1 -1
  29. data/app/views/doorkeeper/applications/show.html.erb +8 -5
  30. data/app/views/doorkeeper/authorizations/error.html.erb +1 -1
  31. data/app/views/doorkeeper/authorizations/new.html.erb +4 -0
  32. data/app/views/doorkeeper/authorized_applications/index.html.erb +0 -1
  33. data/app/views/layouts/doorkeeper/admin.html.erb +15 -15
  34. data/config/locales/en.yml +18 -6
  35. data/doorkeeper.gemspec +6 -5
  36. data/gemfiles/rails_4_2.gemfile +6 -4
  37. data/gemfiles/rails_5_0.gemfile +4 -4
  38. data/gemfiles/rails_5_1.gemfile +6 -7
  39. data/gemfiles/rails_5_2.gemfile +12 -0
  40. data/gemfiles/rails_master.gemfile +14 -0
  41. data/lib/doorkeeper/config.rb +107 -68
  42. data/lib/doorkeeper/engine.rb +7 -3
  43. data/lib/doorkeeper/errors.rb +2 -5
  44. data/lib/doorkeeper/grape/helpers.rb +14 -9
  45. data/lib/doorkeeper/helpers/controller.rb +15 -6
  46. data/lib/doorkeeper/models/access_grant_mixin.rb +52 -23
  47. data/lib/doorkeeper/models/access_token_mixin.rb +51 -52
  48. data/lib/doorkeeper/models/application_mixin.rb +16 -30
  49. data/lib/doorkeeper/models/concerns/expirable.rb +7 -5
  50. data/lib/doorkeeper/models/concerns/orderable.rb +13 -0
  51. data/lib/doorkeeper/models/concerns/scopes.rb +1 -1
  52. data/lib/doorkeeper/oauth/authorization/code.rb +31 -8
  53. data/lib/doorkeeper/oauth/authorization/context.rb +15 -0
  54. data/lib/doorkeeper/oauth/authorization/token.rb +41 -20
  55. data/lib/doorkeeper/oauth/authorization_code_request.rb +33 -3
  56. data/lib/doorkeeper/oauth/base_request.rb +22 -7
  57. data/lib/doorkeeper/oauth/client/credentials.rb +6 -4
  58. data/lib/doorkeeper/oauth/client.rb +2 -2
  59. data/lib/doorkeeper/oauth/client_credentials/issuer.rb +6 -1
  60. data/lib/doorkeeper/oauth/client_credentials/validation.rb +4 -2
  61. data/lib/doorkeeper/oauth/error.rb +2 -2
  62. data/lib/doorkeeper/oauth/error_response.rb +11 -4
  63. data/lib/doorkeeper/oauth/forbidden_token_response.rb +1 -1
  64. data/lib/doorkeeper/oauth/helpers/scope_checker.rb +0 -8
  65. data/lib/doorkeeper/oauth/helpers/uri_checker.rb +15 -0
  66. data/lib/doorkeeper/oauth/invalid_token_response.rb +3 -4
  67. data/lib/doorkeeper/oauth/password_access_token_request.rb +8 -4
  68. data/lib/doorkeeper/oauth/pre_authorization.rb +45 -13
  69. data/lib/doorkeeper/oauth/refresh_token_request.rb +7 -1
  70. data/lib/doorkeeper/oauth/scopes.rb +19 -9
  71. data/lib/doorkeeper/oauth/token.rb +6 -3
  72. data/lib/doorkeeper/oauth/token_introspection.rb +128 -0
  73. data/lib/doorkeeper/oauth/token_response.rb +4 -2
  74. data/lib/doorkeeper/oauth.rb +13 -0
  75. data/lib/doorkeeper/orm/active_record/access_grant.rb +27 -0
  76. data/lib/doorkeeper/orm/active_record/access_token.rb +21 -20
  77. data/lib/doorkeeper/orm/active_record/application.rb +34 -0
  78. data/lib/doorkeeper/orm/active_record/stale_records_cleaner.rb +26 -0
  79. data/lib/doorkeeper/orm/active_record.rb +21 -8
  80. data/lib/doorkeeper/rails/helpers.rb +7 -10
  81. data/lib/doorkeeper/rails/routes.rb +21 -7
  82. data/lib/doorkeeper/rake/db.rake +40 -0
  83. data/lib/doorkeeper/rake/setup.rake +6 -0
  84. data/lib/doorkeeper/rake.rb +14 -0
  85. data/lib/doorkeeper/request/password.rb +1 -11
  86. data/lib/doorkeeper/request.rb +29 -23
  87. data/lib/doorkeeper/validations.rb +3 -2
  88. data/lib/doorkeeper/version.rb +14 -1
  89. data/lib/doorkeeper.rb +6 -17
  90. data/lib/generators/doorkeeper/application_owner_generator.rb +26 -12
  91. data/lib/generators/doorkeeper/confidential_applications_generator.rb +32 -0
  92. data/lib/generators/doorkeeper/install_generator.rb +17 -9
  93. data/lib/generators/doorkeeper/migration_generator.rb +26 -9
  94. data/lib/generators/doorkeeper/pkce_generator.rb +32 -0
  95. data/lib/generators/doorkeeper/previous_refresh_token_generator.rb +31 -20
  96. data/lib/generators/doorkeeper/templates/add_confidential_to_applications.rb.erb +13 -0
  97. data/lib/generators/doorkeeper/templates/{add_owner_to_application_migration.rb → add_owner_to_application_migration.rb.erb} +1 -1
  98. data/lib/generators/doorkeeper/templates/{add_previous_refresh_token_to_access_tokens.rb → add_previous_refresh_token_to_access_tokens.rb.erb} +1 -1
  99. data/lib/generators/doorkeeper/templates/enable_pkce_migration.rb.erb +6 -0
  100. data/lib/generators/doorkeeper/templates/initializer.rb +88 -10
  101. data/lib/generators/doorkeeper/templates/{migration.rb → migration.rb.erb} +2 -1
  102. data/lib/generators/doorkeeper/views_generator.rb +3 -1
  103. data/spec/controllers/application_metal_controller_spec.rb +50 -0
  104. data/spec/controllers/applications_controller_spec.rb +141 -17
  105. data/spec/controllers/authorizations_controller_spec.rb +255 -20
  106. data/spec/controllers/protected_resources_controller_spec.rb +44 -35
  107. data/spec/controllers/token_info_controller_spec.rb +17 -21
  108. data/spec/controllers/tokens_controller_spec.rb +142 -10
  109. data/spec/dummy/app/assets/config/manifest.js +2 -0
  110. data/spec/dummy/config/environments/test.rb +4 -5
  111. data/spec/dummy/config/initializers/doorkeeper.rb +18 -1
  112. data/spec/dummy/config/initializers/{active_record_belongs_to_required_by_default.rb → new_framework_defaults.rb} +5 -1
  113. data/spec/dummy/config/initializers/secret_token.rb +0 -1
  114. data/spec/dummy/config/routes.rb +3 -42
  115. data/spec/dummy/db/migrate/20111122132257_create_users.rb +3 -1
  116. data/spec/dummy/db/migrate/20120312140401_add_password_to_users.rb +3 -1
  117. data/spec/dummy/db/migrate/20151223192035_create_doorkeeper_tables.rb +3 -1
  118. data/spec/dummy/db/migrate/20151223200000_add_owner_to_application.rb +3 -1
  119. data/spec/dummy/db/migrate/20160320211015_add_previous_refresh_token_to_access_tokens.rb +3 -1
  120. data/spec/dummy/db/migrate/20170822064514_enable_pkce.rb +6 -0
  121. data/spec/dummy/db/migrate/20180210183654_add_confidential_to_applications.rb +13 -0
  122. data/spec/dummy/db/schema.rb +38 -37
  123. data/spec/factories.rb +1 -1
  124. data/spec/generators/application_owner_generator_spec.rb +25 -6
  125. data/spec/generators/confidential_applications_generator_spec.rb +45 -0
  126. data/spec/generators/install_generator_spec.rb +1 -1
  127. data/spec/generators/migration_generator_spec.rb +25 -4
  128. data/spec/generators/pkce_generator_spec.rb +43 -0
  129. data/spec/generators/previous_refresh_token_generator_spec.rb +57 -0
  130. data/spec/generators/views_generator_spec.rb +1 -1
  131. data/spec/grape/grape_integration_spec.rb +135 -0
  132. data/spec/helpers/doorkeeper/dashboard_helper_spec.rb +2 -2
  133. data/spec/lib/config_spec.rb +170 -22
  134. data/spec/lib/doorkeeper_spec.rb +1 -126
  135. data/spec/lib/models/expirable_spec.rb +0 -3
  136. data/spec/lib/models/revocable_spec.rb +2 -4
  137. data/spec/lib/models/scopes_spec.rb +0 -4
  138. data/spec/lib/oauth/authorization/uri_builder_spec.rb +0 -4
  139. data/spec/lib/oauth/authorization_code_request_spec.rb +63 -13
  140. data/spec/lib/oauth/base_request_spec.rb +19 -10
  141. data/spec/lib/oauth/base_response_spec.rb +1 -1
  142. data/spec/lib/oauth/client/credentials_spec.rb +5 -5
  143. data/spec/lib/oauth/client_credentials/creator_spec.rb +6 -2
  144. data/spec/lib/oauth/client_credentials/issuer_spec.rb +26 -7
  145. data/spec/lib/oauth/client_credentials/validation_spec.rb +2 -3
  146. data/spec/lib/oauth/client_credentials_integration_spec.rb +2 -2
  147. data/spec/lib/oauth/client_credentials_request_spec.rb +4 -5
  148. data/spec/lib/oauth/client_spec.rb +0 -3
  149. data/spec/lib/oauth/code_request_spec.rb +5 -5
  150. data/spec/lib/oauth/error_response_spec.rb +0 -3
  151. data/spec/lib/oauth/error_spec.rb +1 -3
  152. data/spec/lib/oauth/forbidden_token_response_spec.rb +1 -4
  153. data/spec/lib/oauth/helpers/scope_checker_spec.rb +0 -3
  154. data/spec/lib/oauth/helpers/unique_token_spec.rb +0 -1
  155. data/spec/lib/oauth/helpers/uri_checker_spec.rb +115 -3
  156. data/spec/lib/oauth/invalid_token_response_spec.rb +2 -5
  157. data/spec/lib/oauth/password_access_token_request_spec.rb +46 -5
  158. data/spec/lib/oauth/pre_authorization_spec.rb +40 -6
  159. data/spec/lib/oauth/refresh_token_request_spec.rb +30 -14
  160. data/spec/lib/oauth/scopes_spec.rb +28 -4
  161. data/spec/lib/oauth/token_request_spec.rb +10 -13
  162. data/spec/lib/oauth/token_response_spec.rb +0 -1
  163. data/spec/lib/oauth/token_spec.rb +37 -14
  164. data/spec/lib/orm/active_record/stale_records_cleaner_spec.rb +79 -0
  165. data/spec/lib/request/strategy_spec.rb +0 -1
  166. data/spec/lib/server_spec.rb +10 -0
  167. data/spec/models/doorkeeper/access_grant_spec.rb +2 -2
  168. data/spec/models/doorkeeper/access_token_spec.rb +118 -60
  169. data/spec/models/doorkeeper/application_spec.rb +101 -23
  170. data/spec/requests/applications/applications_request_spec.rb +94 -6
  171. data/spec/requests/applications/authorized_applications_spec.rb +1 -1
  172. data/spec/requests/endpoints/authorization_spec.rb +1 -1
  173. data/spec/requests/endpoints/token_spec.rb +15 -6
  174. data/spec/requests/flows/authorization_code_errors_spec.rb +1 -1
  175. data/spec/requests/flows/authorization_code_spec.rb +198 -1
  176. data/spec/requests/flows/client_credentials_spec.rb +73 -5
  177. data/spec/requests/flows/implicit_grant_errors_spec.rb +3 -3
  178. data/spec/requests/flows/implicit_grant_spec.rb +38 -11
  179. data/spec/requests/flows/password_spec.rb +160 -24
  180. data/spec/requests/flows/refresh_token_spec.rb +6 -6
  181. data/spec/requests/flows/revoke_token_spec.rb +26 -26
  182. data/spec/requests/flows/skip_authorization_spec.rb +16 -11
  183. data/spec/requests/protected_resources/metal_spec.rb +2 -2
  184. data/spec/requests/protected_resources/private_api_spec.rb +2 -2
  185. data/spec/routing/custom_controller_routes_spec.rb +63 -7
  186. data/spec/routing/default_routes_spec.rb +6 -2
  187. data/spec/routing/scoped_routes_spec.rb +16 -2
  188. data/spec/spec_helper.rb +54 -3
  189. data/spec/spec_helper_integration.rb +2 -63
  190. data/spec/support/dependencies/factory_bot.rb +2 -0
  191. data/spec/support/doorkeeper_rspec.rb +19 -0
  192. data/spec/support/helpers/access_token_request_helper.rb +1 -1
  193. data/spec/support/helpers/authorization_request_helper.rb +4 -4
  194. data/spec/support/helpers/model_helper.rb +9 -4
  195. data/spec/support/helpers/request_spec_helper.rb +10 -6
  196. data/spec/support/helpers/url_helper.rb +15 -10
  197. data/spec/support/http_method_shim.rb +12 -16
  198. data/spec/support/shared/controllers_shared_context.rb +2 -6
  199. data/spec/support/shared/models_shared_examples.rb +4 -4
  200. data/spec/validators/redirect_uri_validator_spec.rb +58 -7
  201. data/spec/version/version_spec.rb +15 -0
  202. data/vendor/assets/stylesheets/doorkeeper/bootstrap.min.css +4 -5
  203. metadata +73 -19
  204. data/spec/controllers/application_metal_controller.rb +0 -10
  205. data/spec/support/dependencies/factory_girl.rb +0 -2
@@ -15,19 +15,19 @@ module Doorkeeper
15
15
  end
16
16
 
17
17
  def self.configuration
18
- @config || (fail MissingConfiguration)
18
+ @config || (raise MissingConfiguration)
19
19
  end
20
20
 
21
21
  def self.setup_orm_adapter
22
22
  @orm_adapter = "doorkeeper/orm/#{configuration.orm}".classify.constantize
23
- rescue NameError => e
24
- fail e, "ORM adapter not found (#{configuration.orm})", <<-ERROR_MSG.squish
25
- [doorkeeper] ORM adapter not found (#{configuration.orm}), or there was an error
26
- trying to load it.
27
-
28
- You probably need to add the related gem for this adapter to work with
29
- doorkeeper.
30
- ERROR_MSG
23
+ rescue NameError => error
24
+ raise error, "ORM adapter not found (#{configuration.orm})", <<-ERROR_MSG.strip_heredoc
25
+ [doorkeeper] ORM adapter not found (#{configuration.orm}), or there was an error
26
+ trying to load it.
27
+
28
+ You probably need to add the related gem for this adapter to work with
29
+ doorkeeper.
30
+ ERROR_MSG
31
31
  end
32
32
 
33
33
  def self.setup_orm_models
@@ -59,12 +59,12 @@ doorkeeper.
59
59
  # @option opts[Boolean] :confirmation (false)
60
60
  # Set confirm_application_owner variable
61
61
  def enable_application_owner(opts = {})
62
- @config.instance_variable_set('@enable_application_owner', true)
62
+ @config.instance_variable_set(:@enable_application_owner, true)
63
63
  confirm_application_owner if opts[:confirmation].present? && opts[:confirmation]
64
64
  end
65
65
 
66
66
  def confirm_application_owner
67
- @config.instance_variable_set('@confirm_application_owner', true)
67
+ @config.instance_variable_set(:@confirm_application_owner, true)
68
68
  end
69
69
 
70
70
  # Define default access token scopes for your provider
@@ -72,7 +72,7 @@ doorkeeper.
72
72
  # @param scopes [Array] Default set of access (OAuth::Scopes.new)
73
73
  # token scopes
74
74
  def default_scopes(*scopes)
75
- @config.instance_variable_set('@default_scopes', OAuth::Scopes.from_array(scopes))
75
+ @config.instance_variable_set(:@default_scopes, OAuth::Scopes.from_array(scopes))
76
76
  end
77
77
 
78
78
  # Define default access token scopes for your provider
@@ -80,7 +80,7 @@ doorkeeper.
80
80
  # @param scopes [Array] Optional set of access (OAuth::Scopes.new)
81
81
  # token scopes
82
82
  def optional_scopes(*scopes)
83
- @config.instance_variable_set('@optional_scopes', OAuth::Scopes.from_array(scopes))
83
+ @config.instance_variable_set(:@optional_scopes, OAuth::Scopes.from_array(scopes))
84
84
  end
85
85
 
86
86
  # Change the way client credentials are retrieved from the request object.
@@ -90,7 +90,7 @@ doorkeeper.
90
90
  #
91
91
  # @param methods [Array] Define client credentials
92
92
  def client_credentials(*methods)
93
- @config.instance_variable_set('@client_credentials', methods)
93
+ @config.instance_variable_set(:@client_credentials_methods, methods)
94
94
  end
95
95
 
96
96
  # Change the way access token is authenticated from the request object.
@@ -100,57 +100,38 @@ doorkeeper.
100
100
  #
101
101
  # @param methods [Array] Define access token methods
102
102
  def access_token_methods(*methods)
103
- @config.instance_variable_set('@access_token_methods', methods)
103
+ @config.instance_variable_set(:@access_token_methods, methods)
104
104
  end
105
105
 
106
106
  # Issue access tokens with refresh token (disabled by default)
107
107
  def use_refresh_token
108
- @config.instance_variable_set('@refresh_token_enabled', true)
109
- end
110
-
111
- # WWW-Authenticate Realm (default "Doorkeeper").
112
- #
113
- # @param realm [String] ("Doorkeeper") Authentication realm
114
- def realm(realm)
115
- @config.instance_variable_set('@realm', realm)
108
+ @config.instance_variable_set(:@refresh_token_enabled, true)
116
109
  end
117
110
 
118
111
  # Reuse access token for the same resource owner within an application
119
112
  # (disabled by default)
120
113
  # Rationale: https://github.com/doorkeeper-gem/doorkeeper/issues/383
121
114
  def reuse_access_token
122
- @config.instance_variable_set("@reuse_access_token", true)
115
+ @config.instance_variable_set(:@reuse_access_token, true)
123
116
  end
124
117
 
125
- # Forces the usage of the HTTPS protocol in non-native redirect uris
126
- # (enabled by default in non-development environments). OAuth2
127
- # delegates security in communication to the HTTPS protocol so it is
128
- # wise to keep this enabled.
129
- #
130
- # @param [Boolean] boolean value for the parameter, true by default in
131
- # non-development environment
132
- def force_ssl_in_redirect_uri(boolean)
133
- @config.instance_variable_set("@force_ssl_in_redirect_uri", boolean)
118
+ # Use an API mode for applications generated with --api argument
119
+ # It will skip applications controller, disable forgery protection
120
+ def api_only
121
+ @config.instance_variable_set(:@api_only, true)
134
122
  end
135
123
 
136
- # Use a custom class for generating the access token.
137
- # https://github.com/doorkeeper-gem/doorkeeper#custom-access-token-generator
138
- #
139
- # @param access_token_generator [String]
140
- # the name of the access token generator class
141
- def access_token_generator(access_token_generator)
142
- @config.instance_variable_set(
143
- '@access_token_generator', access_token_generator
144
- )
124
+ # Forbids creating/updating applications with arbitrary scopes that are
125
+ # not in configuration, i.e. `default_scopes` or `optional_scopes`.
126
+ # (disabled by default)
127
+ def enforce_configured_scopes
128
+ @config.instance_variable_set(:@enforce_configured_scopes, true)
145
129
  end
146
130
 
147
- # The controller Doorkeeper::ApplicationController inherits from.
148
- # Defaults to ActionController::Base.
149
- # https://github.com/doorkeeper-gem/doorkeeper#custom-base-controller
150
- #
151
- # @param base_controller [String] the name of the base controller
152
- def base_controller(base_controller)
153
- @config.instance_variable_set('@base_controller', base_controller)
131
+ # Enforce request content type as the spec requires:
132
+ # disabled by default for backward compatibility.
133
+ def enforce_content_type
134
+ @config.instance_variable_set(:@enforce_content_type, true)
154
135
  end
155
136
  end
156
137
 
@@ -210,10 +191,6 @@ doorkeeper.
210
191
 
211
192
  public attribute
212
193
  end
213
-
214
- def extended(base)
215
- base.send(:private, :option)
216
- end
217
194
  end
218
195
 
219
196
  extend Option
@@ -221,48 +198,110 @@ doorkeeper.
221
198
  option :resource_owner_authenticator,
222
199
  as: :authenticate_resource_owner,
223
200
  default: (lambda do |_routes|
224
- logger.warn(I18n.translate('doorkeeper.errors.messages.resource_owner_authenticator_not_configured'))
201
+ ::Rails.logger.warn(
202
+ I18n.t('doorkeeper.errors.messages.resource_owner_authenticator_not_configured')
203
+ )
204
+
225
205
  nil
226
206
  end)
207
+
227
208
  option :admin_authenticator,
228
209
  as: :authenticate_admin,
229
210
  default: ->(_routes) {}
211
+
230
212
  option :resource_owner_from_credentials,
231
213
  default: (lambda do |_routes|
232
- warn(I18n.translate('doorkeeper.errors.messages.credential_flow_not_configured'))
214
+ ::Rails.logger.warn(
215
+ I18n.t('doorkeeper.errors.messages.credential_flow_not_configured')
216
+ )
217
+
233
218
  nil
234
219
  end)
235
-
220
+ option :before_successful_authorization, default: ->(_context) {}
221
+ option :after_successful_authorization, default: ->(_context) {}
222
+ option :before_successful_strategy_response, default: ->(_request) {}
223
+ option :after_successful_strategy_response,
224
+ default: ->(_request, _response) {}
236
225
  option :skip_authorization, default: ->(_routes) {}
237
226
  option :access_token_expires_in, default: 7200
238
- option :custom_access_token_expires_in, default: ->(_app) { nil }
227
+ option :custom_access_token_expires_in, default: ->(_context) { nil }
239
228
  option :authorization_code_expires_in, default: 600
240
229
  option :orm, default: :active_record
241
230
  option :native_redirect_uri, default: 'urn:ietf:wg:oauth:2.0:oob'
242
231
  option :active_record_options, default: {}
232
+ option :grant_flows, default: %w[authorization_code client_credentials]
233
+
234
+ # Allows to forbid specific Application redirect URI's by custom rules.
235
+ # Doesn't forbid any URI by default.
236
+ #
237
+ # @param forbid_redirect_uri [Proc] Block or any object respond to #call
238
+ #
239
+ option :forbid_redirect_uri, default: ->(_uri) { false }
240
+
241
+ # WWW-Authenticate Realm (default "Doorkeeper").
242
+ #
243
+ # @param realm [String] ("Doorkeeper") Authentication realm
244
+ #
243
245
  option :realm, default: 'Doorkeeper'
246
+
247
+ # Forces the usage of the HTTPS protocol in non-native redirect uris
248
+ # (enabled by default in non-development environments). OAuth2
249
+ # delegates security in communication to the HTTPS protocol so it is
250
+ # wise to keep this enabled.
251
+ #
252
+ # @param [Boolean] boolean_or_block value for the parameter, true by default in
253
+ # non-development environment
254
+ #
255
+ # @yield [uri] Conditional usage of SSL redirect uris.
256
+ # @yieldparam [URI] Redirect URI
257
+ # @yieldreturn [Boolean] Indicates necessity of usage of the HTTPS protocol
258
+ # in non-native redirect uris
259
+ #
244
260
  option :force_ssl_in_redirect_uri, default: !Rails.env.development?
245
- option :grant_flows, default: %w(authorization_code client_credentials)
261
+
262
+ # Use a custom class for generating the access token.
263
+ # https://github.com/doorkeeper-gem/doorkeeper#custom-access-token-generator
264
+ #
265
+ # @param access_token_generator [String]
266
+ # the name of the access token generator class
267
+ #
246
268
  option :access_token_generator,
247
269
  default: 'Doorkeeper::OAuth::Helpers::UniqueToken'
270
+
271
+ # The controller Doorkeeper::ApplicationController inherits from.
272
+ # Defaults to ActionController::Base.
273
+ # https://github.com/doorkeeper-gem/doorkeeper#custom-base-controller
274
+ #
275
+ # @param base_controller [String] the name of the base controller
248
276
  option :base_controller,
249
277
  default: 'ActionController::Base'
250
278
 
251
279
  attr_reader :reuse_access_token
280
+ attr_reader :api_only
281
+ attr_reader :enforce_content_type
282
+
283
+ def api_only
284
+ @api_only ||= false
285
+ end
286
+
287
+ def enforce_content_type
288
+ @enforce_content_type ||= false
289
+ end
252
290
 
253
291
  def refresh_token_enabled?
254
- @refresh_token_enabled ||= false
255
- !!@refresh_token_enabled
292
+ !!(defined?(@refresh_token_enabled) && @refresh_token_enabled)
293
+ end
294
+
295
+ def enforce_configured_scopes?
296
+ !!(defined?(@enforce_configured_scopes) && @enforce_configured_scopes)
256
297
  end
257
298
 
258
299
  def enable_application_owner?
259
- @enable_application_owner ||= false
260
- !!@enable_application_owner
300
+ !!(defined?(@enable_application_owner) && @enable_application_owner)
261
301
  end
262
302
 
263
303
  def confirm_application_owner?
264
- @confirm_application_owner ||= false
265
- !!@confirm_application_owner
304
+ !!(defined?(@confirm_application_owner) && @confirm_application_owner)
266
305
  end
267
306
 
268
307
  def default_scopes
@@ -278,19 +317,19 @@ doorkeeper.
278
317
  end
279
318
 
280
319
  def client_credentials_methods
281
- @client_credentials ||= [:from_basic, :from_params]
320
+ @client_credentials_methods ||= %i[from_basic from_params]
282
321
  end
283
322
 
284
323
  def access_token_methods
285
- @access_token_methods ||= [:from_bearer_authorization, :from_access_token_param, :from_bearer_param]
324
+ @access_token_methods ||= %i[from_bearer_authorization from_access_token_param from_bearer_param]
286
325
  end
287
326
 
288
327
  def authorization_response_types
289
- @authorization_response_types ||= calculate_authorization_response_types
328
+ @authorization_response_types ||= calculate_authorization_response_types.freeze
290
329
  end
291
330
 
292
331
  def token_grant_types
293
- @token_grant_types ||= calculate_token_grant_types
332
+ @token_grant_types ||= calculate_token_grant_types.freeze
294
333
  end
295
334
 
296
335
  private
@@ -1,7 +1,7 @@
1
1
  module Doorkeeper
2
2
  class Engine < Rails::Engine
3
3
  initializer "doorkeeper.params.filter" do |app|
4
- parameters = %w(client_secret code authentication_token access_token refresh_token)
4
+ parameters = %w[client_secret code authentication_token access_token refresh_token]
5
5
  app.config.filter_parameters << /^(#{Regexp.union parameters})$/
6
6
  end
7
7
 
@@ -17,10 +17,14 @@ module Doorkeeper
17
17
 
18
18
  if defined?(Sprockets) && Sprockets::VERSION.chr.to_i >= 4
19
19
  initializer 'doorkeeper.assets.precompile' do |app|
20
- app.config.assets.precompile += %w(
20
+ # Force users to use:
21
+ # //= link doorkeeper/admin/application.css
22
+ # in Doorkeeper 5 for Sprockets 4 instead of precompile.
23
+ # Add note to official docs & Wiki
24
+ app.config.assets.precompile += %w[
21
25
  doorkeeper/application.css
22
26
  doorkeeper/admin/application.css
23
- )
27
+ ]
24
28
  end
25
29
  end
26
30
  end
@@ -36,10 +36,7 @@ module Doorkeeper
36
36
  end
37
37
  end
38
38
 
39
- class UnableToGenerateToken < DoorkeeperError
40
- end
41
-
42
- class TokenGeneratorNotFound < DoorkeeperError
43
- end
39
+ UnableToGenerateToken = Class.new(DoorkeeperError)
40
+ TokenGeneratorNotFound = Class.new(DoorkeeperError)
44
41
  end
45
42
  end
@@ -9,7 +9,7 @@ module Doorkeeper
9
9
 
10
10
  # endpoint specific scopes > parameter scopes > default scopes
11
11
  def doorkeeper_authorize!(*scopes)
12
- endpoint_scopes = env["api.endpoint"].route_setting(:scopes)
12
+ endpoint_scopes = endpoint.route_setting(:scopes) || endpoint.options[:route_options][:scopes]
13
13
  scopes = if endpoint_scopes
14
14
  Doorkeeper::OAuth::Scopes.from_array(endpoint_scopes)
15
15
  elsif scopes && !scopes.empty?
@@ -20,20 +20,18 @@ module Doorkeeper
20
20
  end
21
21
 
22
22
  def doorkeeper_render_error_with(error)
23
- status_code = case error.status
24
- when :unauthorized
25
- 401
26
- when :forbidden
27
- 403
28
- end
29
-
23
+ status_code = error_status_codes[error.status]
30
24
  error!({ error: error.description }, status_code, error.headers)
31
25
  end
32
26
 
33
27
  private
34
28
 
29
+ def endpoint
30
+ env['api.endpoint']
31
+ end
32
+
35
33
  def doorkeeper_token
36
- @_doorkeeper_token ||= OAuth::Token.authenticate(
34
+ @doorkeeper_token ||= OAuth::Token.authenticate(
37
35
  decorated_request,
38
36
  *Doorkeeper.configuration.access_token_methods
39
37
  )
@@ -42,6 +40,13 @@ module Doorkeeper
42
40
  def decorated_request
43
41
  AuthorizationDecorator.new(request)
44
42
  end
43
+
44
+ def error_status_codes
45
+ {
46
+ unauthorized: 401,
47
+ forbidden: 403
48
+ }
49
+ end
45
50
  end
46
51
  end
47
52
  end
@@ -5,11 +5,13 @@ module Doorkeeper
5
5
  module Controller
6
6
  private
7
7
 
8
- def authenticate_resource_owner! # :doc:
8
+ # :doc:
9
+ def authenticate_resource_owner!
9
10
  current_resource_owner
10
11
  end
11
12
 
12
- def current_resource_owner # :doc:
13
+ # :doc:
14
+ def current_resource_owner
13
15
  instance_eval(&Doorkeeper.configuration.authenticate_resource_owner)
14
16
  end
15
17
 
@@ -17,7 +19,8 @@ module Doorkeeper
17
19
  instance_eval(&Doorkeeper.configuration.resource_owner_from_credentials)
18
20
  end
19
21
 
20
- def authenticate_admin! # :doc:
22
+ # :doc:
23
+ def authenticate_admin!
21
24
  instance_eval(&Doorkeeper.configuration.authenticate_admin)
22
25
  end
23
26
 
@@ -25,12 +28,13 @@ module Doorkeeper
25
28
  @server ||= Server.new(self)
26
29
  end
27
30
 
28
- def doorkeeper_token # :doc:
29
- @token ||= OAuth::Token.authenticate request, *config_methods
31
+ # :doc:
32
+ def doorkeeper_token
33
+ @doorkeeper_token ||= OAuth::Token.authenticate request, *config_methods
30
34
  end
31
35
 
32
36
  def config_methods
33
- @methods ||= Doorkeeper.configuration.access_token_methods
37
+ @config_methods ||= Doorkeeper.configuration.access_token_methods
34
38
  end
35
39
 
36
40
  def get_error_response_from_exception(exception)
@@ -47,6 +51,11 @@ module Doorkeeper
47
51
  def skip_authorization?
48
52
  !!instance_exec([@server.current_resource_owner, @pre_auth.client], &Doorkeeper.configuration.skip_authorization)
49
53
  end
54
+
55
+ def enforce_content_type
56
+ return if request.content_type == 'application/x-www-form-urlencoded'
57
+ render json: {}, status: :unsupported_media_type
58
+ end
50
59
  end
51
60
  end
52
61
  end
@@ -6,24 +6,16 @@ module Doorkeeper
6
6
  include Models::Expirable
7
7
  include Models::Revocable
8
8
  include Models::Accessible
9
+ include Models::Orderable
9
10
  include Models::Scopes
10
- include ActiveModel::MassAssignmentSecurity if defined?(::ProtectedAttributes)
11
11
 
12
- included do
13
- belongs_to_options = {
14
- class_name: 'Doorkeeper::Application',
15
- inverse_of: :access_grants
16
- }
17
- if defined?(ActiveRecord::Base) && ActiveRecord::VERSION::MAJOR >= 5
18
- belongs_to_options[:optional] = true
19
- end
20
-
21
- belongs_to :application, belongs_to_options
22
-
23
- validates :resource_owner_id, :application_id, :token, :expires_in, :redirect_uri, presence: true
24
- validates :token, uniqueness: true
12
+ # never uses pkce, if pkce migrations were not generated
13
+ def uses_pkce?
14
+ pkce_supported? && code_challenge.present?
15
+ end
25
16
 
26
- before_validation :generate_token, on: :create
17
+ def pkce_supported?
18
+ respond_to? :code_challenge
27
19
  end
28
20
 
29
21
  module ClassMethods
@@ -38,16 +30,53 @@ module Doorkeeper
38
30
  def by_token(token)
39
31
  find_by(token: token.to_s)
40
32
  end
41
- end
42
33
 
43
- private
34
+ # Implements PKCE code_challenge encoding without base64 padding as described in the spec.
35
+ # https://tools.ietf.org/html/rfc7636#appendix-A
36
+ # Appendix A. Notes on Implementing Base64url Encoding without Padding
37
+ #
38
+ # This appendix describes how to implement a base64url-encoding
39
+ # function without padding, based upon the standard base64-encoding
40
+ # function that uses padding.
41
+ #
42
+ # To be concrete, example C# code implementing these functions is shown
43
+ # below. Similar code could be used in other languages.
44
+ #
45
+ # static string base64urlencode(byte [] arg)
46
+ # {
47
+ # string s = Convert.ToBase64String(arg); // Regular base64 encoder
48
+ # s = s.Split('=')[0]; // Remove any trailing '='s
49
+ # s = s.Replace('+', '-'); // 62nd char of encoding
50
+ # s = s.Replace('/', '_'); // 63rd char of encoding
51
+ # return s;
52
+ # }
53
+ #
54
+ # An example correspondence between unencoded and encoded values
55
+ # follows. The octet sequence below encodes into the string below,
56
+ # which when decoded, reproduces the octet sequence.
57
+ #
58
+ # 3 236 255 224 193
59
+ #
60
+ # A-z_4ME
61
+ #
62
+ # https://ruby-doc.org/stdlib-2.1.3/libdoc/base64/rdoc/Base64.html#method-i-urlsafe_encode64
63
+ #
64
+ # urlsafe_encode64(bin)
65
+ # Returns the Base64-encoded version of bin. This method complies with
66
+ # “Base 64 Encoding with URL and Filename Safe Alphabet” in RFC 4648.
67
+ # The alphabet uses '-' instead of '+' and '_' instead of '/'.
44
68
 
45
- # Generates token value with UniqueToken class.
46
- #
47
- # @return [String] token value
48
- #
49
- def generate_token
50
- self.token = UniqueToken.generate
69
+ # @param code_verifier [#to_s] a one time use value (any object that responds to `#to_s`)
70
+ #
71
+ # @return [#to_s] An encoded code challenge based on the provided verifier suitable for PKCE validation
72
+ def generate_code_challenge(code_verifier)
73
+ padded_result = Base64.urlsafe_encode64(Digest::SHA256.digest(code_verifier))
74
+ padded_result.split('=')[0] # Remove any trailing '='
75
+ end
76
+
77
+ def pkce_supported?
78
+ new.pkce_supported?
79
+ end
51
80
  end
52
81
  end
53
82
  end