doorkeeper 4.2.0 → 5.6.8

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 (273) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +1119 -0
  3. data/README.md +112 -349
  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 +115 -18
  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 +118 -38
  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 +4 -2
  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 +36 -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 +551 -155
  30. data/lib/doorkeeper/engine.rb +19 -6
  31. data/lib/doorkeeper/errors.rb +55 -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 +383 -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/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 -7
  47. data/lib/doorkeeper/models/concerns/polymorphic_resource_owner.rb +30 -0
  48. data/lib/doorkeeper/models/concerns/resource_ownerable.rb +47 -0
  49. data/lib/doorkeeper/models/concerns/reusable.rb +19 -0
  50. data/lib/doorkeeper/models/concerns/revocable.rb +12 -18
  51. data/lib/doorkeeper/models/concerns/scopes.rb +12 -2
  52. data/lib/doorkeeper/models/concerns/secret_storable.rb +106 -0
  53. data/lib/doorkeeper/oauth/authorization/code.rb +54 -12
  54. data/lib/doorkeeper/oauth/authorization/context.rb +17 -0
  55. data/lib/doorkeeper/oauth/authorization/token.rb +72 -28
  56. data/lib/doorkeeper/oauth/authorization/uri_builder.rb +22 -18
  57. data/lib/doorkeeper/oauth/authorization_code_request.rb +77 -17
  58. data/lib/doorkeeper/oauth/base_request.rb +67 -0
  59. data/lib/doorkeeper/oauth/base_response.rb +31 -0
  60. data/lib/doorkeeper/oauth/client/credentials.rb +23 -10
  61. data/lib/doorkeeper/oauth/client.rb +10 -12
  62. data/lib/doorkeeper/oauth/client_credentials/creator.rb +44 -4
  63. data/lib/doorkeeper/oauth/client_credentials/issuer.rb +21 -13
  64. data/lib/doorkeeper/oauth/client_credentials/validator.rb +55 -0
  65. data/lib/doorkeeper/oauth/client_credentials_request.rb +20 -16
  66. data/lib/doorkeeper/oauth/code_request.rb +9 -13
  67. data/lib/doorkeeper/oauth/code_response.rb +28 -15
  68. data/lib/doorkeeper/oauth/error.rb +5 -3
  69. data/lib/doorkeeper/oauth/error_response.rb +43 -20
  70. data/lib/doorkeeper/oauth/forbidden_token_response.rb +11 -3
  71. data/lib/doorkeeper/oauth/helpers/scope_checker.rb +23 -18
  72. data/lib/doorkeeper/oauth/helpers/unique_token.rb +20 -3
  73. data/lib/doorkeeper/oauth/helpers/uri_checker.rb +53 -3
  74. data/lib/doorkeeper/oauth/hooks/context.rb +21 -0
  75. data/lib/doorkeeper/oauth/invalid_request_response.rb +47 -0
  76. data/lib/doorkeeper/oauth/invalid_token_response.rb +31 -5
  77. data/lib/doorkeeper/oauth/nonstandard.rb +39 -0
  78. data/lib/doorkeeper/oauth/password_access_token_request.rb +46 -14
  79. data/lib/doorkeeper/oauth/pre_authorization.rb +138 -28
  80. data/lib/doorkeeper/oauth/refresh_token_request.rb +74 -41
  81. data/lib/doorkeeper/oauth/scopes.rb +26 -12
  82. data/lib/doorkeeper/oauth/token.rb +25 -23
  83. data/lib/doorkeeper/oauth/token_introspection.rb +204 -0
  84. data/lib/doorkeeper/oauth/token_request.rb +9 -22
  85. data/lib/doorkeeper/oauth/token_response.rb +13 -10
  86. data/lib/doorkeeper/oauth.rb +13 -0
  87. data/lib/doorkeeper/orm/active_record/access_grant.rb +6 -4
  88. data/lib/doorkeeper/orm/active_record/access_token.rb +5 -25
  89. data/lib/doorkeeper/orm/active_record/application.rb +6 -15
  90. data/lib/doorkeeper/orm/active_record/mixins/access_grant.rb +63 -0
  91. data/lib/doorkeeper/orm/active_record/mixins/access_token.rb +77 -0
  92. data/lib/doorkeeper/orm/active_record/mixins/application.rb +210 -0
  93. data/lib/doorkeeper/orm/active_record/redirect_uri_validator.rb +66 -0
  94. data/lib/doorkeeper/orm/active_record/stale_records_cleaner.rb +36 -0
  95. data/lib/doorkeeper/orm/active_record.rb +34 -12
  96. data/lib/doorkeeper/rails/helpers.rb +14 -15
  97. data/lib/doorkeeper/rails/routes/abstract_router.rb +35 -0
  98. data/lib/doorkeeper/rails/routes/mapper.rb +3 -1
  99. data/lib/doorkeeper/rails/routes/mapping.rb +10 -8
  100. data/lib/doorkeeper/rails/routes/registry.rb +45 -0
  101. data/lib/doorkeeper/rails/routes.rb +50 -29
  102. data/lib/doorkeeper/rake/db.rake +40 -0
  103. data/lib/doorkeeper/rake/setup.rake +6 -0
  104. data/lib/doorkeeper/rake.rb +14 -0
  105. data/lib/doorkeeper/request/authorization_code.rb +12 -4
  106. data/lib/doorkeeper/request/client_credentials.rb +3 -3
  107. data/lib/doorkeeper/request/code.rb +1 -1
  108. data/lib/doorkeeper/request/password.rb +5 -14
  109. data/lib/doorkeeper/request/refresh_token.rb +6 -5
  110. data/lib/doorkeeper/request/strategy.rb +4 -2
  111. data/lib/doorkeeper/request/token.rb +1 -1
  112. data/lib/doorkeeper/request.rb +62 -29
  113. data/lib/doorkeeper/secret_storing/base.rb +64 -0
  114. data/lib/doorkeeper/secret_storing/bcrypt.rb +60 -0
  115. data/lib/doorkeeper/secret_storing/plain.rb +33 -0
  116. data/lib/doorkeeper/secret_storing/sha256_hash.rb +26 -0
  117. data/lib/doorkeeper/server.rb +9 -19
  118. data/lib/doorkeeper/stale_records_cleaner.rb +24 -0
  119. data/lib/doorkeeper/validations.rb +5 -2
  120. data/lib/doorkeeper/version.rb +12 -1
  121. data/lib/doorkeeper.rb +180 -57
  122. data/lib/generators/doorkeeper/application_owner_generator.rb +28 -13
  123. data/lib/generators/doorkeeper/confidential_applications_generator.rb +33 -0
  124. data/lib/generators/doorkeeper/enable_polymorphic_resource_owner_generator.rb +39 -0
  125. data/lib/generators/doorkeeper/install_generator.rb +19 -9
  126. data/lib/generators/doorkeeper/migration_generator.rb +27 -10
  127. data/lib/generators/doorkeeper/pkce_generator.rb +33 -0
  128. data/lib/generators/doorkeeper/previous_refresh_token_generator.rb +31 -19
  129. data/lib/generators/doorkeeper/templates/add_confidential_to_applications.rb.erb +13 -0
  130. data/lib/generators/doorkeeper/templates/add_owner_to_application_migration.rb.erb +9 -0
  131. data/lib/generators/doorkeeper/templates/{add_previous_refresh_token_to_access_tokens.rb → add_previous_refresh_token_to_access_tokens.rb.erb} +3 -1
  132. data/lib/generators/doorkeeper/templates/enable_pkce_migration.rb.erb +8 -0
  133. data/lib/generators/doorkeeper/templates/enable_polymorphic_resource_owner_migration.rb.erb +17 -0
  134. data/lib/generators/doorkeeper/templates/initializer.rb +436 -33
  135. data/lib/generators/doorkeeper/templates/migration.rb.erb +98 -0
  136. data/lib/generators/doorkeeper/views_generator.rb +8 -4
  137. data/vendor/assets/stylesheets/doorkeeper/bootstrap.min.css +4 -5
  138. metadata +129 -281
  139. data/.gitignore +0 -14
  140. data/.hound.yml +0 -13
  141. data/.rspec +0 -1
  142. data/.travis.yml +0 -20
  143. data/CONTRIBUTING.md +0 -47
  144. data/Gemfile +0 -14
  145. data/NEWS.md +0 -593
  146. data/RELEASING.md +0 -17
  147. data/Rakefile +0 -20
  148. data/app/validators/redirect_uri_validator.rb +0 -34
  149. data/doorkeeper.gemspec +0 -28
  150. data/lib/doorkeeper/oauth/client/methods.rb +0 -18
  151. data/lib/doorkeeper/oauth/client_credentials/validation.rb +0 -45
  152. data/lib/doorkeeper/oauth/request_concern.rb +0 -48
  153. data/lib/generators/doorkeeper/templates/add_owner_to_application_migration.rb +0 -7
  154. data/lib/generators/doorkeeper/templates/migration.rb +0 -68
  155. data/spec/controllers/application_metal_controller.rb +0 -10
  156. data/spec/controllers/applications_controller_spec.rb +0 -58
  157. data/spec/controllers/authorizations_controller_spec.rb +0 -189
  158. data/spec/controllers/protected_resources_controller_spec.rb +0 -300
  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 -5
  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 -23
  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 -44
  179. data/spec/dummy/config/initializers/active_record_belongs_to_required_by_default.rb +0 -6
  180. data/spec/dummy/config/initializers/backtrace_silencers.rb +0 -7
  181. data/spec/dummy/config/initializers/doorkeeper.rb +0 -96
  182. data/spec/dummy/config/initializers/secret_token.rb +0 -9
  183. data/spec/dummy/config/initializers/session_store.rb +0 -8
  184. data/spec/dummy/config/initializers/wrap_parameters.rb +0 -14
  185. data/spec/dummy/config/locales/doorkeeper.en.yml +0 -5
  186. data/spec/dummy/config/routes.rb +0 -52
  187. data/spec/dummy/config.ru +0 -4
  188. data/spec/dummy/db/migrate/20111122132257_create_users.rb +0 -9
  189. data/spec/dummy/db/migrate/20120312140401_add_password_to_users.rb +0 -5
  190. data/spec/dummy/db/migrate/20151223192035_create_doorkeeper_tables.rb +0 -60
  191. data/spec/dummy/db/migrate/20151223200000_add_owner_to_application.rb +0 -7
  192. data/spec/dummy/db/migrate/20160320211015_add_previous_refresh_token_to_access_tokens.rb +0 -11
  193. data/spec/dummy/db/schema.rb +0 -67
  194. data/spec/dummy/public/404.html +0 -26
  195. data/spec/dummy/public/422.html +0 -26
  196. data/spec/dummy/public/500.html +0 -26
  197. data/spec/dummy/public/favicon.ico +0 -0
  198. data/spec/dummy/script/rails +0 -6
  199. data/spec/factories.rb +0 -28
  200. data/spec/generators/application_owner_generator_spec.rb +0 -22
  201. data/spec/generators/install_generator_spec.rb +0 -31
  202. data/spec/generators/migration_generator_spec.rb +0 -20
  203. data/spec/generators/templates/routes.rb +0 -3
  204. data/spec/generators/views_generator_spec.rb +0 -27
  205. data/spec/helpers/doorkeeper/dashboard_helper_spec.rb +0 -24
  206. data/spec/lib/config_spec.rb +0 -334
  207. data/spec/lib/doorkeeper_spec.rb +0 -28
  208. data/spec/lib/models/expirable_spec.rb +0 -51
  209. data/spec/lib/models/revocable_spec.rb +0 -59
  210. data/spec/lib/models/scopes_spec.rb +0 -43
  211. data/spec/lib/oauth/authorization/uri_builder_spec.rb +0 -42
  212. data/spec/lib/oauth/authorization_code_request_spec.rb +0 -80
  213. data/spec/lib/oauth/client/credentials_spec.rb +0 -47
  214. data/spec/lib/oauth/client/methods_spec.rb +0 -54
  215. data/spec/lib/oauth/client_credentials/creator_spec.rb +0 -44
  216. data/spec/lib/oauth/client_credentials/issuer_spec.rb +0 -86
  217. data/spec/lib/oauth/client_credentials/validation_spec.rb +0 -54
  218. data/spec/lib/oauth/client_credentials_integration_spec.rb +0 -27
  219. data/spec/lib/oauth/client_credentials_request_spec.rb +0 -104
  220. data/spec/lib/oauth/client_spec.rb +0 -39
  221. data/spec/lib/oauth/code_request_spec.rb +0 -45
  222. data/spec/lib/oauth/code_response_spec.rb +0 -34
  223. data/spec/lib/oauth/error_response_spec.rb +0 -61
  224. data/spec/lib/oauth/error_spec.rb +0 -23
  225. data/spec/lib/oauth/forbidden_token_response_spec.rb +0 -23
  226. data/spec/lib/oauth/helpers/scope_checker_spec.rb +0 -64
  227. data/spec/lib/oauth/helpers/unique_token_spec.rb +0 -20
  228. data/spec/lib/oauth/helpers/uri_checker_spec.rb +0 -104
  229. data/spec/lib/oauth/invalid_token_response_spec.rb +0 -28
  230. data/spec/lib/oauth/password_access_token_request_spec.rb +0 -90
  231. data/spec/lib/oauth/pre_authorization_spec.rb +0 -155
  232. data/spec/lib/oauth/refresh_token_request_spec.rb +0 -154
  233. data/spec/lib/oauth/scopes_spec.rb +0 -122
  234. data/spec/lib/oauth/token_request_spec.rb +0 -98
  235. data/spec/lib/oauth/token_response_spec.rb +0 -85
  236. data/spec/lib/oauth/token_spec.rb +0 -116
  237. data/spec/lib/request/strategy_spec.rb +0 -53
  238. data/spec/lib/server_spec.rb +0 -52
  239. data/spec/models/doorkeeper/access_grant_spec.rb +0 -36
  240. data/spec/models/doorkeeper/access_token_spec.rb +0 -394
  241. data/spec/models/doorkeeper/application_spec.rb +0 -179
  242. data/spec/requests/applications/applications_request_spec.rb +0 -94
  243. data/spec/requests/applications/authorized_applications_spec.rb +0 -30
  244. data/spec/requests/endpoints/authorization_spec.rb +0 -72
  245. data/spec/requests/endpoints/token_spec.rb +0 -64
  246. data/spec/requests/flows/authorization_code_errors_spec.rb +0 -66
  247. data/spec/requests/flows/authorization_code_spec.rb +0 -156
  248. data/spec/requests/flows/client_credentials_spec.rb +0 -58
  249. data/spec/requests/flows/implicit_grant_errors_spec.rb +0 -32
  250. data/spec/requests/flows/implicit_grant_spec.rb +0 -61
  251. data/spec/requests/flows/password_spec.rb +0 -115
  252. data/spec/requests/flows/refresh_token_spec.rb +0 -174
  253. data/spec/requests/flows/revoke_token_spec.rb +0 -157
  254. data/spec/requests/flows/skip_authorization_spec.rb +0 -59
  255. data/spec/requests/protected_resources/metal_spec.rb +0 -14
  256. data/spec/requests/protected_resources/private_api_spec.rb +0 -81
  257. data/spec/routing/custom_controller_routes_spec.rb +0 -71
  258. data/spec/routing/default_routes_spec.rb +0 -35
  259. data/spec/routing/scoped_routes_spec.rb +0 -31
  260. data/spec/spec_helper.rb +0 -2
  261. data/spec/spec_helper_integration.rb +0 -59
  262. data/spec/support/dependencies/factory_girl.rb +0 -2
  263. data/spec/support/helpers/access_token_request_helper.rb +0 -11
  264. data/spec/support/helpers/authorization_request_helper.rb +0 -41
  265. data/spec/support/helpers/config_helper.rb +0 -9
  266. data/spec/support/helpers/model_helper.rb +0 -67
  267. data/spec/support/helpers/request_spec_helper.rb +0 -76
  268. data/spec/support/helpers/url_helper.rb +0 -55
  269. data/spec/support/http_method_shim.rb +0 -24
  270. data/spec/support/orm/active_record.rb +0 -3
  271. data/spec/support/shared/controllers_shared_context.rb +0 -69
  272. data/spec/support/shared/models_shared_examples.rb +0 -52
  273. data/spec/validators/redirect_uri_validator_spec.rb +0 -78
@@ -1,23 +1,37 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
2
4
  module OAuth
3
5
  class PreAuthorization
4
6
  include Validations
5
7
 
6
- validate :response_type, error: :unsupported_response_type
7
- validate :client, error: :invalid_client
8
- validate :scopes, error: :invalid_scope
9
- validate :redirect_uri, error: :invalid_redirect_uri
8
+ validate :client_id, error: Errors::InvalidRequest
9
+ validate :client, error: Errors::InvalidClient
10
+ validate :client_supports_grant_flow, error: Errors::UnauthorizedClient
11
+ validate :resource_owner_authorize_for_client, error: Errors::InvalidClient
12
+ validate :redirect_uri, error: Errors::InvalidRedirectUri
13
+ validate :params, error: Errors::InvalidRequest
14
+ validate :response_type, error: Errors::UnsupportedResponseType
15
+ validate :response_mode, error: Errors::UnsupportedResponseMode
16
+ validate :scopes, error: Errors::InvalidScope
17
+ validate :code_challenge_method, error: Errors::InvalidCodeChallengeMethod
10
18
 
11
- attr_accessor :server, :client, :response_type, :redirect_uri, :state
12
- attr_writer :scope
19
+ attr_reader :client, :code_challenge, :code_challenge_method, :missing_param,
20
+ :redirect_uri, :resource_owner, :response_type, :state,
21
+ :authorization_response_flow, :response_mode, :custom_access_token_attributes
13
22
 
14
- def initialize(server, client, attrs = {})
15
- @server = server
16
- @client = client
17
- @response_type = attrs[:response_type]
18
- @redirect_uri = attrs[:redirect_uri]
19
- @scope = attrs[:scope]
20
- @state = attrs[:state]
23
+ def initialize(server, parameters = {}, resource_owner = nil)
24
+ @server = server
25
+ @client_id = parameters[:client_id]
26
+ @response_type = parameters[:response_type]
27
+ @response_mode = parameters[:response_mode]
28
+ @redirect_uri = parameters[:redirect_uri]
29
+ @scope = parameters[:scope]
30
+ @state = parameters[:state]
31
+ @code_challenge = parameters[:code_challenge]
32
+ @code_challenge_method = parameters[:code_challenge_method]
33
+ @resource_owner = resource_owner
34
+ @custom_access_token_attributes = parameters.slice(*Doorkeeper.config.custom_access_token_attributes)
21
35
  end
22
36
 
23
37
  def authorizable?
@@ -25,41 +39,137 @@ module Doorkeeper
25
39
  end
26
40
 
27
41
  def scopes
28
- Scopes.from_string scope
42
+ Scopes.from_string(scope)
29
43
  end
30
44
 
31
45
  def scope
32
- @scope.presence || server.default_scopes.to_s
46
+ @scope.presence || (server.default_scopes.presence && build_scopes)
33
47
  end
34
48
 
35
49
  def error_response
36
- OAuth::ErrorResponse.from_request(self)
50
+ if error == Errors::InvalidRequest
51
+ OAuth::InvalidRequestResponse.from_request(
52
+ self,
53
+ response_on_fragment: response_on_fragment?,
54
+ )
55
+ else
56
+ OAuth::ErrorResponse.from_request(self, response_on_fragment: response_on_fragment?)
57
+ end
58
+ end
59
+
60
+ def as_json(_options = nil)
61
+ pre_auth_hash
62
+ end
63
+
64
+ def form_post_response?
65
+ response_mode == "form_post"
37
66
  end
38
67
 
39
68
  private
40
69
 
41
- def validate_response_type
42
- server.authorization_response_types.include? response_type
70
+ attr_reader :client_id, :server
71
+
72
+ def build_scopes
73
+ client_scopes = client.scopes
74
+ if client_scopes.blank?
75
+ server.default_scopes.to_s
76
+ else
77
+ (server.default_scopes & client_scopes).to_s
78
+ end
79
+ end
80
+
81
+ def validate_client_id
82
+ @missing_param = :client_id if client_id.blank?
83
+ @missing_param.nil?
43
84
  end
44
85
 
45
86
  def validate_client
46
- client.present?
87
+ @client = OAuth::Client.find(client_id)
88
+ @client.present?
89
+ end
90
+
91
+ def validate_client_supports_grant_flow
92
+ Doorkeeper.config.allow_grant_flow_for_client?(grant_type, client.application)
93
+ end
94
+
95
+ def validate_resource_owner_authorize_for_client
96
+ # The `authorize_resource_owner_for_client` config option is used for this validation
97
+ client.application.authorized_for_resource_owner?(@resource_owner)
98
+ end
99
+
100
+ def validate_redirect_uri
101
+ return false if redirect_uri.blank?
102
+
103
+ Helpers::URIChecker.valid_for_authorization?(
104
+ redirect_uri,
105
+ client.redirect_uri,
106
+ )
107
+ end
108
+
109
+ def validate_params
110
+ @missing_param = if response_type.blank?
111
+ :response_type
112
+ elsif @scope.blank? && server.default_scopes.blank?
113
+ :scope
114
+ end
115
+
116
+ @missing_param.nil?
117
+ end
118
+
119
+ def validate_response_type
120
+ server.authorization_response_flows.any? do |flow|
121
+ if flow.matches_response_type?(response_type)
122
+ @authorization_response_flow = flow
123
+ true
124
+ end
125
+ end
126
+ end
127
+
128
+ def validate_response_mode
129
+ if response_mode.blank?
130
+ @response_mode = authorization_response_flow.default_response_mode
131
+ return true
132
+ end
133
+
134
+ authorization_response_flow.matches_response_mode?(response_mode)
47
135
  end
48
136
 
49
137
  def validate_scopes
50
- return true unless scope.present?
51
138
  Helpers::ScopeChecker.valid?(
52
- scope,
53
- server.scopes,
54
- client.application.scopes
139
+ scope_str: scope,
140
+ server_scopes: server.scopes,
141
+ app_scopes: client.scopes,
142
+ grant_type: grant_type,
55
143
  )
56
144
  end
57
145
 
58
- # TODO: test uri should be matched against the client's one
59
- def validate_redirect_uri
60
- return false unless redirect_uri.present?
61
- Helpers::URIChecker.native_uri?(redirect_uri) ||
62
- Helpers::URIChecker.valid_for_authorization?(redirect_uri, client.redirect_uri)
146
+ def validate_code_challenge_method
147
+ return true unless Doorkeeper.config.access_grant_model.pkce_supported?
148
+
149
+ code_challenge.blank? ||
150
+ (code_challenge_method.present? && code_challenge_method =~ /^plain$|^S256$/)
151
+ end
152
+
153
+ def response_on_fragment?
154
+ return response_type == "token" if response_mode.nil?
155
+
156
+ response_mode == "fragment"
157
+ end
158
+
159
+ def grant_type
160
+ response_type == "code" ? AUTHORIZATION_CODE : IMPLICIT
161
+ end
162
+
163
+ def pre_auth_hash
164
+ {
165
+ client_id: client.uid,
166
+ redirect_uri: redirect_uri,
167
+ state: state,
168
+ response_type: response_type,
169
+ scope: scope,
170
+ client_name: client.name,
171
+ status: I18n.t("doorkeeper.pre_authorization.status"),
172
+ }
63
173
  end
64
174
  end
65
175
  end
@@ -1,48 +1,47 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
2
4
  module OAuth
3
- class RefreshTokenRequest
4
- include Validations
5
- include OAuth::RequestConcern
5
+ class RefreshTokenRequest < BaseRequest
6
6
  include OAuth::Helpers
7
7
 
8
- validate :token_presence, error: :invalid_request
9
- validate :token, error: :invalid_grant
10
- validate :client, error: :invalid_client
11
- validate :client_match, error: :invalid_grant
12
- validate :scope, error: :invalid_scope
13
-
14
- attr_accessor :access_token, :client, :credentials, :refresh_token,
15
- :server, :refresh_token_parameter
8
+ validate :token_presence, error: Errors::InvalidRequest
9
+ validate :token, error: Errors::InvalidGrant
10
+ validate :client, error: Errors::InvalidClient
11
+ validate :client_match, error: Errors::InvalidGrant
12
+ validate :scope, error: Errors::InvalidScope
16
13
 
17
- private :refresh_token_parameter, :refresh_token_parameter=
14
+ attr_reader :access_token, :client, :credentials, :refresh_token
15
+ attr_reader :missing_param
18
16
 
19
17
  def initialize(server, refresh_token, credentials, parameters = {})
20
- @server = server
21
- @refresh_token = refresh_token
22
- @credentials = credentials
18
+ @server = server
19
+ @refresh_token = refresh_token
20
+ @credentials = credentials
23
21
  @original_scopes = parameters[:scope] || parameters[:scopes]
24
22
  @refresh_token_parameter = parameters[:refresh_token]
25
-
26
- if credentials
27
- @client = Application.by_uid_and_secret credentials.uid,
28
- credentials.secret
29
- end
23
+ @client = load_client(credentials) if credentials
30
24
  end
31
25
 
32
26
  private
33
27
 
28
+ def load_client(credentials)
29
+ Doorkeeper.config.application_model.by_uid_and_secret(credentials.uid, credentials.secret)
30
+ end
31
+
34
32
  def before_successful_response
35
33
  refresh_token.transaction do
36
34
  refresh_token.lock!
37
- raise Errors::InvalidTokenReuse if refresh_token.revoked?
35
+ raise Errors::InvalidGrantReuse if refresh_token.revoked?
38
36
 
39
37
  refresh_token.revoke unless refresh_token_revoked_on_use?
40
38
  create_access_token
41
39
  end
40
+ super
42
41
  end
43
42
 
44
43
  def refresh_token_revoked_on_use?
45
- Doorkeeper::AccessToken.refresh_token_revoked_on_use?
44
+ Doorkeeper.config.access_token_model.refresh_token_revoked_on_use?
46
45
  end
47
46
 
48
47
  def default_scopes
@@ -50,29 +49,46 @@ module Doorkeeper
50
49
  end
51
50
 
52
51
  def create_access_token
53
- @access_token = AccessToken.create!(access_token_attributes)
54
- end
52
+ attributes = {}.merge(custom_token_attributes_with_data)
55
53
 
56
- def access_token_attributes
57
- {
58
- application_id: refresh_token.application_id,
59
- resource_owner_id: refresh_token.resource_owner_id,
60
- scopes: scopes.to_s,
61
- expires_in: access_token_expires_in,
62
- use_refresh_token: true
63
- }.tap do |attributes|
64
- if refresh_token_revoked_on_use?
65
- attributes[:previous_refresh_token] = refresh_token.refresh_token
54
+ resource_owner =
55
+ if Doorkeeper.config.polymorphic_resource_owner?
56
+ refresh_token.resource_owner
57
+ else
58
+ refresh_token.resource_owner_id
66
59
  end
60
+
61
+ if refresh_token_revoked_on_use?
62
+ attributes[:previous_refresh_token] = refresh_token.refresh_token
67
63
  end
68
- end
69
64
 
70
- def access_token_expires_in
71
- Authorization::Token.access_token_expires_in(server, client)
65
+ # RFC6749
66
+ # 1.5. Refresh Token
67
+ #
68
+ # Refresh tokens are issued to the client by the authorization server and are
69
+ # used to obtain a new access token when the current access token
70
+ # becomes invalid or expires, or to obtain additional access tokens
71
+ # with identical or narrower scope (access tokens may have a shorter
72
+ # lifetime and fewer permissions than authorized by the resource
73
+ # owner).
74
+ #
75
+ # Here we assume that TTL of the token received after refreshing should be
76
+ # the same as that of the original token.
77
+ #
78
+ @access_token = Doorkeeper.config.access_token_model.create_for(
79
+ application: refresh_token.application,
80
+ resource_owner: resource_owner,
81
+ scopes: scopes,
82
+ expires_in: refresh_token.expires_in,
83
+ use_refresh_token: true,
84
+ **attributes,
85
+ )
72
86
  end
73
87
 
74
88
  def validate_token_presence
75
- refresh_token.present? || refresh_token_parameter.present?
89
+ @missing_param = :refresh_token if refresh_token.blank? && @refresh_token_parameter.blank?
90
+
91
+ @missing_param.nil?
76
92
  end
77
93
 
78
94
  def validate_token
@@ -80,20 +96,37 @@ module Doorkeeper
80
96
  end
81
97
 
82
98
  def validate_client
83
- !credentials || !!client
99
+ return true if credentials.blank?
100
+
101
+ client.present?
84
102
  end
85
103
 
104
+ # @see https://datatracker.ietf.org/doc/html/rfc6749#section-1.5
105
+ #
86
106
  def validate_client_match
87
- !client || refresh_token.application_id == client.id
107
+ return true if refresh_token.application_id.blank?
108
+
109
+ client && refresh_token.application_id == client.id
88
110
  end
89
111
 
90
112
  def validate_scope
91
113
  if @original_scopes.present?
92
- ScopeChecker.valid?(@original_scopes, refresh_token.scopes)
114
+ ScopeChecker.valid?(
115
+ scope_str: @original_scopes,
116
+ server_scopes: refresh_token.scopes,
117
+ )
93
118
  else
94
119
  true
95
120
  end
96
121
  end
122
+
123
+ def custom_token_attributes_with_data
124
+ refresh_token
125
+ .attributes
126
+ .with_indifferent_access
127
+ .slice(*Doorkeeper.config.custom_access_token_attributes)
128
+ .symbolize_keys
129
+ end
97
130
  end
98
131
  end
99
132
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
2
4
  module OAuth
3
5
  class Scopes
@@ -5,7 +7,7 @@ module Doorkeeper
5
7
  include Comparable
6
8
 
7
9
  def self.from_string(string)
8
- string ||= ''
10
+ string ||= ""
9
11
  new.tap do |scope|
10
12
  scope.add(*string.split)
11
13
  end
@@ -37,28 +39,40 @@ module Doorkeeper
37
39
  end
38
40
 
39
41
  def to_s
40
- @scopes.join(' ')
42
+ @scopes.join(" ")
41
43
  end
42
44
 
43
- def has_scopes?(scopes)
44
- scopes.all? { |s| exists?(s) }
45
+ def scopes?(scopes)
46
+ scopes.all? { |scope| exists?(scope) }
45
47
  end
46
48
 
49
+ alias has_scopes? scopes?
50
+
47
51
  def +(other)
48
- if other.is_a? Scopes
49
- self.class.from_array(all + other.all)
50
- else
51
- super(other)
52
- end
52
+ self.class.from_array(all + to_array(other))
53
53
  end
54
54
 
55
55
  def <=>(other)
56
- map(&:to_s).sort <=> other.map(&:to_s).sort
56
+ if other.respond_to?(:map)
57
+ map(&:to_s).sort <=> other.map(&:to_s).sort
58
+ else
59
+ super
60
+ end
57
61
  end
58
62
 
59
63
  def &(other)
60
- other_array = other.present? ? other.all : []
61
- self.class.from_array(all & other_array)
64
+ self.class.from_array(all & to_array(other))
65
+ end
66
+
67
+ private
68
+
69
+ def to_array(other)
70
+ case other
71
+ when Scopes
72
+ other.all
73
+ else
74
+ other.to_a
75
+ end
62
76
  end
63
77
  end
64
78
  end
@@ -1,7 +1,27 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
2
4
  module OAuth
3
5
  class Token
4
- module Methods
6
+ class << self
7
+ def from_request(request, *methods)
8
+ methods.inject(nil) do |_, method|
9
+ method = self.method(method) if method.is_a?(Symbol)
10
+ credentials = method.call(request)
11
+ break credentials if credentials.present?
12
+ end
13
+ end
14
+
15
+ def authenticate(request, *methods)
16
+ if (token = from_request(request, *methods))
17
+ access_token = Doorkeeper.config.access_token_model.by_token(token)
18
+ if access_token.present? && Doorkeeper.config.refresh_token_enabled?
19
+ access_token.revoke_previous_refresh_token!
20
+ end
21
+ access_token
22
+ end
23
+ end
24
+
5
25
  def from_access_token_param(request)
6
26
  request.parameters[:access_token]
7
27
  end
@@ -12,13 +32,13 @@ module Doorkeeper
12
32
 
13
33
  def from_bearer_authorization(request)
14
34
  pattern = /^Bearer /i
15
- header = request.authorization
35
+ header = request.authorization
16
36
  token_from_header(header, pattern) if match?(header, pattern)
17
37
  end
18
38
 
19
39
  def from_basic_authorization(request)
20
40
  pattern = /^Basic /i
21
- header = request.authorization
41
+ header = request.authorization
22
42
  token_from_basic_header(header, pattern) if match?(header, pattern)
23
43
  end
24
44
 
@@ -34,29 +54,11 @@ module Doorkeeper
34
54
  end
35
55
 
36
56
  def token_from_header(header, pattern)
37
- header.gsub pattern, ''
57
+ header.gsub(pattern, "")
38
58
  end
39
59
 
40
60
  def match?(header, pattern)
41
- header && header.match(pattern)
42
- end
43
- end
44
-
45
- extend Methods
46
-
47
- def self.from_request(request, *methods)
48
- methods.inject(nil) do |credentials, method|
49
- method = self.method(method) if method.is_a?(Symbol)
50
- credentials = method.call(request)
51
- break credentials unless credentials.blank?
52
- end
53
- end
54
-
55
- def self.authenticate(request, *methods)
56
- if token = from_request(request, *methods)
57
- access_token = AccessToken.by_token(token)
58
- access_token.revoke_previous_refresh_token! if access_token
59
- access_token
61
+ header&.match(pattern)
60
62
  end
61
63
  end
62
64
  end