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
@@ -0,0 +1,202 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Doorkeeper
4
+ module OAuth
5
+ # RFC7662 OAuth 2.0 Token Introspection
6
+ #
7
+ # @see https://datatracker.ietf.org/doc/html/rfc7662
8
+ class TokenIntrospection
9
+ def initialize(server, token)
10
+ @server = server
11
+ @token = token
12
+
13
+ authorize!
14
+ end
15
+
16
+ def authorized?
17
+ @error.blank?
18
+ end
19
+
20
+ def error_response
21
+ return if @error.blank?
22
+
23
+ if @error == :invalid_token
24
+ OAuth::InvalidTokenResponse.from_access_token(authorized_token)
25
+ elsif @error == :invalid_request
26
+ OAuth::InvalidRequestResponse.from_request(self)
27
+ else
28
+ OAuth::ErrorResponse.new(name: @error)
29
+ end
30
+ end
31
+
32
+ def to_json(*)
33
+ active? ? success_response : failure_response
34
+ end
35
+
36
+ private
37
+
38
+ attr_reader :server, :token
39
+ attr_reader :error, :invalid_request_reason
40
+
41
+ # If the protected resource uses OAuth 2.0 client credentials to
42
+ # authenticate to the introspection endpoint and its credentials are
43
+ # invalid, the authorization server responds with an HTTP 401
44
+ # (Unauthorized) as described in Section 5.2 of OAuth 2.0 [RFC6749].
45
+ #
46
+ # Endpoint must first validate the authentication.
47
+ # If the authentication is invalid, the endpoint should respond with
48
+ # an HTTP 401 status code and an invalid_client response.
49
+ #
50
+ # @see https://www.oauth.com/oauth2-servers/token-introspection-endpoint/
51
+ #
52
+ # To prevent token scanning attacks, the endpoint MUST also require
53
+ # some form of authorization to access this endpoint, such as client
54
+ # authentication as described in OAuth 2.0 [RFC6749] or a separate
55
+ # OAuth 2.0 access token such as the bearer token described in OAuth
56
+ # 2.0 Bearer Token Usage [RFC6750].
57
+ #
58
+ def authorize!
59
+ # Requested client authorization
60
+ if server.credentials
61
+ @error = :invalid_client unless authorized_client
62
+ elsif authorized_token
63
+ # Requested bearer token authorization
64
+ #
65
+ # If the protected resource uses an OAuth 2.0 bearer token to authorize
66
+ # its call to the introspection endpoint and the token used for
67
+ # authorization does not contain sufficient privileges or is otherwise
68
+ # invalid for this request, the authorization server responds with an
69
+ # HTTP 401 code as described in Section 3 of OAuth 2.0 Bearer Token
70
+ # Usage [RFC6750].
71
+ #
72
+ @error = :invalid_token unless valid_authorized_token?
73
+ else
74
+ @error = :invalid_request
75
+ @invalid_request_reason = :request_not_authorized
76
+ end
77
+ end
78
+
79
+ # Client Authentication
80
+ def authorized_client
81
+ @authorized_client ||= server.credentials && server.client
82
+ end
83
+
84
+ # Bearer Token Authentication
85
+ def authorized_token
86
+ @authorized_token ||= Doorkeeper.authenticate(server.context.request)
87
+ end
88
+
89
+ # 2.2. Introspection Response
90
+ def success_response
91
+ customize_response(
92
+ active: true,
93
+ scope: @token.scopes_string,
94
+ client_id: @token.try(:application).try(:uid),
95
+ token_type: @token.token_type,
96
+ exp: @token.expires_at.to_i,
97
+ iat: @token.created_at.to_i,
98
+ )
99
+ end
100
+
101
+ # If the introspection call is properly authorized but the token is not
102
+ # active, does not exist on this server, or the protected resource is
103
+ # not allowed to introspect this particular token, then the
104
+ # authorization server MUST return an introspection response with the
105
+ # "active" field set to "false". Note that to avoid disclosing too
106
+ # much of the authorization server's state to a third party, the
107
+ # authorization server SHOULD NOT include any additional information
108
+ # about an inactive token, including why the token is inactive.
109
+ #
110
+ # @see https://datatracker.ietf.org/doc/html/rfc7662 2.2. Introspection Response
111
+ #
112
+ def failure_response
113
+ {
114
+ active: false,
115
+ }
116
+ end
117
+
118
+ # Boolean indicator of whether or not the presented token
119
+ # is currently active. The specifics of a token's "active" state
120
+ # will vary depending on the implementation of the authorization
121
+ # server and the information it keeps about its tokens, but a "true"
122
+ # value return for the "active" property will generally indicate
123
+ # that a given token has been issued by this authorization server,
124
+ # has not been revoked by the resource owner, and is within its
125
+ # given time window of validity (e.g., after its issuance time and
126
+ # before its expiration time).
127
+ #
128
+ # Any other error is considered an "inactive" token.
129
+ #
130
+ # * The token requested does not exist or is invalid
131
+ # * The token expired
132
+ # * The token was issued to a different client than is making this request
133
+ #
134
+ # Since resource servers using token introspection rely on the
135
+ # authorization server to determine the state of a token, the
136
+ # authorization server MUST perform all applicable checks against a
137
+ # token's state. For instance, these tests include the following:
138
+ #
139
+ # o If the token can expire, the authorization server MUST determine
140
+ # whether or not the token has expired.
141
+ # o If the token can be issued before it is able to be used, the
142
+ # authorization server MUST determine whether or not a token's valid
143
+ # period has started yet.
144
+ # o If the token can be revoked after it was issued, the authorization
145
+ # server MUST determine whether or not such a revocation has taken
146
+ # place.
147
+ # o If the token has been signed, the authorization server MUST
148
+ # validate the signature.
149
+ # o If the token can be used only at certain resource servers, the
150
+ # authorization server MUST determine whether or not the token can
151
+ # be used at the resource server making the introspection call.
152
+ #
153
+ def active?
154
+ if authorized_client
155
+ valid_token? && token_introspection_allowed?(auth_client: authorized_client.application)
156
+ else
157
+ valid_token?
158
+ end
159
+ end
160
+
161
+ # Token can be valid only if it is not expired or revoked.
162
+ def valid_token?
163
+ @token&.accessible?
164
+ end
165
+
166
+ def valid_authorized_token?
167
+ !authorized_token_matches_introspected? &&
168
+ authorized_token.accessible? &&
169
+ token_introspection_allowed?(auth_token: authorized_token)
170
+ end
171
+
172
+ # RFC7662 Section 2.1
173
+ def authorized_token_matches_introspected?
174
+ authorized_token.token == @token&.token
175
+ end
176
+
177
+ # Config constraints for introspection in Doorkeeper.config.allow_token_introspection
178
+ def token_introspection_allowed?(auth_client: nil, auth_token: nil)
179
+ allow_introspection = Doorkeeper.config.allow_token_introspection
180
+ return allow_introspection unless allow_introspection.respond_to?(:call)
181
+
182
+ allow_introspection.call(@token, auth_client, auth_token)
183
+ end
184
+
185
+ # Allows to customize introspection response.
186
+ # Provides context (controller) and token for generating developer-specific
187
+ # response.
188
+ #
189
+ # @see https://datatracker.ietf.org/doc/html/rfc7662#section-2.2
190
+ #
191
+ def customize_response(response)
192
+ customized_response = Doorkeeper.config.custom_introspection_response.call(
193
+ token,
194
+ server.context,
195
+ )
196
+ return response if customized_response.blank?
197
+
198
+ response.merge(customized_response)
199
+ end
200
+ end
201
+ end
202
+ end
@@ -1,37 +1,24 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
2
4
  module OAuth
3
5
  class TokenRequest
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::Token.new(pre_auth, resource_owner)
15
- auth.issue_token
16
- @response = CodeResponse.new pre_auth,
17
- auth,
18
- response_on_fragment: true
19
- else
20
- @response = error_response
21
- end
14
+ auth = Authorization::Token.new(pre_auth, resource_owner)
15
+ auth.issue_token!
16
+ CodeResponse.new(pre_auth, auth, response_on_fragment: true)
22
17
  end
23
18
 
24
19
  def deny
25
20
  pre_auth.error = :access_denied
26
- error_response
27
- end
28
-
29
- private
30
-
31
- def error_response
32
- ErrorResponse.from_request pre_auth,
33
- redirect_uri: pre_auth.redirect_uri,
34
- response_on_fragment: true
21
+ pre_auth.error_response
35
22
  end
36
23
  end
37
24
  end
@@ -1,7 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
2
4
  module OAuth
3
5
  class TokenResponse
4
- attr_accessor :token
6
+ attr_reader :token
5
7
 
6
8
  def initialize(token)
7
9
  @token = token
@@ -9,12 +11,12 @@ module Doorkeeper
9
11
 
10
12
  def body
11
13
  {
12
- 'access_token' => token.token,
13
- 'token_type' => token.token_type,
14
- 'expires_in' => token.expires_in_seconds,
15
- 'refresh_token' => token.refresh_token,
16
- 'scope' => token.scopes_string,
17
- 'created_at' => token.created_at.to_i,
14
+ "access_token" => token.plaintext_token,
15
+ "token_type" => token.token_type,
16
+ "expires_in" => token.expires_in_seconds,
17
+ "refresh_token" => token.plaintext_refresh_token,
18
+ "scope" => token.scopes_string,
19
+ "created_at" => token.created_at.to_i,
18
20
  }.reject { |_, value| value.blank? }
19
21
  end
20
22
 
@@ -23,9 +25,11 @@ module Doorkeeper
23
25
  end
24
26
 
25
27
  def headers
26
- { 'Cache-Control' => 'no-store',
27
- 'Pragma' => 'no-cache',
28
- 'Content-Type' => 'application/json; charset=utf-8' }
28
+ {
29
+ "Cache-Control" => "no-store",
30
+ "Pragma" => "no-cache",
31
+ "Content-Type" => "application/json; charset=utf-8",
32
+ }
29
33
  end
30
34
  end
31
35
  end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Doorkeeper
4
+ module OAuth
5
+ GRANT_TYPES = [
6
+ AUTHORIZATION_CODE = "authorization_code",
7
+ IMPLICIT = "implicit",
8
+ PASSWORD = "password",
9
+ CLIENT_CREDENTIALS = "client_credentials",
10
+ REFRESH_TOKEN = "refresh_token",
11
+ ].freeze
12
+ end
13
+ end
@@ -1,7 +1,9 @@
1
- module Doorkeeper
2
- class AccessGrant < ActiveRecord::Base
3
- self.table_name = "#{table_name_prefix}oauth_access_grants#{table_name_suffix}".to_sym
1
+ # frozen_string_literal: true
2
+
3
+ require "doorkeeper/orm/active_record/mixins/access_grant"
4
4
 
5
- include AccessGrantMixin
5
+ module Doorkeeper
6
+ class AccessGrant < ::ActiveRecord::Base
7
+ include Doorkeeper::Orm::ActiveRecord::Mixins::AccessGrant
6
8
  end
7
9
  end
@@ -1,21 +1,9 @@
1
- module Doorkeeper
2
- class AccessToken < ActiveRecord::Base
3
- self.table_name = "#{table_name_prefix}oauth_access_tokens#{table_name_suffix}".to_sym
4
-
5
- include AccessTokenMixin
1
+ # frozen_string_literal: true
6
2
 
7
- def self.delete_all_for(application_id, resource_owner)
8
- where(application_id: application_id,
9
- resource_owner_id: resource_owner.id).delete_all
10
- end
11
- private_class_method :delete_all_for
3
+ require "doorkeeper/orm/active_record/mixins/access_token"
12
4
 
13
- def self.order_method
14
- :order
15
- end
16
-
17
- def self.created_at_desc
18
- 'created_at desc'
19
- end
5
+ module Doorkeeper
6
+ class AccessToken < ::ActiveRecord::Base
7
+ include Doorkeeper::Orm::ActiveRecord::Mixins::AccessToken
20
8
  end
21
9
  end
@@ -1,24 +1,10 @@
1
- module Doorkeeper
2
- class Application < ActiveRecord::Base
3
- self.table_name = "#{table_name_prefix}oauth_applications#{table_name_suffix}".to_sym
4
-
5
- include ApplicationMixin
1
+ # frozen_string_literal: true
6
2
 
7
- if ActiveRecord::VERSION::MAJOR >= 4
8
- has_many :authorized_tokens, -> { where(revoked_at: nil) }, class_name: 'AccessToken'
9
- else
10
- has_many :authorized_tokens, class_name: 'AccessToken', conditions: { revoked_at: nil }
11
- end
12
- has_many :authorized_applications, through: :authorized_tokens, source: :application
3
+ require "doorkeeper/orm/active_record/redirect_uri_validator"
4
+ require "doorkeeper/orm/active_record/mixins/application"
13
5
 
14
- def self.column_names_with_table
15
- self.column_names.map { |c| "#{table_name}.#{c}" }
16
- end
17
-
18
- def self.authorized_for(resource_owner)
19
- joins(:authorized_applications).
20
- where(AccessToken.table_name => { resource_owner_id: resource_owner.id, revoked_at: nil }).
21
- group(column_names_with_table.join(','))
22
- end
6
+ module Doorkeeper
7
+ class Application < ::ActiveRecord::Base
8
+ include ::Doorkeeper::Orm::ActiveRecord::Mixins::Application
23
9
  end
24
10
  end
@@ -0,0 +1,69 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Doorkeeper::Orm::ActiveRecord::Mixins
4
+ module AccessGrant
5
+ extend ActiveSupport::Concern
6
+
7
+ included do
8
+ self.table_name = compute_doorkeeper_table_name
9
+ self.strict_loading_by_default = false if respond_to?(:strict_loading_by_default)
10
+
11
+ include ::Doorkeeper::AccessGrantMixin
12
+
13
+ belongs_to :application, class_name: Doorkeeper.config.application_class.to_s,
14
+ optional: true,
15
+ inverse_of: :access_grants
16
+
17
+ if Doorkeeper.config.polymorphic_resource_owner?
18
+ belongs_to :resource_owner, polymorphic: true, optional: false
19
+ else
20
+ validates :resource_owner_id, presence: true
21
+ end
22
+
23
+ validates :application_id,
24
+ :token,
25
+ :expires_in,
26
+ :redirect_uri,
27
+ presence: true
28
+
29
+ validates :token, uniqueness: { case_sensitive: true }
30
+
31
+ before_validation :generate_token, on: :create
32
+
33
+ # We keep a volatile copy of the raw token for initial communication
34
+ # The stored refresh_token may be mapped and not available in cleartext.
35
+ #
36
+ # Some strategies allow restoring stored secrets (e.g. symmetric encryption)
37
+ # while hashing strategies do not, so you cannot rely on this value
38
+ # returning a present value for persisted tokens.
39
+ def plaintext_token
40
+ if secret_strategy.allows_restoring_secrets?
41
+ secret_strategy.restore_secret(self, :token)
42
+ else
43
+ @raw_token
44
+ end
45
+ end
46
+
47
+ private
48
+
49
+ # Generates token value with UniqueToken class.
50
+ #
51
+ # @return [String] token value
52
+ #
53
+ def generate_token
54
+ @raw_token = Doorkeeper::OAuth::Helpers::UniqueToken.generate
55
+ secret_strategy.store_secret(self, :token, @raw_token)
56
+ end
57
+ end
58
+
59
+ module ClassMethods
60
+ private
61
+
62
+ def compute_doorkeeper_table_name
63
+ table_name = "oauth_access_grant"
64
+ table_name = table_name.pluralize if pluralize_table_names
65
+ "#{table_name_prefix}#{table_name}#{table_name_suffix}"
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,81 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Doorkeeper::Orm::ActiveRecord::Mixins
4
+ module AccessToken
5
+ extend ActiveSupport::Concern
6
+
7
+ included do
8
+ self.table_name = compute_doorkeeper_table_name
9
+ self.strict_loading_by_default = false if respond_to?(:strict_loading_by_default)
10
+
11
+ include ::Doorkeeper::AccessTokenMixin
12
+
13
+ belongs_to :application, class_name: Doorkeeper.config.application_class.to_s,
14
+ inverse_of: :access_tokens,
15
+ optional: true
16
+
17
+ if Doorkeeper.config.polymorphic_resource_owner?
18
+ belongs_to :resource_owner, polymorphic: true, optional: true
19
+ end
20
+
21
+ validates :token, presence: true, uniqueness: { case_sensitive: true }
22
+ validates :refresh_token, uniqueness: { case_sensitive: true }, if: :use_refresh_token?
23
+
24
+ # @attr_writer [Boolean, nil] use_refresh_token
25
+ # indicates the possibility of using refresh token
26
+ attr_writer :use_refresh_token
27
+
28
+ before_validation :generate_token, on: :create
29
+ before_validation :generate_refresh_token,
30
+ on: :create, if: :use_refresh_token?
31
+ end
32
+
33
+ module ClassMethods
34
+ # Searches for not revoked Access Tokens associated with the
35
+ # specific Resource Owner.
36
+ #
37
+ # @param resource_owner [ActiveRecord::Base]
38
+ # Resource Owner model instance
39
+ #
40
+ # @return [ActiveRecord::Relation]
41
+ # active Access Tokens for Resource Owner
42
+ #
43
+ def active_for(resource_owner)
44
+ by_resource_owner(resource_owner).where(revoked_at: nil)
45
+ end
46
+
47
+ def refresh_token_revoked_on_use?
48
+ column_names.include?("previous_refresh_token")
49
+ end
50
+
51
+ # Returns non-expired and non-revoked access tokens
52
+ def not_expired
53
+ relation = where(revoked_at: nil)
54
+
55
+ if supports_expiration_time_math?
56
+ # have not reached the expiration time or it never expires
57
+ relation.where("#{expiration_time_sql} > ?", Time.now.utc).or(
58
+ relation.where(expires_in: nil)
59
+ )
60
+ else
61
+ ::Kernel.warn <<~WARNING.squish
62
+ [DOORKEEPER] Doorkeeper doesn't support expiration time math for your database adapter (#{adapter_name}).
63
+ Please add a class method `custom_expiration_time_sql` for your AccessToken class/mixin to provide a custom
64
+ SQL expression to calculate access token expiration time. See lib/doorkeeper/orm/active_record/mixins/access_token.rb
65
+ for more details.
66
+ WARNING
67
+
68
+ relation
69
+ end
70
+ end
71
+
72
+ private
73
+
74
+ def compute_doorkeeper_table_name
75
+ table_name = "oauth_access_token"
76
+ table_name = table_name.pluralize if pluralize_table_names
77
+ "#{table_name_prefix}#{table_name}#{table_name_suffix}"
78
+ end
79
+ end
80
+ end
81
+ end