doorkeeper 4.2.0 → 5.6.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (273) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +1119 -0
  3. data/README.md +112 -349
  4. data/app/assets/stylesheets/doorkeeper/admin/application.css +2 -2
  5. data/app/controllers/doorkeeper/application_controller.rb +6 -7
  6. data/app/controllers/doorkeeper/application_metal_controller.rb +7 -11
  7. data/app/controllers/doorkeeper/applications_controller.rb +65 -20
  8. data/app/controllers/doorkeeper/authorizations_controller.rb +115 -18
  9. data/app/controllers/doorkeeper/authorized_applications_controller.rb +22 -3
  10. data/app/controllers/doorkeeper/token_info_controller.rb +16 -4
  11. data/app/controllers/doorkeeper/tokens_controller.rb +118 -38
  12. data/app/helpers/doorkeeper/dashboard_helper.rb +10 -6
  13. data/app/views/doorkeeper/applications/_delete_form.html.erb +4 -3
  14. data/app/views/doorkeeper/applications/_form.html.erb +33 -21
  15. data/app/views/doorkeeper/applications/edit.html.erb +1 -1
  16. data/app/views/doorkeeper/applications/index.html.erb +18 -6
  17. data/app/views/doorkeeper/applications/new.html.erb +1 -1
  18. data/app/views/doorkeeper/applications/show.html.erb +40 -16
  19. data/app/views/doorkeeper/authorizations/error.html.erb +4 -2
  20. data/app/views/doorkeeper/authorizations/form_post.html.erb +15 -0
  21. data/app/views/doorkeeper/authorizations/new.html.erb +17 -11
  22. data/app/views/doorkeeper/authorized_applications/_delete_form.html.erb +1 -2
  23. data/app/views/doorkeeper/authorized_applications/index.html.erb +0 -1
  24. data/app/views/layouts/doorkeeper/admin.html.erb +16 -14
  25. data/config/locales/en.yml +36 -9
  26. data/lib/doorkeeper/config/abstract_builder.rb +28 -0
  27. data/lib/doorkeeper/config/option.rb +82 -0
  28. data/lib/doorkeeper/config/validations.rb +53 -0
  29. data/lib/doorkeeper/config.rb +551 -155
  30. data/lib/doorkeeper/engine.rb +19 -6
  31. data/lib/doorkeeper/errors.rb +55 -10
  32. data/lib/doorkeeper/grant_flow/fallback_flow.rb +15 -0
  33. data/lib/doorkeeper/grant_flow/flow.rb +44 -0
  34. data/lib/doorkeeper/grant_flow/registry.rb +50 -0
  35. data/lib/doorkeeper/grant_flow.rb +45 -0
  36. data/lib/doorkeeper/grape/authorization_decorator.rb +6 -4
  37. data/lib/doorkeeper/grape/helpers.rb +24 -12
  38. data/lib/doorkeeper/helpers/controller.rb +49 -27
  39. data/lib/doorkeeper/models/access_grant_mixin.rb +100 -21
  40. data/lib/doorkeeper/models/access_token_mixin.rb +383 -75
  41. data/lib/doorkeeper/models/application_mixin.rb +72 -25
  42. data/lib/doorkeeper/models/concerns/accessible.rb +6 -0
  43. data/lib/doorkeeper/models/concerns/expirable.rb +20 -6
  44. data/lib/doorkeeper/models/concerns/expiration_time_sql_math.rb +88 -0
  45. data/lib/doorkeeper/models/concerns/orderable.rb +15 -0
  46. data/lib/doorkeeper/models/concerns/ownership.rb +4 -7
  47. data/lib/doorkeeper/models/concerns/polymorphic_resource_owner.rb +30 -0
  48. data/lib/doorkeeper/models/concerns/resource_ownerable.rb +47 -0
  49. data/lib/doorkeeper/models/concerns/reusable.rb +19 -0
  50. data/lib/doorkeeper/models/concerns/revocable.rb +12 -18
  51. data/lib/doorkeeper/models/concerns/scopes.rb +12 -2
  52. data/lib/doorkeeper/models/concerns/secret_storable.rb +106 -0
  53. data/lib/doorkeeper/oauth/authorization/code.rb +54 -12
  54. data/lib/doorkeeper/oauth/authorization/context.rb +17 -0
  55. data/lib/doorkeeper/oauth/authorization/token.rb +72 -28
  56. data/lib/doorkeeper/oauth/authorization/uri_builder.rb +22 -18
  57. data/lib/doorkeeper/oauth/authorization_code_request.rb +77 -17
  58. data/lib/doorkeeper/oauth/base_request.rb +67 -0
  59. data/lib/doorkeeper/oauth/base_response.rb +31 -0
  60. data/lib/doorkeeper/oauth/client/credentials.rb +23 -10
  61. data/lib/doorkeeper/oauth/client.rb +10 -12
  62. data/lib/doorkeeper/oauth/client_credentials/creator.rb +44 -4
  63. data/lib/doorkeeper/oauth/client_credentials/issuer.rb +21 -13
  64. data/lib/doorkeeper/oauth/client_credentials/validator.rb +55 -0
  65. data/lib/doorkeeper/oauth/client_credentials_request.rb +20 -16
  66. data/lib/doorkeeper/oauth/code_request.rb +9 -13
  67. data/lib/doorkeeper/oauth/code_response.rb +28 -15
  68. data/lib/doorkeeper/oauth/error.rb +5 -3
  69. data/lib/doorkeeper/oauth/error_response.rb +43 -20
  70. data/lib/doorkeeper/oauth/forbidden_token_response.rb +11 -3
  71. data/lib/doorkeeper/oauth/helpers/scope_checker.rb +23 -18
  72. data/lib/doorkeeper/oauth/helpers/unique_token.rb +20 -3
  73. data/lib/doorkeeper/oauth/helpers/uri_checker.rb +53 -3
  74. data/lib/doorkeeper/oauth/hooks/context.rb +21 -0
  75. data/lib/doorkeeper/oauth/invalid_request_response.rb +47 -0
  76. data/lib/doorkeeper/oauth/invalid_token_response.rb +31 -5
  77. data/lib/doorkeeper/oauth/nonstandard.rb +39 -0
  78. data/lib/doorkeeper/oauth/password_access_token_request.rb +46 -14
  79. data/lib/doorkeeper/oauth/pre_authorization.rb +138 -28
  80. data/lib/doorkeeper/oauth/refresh_token_request.rb +74 -41
  81. data/lib/doorkeeper/oauth/scopes.rb +26 -12
  82. data/lib/doorkeeper/oauth/token.rb +25 -23
  83. data/lib/doorkeeper/oauth/token_introspection.rb +204 -0
  84. data/lib/doorkeeper/oauth/token_request.rb +9 -22
  85. data/lib/doorkeeper/oauth/token_response.rb +13 -10
  86. data/lib/doorkeeper/oauth.rb +13 -0
  87. data/lib/doorkeeper/orm/active_record/access_grant.rb +6 -4
  88. data/lib/doorkeeper/orm/active_record/access_token.rb +5 -25
  89. data/lib/doorkeeper/orm/active_record/application.rb +6 -15
  90. data/lib/doorkeeper/orm/active_record/mixins/access_grant.rb +63 -0
  91. data/lib/doorkeeper/orm/active_record/mixins/access_token.rb +77 -0
  92. data/lib/doorkeeper/orm/active_record/mixins/application.rb +210 -0
  93. data/lib/doorkeeper/orm/active_record/redirect_uri_validator.rb +66 -0
  94. data/lib/doorkeeper/orm/active_record/stale_records_cleaner.rb +36 -0
  95. data/lib/doorkeeper/orm/active_record.rb +34 -12
  96. data/lib/doorkeeper/rails/helpers.rb +14 -15
  97. data/lib/doorkeeper/rails/routes/abstract_router.rb +35 -0
  98. data/lib/doorkeeper/rails/routes/mapper.rb +3 -1
  99. data/lib/doorkeeper/rails/routes/mapping.rb +10 -8
  100. data/lib/doorkeeper/rails/routes/registry.rb +45 -0
  101. data/lib/doorkeeper/rails/routes.rb +50 -29
  102. data/lib/doorkeeper/rake/db.rake +40 -0
  103. data/lib/doorkeeper/rake/setup.rake +6 -0
  104. data/lib/doorkeeper/rake.rb +14 -0
  105. data/lib/doorkeeper/request/authorization_code.rb +12 -4
  106. data/lib/doorkeeper/request/client_credentials.rb +3 -3
  107. data/lib/doorkeeper/request/code.rb +1 -1
  108. data/lib/doorkeeper/request/password.rb +5 -14
  109. data/lib/doorkeeper/request/refresh_token.rb +6 -5
  110. data/lib/doorkeeper/request/strategy.rb +4 -2
  111. data/lib/doorkeeper/request/token.rb +1 -1
  112. data/lib/doorkeeper/request.rb +62 -29
  113. data/lib/doorkeeper/secret_storing/base.rb +64 -0
  114. data/lib/doorkeeper/secret_storing/bcrypt.rb +60 -0
  115. data/lib/doorkeeper/secret_storing/plain.rb +33 -0
  116. data/lib/doorkeeper/secret_storing/sha256_hash.rb +26 -0
  117. data/lib/doorkeeper/server.rb +9 -19
  118. data/lib/doorkeeper/stale_records_cleaner.rb +24 -0
  119. data/lib/doorkeeper/validations.rb +5 -2
  120. data/lib/doorkeeper/version.rb +12 -1
  121. data/lib/doorkeeper.rb +180 -57
  122. data/lib/generators/doorkeeper/application_owner_generator.rb +28 -13
  123. data/lib/generators/doorkeeper/confidential_applications_generator.rb +33 -0
  124. data/lib/generators/doorkeeper/enable_polymorphic_resource_owner_generator.rb +39 -0
  125. data/lib/generators/doorkeeper/install_generator.rb +19 -9
  126. data/lib/generators/doorkeeper/migration_generator.rb +27 -10
  127. data/lib/generators/doorkeeper/pkce_generator.rb +33 -0
  128. data/lib/generators/doorkeeper/previous_refresh_token_generator.rb +31 -19
  129. data/lib/generators/doorkeeper/templates/add_confidential_to_applications.rb.erb +13 -0
  130. data/lib/generators/doorkeeper/templates/add_owner_to_application_migration.rb.erb +9 -0
  131. data/lib/generators/doorkeeper/templates/{add_previous_refresh_token_to_access_tokens.rb → add_previous_refresh_token_to_access_tokens.rb.erb} +3 -1
  132. data/lib/generators/doorkeeper/templates/enable_pkce_migration.rb.erb +8 -0
  133. data/lib/generators/doorkeeper/templates/enable_polymorphic_resource_owner_migration.rb.erb +17 -0
  134. data/lib/generators/doorkeeper/templates/initializer.rb +436 -33
  135. data/lib/generators/doorkeeper/templates/migration.rb.erb +98 -0
  136. data/lib/generators/doorkeeper/views_generator.rb +8 -4
  137. data/vendor/assets/stylesheets/doorkeeper/bootstrap.min.css +4 -5
  138. metadata +129 -281
  139. data/.gitignore +0 -14
  140. data/.hound.yml +0 -13
  141. data/.rspec +0 -1
  142. data/.travis.yml +0 -20
  143. data/CONTRIBUTING.md +0 -47
  144. data/Gemfile +0 -14
  145. data/NEWS.md +0 -593
  146. data/RELEASING.md +0 -17
  147. data/Rakefile +0 -20
  148. data/app/validators/redirect_uri_validator.rb +0 -34
  149. data/doorkeeper.gemspec +0 -28
  150. data/lib/doorkeeper/oauth/client/methods.rb +0 -18
  151. data/lib/doorkeeper/oauth/client_credentials/validation.rb +0 -45
  152. data/lib/doorkeeper/oauth/request_concern.rb +0 -48
  153. data/lib/generators/doorkeeper/templates/add_owner_to_application_migration.rb +0 -7
  154. data/lib/generators/doorkeeper/templates/migration.rb +0 -68
  155. data/spec/controllers/application_metal_controller.rb +0 -10
  156. data/spec/controllers/applications_controller_spec.rb +0 -58
  157. data/spec/controllers/authorizations_controller_spec.rb +0 -189
  158. data/spec/controllers/protected_resources_controller_spec.rb +0 -300
  159. data/spec/controllers/token_info_controller_spec.rb +0 -52
  160. data/spec/controllers/tokens_controller_spec.rb +0 -88
  161. data/spec/dummy/Rakefile +0 -7
  162. data/spec/dummy/app/controllers/application_controller.rb +0 -3
  163. data/spec/dummy/app/controllers/custom_authorizations_controller.rb +0 -7
  164. data/spec/dummy/app/controllers/full_protected_resources_controller.rb +0 -12
  165. data/spec/dummy/app/controllers/home_controller.rb +0 -17
  166. data/spec/dummy/app/controllers/metal_controller.rb +0 -11
  167. data/spec/dummy/app/controllers/semi_protected_resources_controller.rb +0 -11
  168. data/spec/dummy/app/helpers/application_helper.rb +0 -5
  169. data/spec/dummy/app/models/user.rb +0 -5
  170. data/spec/dummy/app/views/home/index.html.erb +0 -0
  171. data/spec/dummy/app/views/layouts/application.html.erb +0 -14
  172. data/spec/dummy/config/application.rb +0 -23
  173. data/spec/dummy/config/boot.rb +0 -9
  174. data/spec/dummy/config/database.yml +0 -15
  175. data/spec/dummy/config/environment.rb +0 -5
  176. data/spec/dummy/config/environments/development.rb +0 -29
  177. data/spec/dummy/config/environments/production.rb +0 -62
  178. data/spec/dummy/config/environments/test.rb +0 -44
  179. data/spec/dummy/config/initializers/active_record_belongs_to_required_by_default.rb +0 -6
  180. data/spec/dummy/config/initializers/backtrace_silencers.rb +0 -7
  181. data/spec/dummy/config/initializers/doorkeeper.rb +0 -96
  182. data/spec/dummy/config/initializers/secret_token.rb +0 -9
  183. data/spec/dummy/config/initializers/session_store.rb +0 -8
  184. data/spec/dummy/config/initializers/wrap_parameters.rb +0 -14
  185. data/spec/dummy/config/locales/doorkeeper.en.yml +0 -5
  186. data/spec/dummy/config/routes.rb +0 -52
  187. data/spec/dummy/config.ru +0 -4
  188. data/spec/dummy/db/migrate/20111122132257_create_users.rb +0 -9
  189. data/spec/dummy/db/migrate/20120312140401_add_password_to_users.rb +0 -5
  190. data/spec/dummy/db/migrate/20151223192035_create_doorkeeper_tables.rb +0 -60
  191. data/spec/dummy/db/migrate/20151223200000_add_owner_to_application.rb +0 -7
  192. data/spec/dummy/db/migrate/20160320211015_add_previous_refresh_token_to_access_tokens.rb +0 -11
  193. data/spec/dummy/db/schema.rb +0 -67
  194. data/spec/dummy/public/404.html +0 -26
  195. data/spec/dummy/public/422.html +0 -26
  196. data/spec/dummy/public/500.html +0 -26
  197. data/spec/dummy/public/favicon.ico +0 -0
  198. data/spec/dummy/script/rails +0 -6
  199. data/spec/factories.rb +0 -28
  200. data/spec/generators/application_owner_generator_spec.rb +0 -22
  201. data/spec/generators/install_generator_spec.rb +0 -31
  202. data/spec/generators/migration_generator_spec.rb +0 -20
  203. data/spec/generators/templates/routes.rb +0 -3
  204. data/spec/generators/views_generator_spec.rb +0 -27
  205. data/spec/helpers/doorkeeper/dashboard_helper_spec.rb +0 -24
  206. data/spec/lib/config_spec.rb +0 -334
  207. data/spec/lib/doorkeeper_spec.rb +0 -28
  208. data/spec/lib/models/expirable_spec.rb +0 -51
  209. data/spec/lib/models/revocable_spec.rb +0 -59
  210. data/spec/lib/models/scopes_spec.rb +0 -43
  211. data/spec/lib/oauth/authorization/uri_builder_spec.rb +0 -42
  212. data/spec/lib/oauth/authorization_code_request_spec.rb +0 -80
  213. data/spec/lib/oauth/client/credentials_spec.rb +0 -47
  214. data/spec/lib/oauth/client/methods_spec.rb +0 -54
  215. data/spec/lib/oauth/client_credentials/creator_spec.rb +0 -44
  216. data/spec/lib/oauth/client_credentials/issuer_spec.rb +0 -86
  217. data/spec/lib/oauth/client_credentials/validation_spec.rb +0 -54
  218. data/spec/lib/oauth/client_credentials_integration_spec.rb +0 -27
  219. data/spec/lib/oauth/client_credentials_request_spec.rb +0 -104
  220. data/spec/lib/oauth/client_spec.rb +0 -39
  221. data/spec/lib/oauth/code_request_spec.rb +0 -45
  222. data/spec/lib/oauth/code_response_spec.rb +0 -34
  223. data/spec/lib/oauth/error_response_spec.rb +0 -61
  224. data/spec/lib/oauth/error_spec.rb +0 -23
  225. data/spec/lib/oauth/forbidden_token_response_spec.rb +0 -23
  226. data/spec/lib/oauth/helpers/scope_checker_spec.rb +0 -64
  227. data/spec/lib/oauth/helpers/unique_token_spec.rb +0 -20
  228. data/spec/lib/oauth/helpers/uri_checker_spec.rb +0 -104
  229. data/spec/lib/oauth/invalid_token_response_spec.rb +0 -28
  230. data/spec/lib/oauth/password_access_token_request_spec.rb +0 -90
  231. data/spec/lib/oauth/pre_authorization_spec.rb +0 -155
  232. data/spec/lib/oauth/refresh_token_request_spec.rb +0 -154
  233. data/spec/lib/oauth/scopes_spec.rb +0 -122
  234. data/spec/lib/oauth/token_request_spec.rb +0 -98
  235. data/spec/lib/oauth/token_response_spec.rb +0 -85
  236. data/spec/lib/oauth/token_spec.rb +0 -116
  237. data/spec/lib/request/strategy_spec.rb +0 -53
  238. data/spec/lib/server_spec.rb +0 -52
  239. data/spec/models/doorkeeper/access_grant_spec.rb +0 -36
  240. data/spec/models/doorkeeper/access_token_spec.rb +0 -394
  241. data/spec/models/doorkeeper/application_spec.rb +0 -179
  242. data/spec/requests/applications/applications_request_spec.rb +0 -94
  243. data/spec/requests/applications/authorized_applications_spec.rb +0 -30
  244. data/spec/requests/endpoints/authorization_spec.rb +0 -72
  245. data/spec/requests/endpoints/token_spec.rb +0 -64
  246. data/spec/requests/flows/authorization_code_errors_spec.rb +0 -66
  247. data/spec/requests/flows/authorization_code_spec.rb +0 -156
  248. data/spec/requests/flows/client_credentials_spec.rb +0 -58
  249. data/spec/requests/flows/implicit_grant_errors_spec.rb +0 -32
  250. data/spec/requests/flows/implicit_grant_spec.rb +0 -61
  251. data/spec/requests/flows/password_spec.rb +0 -115
  252. data/spec/requests/flows/refresh_token_spec.rb +0 -174
  253. data/spec/requests/flows/revoke_token_spec.rb +0 -157
  254. data/spec/requests/flows/skip_authorization_spec.rb +0 -59
  255. data/spec/requests/protected_resources/metal_spec.rb +0 -14
  256. data/spec/requests/protected_resources/private_api_spec.rb +0 -81
  257. data/spec/routing/custom_controller_routes_spec.rb +0 -71
  258. data/spec/routing/default_routes_spec.rb +0 -35
  259. data/spec/routing/scoped_routes_spec.rb +0 -31
  260. data/spec/spec_helper.rb +0 -2
  261. data/spec/spec_helper_integration.rb +0 -59
  262. data/spec/support/dependencies/factory_girl.rb +0 -2
  263. data/spec/support/helpers/access_token_request_helper.rb +0 -11
  264. data/spec/support/helpers/authorization_request_helper.rb +0 -41
  265. data/spec/support/helpers/config_helper.rb +0 -9
  266. data/spec/support/helpers/model_helper.rb +0 -67
  267. data/spec/support/helpers/request_spec_helper.rb +0 -76
  268. data/spec/support/helpers/url_helper.rb +0 -55
  269. data/spec/support/http_method_shim.rb +0 -24
  270. data/spec/support/orm/active_record.rb +0 -3
  271. data/spec/support/shared/controllers_shared_context.rb +0 -69
  272. data/spec/support/shared/models_shared_examples.rb +0 -52
  273. data/spec/validators/redirect_uri_validator_spec.rb +0 -78
@@ -1,21 +1,35 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
2
4
  module Models
3
5
  module Expirable
6
+ # Indicates whether the object is expired (`#expires_in` present and
7
+ # expiration time has come).
8
+ #
9
+ # @return [Boolean] true if object expired and false in other case
4
10
  def expired?
5
- expires_in && Time.now.utc > expired_time
11
+ !!(expires_in && Time.now.utc > expires_at)
6
12
  end
7
13
 
14
+ # Calculates expiration time in seconds.
15
+ #
16
+ # @return [Integer, nil] number of seconds if object has expiration time
17
+ # or nil if object never expires.
8
18
  def expires_in_seconds
9
19
  return nil if expires_in.nil?
10
- expires = (created_at + expires_in.seconds) - Time.now.utc
20
+
21
+ expires = expires_at - Time.now.utc
11
22
  expires_sec = expires.seconds.round(0)
12
23
  expires_sec > 0 ? expires_sec : 0
13
24
  end
14
25
 
15
- private
16
-
17
- def expired_time
18
- created_at + expires_in.seconds
26
+ # Expiration time (date time of creation + TTL).
27
+ #
28
+ # @return [Time, nil] expiration time in UTC
29
+ # or nil if the object never expires.
30
+ #
31
+ def expires_at
32
+ expires_in && created_at + expires_in.seconds
19
33
  end
20
34
  end
21
35
  end
@@ -0,0 +1,88 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Doorkeeper
4
+ module Models
5
+ module ExpirationTimeSqlMath
6
+ extend ::ActiveSupport::Concern
7
+
8
+ class ExpirationTimeSqlGenerator
9
+ attr_reader :model
10
+
11
+ delegate :table_name, to: :@model
12
+
13
+ def initialize(model)
14
+ @model = model
15
+ end
16
+
17
+ def generate_sql
18
+ raise "`generate_sql` should be overridden for a #{self.class.name}!"
19
+ end
20
+ end
21
+
22
+ class MySqlExpirationTimeSqlGenerator < ExpirationTimeSqlGenerator
23
+ def generate_sql
24
+ Arel.sql("DATE_ADD(#{table_name}.created_at, INTERVAL #{table_name}.expires_in SECOND)")
25
+ end
26
+ end
27
+
28
+ class SqlLiteExpirationTimeSqlGenerator < ExpirationTimeSqlGenerator
29
+ def generate_sql
30
+ Arel.sql("DATETIME(#{table_name}.created_at, '+' || #{table_name}.expires_in || ' SECONDS')")
31
+ end
32
+ end
33
+
34
+ class SqlServerExpirationTimeSqlGenerator < ExpirationTimeSqlGenerator
35
+ def generate_sql
36
+ Arel.sql("DATEADD(second, #{table_name}.expires_in, #{table_name}.created_at) AT TIME ZONE 'UTC'")
37
+ end
38
+ end
39
+
40
+ class OracleExpirationTimeSqlGenerator < ExpirationTimeSqlGenerator
41
+ def generate_sql
42
+ Arel.sql("#{table_name}.created_at + INTERVAL to_char(#{table_name}.expires_in) second")
43
+ end
44
+ end
45
+
46
+ class PostgresExpirationTimeSqlGenerator < ExpirationTimeSqlGenerator
47
+ def generate_sql
48
+ Arel.sql("#{table_name}.created_at + #{table_name}.expires_in * INTERVAL '1 SECOND'")
49
+ end
50
+ end
51
+
52
+ ADAPTERS_MAPPING = {
53
+ "sqlite" => SqlLiteExpirationTimeSqlGenerator,
54
+ "sqlite3" => SqlLiteExpirationTimeSqlGenerator,
55
+ "postgis" => PostgresExpirationTimeSqlGenerator,
56
+ "postgresql" => PostgresExpirationTimeSqlGenerator,
57
+ "mysql" => MySqlExpirationTimeSqlGenerator,
58
+ "mysql2" => MySqlExpirationTimeSqlGenerator,
59
+ "trilogy" => MySqlExpirationTimeSqlGenerator,
60
+ "sqlserver" => SqlServerExpirationTimeSqlGenerator,
61
+ "oracleenhanced" => OracleExpirationTimeSqlGenerator,
62
+ }.freeze
63
+
64
+ module ClassMethods
65
+ def supports_expiration_time_math?
66
+ ADAPTERS_MAPPING.key?(adapter_name.downcase) ||
67
+ respond_to?(:custom_expiration_time_sql)
68
+ end
69
+
70
+ def expiration_time_sql
71
+ if respond_to?(:custom_expiration_time_sql)
72
+ custom_expiration_time_sql
73
+ else
74
+ expiration_time_sql_expression
75
+ end
76
+ end
77
+
78
+ def expiration_time_sql_expression
79
+ ADAPTERS_MAPPING.fetch(adapter_name.downcase).new(self).generate_sql
80
+ end
81
+
82
+ def adapter_name
83
+ ActiveRecord::Base.connection.adapter_name
84
+ end
85
+ end
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Doorkeeper
4
+ module Models
5
+ module Orderable
6
+ extend ActiveSupport::Concern
7
+
8
+ module ClassMethods
9
+ def ordered_by(attribute, direction = :asc)
10
+ order(attribute => direction)
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -1,20 +1,17 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
2
4
  module Models
3
5
  module Ownership
4
6
  extend ActiveSupport::Concern
5
7
 
6
8
  included do
7
- belongs_to_options = { polymorphic: true }
8
- if defined?(ActiveRecord::Base) && ActiveRecord::VERSION::MAJOR >= 5
9
- belongs_to_options[:optional] = true
10
- end
11
-
12
- belongs_to :owner, belongs_to_options
9
+ belongs_to :owner, polymorphic: true, optional: true
13
10
  validates :owner, presence: true, if: :validate_owner?
14
11
  end
15
12
 
16
13
  def validate_owner?
17
- Doorkeeper.configuration.confirm_application_owner?
14
+ Doorkeeper.config.confirm_application_owner?
18
15
  end
19
16
  end
20
17
  end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Doorkeeper
4
+ module Models
5
+ module PolymorphicResourceOwner
6
+ module ForAccessGrant
7
+ extend ActiveSupport::Concern
8
+
9
+ included do
10
+ if Doorkeeper.config.polymorphic_resource_owner?
11
+ belongs_to :resource_owner, polymorphic: true, optional: false
12
+ else
13
+ validates :resource_owner_id, presence: true
14
+ end
15
+ end
16
+ end
17
+
18
+ module ForAccessToken
19
+ extend ActiveSupport::Concern
20
+
21
+ included do
22
+ if Doorkeeper.config.polymorphic_resource_owner?
23
+ belongs_to :resource_owner, polymorphic: true, optional: true
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
30
+
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Doorkeeper
4
+ module Models
5
+ module ResourceOwnerable
6
+ extend ActiveSupport::Concern
7
+
8
+ module ClassMethods
9
+ # Searches for record by Resource Owner considering Doorkeeper
10
+ # configuration for resource owner association.
11
+ #
12
+ # @param resource_owner [ActiveRecord::Base, Integer]
13
+ # resource owner
14
+ #
15
+ # @return [Doorkeeper::AccessGrant, Doorkeeper::AccessToken]
16
+ # collection of records
17
+ #
18
+ def by_resource_owner(resource_owner)
19
+ if Doorkeeper.configuration.polymorphic_resource_owner?
20
+ where(resource_owner: resource_owner)
21
+ else
22
+ where(resource_owner_id: resource_owner_id_for(resource_owner))
23
+ end
24
+ end
25
+
26
+ protected
27
+
28
+ # Backward compatible way to retrieve resource owner itself (if
29
+ # polymorphic association enabled) or just it's ID.
30
+ #
31
+ # @param resource_owner [ActiveRecord::Base, Integer]
32
+ # resource owner
33
+ #
34
+ # @return [ActiveRecord::Base, Integer]
35
+ # instance of Resource Owner or it's ID
36
+ #
37
+ def resource_owner_id_for(resource_owner)
38
+ if resource_owner.respond_to?(:to_key)
39
+ resource_owner.id
40
+ else
41
+ resource_owner
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Doorkeeper
4
+ module Models
5
+ module Reusable
6
+ # Indicates whether the object is reusable (i.e. It is not expired and
7
+ # has not crossed reuse_limit).
8
+ #
9
+ # @return [Boolean] true if can be reused and false in other case
10
+ def reusable?
11
+ return false if expired?
12
+ return true unless expires_in
13
+
14
+ threshold_limit = 100 - Doorkeeper.config.token_reuse_limit
15
+ expires_in_seconds >= threshold_limit * expires_in / 100
16
+ end
17
+ end
18
+ end
19
+ end
@@ -1,30 +1,24 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
2
4
  module Models
3
5
  module Revocable
6
+ # Revokes the object (updates `:revoked_at` attribute setting its value
7
+ # to the specific time).
8
+ #
9
+ # @param clock [Time] time object
10
+ #
4
11
  def revoke(clock = Time)
5
- update_attribute :revoked_at, clock.now.utc
12
+ update_attribute(:revoked_at, clock.now.utc)
6
13
  end
7
14
 
15
+ # Indicates whether the object has been revoked.
16
+ #
17
+ # @return [Boolean] true if revoked, false in other case
18
+ #
8
19
  def revoked?
9
20
  !!(revoked_at && revoked_at <= Time.now.utc)
10
21
  end
11
-
12
- def revoke_previous_refresh_token!
13
- return unless refresh_token_revoked_on_use?
14
- old_refresh_token.revoke if old_refresh_token
15
- update_attribute :previous_refresh_token, ""
16
- end
17
-
18
- private
19
-
20
- def old_refresh_token
21
- @old_refresh_token ||=
22
- AccessToken.by_refresh_token(previous_refresh_token)
23
- end
24
-
25
- def refresh_token_revoked_on_use?
26
- AccessToken.refresh_token_revoked_on_use?
27
- end
28
22
  end
29
23
  end
30
24
  end
@@ -1,8 +1,18 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
2
4
  module Models
3
5
  module Scopes
4
6
  def scopes
5
- OAuth::Scopes.from_string(self[:scopes])
7
+ OAuth::Scopes.from_string(scopes_string)
8
+ end
9
+
10
+ def scopes=(value)
11
+ if value.is_a?(Array)
12
+ super(Doorkeeper::OAuth::Scopes.from_array(value).to_s)
13
+ else
14
+ super(Doorkeeper::OAuth::Scopes.from_string(value.to_s).to_s)
15
+ end
6
16
  end
7
17
 
8
18
  def scopes_string
@@ -10,7 +20,7 @@ module Doorkeeper
10
20
  end
11
21
 
12
22
  def includes_scope?(*required_scopes)
13
- required_scopes.blank? || required_scopes.any? { |s| scopes.exists?(s.to_s) }
23
+ required_scopes.blank? || required_scopes.any? { |scope| scopes.exists?(scope.to_s) }
14
24
  end
15
25
  end
16
26
  end
@@ -0,0 +1,106 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Doorkeeper
4
+ module Models
5
+ ##
6
+ # Storable finder to provide lookups for input plaintext values which are
7
+ # mapped to their stored versions (e.g., hashing, encryption) before lookup.
8
+ module SecretStorable
9
+ extend ActiveSupport::Concern
10
+
11
+ delegate :secret_strategy,
12
+ :fallback_secret_strategy,
13
+ to: :class
14
+
15
+ # :nodoc
16
+ module ClassMethods
17
+ # Compare the given plaintext with the secret
18
+ #
19
+ # @param input [String]
20
+ # The plain input to compare.
21
+ #
22
+ # @param secret [String]
23
+ # The secret value to compare with.
24
+ #
25
+ # @return [Boolean]
26
+ # Whether input matches secret as per the secret strategy
27
+ #
28
+ delegate :secret_matches?, to: :secret_strategy
29
+
30
+ # Returns an instance of the Doorkeeper::AccessToken with
31
+ # specific token value.
32
+ #
33
+ # @param attr [Symbol]
34
+ # The token attribute we're looking with.
35
+ #
36
+ # @param token [#to_s]
37
+ # token value (any object that responds to `#to_s`)
38
+ #
39
+ # @return [Doorkeeper::AccessToken, nil] AccessToken object or nil
40
+ # if there is no record with such token
41
+ #
42
+ def find_by_plaintext_token(attr, token)
43
+ token = token.to_s
44
+
45
+ find_by(attr => secret_strategy.transform_secret(token)) ||
46
+ find_by_fallback_token(attr, token)
47
+ end
48
+
49
+ # Allow looking up previously plain tokens as a fallback
50
+ # IFF a fallback strategy has been defined
51
+ #
52
+ # @param attr [Symbol]
53
+ # The token attribute we're looking with.
54
+ #
55
+ # @param plain_secret [#to_s]
56
+ # plain secret value (any object that responds to `#to_s`)
57
+ #
58
+ # @return [Doorkeeper::AccessToken, nil] AccessToken object or nil
59
+ # if there is no record with such token
60
+ #
61
+ def find_by_fallback_token(attr, plain_secret)
62
+ return nil unless fallback_secret_strategy
63
+
64
+ # Use the previous strategy to look up
65
+ stored_token = fallback_secret_strategy.transform_secret(plain_secret)
66
+ find_by(attr => stored_token).tap do |resource|
67
+ return nil unless resource
68
+
69
+ upgrade_fallback_value resource, attr, plain_secret
70
+ end
71
+ end
72
+
73
+ # Allow implementations in ORMs to replace a plain
74
+ # value falling back to to avoid it remaining as plain text.
75
+ #
76
+ # @param instance
77
+ # An instance of this model with a plain value token.
78
+ #
79
+ # @param attr
80
+ # The secret attribute name to upgrade.
81
+ #
82
+ # @param plain_secret
83
+ # The plain secret to upgrade.
84
+ #
85
+ def upgrade_fallback_value(instance, attr, plain_secret)
86
+ upgraded = secret_strategy.store_secret(instance, attr, plain_secret)
87
+ instance.update(attr => upgraded)
88
+ end
89
+
90
+ ##
91
+ # Determines the secret storing transformer
92
+ # Unless configured otherwise, uses the plain secret strategy
93
+ def secret_strategy
94
+ ::Doorkeeper::SecretStoring::Plain
95
+ end
96
+
97
+ ##
98
+ # Determine the fallback storing strategy
99
+ # Unless configured, there will be no fallback
100
+ def fallback_secret_strategy
101
+ nil
102
+ end
103
+ end
104
+ end
105
+ end
106
+ end
@@ -1,30 +1,72 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
2
4
  module OAuth
3
5
  module Authorization
4
6
  class Code
5
- attr_accessor :pre_auth, :resource_owner, :token
7
+ attr_reader :pre_auth, :resource_owner, :token
6
8
 
7
9
  def initialize(pre_auth, resource_owner)
8
- @pre_auth = pre_auth
10
+ @pre_auth = pre_auth
9
11
  @resource_owner = resource_owner
10
12
  end
11
13
 
12
- def issue_token
13
- @token ||= AccessGrant.create!(
14
+ def issue_token!
15
+ return @token if defined?(@token)
16
+
17
+ @token = Doorkeeper.config.access_grant_model.create!(access_grant_attributes)
18
+ end
19
+
20
+ def oob_redirect
21
+ { action: :show, code: token.plaintext_token }
22
+ end
23
+
24
+ def access_grant?
25
+ true
26
+ end
27
+
28
+ private
29
+
30
+ def authorization_code_expires_in
31
+ Doorkeeper.config.authorization_code_expires_in
32
+ end
33
+
34
+ def access_grant_attributes
35
+ attributes = {
14
36
  application_id: pre_auth.client.id,
15
- resource_owner_id: resource_owner.id,
16
- expires_in: configuration.authorization_code_expires_in,
37
+ expires_in: authorization_code_expires_in,
17
38
  redirect_uri: pre_auth.redirect_uri,
18
- scopes: pre_auth.scopes.to_s
19
- )
39
+ scopes: pre_auth.scopes.to_s,
40
+ }
41
+
42
+ if Doorkeeper.config.polymorphic_resource_owner?
43
+ attributes[:resource_owner] = resource_owner
44
+ else
45
+ attributes[:resource_owner_id] = resource_owner.id
46
+ end
47
+
48
+ pkce_attributes.merge(attributes).merge(custom_attributes)
49
+ end
50
+
51
+ def custom_attributes
52
+ # Custom access token attributes are saved into the access grant,
53
+ # and then included in subsequently generated access tokens.
54
+ @pre_auth.custom_access_token_attributes.to_h.with_indifferent_access
20
55
  end
21
56
 
22
- def native_redirect
23
- { action: :show, code: token.token }
57
+ def pkce_attributes
58
+ return {} unless pkce_supported?
59
+
60
+ {
61
+ code_challenge: pre_auth.code_challenge,
62
+ code_challenge_method: pre_auth.code_challenge_method,
63
+ }
24
64
  end
25
65
 
26
- def configuration
27
- Doorkeeper.configuration
66
+ # Ensures firstly, if migration with additional PKCE columns was
67
+ # generated and migrated
68
+ def pkce_supported?
69
+ Doorkeeper.config.access_grant_model.pkce_supported?
28
70
  end
29
71
  end
30
72
  end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Doorkeeper
4
+ module OAuth
5
+ module Authorization
6
+ class Context
7
+ attr_reader :client, :grant_type, :resource_owner, :scopes
8
+
9
+ def initialize(**attributes)
10
+ attributes.each do |name, value|
11
+ instance_variable_set(:"@#{name}", value) if respond_to?(name)
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -1,54 +1,98 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doorkeeper
2
4
  module OAuth
3
5
  module Authorization
4
6
  class Token
5
- attr_accessor :pre_auth, :resource_owner, :token
7
+ attr_reader :pre_auth, :resource_owner, :token
8
+
9
+ class << self
10
+ def build_context(pre_auth_or_oauth_client, grant_type, scopes, resource_owner)
11
+ oauth_client = if pre_auth_or_oauth_client.respond_to?(:application)
12
+ pre_auth_or_oauth_client.application
13
+ elsif pre_auth_or_oauth_client.respond_to?(:client)
14
+ pre_auth_or_oauth_client.client
15
+ else
16
+ pre_auth_or_oauth_client
17
+ end
18
+
19
+ Doorkeeper::OAuth::Authorization::Context.new(
20
+ client: oauth_client,
21
+ grant_type: grant_type,
22
+ scopes: scopes,
23
+ resource_owner: resource_owner,
24
+ )
25
+ end
26
+
27
+ def access_token_expires_in(configuration, context)
28
+ if configuration.option_defined?(:custom_access_token_expires_in)
29
+ expiration = configuration.custom_access_token_expires_in.call(context)
30
+ return nil if expiration == Float::INFINITY
31
+
32
+ expiration || configuration.access_token_expires_in
33
+ else
34
+ configuration.access_token_expires_in
35
+ end
36
+ end
37
+
38
+ def refresh_token_enabled?(server, context)
39
+ if server.refresh_token_enabled?.respond_to?(:call)
40
+ server.refresh_token_enabled?.call(context)
41
+ else
42
+ !!server.refresh_token_enabled?
43
+ end
44
+ end
45
+ end
6
46
 
7
47
  def initialize(pre_auth, resource_owner)
8
48
  @pre_auth = pre_auth
9
49
  @resource_owner = resource_owner
10
50
  end
11
51
 
12
- def self.access_token_expires_in(server, pre_auth_or_oauth_client)
13
- if expiration = custom_expiration(server, pre_auth_or_oauth_client)
14
- expiration
15
- else
16
- server.access_token_expires_in
17
- end
18
- end
52
+ def issue_token!
53
+ return @token if defined?(@token)
19
54
 
20
- def issue_token
21
- @token ||= AccessToken.find_or_create_for(
55
+ context = self.class.build_context(
22
56
  pre_auth.client,
23
- resource_owner.id,
57
+ Doorkeeper::OAuth::IMPLICIT,
24
58
  pre_auth.scopes,
25
- self.class.access_token_expires_in(configuration, pre_auth),
26
- false
59
+ resource_owner,
27
60
  )
61
+
62
+ @token = Doorkeeper.config.access_token_model.find_or_create_for(
63
+ application: application,
64
+ resource_owner: resource_owner,
65
+ scopes: pre_auth.scopes,
66
+ expires_in: self.class.access_token_expires_in(Doorkeeper.config, context),
67
+ use_refresh_token: false,
68
+ )
69
+ end
70
+
71
+ def application
72
+ return unless pre_auth.client
73
+
74
+ pre_auth.client.is_a?(Doorkeeper.config.application_model) ? pre_auth.client : pre_auth.client.application
28
75
  end
29
76
 
30
- def native_redirect
77
+ def oob_redirect
31
78
  {
32
- controller: 'doorkeeper/token_info',
79
+ controller: controller,
33
80
  action: :show,
34
- access_token: token.token
81
+ access_token: token.plaintext_token,
35
82
  }
36
83
  end
37
84
 
38
- private
39
-
40
- def self.custom_expiration(server, pre_auth_or_oauth_client)
41
- oauth_client = if pre_auth_or_oauth_client.respond_to?(:client)
42
- pre_auth_or_oauth_client.client
43
- else
44
- pre_auth_or_oauth_client
45
- end
46
-
47
- server.custom_access_token_expires_in.call(oauth_client)
85
+ def access_token?
86
+ true
48
87
  end
49
88
 
50
- def configuration
51
- Doorkeeper.configuration
89
+ private
90
+
91
+ def controller
92
+ @controller ||= begin
93
+ mapping = Doorkeeper::Rails::Routes.mapping[:token_info] || {}
94
+ mapping[:controllers] || "doorkeeper/token_info"
95
+ end
52
96
  end
53
97
  end
54
98
  end