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,23 +1,36 @@
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
8
+ validate :client_id, error: :invalid_request
7
9
  validate :client, error: :invalid_client
8
- validate :scopes, error: :invalid_scope
10
+ validate :client_supports_grant_flow, error: :unauthorized_client
11
+ validate :resource_owner_authorize_for_client, error: :invalid_client
9
12
  validate :redirect_uri, error: :invalid_redirect_uri
13
+ validate :params, error: :invalid_request
14
+ validate :response_type, error: :unsupported_response_type
15
+ validate :response_mode, error: :unsupported_response_mode
16
+ validate :scopes, error: :invalid_scope
17
+ validate :code_challenge_method, error: :invalid_code_challenge_method
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
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
21
34
  end
22
35
 
23
36
  def authorizable?
@@ -25,41 +38,137 @@ module Doorkeeper
25
38
  end
26
39
 
27
40
  def scopes
28
- Scopes.from_string scope
41
+ Scopes.from_string(scope)
29
42
  end
30
43
 
31
44
  def scope
32
- @scope.presence || server.default_scopes.to_s
45
+ @scope.presence || (server.default_scopes.presence && build_scopes)
33
46
  end
34
47
 
35
48
  def error_response
36
- OAuth::ErrorResponse.from_request(self)
49
+ if error == :invalid_request
50
+ OAuth::InvalidRequestResponse.from_request(
51
+ self,
52
+ response_on_fragment: response_on_fragment?,
53
+ )
54
+ else
55
+ OAuth::ErrorResponse.from_request(self, response_on_fragment: response_on_fragment?)
56
+ end
57
+ end
58
+
59
+ def as_json(_options = nil)
60
+ pre_auth_hash
61
+ end
62
+
63
+ def form_post_response?
64
+ response_mode == "form_post"
37
65
  end
38
66
 
39
67
  private
40
68
 
41
- def validate_response_type
42
- server.authorization_response_types.include? response_type
69
+ attr_reader :client_id, :server
70
+
71
+ def build_scopes
72
+ client_scopes = client.scopes
73
+ if client_scopes.blank?
74
+ server.default_scopes.to_s
75
+ else
76
+ (server.default_scopes & client_scopes).to_s
77
+ end
78
+ end
79
+
80
+ def validate_client_id
81
+ @missing_param = :client_id if client_id.blank?
82
+ @missing_param.nil?
43
83
  end
44
84
 
45
85
  def validate_client
46
- client.present?
86
+ @client = OAuth::Client.find(client_id)
87
+ @client.present?
88
+ end
89
+
90
+ def validate_client_supports_grant_flow
91
+ Doorkeeper.config.allow_grant_flow_for_client?(grant_type, client.application)
92
+ end
93
+
94
+ def validate_resource_owner_authorize_for_client
95
+ # The `authorize_resource_owner_for_client` config option is used for this validation
96
+ client.application.authorized_for_resource_owner?(@resource_owner)
97
+ end
98
+
99
+ def validate_redirect_uri
100
+ return false if redirect_uri.blank?
101
+
102
+ Helpers::URIChecker.valid_for_authorization?(
103
+ redirect_uri,
104
+ client.redirect_uri,
105
+ )
106
+ end
107
+
108
+ def validate_params
109
+ @missing_param = if response_type.blank?
110
+ :response_type
111
+ elsif @scope.blank? && server.default_scopes.blank?
112
+ :scope
113
+ end
114
+
115
+ @missing_param.nil?
116
+ end
117
+
118
+ def validate_response_type
119
+ server.authorization_response_flows.any? do |flow|
120
+ if flow.matches_response_type?(response_type)
121
+ @authorization_response_flow = flow
122
+ true
123
+ end
124
+ end
125
+ end
126
+
127
+ def validate_response_mode
128
+ if response_mode.blank?
129
+ @response_mode = authorization_response_flow.default_response_mode
130
+ return true
131
+ end
132
+
133
+ authorization_response_flow.matches_response_mode?(response_mode)
47
134
  end
48
135
 
49
136
  def validate_scopes
50
- return true unless scope.present?
51
137
  Helpers::ScopeChecker.valid?(
52
- scope,
53
- server.scopes,
54
- client.application.scopes
138
+ scope_str: scope,
139
+ server_scopes: server.scopes,
140
+ app_scopes: client.scopes,
141
+ grant_type: grant_type,
55
142
  )
56
143
  end
57
144
 
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)
145
+ def validate_code_challenge_method
146
+ return true unless Doorkeeper.config.access_grant_model.pkce_supported?
147
+
148
+ code_challenge.blank? ||
149
+ (code_challenge_method.present? && code_challenge_method =~ /^plain$|^S256$/)
150
+ end
151
+
152
+ def response_on_fragment?
153
+ return response_type == "token" if response_mode.nil?
154
+
155
+ response_mode == "fragment"
156
+ end
157
+
158
+ def grant_type
159
+ response_type == "code" ? AUTHORIZATION_CODE : IMPLICIT
160
+ end
161
+
162
+ def pre_auth_hash
163
+ {
164
+ client_id: client.uid,
165
+ redirect_uri: redirect_uri,
166
+ state: state,
167
+ response_type: response_type,
168
+ scope: scope,
169
+ client_name: client.name,
170
+ status: I18n.t("doorkeeper.pre_authorization.status"),
171
+ }
63
172
  end
64
173
  end
65
174
  end
@@ -1,8 +1,8 @@
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
8
  validate :token_presence, error: :invalid_request
@@ -11,34 +11,37 @@ module Doorkeeper
11
11
  validate :client_match, error: :invalid_grant
12
12
  validate :scope, error: :invalid_scope
13
13
 
14
- attr_accessor :access_token, :client, :credentials, :refresh_token,
15
- :server
14
+ attr_reader :access_token, :client, :credentials, :refresh_token
15
+ attr_reader :missing_param
16
16
 
17
17
  def initialize(server, refresh_token, credentials, parameters = {})
18
- @server = server
19
- @refresh_token = refresh_token
20
- @credentials = credentials
18
+ @server = server
19
+ @refresh_token = refresh_token
20
+ @credentials = credentials
21
21
  @original_scopes = parameters[:scope] || parameters[:scopes]
22
22
  @refresh_token_parameter = parameters[:refresh_token]
23
-
24
- if credentials
25
- @client = Application.by_uid_and_secret credentials.uid,
26
- credentials.secret
27
- end
23
+ @client = load_client(credentials) if credentials
28
24
  end
29
25
 
30
26
  private
31
27
 
32
- attr_reader :refresh_token_parameter
28
+ def load_client(credentials)
29
+ server_config.application_model.by_uid_and_secret(credentials.uid, credentials.secret)
30
+ end
33
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
- refresh_token.revoke
37
+ refresh_token.revoke unless refresh_token_revoked_on_use?
40
38
  create_access_token
41
39
  end
40
+ super
41
+ end
42
+
43
+ def refresh_token_revoked_on_use?
44
+ server_config.access_token_model.refresh_token_revoked_on_use?
42
45
  end
43
46
 
44
47
  def default_scopes
@@ -46,21 +49,46 @@ module Doorkeeper
46
49
  end
47
50
 
48
51
  def create_access_token
49
- expires_in = Authorization::Token.access_token_expires_in(
50
- server,
51
- client
52
- )
52
+ attributes = {}
53
53
 
54
- @access_token = AccessToken.create!(
55
- application_id: refresh_token.application_id,
56
- resource_owner_id: refresh_token.resource_owner_id,
57
- scopes: scopes.to_s,
58
- expires_in: expires_in,
59
- use_refresh_token: true)
54
+ resource_owner =
55
+ if Doorkeeper.config.polymorphic_resource_owner?
56
+ refresh_token.resource_owner
57
+ else
58
+ refresh_token.resource_owner_id
59
+ end
60
+
61
+ if refresh_token_revoked_on_use?
62
+ attributes[:previous_refresh_token] = refresh_token.refresh_token
63
+ end
64
+
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 = server_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
+ )
60
86
  end
61
87
 
62
88
  def validate_token_presence
63
- 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?
64
92
  end
65
93
 
66
94
  def validate_token
@@ -68,16 +96,25 @@ module Doorkeeper
68
96
  end
69
97
 
70
98
  def validate_client
71
- !credentials || !!client
99
+ return true if credentials.blank?
100
+
101
+ client.present?
72
102
  end
73
103
 
104
+ # @see https://datatracker.ietf.org/doc/html/rfc6749#section-1.5
105
+ #
74
106
  def validate_client_match
75
- !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
76
110
  end
77
111
 
78
112
  def validate_scope
79
113
  if @original_scopes.present?
80
- ScopeChecker.valid?(@original_scopes, refresh_token.scopes)
114
+ ScopeChecker.valid?(
115
+ scope_str: @original_scopes,
116
+ server_scopes: refresh_token.scopes,
117
+ )
81
118
  else
82
119
  true
83
120
  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(self.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
- self.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
 
@@ -26,36 +46,19 @@ module Doorkeeper
26
46
 
27
47
  def token_from_basic_header(header, pattern)
28
48
  encoded_header = token_from_header(header, pattern)
29
- token, _ = decode_basic_credentials(encoded_header)
30
- token
49
+ decode_basic_credentials_token(encoded_header)
31
50
  end
32
51
 
33
- def decode_basic_credentials(encoded_header)
34
- Base64.decode64(encoded_header).split(/:/, 2)
52
+ def decode_basic_credentials_token(encoded_header)
53
+ Base64.decode64(encoded_header).split(/:/, 2).first
35
54
  end
36
55
 
37
56
  def token_from_header(header, pattern)
38
- header.gsub pattern, ''
57
+ header.gsub(pattern, "")
39
58
  end
40
59
 
41
60
  def match?(header, pattern)
42
- header && header.match(pattern)
43
- end
44
- end
45
-
46
- extend Methods
47
-
48
- def self.from_request(request, *methods)
49
- methods.inject(nil) do |credentials, method|
50
- method = self.method(method) if method.is_a?(Symbol)
51
- credentials = method.call(request)
52
- break credentials unless credentials.blank?
53
- end
54
- end
55
-
56
- def self.authenticate(request, *methods)
57
- if token = from_request(request, *methods)
58
- AccessToken.by_token(token)
61
+ header&.match(pattern)
59
62
  end
60
63
  end
61
64
  end