doorkeeper 4.2.0 → 5.5.2

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of doorkeeper might be problematic. Click here for more details.

Files changed (271) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +1038 -0
  3. data/README.md +110 -348
  4. data/app/assets/stylesheets/doorkeeper/admin/application.css +2 -2
  5. data/app/controllers/doorkeeper/application_controller.rb +6 -7
  6. data/app/controllers/doorkeeper/application_metal_controller.rb +7 -11
  7. data/app/controllers/doorkeeper/applications_controller.rb +65 -20
  8. data/app/controllers/doorkeeper/authorizations_controller.rb +97 -17
  9. data/app/controllers/doorkeeper/authorized_applications_controller.rb +22 -3
  10. data/app/controllers/doorkeeper/token_info_controller.rb +16 -4
  11. data/app/controllers/doorkeeper/tokens_controller.rb +112 -35
  12. data/app/helpers/doorkeeper/dashboard_helper.rb +10 -6
  13. data/app/views/doorkeeper/applications/_delete_form.html.erb +4 -3
  14. data/app/views/doorkeeper/applications/_form.html.erb +33 -21
  15. data/app/views/doorkeeper/applications/edit.html.erb +1 -1
  16. data/app/views/doorkeeper/applications/index.html.erb +18 -6
  17. data/app/views/doorkeeper/applications/new.html.erb +1 -1
  18. data/app/views/doorkeeper/applications/show.html.erb +40 -16
  19. data/app/views/doorkeeper/authorizations/error.html.erb +1 -1
  20. data/app/views/doorkeeper/authorizations/form_post.html.erb +15 -0
  21. data/app/views/doorkeeper/authorizations/new.html.erb +7 -1
  22. data/app/views/doorkeeper/authorized_applications/_delete_form.html.erb +1 -2
  23. data/app/views/doorkeeper/authorized_applications/index.html.erb +0 -1
  24. data/app/views/layouts/doorkeeper/admin.html.erb +16 -14
  25. data/config/locales/en.yml +33 -9
  26. data/lib/doorkeeper/config/abstract_builder.rb +28 -0
  27. data/lib/doorkeeper/config/option.rb +82 -0
  28. data/lib/doorkeeper/config/validations.rb +53 -0
  29. data/lib/doorkeeper/config.rb +545 -143
  30. data/lib/doorkeeper/engine.rb +11 -5
  31. data/lib/doorkeeper/errors.rb +37 -10
  32. data/lib/doorkeeper/grant_flow/fallback_flow.rb +15 -0
  33. data/lib/doorkeeper/grant_flow/flow.rb +44 -0
  34. data/lib/doorkeeper/grant_flow/registry.rb +50 -0
  35. data/lib/doorkeeper/grant_flow.rb +45 -0
  36. data/lib/doorkeeper/grape/authorization_decorator.rb +6 -4
  37. data/lib/doorkeeper/grape/helpers.rb +24 -12
  38. data/lib/doorkeeper/helpers/controller.rb +49 -27
  39. data/lib/doorkeeper/models/access_grant_mixin.rb +100 -21
  40. data/lib/doorkeeper/models/access_token_mixin.rb +379 -75
  41. data/lib/doorkeeper/models/application_mixin.rb +72 -25
  42. data/lib/doorkeeper/models/concerns/accessible.rb +6 -0
  43. data/lib/doorkeeper/models/concerns/expirable.rb +20 -6
  44. data/lib/doorkeeper/models/concerns/orderable.rb +15 -0
  45. data/lib/doorkeeper/models/concerns/ownership.rb +4 -7
  46. data/lib/doorkeeper/models/concerns/resource_ownerable.rb +47 -0
  47. data/lib/doorkeeper/models/concerns/reusable.rb +19 -0
  48. data/lib/doorkeeper/models/concerns/revocable.rb +12 -18
  49. data/lib/doorkeeper/models/concerns/scopes.rb +12 -2
  50. data/lib/doorkeeper/models/concerns/secret_storable.rb +106 -0
  51. data/lib/doorkeeper/oauth/authorization/code.rb +48 -12
  52. data/lib/doorkeeper/oauth/authorization/context.rb +17 -0
  53. data/lib/doorkeeper/oauth/authorization/token.rb +66 -28
  54. data/lib/doorkeeper/oauth/authorization/uri_builder.rb +22 -18
  55. data/lib/doorkeeper/oauth/authorization_code_request.rb +64 -14
  56. data/lib/doorkeeper/oauth/base_request.rb +66 -0
  57. data/lib/doorkeeper/oauth/base_response.rb +31 -0
  58. data/lib/doorkeeper/oauth/client/credentials.rb +23 -10
  59. data/lib/doorkeeper/oauth/client.rb +10 -12
  60. data/lib/doorkeeper/oauth/client_credentials/creator.rb +47 -4
  61. data/lib/doorkeeper/oauth/client_credentials/issuer.rb +16 -9
  62. data/lib/doorkeeper/oauth/client_credentials/validator.rb +56 -0
  63. data/lib/doorkeeper/oauth/client_credentials_request.rb +11 -15
  64. data/lib/doorkeeper/oauth/code_request.rb +8 -12
  65. data/lib/doorkeeper/oauth/code_response.rb +28 -15
  66. data/lib/doorkeeper/oauth/error.rb +5 -3
  67. data/lib/doorkeeper/oauth/error_response.rb +41 -20
  68. data/lib/doorkeeper/oauth/forbidden_token_response.rb +10 -3
  69. data/lib/doorkeeper/oauth/helpers/scope_checker.rb +23 -18
  70. data/lib/doorkeeper/oauth/helpers/unique_token.rb +20 -3
  71. data/lib/doorkeeper/oauth/helpers/uri_checker.rb +53 -3
  72. data/lib/doorkeeper/oauth/hooks/context.rb +21 -0
  73. data/lib/doorkeeper/oauth/invalid_request_response.rb +43 -0
  74. data/lib/doorkeeper/oauth/invalid_token_response.rb +31 -5
  75. data/lib/doorkeeper/oauth/nonstandard.rb +39 -0
  76. data/lib/doorkeeper/oauth/password_access_token_request.rb +45 -13
  77. data/lib/doorkeeper/oauth/pre_authorization.rb +135 -26
  78. data/lib/doorkeeper/oauth/refresh_token_request.rb +61 -36
  79. data/lib/doorkeeper/oauth/scopes.rb +26 -12
  80. data/lib/doorkeeper/oauth/token.rb +25 -23
  81. data/lib/doorkeeper/oauth/token_introspection.rb +202 -0
  82. data/lib/doorkeeper/oauth/token_request.rb +8 -21
  83. data/lib/doorkeeper/oauth/token_response.rb +14 -10
  84. data/lib/doorkeeper/oauth.rb +13 -0
  85. data/lib/doorkeeper/orm/active_record/access_grant.rb +6 -4
  86. data/lib/doorkeeper/orm/active_record/access_token.rb +5 -25
  87. data/lib/doorkeeper/orm/active_record/application.rb +6 -15
  88. data/lib/doorkeeper/orm/active_record/mixins/access_grant.rb +68 -0
  89. data/lib/doorkeeper/orm/active_record/mixins/access_token.rb +59 -0
  90. data/lib/doorkeeper/orm/active_record/mixins/application.rb +198 -0
  91. data/lib/doorkeeper/orm/active_record/redirect_uri_validator.rb +66 -0
  92. data/lib/doorkeeper/orm/active_record/stale_records_cleaner.rb +33 -0
  93. data/lib/doorkeeper/orm/active_record.rb +37 -8
  94. data/lib/doorkeeper/rails/helpers.rb +14 -15
  95. data/lib/doorkeeper/rails/routes/abstract_router.rb +35 -0
  96. data/lib/doorkeeper/rails/routes/mapper.rb +3 -1
  97. data/lib/doorkeeper/rails/routes/mapping.rb +10 -8
  98. data/lib/doorkeeper/rails/routes/registry.rb +45 -0
  99. data/lib/doorkeeper/rails/routes.rb +42 -30
  100. data/lib/doorkeeper/rake/db.rake +40 -0
  101. data/lib/doorkeeper/rake/setup.rake +11 -0
  102. data/lib/doorkeeper/rake.rb +14 -0
  103. data/lib/doorkeeper/request/authorization_code.rb +12 -4
  104. data/lib/doorkeeper/request/client_credentials.rb +3 -3
  105. data/lib/doorkeeper/request/code.rb +1 -1
  106. data/lib/doorkeeper/request/password.rb +5 -14
  107. data/lib/doorkeeper/request/refresh_token.rb +6 -5
  108. data/lib/doorkeeper/request/strategy.rb +4 -2
  109. data/lib/doorkeeper/request/token.rb +1 -1
  110. data/lib/doorkeeper/request.rb +62 -29
  111. data/lib/doorkeeper/secret_storing/base.rb +64 -0
  112. data/lib/doorkeeper/secret_storing/bcrypt.rb +60 -0
  113. data/lib/doorkeeper/secret_storing/plain.rb +33 -0
  114. data/lib/doorkeeper/secret_storing/sha256_hash.rb +26 -0
  115. data/lib/doorkeeper/server.rb +9 -19
  116. data/lib/doorkeeper/stale_records_cleaner.rb +24 -0
  117. data/lib/doorkeeper/validations.rb +5 -2
  118. data/lib/doorkeeper/version.rb +12 -1
  119. data/lib/doorkeeper.rb +111 -56
  120. data/lib/generators/doorkeeper/application_owner_generator.rb +28 -13
  121. data/lib/generators/doorkeeper/confidential_applications_generator.rb +33 -0
  122. data/lib/generators/doorkeeper/enable_polymorphic_resource_owner_generator.rb +39 -0
  123. data/lib/generators/doorkeeper/install_generator.rb +19 -9
  124. data/lib/generators/doorkeeper/migration_generator.rb +27 -10
  125. data/lib/generators/doorkeeper/pkce_generator.rb +33 -0
  126. data/lib/generators/doorkeeper/previous_refresh_token_generator.rb +31 -19
  127. data/lib/generators/doorkeeper/templates/add_confidential_to_applications.rb.erb +13 -0
  128. data/lib/generators/doorkeeper/templates/add_owner_to_application_migration.rb.erb +9 -0
  129. data/lib/generators/doorkeeper/templates/{add_previous_refresh_token_to_access_tokens.rb → add_previous_refresh_token_to_access_tokens.rb.erb} +3 -1
  130. data/lib/generators/doorkeeper/templates/enable_pkce_migration.rb.erb +8 -0
  131. data/lib/generators/doorkeeper/templates/enable_polymorphic_resource_owner_migration.rb.erb +17 -0
  132. data/lib/generators/doorkeeper/templates/initializer.rb +410 -31
  133. data/lib/generators/doorkeeper/templates/migration.rb.erb +88 -0
  134. data/lib/generators/doorkeeper/views_generator.rb +8 -4
  135. data/vendor/assets/stylesheets/doorkeeper/bootstrap.min.css +4 -5
  136. metadata +132 -286
  137. data/.gitignore +0 -14
  138. data/.hound.yml +0 -13
  139. data/.rspec +0 -1
  140. data/.travis.yml +0 -20
  141. data/CONTRIBUTING.md +0 -47
  142. data/Gemfile +0 -14
  143. data/NEWS.md +0 -593
  144. data/RELEASING.md +0 -17
  145. data/Rakefile +0 -20
  146. data/app/validators/redirect_uri_validator.rb +0 -34
  147. data/doorkeeper.gemspec +0 -28
  148. data/lib/doorkeeper/oauth/client/methods.rb +0 -18
  149. data/lib/doorkeeper/oauth/client_credentials/validation.rb +0 -45
  150. data/lib/doorkeeper/oauth/request_concern.rb +0 -48
  151. data/lib/generators/doorkeeper/templates/add_owner_to_application_migration.rb +0 -7
  152. data/lib/generators/doorkeeper/templates/migration.rb +0 -68
  153. data/spec/controllers/application_metal_controller.rb +0 -10
  154. data/spec/controllers/applications_controller_spec.rb +0 -58
  155. data/spec/controllers/authorizations_controller_spec.rb +0 -189
  156. data/spec/controllers/protected_resources_controller_spec.rb +0 -300
  157. data/spec/controllers/token_info_controller_spec.rb +0 -52
  158. data/spec/controllers/tokens_controller_spec.rb +0 -88
  159. data/spec/dummy/Rakefile +0 -7
  160. data/spec/dummy/app/controllers/application_controller.rb +0 -3
  161. data/spec/dummy/app/controllers/custom_authorizations_controller.rb +0 -7
  162. data/spec/dummy/app/controllers/full_protected_resources_controller.rb +0 -12
  163. data/spec/dummy/app/controllers/home_controller.rb +0 -17
  164. data/spec/dummy/app/controllers/metal_controller.rb +0 -11
  165. data/spec/dummy/app/controllers/semi_protected_resources_controller.rb +0 -11
  166. data/spec/dummy/app/helpers/application_helper.rb +0 -5
  167. data/spec/dummy/app/models/user.rb +0 -5
  168. data/spec/dummy/app/views/home/index.html.erb +0 -0
  169. data/spec/dummy/app/views/layouts/application.html.erb +0 -14
  170. data/spec/dummy/config/application.rb +0 -23
  171. data/spec/dummy/config/boot.rb +0 -9
  172. data/spec/dummy/config/database.yml +0 -15
  173. data/spec/dummy/config/environment.rb +0 -5
  174. data/spec/dummy/config/environments/development.rb +0 -29
  175. data/spec/dummy/config/environments/production.rb +0 -62
  176. data/spec/dummy/config/environments/test.rb +0 -44
  177. data/spec/dummy/config/initializers/active_record_belongs_to_required_by_default.rb +0 -6
  178. data/spec/dummy/config/initializers/backtrace_silencers.rb +0 -7
  179. data/spec/dummy/config/initializers/doorkeeper.rb +0 -96
  180. data/spec/dummy/config/initializers/secret_token.rb +0 -9
  181. data/spec/dummy/config/initializers/session_store.rb +0 -8
  182. data/spec/dummy/config/initializers/wrap_parameters.rb +0 -14
  183. data/spec/dummy/config/locales/doorkeeper.en.yml +0 -5
  184. data/spec/dummy/config/routes.rb +0 -52
  185. data/spec/dummy/config.ru +0 -4
  186. data/spec/dummy/db/migrate/20111122132257_create_users.rb +0 -9
  187. data/spec/dummy/db/migrate/20120312140401_add_password_to_users.rb +0 -5
  188. data/spec/dummy/db/migrate/20151223192035_create_doorkeeper_tables.rb +0 -60
  189. data/spec/dummy/db/migrate/20151223200000_add_owner_to_application.rb +0 -7
  190. data/spec/dummy/db/migrate/20160320211015_add_previous_refresh_token_to_access_tokens.rb +0 -11
  191. data/spec/dummy/db/schema.rb +0 -67
  192. data/spec/dummy/public/404.html +0 -26
  193. data/spec/dummy/public/422.html +0 -26
  194. data/spec/dummy/public/500.html +0 -26
  195. data/spec/dummy/public/favicon.ico +0 -0
  196. data/spec/dummy/script/rails +0 -6
  197. data/spec/factories.rb +0 -28
  198. data/spec/generators/application_owner_generator_spec.rb +0 -22
  199. data/spec/generators/install_generator_spec.rb +0 -31
  200. data/spec/generators/migration_generator_spec.rb +0 -20
  201. data/spec/generators/templates/routes.rb +0 -3
  202. data/spec/generators/views_generator_spec.rb +0 -27
  203. data/spec/helpers/doorkeeper/dashboard_helper_spec.rb +0 -24
  204. data/spec/lib/config_spec.rb +0 -334
  205. data/spec/lib/doorkeeper_spec.rb +0 -28
  206. data/spec/lib/models/expirable_spec.rb +0 -51
  207. data/spec/lib/models/revocable_spec.rb +0 -59
  208. data/spec/lib/models/scopes_spec.rb +0 -43
  209. data/spec/lib/oauth/authorization/uri_builder_spec.rb +0 -42
  210. data/spec/lib/oauth/authorization_code_request_spec.rb +0 -80
  211. data/spec/lib/oauth/client/credentials_spec.rb +0 -47
  212. data/spec/lib/oauth/client/methods_spec.rb +0 -54
  213. data/spec/lib/oauth/client_credentials/creator_spec.rb +0 -44
  214. data/spec/lib/oauth/client_credentials/issuer_spec.rb +0 -86
  215. data/spec/lib/oauth/client_credentials/validation_spec.rb +0 -54
  216. data/spec/lib/oauth/client_credentials_integration_spec.rb +0 -27
  217. data/spec/lib/oauth/client_credentials_request_spec.rb +0 -104
  218. data/spec/lib/oauth/client_spec.rb +0 -39
  219. data/spec/lib/oauth/code_request_spec.rb +0 -45
  220. data/spec/lib/oauth/code_response_spec.rb +0 -34
  221. data/spec/lib/oauth/error_response_spec.rb +0 -61
  222. data/spec/lib/oauth/error_spec.rb +0 -23
  223. data/spec/lib/oauth/forbidden_token_response_spec.rb +0 -23
  224. data/spec/lib/oauth/helpers/scope_checker_spec.rb +0 -64
  225. data/spec/lib/oauth/helpers/unique_token_spec.rb +0 -20
  226. data/spec/lib/oauth/helpers/uri_checker_spec.rb +0 -104
  227. data/spec/lib/oauth/invalid_token_response_spec.rb +0 -28
  228. data/spec/lib/oauth/password_access_token_request_spec.rb +0 -90
  229. data/spec/lib/oauth/pre_authorization_spec.rb +0 -155
  230. data/spec/lib/oauth/refresh_token_request_spec.rb +0 -154
  231. data/spec/lib/oauth/scopes_spec.rb +0 -122
  232. data/spec/lib/oauth/token_request_spec.rb +0 -98
  233. data/spec/lib/oauth/token_response_spec.rb +0 -85
  234. data/spec/lib/oauth/token_spec.rb +0 -116
  235. data/spec/lib/request/strategy_spec.rb +0 -53
  236. data/spec/lib/server_spec.rb +0 -52
  237. data/spec/models/doorkeeper/access_grant_spec.rb +0 -36
  238. data/spec/models/doorkeeper/access_token_spec.rb +0 -394
  239. data/spec/models/doorkeeper/application_spec.rb +0 -179
  240. data/spec/requests/applications/applications_request_spec.rb +0 -94
  241. data/spec/requests/applications/authorized_applications_spec.rb +0 -30
  242. data/spec/requests/endpoints/authorization_spec.rb +0 -72
  243. data/spec/requests/endpoints/token_spec.rb +0 -64
  244. data/spec/requests/flows/authorization_code_errors_spec.rb +0 -66
  245. data/spec/requests/flows/authorization_code_spec.rb +0 -156
  246. data/spec/requests/flows/client_credentials_spec.rb +0 -58
  247. data/spec/requests/flows/implicit_grant_errors_spec.rb +0 -32
  248. data/spec/requests/flows/implicit_grant_spec.rb +0 -61
  249. data/spec/requests/flows/password_spec.rb +0 -115
  250. data/spec/requests/flows/refresh_token_spec.rb +0 -174
  251. data/spec/requests/flows/revoke_token_spec.rb +0 -157
  252. data/spec/requests/flows/skip_authorization_spec.rb +0 -59
  253. data/spec/requests/protected_resources/metal_spec.rb +0 -14
  254. data/spec/requests/protected_resources/private_api_spec.rb +0 -81
  255. data/spec/routing/custom_controller_routes_spec.rb +0 -71
  256. data/spec/routing/default_routes_spec.rb +0 -35
  257. data/spec/routing/scoped_routes_spec.rb +0 -31
  258. data/spec/spec_helper.rb +0 -2
  259. data/spec/spec_helper_integration.rb +0 -59
  260. data/spec/support/dependencies/factory_girl.rb +0 -2
  261. data/spec/support/helpers/access_token_request_helper.rb +0 -11
  262. data/spec/support/helpers/authorization_request_helper.rb +0 -41
  263. data/spec/support/helpers/config_helper.rb +0 -9
  264. data/spec/support/helpers/model_helper.rb +0 -67
  265. data/spec/support/helpers/request_spec_helper.rb +0 -76
  266. data/spec/support/helpers/url_helper.rb +0 -55
  267. data/spec/support/http_method_shim.rb +0 -24
  268. data/spec/support/orm/active_record.rb +0 -3
  269. data/spec/support/shared/controllers_shared_context.rb +0 -69
  270. data/spec/support/shared/models_shared_examples.rb +0 -52
  271. data/spec/validators/redirect_uri_validator_spec.rb +0 -78
@@ -1,21 +1,25 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
2
4
  module OAuth
3
- class AuthorizationCodeRequest
4
- include Validations
5
- include OAuth::RequestConcern
6
-
7
- validate :attributes, error: :invalid_request
5
+ class AuthorizationCodeRequest < BaseRequest
6
+ validate :params, error: :invalid_request
8
7
  validate :client, error: :invalid_client
9
8
  validate :grant, error: :invalid_grant
9
+ # @see https://tools.ietf.org/html/rfc6749#section-5.2
10
10
  validate :redirect_uri, error: :invalid_grant
11
+ validate :code_verifier, error: :invalid_grant
11
12
 
12
- attr_accessor :server, :grant, :client, :redirect_uri, :access_token
13
+ attr_reader :grant, :client, :redirect_uri, :access_token, :code_verifier,
14
+ :invalid_request_reason, :missing_param
13
15
 
14
16
  def initialize(server, grant, client, parameters = {})
15
17
  @server = server
16
18
  @client = client
17
19
  @grant = grant
20
+ @grant_type = Doorkeeper::OAuth::AUTHORIZATION_CODE
18
21
  @redirect_uri = parameters[:redirect_uri]
22
+ @code_verifier = parameters[:code_verifier]
19
23
  end
20
24
 
21
25
  private
@@ -26,28 +30,74 @@ module Doorkeeper
26
30
  raise Errors::InvalidGrantReuse if grant.revoked?
27
31
 
28
32
  grant.revoke
29
- find_or_create_access_token(grant.application,
30
- grant.resource_owner_id,
31
- grant.scopes,
32
- server)
33
+
34
+ find_or_create_access_token(
35
+ grant.application,
36
+ resource_owner,
37
+ grant.scopes,
38
+ server,
39
+ )
33
40
  end
41
+
42
+ super
34
43
  end
35
44
 
36
- def validate_attributes
37
- redirect_uri.present?
45
+ def resource_owner
46
+ if Doorkeeper.config.polymorphic_resource_owner?
47
+ grant.resource_owner
48
+ else
49
+ grant.resource_owner_id
50
+ end
51
+ end
52
+
53
+ def pkce_supported?
54
+ Doorkeeper.config.access_grant_model.pkce_supported?
55
+ end
56
+
57
+ def validate_params
58
+ @missing_param = if grant&.uses_pkce? && code_verifier.blank?
59
+ :code_verifier
60
+ elsif redirect_uri.blank?
61
+ :redirect_uri
62
+ end
63
+
64
+ @missing_param.nil?
38
65
  end
39
66
 
40
67
  def validate_client
41
- !!client
68
+ client.present?
42
69
  end
43
70
 
44
71
  def validate_grant
45
72
  return false unless grant && grant.application_id == client.id
73
+
46
74
  grant.accessible?
47
75
  end
48
76
 
49
77
  def validate_redirect_uri
50
- grant.redirect_uri == redirect_uri
78
+ Helpers::URIChecker.valid_for_authorization?(
79
+ redirect_uri,
80
+ grant.redirect_uri,
81
+ )
82
+ end
83
+
84
+ # if either side (server or client) request PKCE, check the verifier
85
+ # against the DB - if PKCE is supported
86
+ def validate_code_verifier
87
+ return true unless pkce_supported?
88
+ return grant.code_challenge.blank? if code_verifier.blank?
89
+
90
+ if grant.code_challenge_method == "S256"
91
+ grant.code_challenge == generate_code_challenge(code_verifier)
92
+ elsif grant.code_challenge_method == "plain"
93
+ grant.code_challenge == code_verifier
94
+ else
95
+ false
96
+ end
97
+ end
98
+
99
+ def generate_code_challenge(code_verifier)
100
+ server_config.access_grant_model.generate_code_challenge(code_verifier)
51
101
  end
52
102
  end
53
103
  end
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Doorkeeper
4
+ module OAuth
5
+ class BaseRequest
6
+ include Validations
7
+
8
+ attr_reader :grant_type, :server
9
+
10
+ delegate :default_scopes, to: :server
11
+
12
+ def authorize
13
+ if valid?
14
+ before_successful_response
15
+ @response = TokenResponse.new(access_token)
16
+ after_successful_response
17
+ @response
18
+ elsif error == :invalid_request
19
+ @response = InvalidRequestResponse.from_request(self)
20
+ else
21
+ @response = ErrorResponse.from_request(self)
22
+ end
23
+ end
24
+
25
+ def scopes
26
+ @scopes ||= build_scopes
27
+ end
28
+
29
+ def find_or_create_access_token(client, resource_owner, scopes, server)
30
+ context = Authorization::Token.build_context(client, grant_type, scopes, resource_owner)
31
+ @access_token = server_config.access_token_model.find_or_create_for(
32
+ application: client,
33
+ resource_owner: resource_owner,
34
+ scopes: scopes,
35
+ expires_in: Authorization::Token.access_token_expires_in(server, context),
36
+ use_refresh_token: Authorization::Token.refresh_token_enabled?(server, context),
37
+ )
38
+ end
39
+
40
+ def before_successful_response
41
+ server_config.before_successful_strategy_response.call(self)
42
+ end
43
+
44
+ def after_successful_response
45
+ server_config.after_successful_strategy_response.call(self, @response)
46
+ end
47
+
48
+ def server_config
49
+ Doorkeeper.config
50
+ end
51
+
52
+ private
53
+
54
+ def build_scopes
55
+ if @original_scopes.present?
56
+ OAuth::Scopes.from_string(@original_scopes)
57
+ else
58
+ client_scopes = @client&.scopes
59
+ return default_scopes if client_scopes.blank?
60
+
61
+ default_scopes & client_scopes
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Doorkeeper
4
+ module OAuth
5
+ class BaseResponse
6
+ def body
7
+ {}
8
+ end
9
+
10
+ def description
11
+ ""
12
+ end
13
+
14
+ def headers
15
+ {}
16
+ end
17
+
18
+ def redirectable?
19
+ false
20
+ end
21
+
22
+ def redirect_uri
23
+ ""
24
+ end
25
+
26
+ def status
27
+ :ok
28
+ end
29
+ end
30
+ end
31
+ end
@@ -1,20 +1,33 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
2
4
  module OAuth
3
5
  class Client
4
- class Credentials < Struct.new(:uid, :secret)
5
- extend Methods
6
+ Credentials = Struct.new(:uid, :secret) do
7
+ class << self
8
+ def from_request(request, *credentials_methods)
9
+ credentials_methods.inject(nil) do |_, method|
10
+ method = self.method(method) if method.is_a?(Symbol)
11
+ credentials = Credentials.new(*method.call(request))
12
+ break credentials if credentials.present?
13
+ end
14
+ end
6
15
 
7
- def self.from_request(request, *credentials_methods)
8
- credentials_methods.inject(nil) do |credentials, method|
9
- method = self.method(method) if method.is_a?(Symbol)
10
- credentials = Credentials.new(*method.call(request))
11
- break credentials unless credentials.blank?
16
+ def from_params(request)
17
+ request.parameters.values_at(:client_id, :client_secret)
12
18
  end
13
- end
14
19
 
15
- def blank?
16
- uid.blank? || secret.blank?
20
+ def from_basic(request)
21
+ authorization = request.authorization
22
+ if authorization.present? && authorization =~ /^Basic (.*)/m
23
+ Base64.decode64(Regexp.last_match(1)).split(/:/, 2)
24
+ end
25
+ end
17
26
  end
27
+
28
+ # Public clients may have their secret blank, but "credentials" are
29
+ # still present
30
+ delegate :blank?, to: :uid
18
31
  end
19
32
  end
20
33
  end
@@ -1,10 +1,9 @@
1
- require 'doorkeeper/oauth/client/methods'
2
- require 'doorkeeper/oauth/client/credentials'
1
+ # frozen_string_literal: true
3
2
 
4
3
  module Doorkeeper
5
4
  module OAuth
6
5
  class Client
7
- attr_accessor :application
6
+ attr_reader :application
8
7
 
9
8
  delegate :id, :name, :uid, :redirect_uri, :scopes, to: :@application
10
9
 
@@ -12,18 +11,17 @@ module Doorkeeper
12
11
  @application = application
13
12
  end
14
13
 
15
- def self.find(uid, method = Application.method(:by_uid))
16
- if application = method.call(uid)
17
- new(application)
18
- end
14
+ def self.find(uid, method = Doorkeeper.config.application_model.method(:by_uid))
15
+ return unless (application = method.call(uid))
16
+
17
+ new(application)
19
18
  end
20
19
 
21
- def self.authenticate(credentials, method = Application.method(:by_uid_and_secret))
22
- return false if credentials.blank?
20
+ def self.authenticate(credentials, method = Doorkeeper.config.application_model.method(:by_uid_and_secret))
21
+ return if credentials.blank?
22
+ return unless (application = method.call(credentials.uid, credentials.secret))
23
23
 
24
- if application = method.call(credentials.uid, credentials.secret)
25
- new(application)
26
- end
24
+ new(application)
27
25
  end
28
26
  end
29
27
  end
@@ -1,11 +1,54 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
2
4
  module OAuth
3
- class ClientCredentialsRequest
5
+ module ClientCredentials
4
6
  class Creator
5
7
  def call(client, scopes, attributes = {})
6
- AccessToken.find_or_create_for(
7
- client, nil, scopes, attributes[:expires_in],
8
- attributes[:use_refresh_token])
8
+ existing_token = nil
9
+
10
+ if lookup_existing_token?
11
+ existing_token = find_existing_token_for(client, scopes)
12
+ return existing_token if server_config.reuse_access_token && existing_token&.reusable?
13
+ end
14
+
15
+ with_revocation(existing_token: existing_token) do
16
+ server_config.access_token_model.find_or_create_for(
17
+ application: client,
18
+ resource_owner: nil,
19
+ scopes: scopes,
20
+ **attributes,
21
+ )
22
+ end
23
+ end
24
+
25
+ private
26
+
27
+ def with_revocation(existing_token:)
28
+ if existing_token && server_config.revoke_previous_client_credentials_token?
29
+ existing_token.with_lock do
30
+ raise Errors::DoorkeeperError, :invalid_token_reuse if existing_token.revoked?
31
+
32
+ existing_token.revoke
33
+
34
+ yield
35
+ end
36
+ else
37
+ yield
38
+ end
39
+ end
40
+
41
+ def lookup_existing_token?
42
+ server_config.reuse_access_token ||
43
+ server_config.revoke_previous_client_credentials_token?
44
+ end
45
+
46
+ def find_existing_token_for(client, scopes)
47
+ server_config.access_token_model.matching_token_for(client, nil, scopes)
48
+ end
49
+
50
+ def server_config
51
+ Doorkeeper.config
9
52
  end
10
53
  end
11
54
  end
@@ -1,37 +1,44 @@
1
- require 'doorkeeper/oauth/client_credentials/validation'
1
+ # frozen_string_literal: true
2
2
 
3
3
  module Doorkeeper
4
4
  module OAuth
5
- class ClientCredentialsRequest
5
+ module ClientCredentials
6
6
  class Issuer
7
- attr_accessor :token, :validation, :error
7
+ attr_reader :token, :validator, :error
8
8
 
9
- def initialize(server, validation)
9
+ def initialize(server, validator)
10
10
  @server = server
11
- @validation = validation
11
+ @validator = validator
12
12
  end
13
13
 
14
14
  def create(client, scopes, creator = Creator.new)
15
- if validation.valid?
15
+ if validator.valid?
16
16
  @token = create_token(client, scopes, creator)
17
17
  @error = :server_error unless @token
18
18
  else
19
19
  @token = false
20
- @error = validation.error
20
+ @error = validator.error
21
21
  end
22
+
22
23
  @token
23
24
  end
24
25
 
25
26
  private
26
27
 
27
28
  def create_token(client, scopes, creator)
28
- ttl = Authorization::Token.access_token_expires_in(@server, client)
29
+ context = Authorization::Token.build_context(
30
+ client,
31
+ Doorkeeper::OAuth::CLIENT_CREDENTIALS,
32
+ scopes,
33
+ nil,
34
+ )
35
+ ttl = Authorization::Token.access_token_expires_in(@server, context)
29
36
 
30
37
  creator.call(
31
38
  client,
32
39
  scopes,
33
40
  use_refresh_token: false,
34
- expires_in: ttl
41
+ expires_in: ttl,
35
42
  )
36
43
  end
37
44
  end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Doorkeeper
4
+ module OAuth
5
+ module ClientCredentials
6
+ class Validator
7
+ include Validations
8
+ include OAuth::Helpers
9
+
10
+ validate :client, error: :invalid_client
11
+ validate :client_supports_grant_flow, error: :unauthorized_client
12
+ validate :scopes, error: :invalid_scope
13
+
14
+ def initialize(server, request)
15
+ @server = server
16
+ @request = request
17
+ @client = request.client
18
+
19
+ validate
20
+ end
21
+
22
+ private
23
+
24
+ def validate_client
25
+ @client.present?
26
+ end
27
+
28
+ def validate_client_supports_grant_flow
29
+ return if @client.blank?
30
+
31
+ Doorkeeper.config.allow_grant_flow_for_client?(
32
+ Doorkeeper::OAuth::CLIENT_CREDENTIALS,
33
+ @client.application,
34
+ )
35
+ end
36
+
37
+ def validate_scopes
38
+ return true if @request.scopes.blank?
39
+
40
+ application_scopes = if @client.present?
41
+ @client.application.scopes
42
+ else
43
+ ""
44
+ end
45
+
46
+ ScopeChecker.valid?(
47
+ scope_str: @request.scopes.to_s,
48
+ server_scopes: @server.scopes,
49
+ app_scopes: application_scopes,
50
+ grant_type: Doorkeeper::OAuth::CLIENT_CREDENTIALS,
51
+ )
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -1,25 +1,14 @@
1
- require 'doorkeeper/oauth/client_credentials/creator'
2
- require 'doorkeeper/oauth/client_credentials/issuer'
3
- require 'doorkeeper/oauth/client_credentials/validation'
1
+ # frozen_string_literal: true
4
2
 
5
3
  module Doorkeeper
6
4
  module OAuth
7
- class ClientCredentialsRequest
8
- include Validations
9
- include OAuth::RequestConcern
5
+ class ClientCredentialsRequest < BaseRequest
6
+ attr_reader :client, :original_scopes, :response
10
7
 
11
- attr_accessor :server, :client, :original_scopes
12
- attr_reader :response
13
- attr_writer :issuer
14
-
15
- alias_method :error_response, :response
8
+ alias error_response response
16
9
 
17
10
  delegate :error, to: :issuer
18
11
 
19
- def issuer
20
- @issuer ||= Issuer.new(server, Validation.new(server, self))
21
- end
22
-
23
12
  def initialize(server, client, parameters = {})
24
13
  @client = client
25
14
  @server = server
@@ -31,6 +20,13 @@ module Doorkeeper
31
20
  issuer.token
32
21
  end
33
22
 
23
+ def issuer
24
+ @issuer ||= ClientCredentials::Issuer.new(
25
+ server,
26
+ ClientCredentials::Validator.new(server, self),
27
+ )
28
+ end
29
+
34
30
  private
35
31
 
36
32
  def valid?
@@ -1,28 +1,24 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
2
4
  module OAuth
3
5
  class CodeRequest
4
- attr_accessor :pre_auth, :resource_owner, :client
6
+ attr_reader :pre_auth, :resource_owner
5
7
 
6
8
  def initialize(pre_auth, resource_owner)
7
- @pre_auth = pre_auth
8
- @client = pre_auth.client
9
+ @pre_auth = pre_auth
9
10
  @resource_owner = resource_owner
10
11
  end
11
12
 
12
13
  def authorize
13
- if pre_auth.authorizable?
14
- auth = Authorization::Code.new(pre_auth, resource_owner)
15
- auth.issue_token
16
- @response = CodeResponse.new pre_auth, auth
17
- else
18
- @response = ErrorResponse.from_request pre_auth
19
- end
14
+ auth = Authorization::Code.new(pre_auth, resource_owner)
15
+ auth.issue_token!
16
+ CodeResponse.new(pre_auth, auth, response_on_fragment: pre_auth.response_mode == "fragment")
20
17
  end
21
18
 
22
19
  def deny
23
20
  pre_auth.error = :access_denied
24
- ErrorResponse.from_request pre_auth,
25
- redirect_uri: pre_auth.redirect_uri
21
+ pre_auth.error_response
26
22
  end
27
23
  end
28
24
  end
@@ -1,10 +1,11 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
2
4
  module OAuth
3
- class CodeResponse
4
- include OAuth::Authorization::URIBuilder
5
+ class CodeResponse < BaseResponse
5
6
  include OAuth::Helpers
6
7
 
7
- attr_accessor :pre_auth, :auth, :response_on_fragment
8
+ attr_reader :pre_auth, :auth, :response_on_fragment
8
9
 
9
10
  def initialize(pre_auth, auth, options = {})
10
11
  @pre_auth = pre_auth
@@ -16,21 +17,33 @@ module Doorkeeper
16
17
  true
17
18
  end
18
19
 
19
- def redirect_uri
20
- if URIChecker.native_uri? pre_auth.redirect_uri
21
- auth.native_redirect
22
- elsif response_on_fragment
23
- uri_with_fragment(
24
- pre_auth.redirect_uri,
25
- access_token: auth.token.token,
20
+ def issued_token
21
+ auth.token
22
+ end
23
+
24
+ def body
25
+ if auth.try(:access_token?)
26
+ {
27
+ access_token: auth.token.plaintext_token,
26
28
  token_type: auth.token.token_type,
27
29
  expires_in: auth.token.expires_in_seconds,
28
- state: pre_auth.state
29
- )
30
+ state: pre_auth.state,
31
+ }
32
+ elsif auth.try(:access_grant?)
33
+ {
34
+ code: auth.token.plaintext_token,
35
+ state: pre_auth.state,
36
+ }
37
+ end
38
+ end
39
+
40
+ def redirect_uri
41
+ if URIChecker.oob_uri?(pre_auth.redirect_uri)
42
+ auth.oob_redirect
43
+ elsif response_on_fragment
44
+ Authorization::URIBuilder.uri_with_fragment(pre_auth.redirect_uri, body)
30
45
  else
31
- uri_with_query pre_auth.redirect_uri,
32
- code: auth.token.token,
33
- state: pre_auth.state
46
+ Authorization::URIBuilder.uri_with_query(pre_auth.redirect_uri, body)
34
47
  end
35
48
  end
36
49
  end
@@ -1,11 +1,13 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
2
4
  module OAuth
3
- class Error < Struct.new(:name, :state)
5
+ Error = Struct.new(:name, :state) do
4
6
  def description
5
7
  I18n.translate(
6
8
  name,
7
- scope: [:doorkeeper, :errors, :messages],
8
- default: :server_error
9
+ scope: %i[doorkeeper errors messages],
10
+ default: :server_error,
9
11
  )
10
12
  end
11
13
  end