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,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://datatracker.ietf.org/doc/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.is_a?(server_config.application_model) ? client : client&.application,
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,55 @@
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_active_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
+ application = client.is_a?(server_config.application_model) ? client : client&.application
17
+ server_config.access_token_model.create_for(
18
+ application: application,
19
+ resource_owner: nil,
20
+ scopes: scopes,
21
+ **attributes,
22
+ )
23
+ end
24
+ end
25
+
26
+ private
27
+
28
+ def with_revocation(existing_token:)
29
+ if existing_token && server_config.revoke_previous_client_credentials_token?
30
+ existing_token.with_lock do
31
+ raise Errors::DoorkeeperError, :invalid_token_reuse if existing_token.revoked?
32
+
33
+ existing_token.revoke
34
+
35
+ yield
36
+ end
37
+ else
38
+ yield
39
+ end
40
+ end
41
+
42
+ def lookup_existing_token?
43
+ server_config.reuse_access_token ||
44
+ server_config.revoke_previous_client_credentials_token?
45
+ end
46
+
47
+ def find_active_existing_token_for(client, scopes)
48
+ server_config.access_token_model.matching_token_for(client, nil, scopes)
49
+ end
50
+
51
+ def server_config
52
+ Doorkeeper.config
9
53
  end
10
54
  end
11
55
  end
@@ -1,36 +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)
10
- @server, @validation = server, validation
9
+ def initialize(server, validator)
10
+ @server = server
11
+ @validator = validator
11
12
  end
12
13
 
13
14
  def create(client, scopes, creator = Creator.new)
14
- if validation.valid?
15
+ if validator.valid?
15
16
  @token = create_token(client, scopes, creator)
16
17
  @error = :server_error unless @token
17
18
  else
18
19
  @token = false
19
- @error = validation.error
20
+ @error = validator.error
20
21
  end
22
+
21
23
  @token
22
24
  end
23
25
 
24
26
  private
25
27
 
26
28
  def create_token(client, scopes, creator)
27
- 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)
28
36
 
29
37
  creator.call(
30
38
  client,
31
39
  scopes,
32
40
  use_refresh_token: false,
33
- expires_in: ttl
41
+ expires_in: ttl,
34
42
  )
35
43
  end
36
44
  end
@@ -0,0 +1,55 @@
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
+ application_scopes = if @client.present?
39
+ @client.application.scopes
40
+ else
41
+ ""
42
+ end
43
+ return true if @request.scopes.blank? && application_scopes.blank?
44
+
45
+ ScopeChecker.valid?(
46
+ scope_str: @request.scopes.to_s,
47
+ server_scopes: @server.scopes,
48
+ app_scopes: application_scopes,
49
+ grant_type: Doorkeeper::OAuth::CLIENT_CREDENTIALS,
50
+ )
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
@@ -1,26 +1,18 @@
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 :issuer, :server, :client, :original_scopes
12
- attr_reader :response
13
- alias :error_response :response
8
+ alias error_response response
14
9
 
15
10
  delegate :error, to: :issuer
16
11
 
17
- def issuer
18
- @issuer ||= Issuer.new(server, Validation.new(server, self))
19
- end
20
-
21
12
  def initialize(server, client, parameters = {})
22
- @client, @server = client, server
23
- @response = nil
13
+ @client = client
14
+ @server = server
15
+ @response = nil
24
16
  @original_scopes = parameters[:scope]
25
17
  end
26
18
 
@@ -28,6 +20,13 @@ module Doorkeeper
28
20
  issuer.token
29
21
  end
30
22
 
23
+ def issuer
24
+ @issuer ||= ClientCredentials::Issuer.new(
25
+ server,
26
+ ClientCredentials::Validator.new(server, self),
27
+ )
28
+ end
29
+
31
30
  private
32
31
 
33
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,13 +1,15 @@
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
- @pre_auth, @auth = pre_auth, auth
11
+ @pre_auth = pre_auth
12
+ @auth = auth
11
13
  @response_on_fragment = options[:response_on_fragment]
12
14
  end
13
15
 
@@ -15,23 +17,33 @@ module Doorkeeper
15
17
  true
16
18
  end
17
19
 
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,
28
+ token_type: auth.token.token_type,
29
+ expires_in: auth.token.expires_in_seconds,
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
+
18
40
  def redirect_uri
19
- if URIChecker.native_uri? pre_auth.redirect_uri
20
- auth.native_redirect
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)
21
45
  else
22
- if response_on_fragment
23
- uri_with_fragment(
24
- pre_auth.redirect_uri,
25
- access_token: auth.token.token,
26
- token_type: auth.token.token_type,
27
- expires_in: auth.token.expires_in,
28
- state: pre_auth.state
29
- )
30
- else
31
- uri_with_query pre_auth.redirect_uri,
32
- code: auth.token.token,
33
- state: pre_auth.state
34
- end
46
+ Authorization::URIBuilder.uri_with_query(pre_auth.redirect_uri, body)
35
47
  end
36
48
  end
37
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