doorkeeper 4.2.6 → 5.0.0.rc1

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 (205) hide show
  1. checksums.yaml +4 -4
  2. data/.github/ISSUE_TEMPLATE.md +25 -0
  3. data/.github/PULL_REQUEST_TEMPLATE.md +17 -0
  4. data/.gitignore +2 -1
  5. data/.hound.yml +2 -13
  6. data/.rubocop.yml +17 -0
  7. data/.travis.yml +19 -5
  8. data/Appraisals +8 -4
  9. data/CODE_OF_CONDUCT.md +46 -0
  10. data/Gemfile +1 -1
  11. data/NEWS.md +77 -0
  12. data/README.md +169 -34
  13. data/Rakefile +6 -0
  14. data/SECURITY.md +15 -0
  15. data/app/assets/stylesheets/doorkeeper/admin/application.css +2 -2
  16. data/app/controllers/doorkeeper/application_controller.rb +2 -5
  17. data/app/controllers/doorkeeper/application_metal_controller.rb +4 -0
  18. data/app/controllers/doorkeeper/applications_controller.rb +47 -13
  19. data/app/controllers/doorkeeper/authorizations_controller.rb +55 -12
  20. data/app/controllers/doorkeeper/authorized_applications_controller.rb +15 -1
  21. data/app/controllers/doorkeeper/tokens_controller.rb +15 -7
  22. data/app/helpers/doorkeeper/dashboard_helper.rb +8 -6
  23. data/app/validators/redirect_uri_validator.rb +13 -2
  24. data/app/views/doorkeeper/applications/_delete_form.html.erb +3 -1
  25. data/app/views/doorkeeper/applications/_form.html.erb +31 -19
  26. data/app/views/doorkeeper/applications/edit.html.erb +1 -1
  27. data/app/views/doorkeeper/applications/index.html.erb +18 -6
  28. data/app/views/doorkeeper/applications/new.html.erb +1 -1
  29. data/app/views/doorkeeper/applications/show.html.erb +8 -5
  30. data/app/views/doorkeeper/authorizations/error.html.erb +1 -1
  31. data/app/views/doorkeeper/authorizations/new.html.erb +4 -0
  32. data/app/views/doorkeeper/authorized_applications/index.html.erb +0 -1
  33. data/app/views/layouts/doorkeeper/admin.html.erb +15 -15
  34. data/config/locales/en.yml +18 -6
  35. data/doorkeeper.gemspec +6 -5
  36. data/gemfiles/rails_4_2.gemfile +6 -4
  37. data/gemfiles/rails_5_0.gemfile +4 -4
  38. data/gemfiles/rails_5_1.gemfile +6 -7
  39. data/gemfiles/rails_5_2.gemfile +12 -0
  40. data/gemfiles/rails_master.gemfile +14 -0
  41. data/lib/doorkeeper/config.rb +107 -68
  42. data/lib/doorkeeper/engine.rb +7 -3
  43. data/lib/doorkeeper/errors.rb +2 -5
  44. data/lib/doorkeeper/grape/helpers.rb +14 -9
  45. data/lib/doorkeeper/helpers/controller.rb +15 -6
  46. data/lib/doorkeeper/models/access_grant_mixin.rb +52 -23
  47. data/lib/doorkeeper/models/access_token_mixin.rb +51 -52
  48. data/lib/doorkeeper/models/application_mixin.rb +16 -30
  49. data/lib/doorkeeper/models/concerns/expirable.rb +7 -5
  50. data/lib/doorkeeper/models/concerns/orderable.rb +13 -0
  51. data/lib/doorkeeper/models/concerns/scopes.rb +1 -1
  52. data/lib/doorkeeper/oauth/authorization/code.rb +31 -8
  53. data/lib/doorkeeper/oauth/authorization/context.rb +15 -0
  54. data/lib/doorkeeper/oauth/authorization/token.rb +41 -20
  55. data/lib/doorkeeper/oauth/authorization_code_request.rb +33 -3
  56. data/lib/doorkeeper/oauth/base_request.rb +22 -7
  57. data/lib/doorkeeper/oauth/client/credentials.rb +6 -4
  58. data/lib/doorkeeper/oauth/client.rb +2 -2
  59. data/lib/doorkeeper/oauth/client_credentials/issuer.rb +6 -1
  60. data/lib/doorkeeper/oauth/client_credentials/validation.rb +4 -2
  61. data/lib/doorkeeper/oauth/error.rb +2 -2
  62. data/lib/doorkeeper/oauth/error_response.rb +11 -4
  63. data/lib/doorkeeper/oauth/forbidden_token_response.rb +1 -1
  64. data/lib/doorkeeper/oauth/helpers/scope_checker.rb +0 -8
  65. data/lib/doorkeeper/oauth/helpers/uri_checker.rb +15 -0
  66. data/lib/doorkeeper/oauth/invalid_token_response.rb +3 -4
  67. data/lib/doorkeeper/oauth/password_access_token_request.rb +8 -4
  68. data/lib/doorkeeper/oauth/pre_authorization.rb +45 -13
  69. data/lib/doorkeeper/oauth/refresh_token_request.rb +7 -1
  70. data/lib/doorkeeper/oauth/scopes.rb +19 -9
  71. data/lib/doorkeeper/oauth/token.rb +6 -3
  72. data/lib/doorkeeper/oauth/token_introspection.rb +128 -0
  73. data/lib/doorkeeper/oauth/token_response.rb +4 -2
  74. data/lib/doorkeeper/oauth.rb +13 -0
  75. data/lib/doorkeeper/orm/active_record/access_grant.rb +27 -0
  76. data/lib/doorkeeper/orm/active_record/access_token.rb +21 -20
  77. data/lib/doorkeeper/orm/active_record/application.rb +34 -0
  78. data/lib/doorkeeper/orm/active_record/stale_records_cleaner.rb +26 -0
  79. data/lib/doorkeeper/orm/active_record.rb +21 -8
  80. data/lib/doorkeeper/rails/helpers.rb +7 -10
  81. data/lib/doorkeeper/rails/routes.rb +21 -7
  82. data/lib/doorkeeper/rake/db.rake +40 -0
  83. data/lib/doorkeeper/rake/setup.rake +6 -0
  84. data/lib/doorkeeper/rake.rb +14 -0
  85. data/lib/doorkeeper/request/password.rb +1 -11
  86. data/lib/doorkeeper/request.rb +29 -23
  87. data/lib/doorkeeper/validations.rb +3 -2
  88. data/lib/doorkeeper/version.rb +14 -1
  89. data/lib/doorkeeper.rb +6 -17
  90. data/lib/generators/doorkeeper/application_owner_generator.rb +26 -12
  91. data/lib/generators/doorkeeper/confidential_applications_generator.rb +32 -0
  92. data/lib/generators/doorkeeper/install_generator.rb +17 -9
  93. data/lib/generators/doorkeeper/migration_generator.rb +26 -9
  94. data/lib/generators/doorkeeper/pkce_generator.rb +32 -0
  95. data/lib/generators/doorkeeper/previous_refresh_token_generator.rb +31 -20
  96. data/lib/generators/doorkeeper/templates/add_confidential_to_applications.rb.erb +13 -0
  97. data/lib/generators/doorkeeper/templates/{add_owner_to_application_migration.rb → add_owner_to_application_migration.rb.erb} +1 -1
  98. data/lib/generators/doorkeeper/templates/{add_previous_refresh_token_to_access_tokens.rb → add_previous_refresh_token_to_access_tokens.rb.erb} +1 -1
  99. data/lib/generators/doorkeeper/templates/enable_pkce_migration.rb.erb +6 -0
  100. data/lib/generators/doorkeeper/templates/initializer.rb +88 -10
  101. data/lib/generators/doorkeeper/templates/{migration.rb → migration.rb.erb} +2 -1
  102. data/lib/generators/doorkeeper/views_generator.rb +3 -1
  103. data/spec/controllers/application_metal_controller_spec.rb +50 -0
  104. data/spec/controllers/applications_controller_spec.rb +141 -17
  105. data/spec/controllers/authorizations_controller_spec.rb +255 -20
  106. data/spec/controllers/protected_resources_controller_spec.rb +44 -35
  107. data/spec/controllers/token_info_controller_spec.rb +17 -21
  108. data/spec/controllers/tokens_controller_spec.rb +142 -10
  109. data/spec/dummy/app/assets/config/manifest.js +2 -0
  110. data/spec/dummy/config/environments/test.rb +4 -5
  111. data/spec/dummy/config/initializers/doorkeeper.rb +18 -1
  112. data/spec/dummy/config/initializers/{active_record_belongs_to_required_by_default.rb → new_framework_defaults.rb} +5 -1
  113. data/spec/dummy/config/initializers/secret_token.rb +0 -1
  114. data/spec/dummy/config/routes.rb +3 -42
  115. data/spec/dummy/db/migrate/20111122132257_create_users.rb +3 -1
  116. data/spec/dummy/db/migrate/20120312140401_add_password_to_users.rb +3 -1
  117. data/spec/dummy/db/migrate/20151223192035_create_doorkeeper_tables.rb +3 -1
  118. data/spec/dummy/db/migrate/20151223200000_add_owner_to_application.rb +3 -1
  119. data/spec/dummy/db/migrate/20160320211015_add_previous_refresh_token_to_access_tokens.rb +3 -1
  120. data/spec/dummy/db/migrate/20170822064514_enable_pkce.rb +6 -0
  121. data/spec/dummy/db/migrate/20180210183654_add_confidential_to_applications.rb +13 -0
  122. data/spec/dummy/db/schema.rb +38 -37
  123. data/spec/factories.rb +1 -1
  124. data/spec/generators/application_owner_generator_spec.rb +25 -6
  125. data/spec/generators/confidential_applications_generator_spec.rb +45 -0
  126. data/spec/generators/install_generator_spec.rb +1 -1
  127. data/spec/generators/migration_generator_spec.rb +25 -4
  128. data/spec/generators/pkce_generator_spec.rb +43 -0
  129. data/spec/generators/previous_refresh_token_generator_spec.rb +57 -0
  130. data/spec/generators/views_generator_spec.rb +1 -1
  131. data/spec/grape/grape_integration_spec.rb +135 -0
  132. data/spec/helpers/doorkeeper/dashboard_helper_spec.rb +2 -2
  133. data/spec/lib/config_spec.rb +170 -22
  134. data/spec/lib/doorkeeper_spec.rb +1 -126
  135. data/spec/lib/models/expirable_spec.rb +0 -3
  136. data/spec/lib/models/revocable_spec.rb +2 -4
  137. data/spec/lib/models/scopes_spec.rb +0 -4
  138. data/spec/lib/oauth/authorization/uri_builder_spec.rb +0 -4
  139. data/spec/lib/oauth/authorization_code_request_spec.rb +63 -13
  140. data/spec/lib/oauth/base_request_spec.rb +19 -10
  141. data/spec/lib/oauth/base_response_spec.rb +1 -1
  142. data/spec/lib/oauth/client/credentials_spec.rb +5 -5
  143. data/spec/lib/oauth/client_credentials/creator_spec.rb +6 -2
  144. data/spec/lib/oauth/client_credentials/issuer_spec.rb +26 -7
  145. data/spec/lib/oauth/client_credentials/validation_spec.rb +2 -3
  146. data/spec/lib/oauth/client_credentials_integration_spec.rb +2 -2
  147. data/spec/lib/oauth/client_credentials_request_spec.rb +4 -5
  148. data/spec/lib/oauth/client_spec.rb +0 -3
  149. data/spec/lib/oauth/code_request_spec.rb +5 -5
  150. data/spec/lib/oauth/error_response_spec.rb +0 -3
  151. data/spec/lib/oauth/error_spec.rb +1 -3
  152. data/spec/lib/oauth/forbidden_token_response_spec.rb +1 -4
  153. data/spec/lib/oauth/helpers/scope_checker_spec.rb +0 -3
  154. data/spec/lib/oauth/helpers/unique_token_spec.rb +0 -1
  155. data/spec/lib/oauth/helpers/uri_checker_spec.rb +115 -3
  156. data/spec/lib/oauth/invalid_token_response_spec.rb +2 -5
  157. data/spec/lib/oauth/password_access_token_request_spec.rb +46 -5
  158. data/spec/lib/oauth/pre_authorization_spec.rb +40 -6
  159. data/spec/lib/oauth/refresh_token_request_spec.rb +30 -14
  160. data/spec/lib/oauth/scopes_spec.rb +28 -4
  161. data/spec/lib/oauth/token_request_spec.rb +10 -13
  162. data/spec/lib/oauth/token_response_spec.rb +0 -1
  163. data/spec/lib/oauth/token_spec.rb +37 -14
  164. data/spec/lib/orm/active_record/stale_records_cleaner_spec.rb +79 -0
  165. data/spec/lib/request/strategy_spec.rb +0 -1
  166. data/spec/lib/server_spec.rb +10 -0
  167. data/spec/models/doorkeeper/access_grant_spec.rb +2 -2
  168. data/spec/models/doorkeeper/access_token_spec.rb +118 -60
  169. data/spec/models/doorkeeper/application_spec.rb +101 -23
  170. data/spec/requests/applications/applications_request_spec.rb +94 -6
  171. data/spec/requests/applications/authorized_applications_spec.rb +1 -1
  172. data/spec/requests/endpoints/authorization_spec.rb +1 -1
  173. data/spec/requests/endpoints/token_spec.rb +15 -6
  174. data/spec/requests/flows/authorization_code_errors_spec.rb +1 -1
  175. data/spec/requests/flows/authorization_code_spec.rb +198 -1
  176. data/spec/requests/flows/client_credentials_spec.rb +73 -5
  177. data/spec/requests/flows/implicit_grant_errors_spec.rb +3 -3
  178. data/spec/requests/flows/implicit_grant_spec.rb +38 -11
  179. data/spec/requests/flows/password_spec.rb +160 -24
  180. data/spec/requests/flows/refresh_token_spec.rb +6 -6
  181. data/spec/requests/flows/revoke_token_spec.rb +26 -26
  182. data/spec/requests/flows/skip_authorization_spec.rb +16 -11
  183. data/spec/requests/protected_resources/metal_spec.rb +2 -2
  184. data/spec/requests/protected_resources/private_api_spec.rb +2 -2
  185. data/spec/routing/custom_controller_routes_spec.rb +63 -7
  186. data/spec/routing/default_routes_spec.rb +6 -2
  187. data/spec/routing/scoped_routes_spec.rb +16 -2
  188. data/spec/spec_helper.rb +54 -3
  189. data/spec/spec_helper_integration.rb +2 -63
  190. data/spec/support/dependencies/factory_bot.rb +2 -0
  191. data/spec/support/doorkeeper_rspec.rb +19 -0
  192. data/spec/support/helpers/access_token_request_helper.rb +1 -1
  193. data/spec/support/helpers/authorization_request_helper.rb +4 -4
  194. data/spec/support/helpers/model_helper.rb +9 -4
  195. data/spec/support/helpers/request_spec_helper.rb +10 -6
  196. data/spec/support/helpers/url_helper.rb +15 -10
  197. data/spec/support/http_method_shim.rb +12 -16
  198. data/spec/support/shared/controllers_shared_context.rb +2 -6
  199. data/spec/support/shared/models_shared_examples.rb +4 -4
  200. data/spec/validators/redirect_uri_validator_spec.rb +58 -7
  201. data/spec/version/version_spec.rb +15 -0
  202. data/vendor/assets/stylesheets/doorkeeper/bootstrap.min.css +4 -5
  203. metadata +73 -19
  204. data/spec/controllers/application_metal_controller.rb +0 -10
  205. data/spec/support/dependencies/factory_girl.rb +0 -2
data/README.md CHANGED
@@ -1,16 +1,27 @@
1
- # Doorkeeper - awesome OAuth2 provider for your Rails app.
1
+ # Doorkeeper - awesome OAuth 2 provider for your Rails app.
2
2
 
3
+ [![Gem Version](https://badge.fury.io/rb/doorkeeper.svg)](https://rubygems.org/gems/doorkeeper)
3
4
  [![Build Status](https://travis-ci.org/doorkeeper-gem/doorkeeper.svg?branch=master)](https://travis-ci.org/doorkeeper-gem/doorkeeper)
4
5
  [![Dependency Status](https://gemnasium.com/doorkeeper-gem/doorkeeper.svg?travis)](https://gemnasium.com/doorkeeper-gem/doorkeeper)
5
6
  [![Code Climate](https://codeclimate.com/github/doorkeeper-gem/doorkeeper.svg)](https://codeclimate.com/github/doorkeeper-gem/doorkeeper)
6
- [![Gem Version](https://badge.fury.io/rb/doorkeeper.svg)](https://rubygems.org/gems/doorkeeper)
7
+ [![Coverage Status](https://coveralls.io/repos/github/doorkeeper-gem/doorkeeper/badge.svg?branch=master)](https://coveralls.io/github/doorkeeper-gem/doorkeeper?branch=master)
7
8
  [![Security](https://hakiri.io/github/doorkeeper-gem/doorkeeper/master.svg)](https://hakiri.io/github/doorkeeper-gem/doorkeeper/master)
8
9
 
9
10
  Doorkeeper is a gem that makes it easy to introduce OAuth 2 provider
10
11
  functionality to your Rails or Grape application.
11
12
 
12
- [PR 567]: https://github.com/doorkeeper-gem/doorkeeper/pull/567
13
+ Supported features:
13
14
 
15
+ - [The OAuth 2.0 Authorization Framework](https://tools.ietf.org/html/rfc6749)
16
+ - [Authorization Code Flow](http://tools.ietf.org/html/draft-ietf-oauth-v2-22#section-4.1)
17
+ - [Access Token Scopes](http://tools.ietf.org/html/draft-ietf-oauth-v2-22#section-3.3)
18
+ - [Refresh token](http://tools.ietf.org/html/draft-ietf-oauth-v2-22#section-1.5)
19
+ - [Implicit grant](http://tools.ietf.org/html/draft-ietf-oauth-v2-22#section-4.2)
20
+ - [Resource Owner Password Credentials](http://tools.ietf.org/html/draft-ietf-oauth-v2-22#section-4.3)
21
+ - [Client Credentials](http://tools.ietf.org/html/draft-ietf-oauth-v2-22#section-4.4)
22
+ - [Proof Key for Code Exchange](https://tools.ietf.org/html/rfc7636)
23
+ - [OAuth 2.0 Token Revocation](http://tools.ietf.org/html/rfc7009)
24
+ - [OAuth 2.0 Token Introspection](https://tools.ietf.org/html/rfc7662)
14
25
 
15
26
  ## Documentation valid for `master` branch
16
27
 
@@ -18,7 +29,10 @@ Please check the documentation for the version of doorkeeper you are using in:
18
29
  https://github.com/doorkeeper-gem/doorkeeper/releases
19
30
 
20
31
  - See the [wiki](https://github.com/doorkeeper-gem/doorkeeper/wiki)
32
+ - See [upgrade guides](https://github.com/doorkeeper-gem/doorkeeper/wiki/Migration-from-old-versions)
21
33
  - For general questions, please post in [Stack Overflow](http://stackoverflow.com/questions/tagged/doorkeeper)
34
+ - See [SECURITY.md](SECURITY.md) for this project's security disclose
35
+ policy
22
36
 
23
37
  ## Table of Contents
24
38
 
@@ -27,19 +41,26 @@ https://github.com/doorkeeper-gem/doorkeeper/releases
27
41
 
28
42
  - [Installation](#installation)
29
43
  - [Configuration](#configuration)
30
- - [Active Record](#active-record)
31
- - [Other ORMs](#other-orms)
44
+ - [ORM](#orm)
45
+ - [Active Record](#active-record)
46
+ - [MongoDB](#mongodb)
47
+ - [Sequel](#sequel)
48
+ - [Couchbase](#couchbase)
49
+ - [API mode](#api-mode)
32
50
  - [Routes](#routes)
33
51
  - [Authenticating](#authenticating)
34
52
  - [Internationalization (I18n)](#internationalization-i18n)
53
+ - [Rake Tasks](#rake-tasks)
35
54
  - [Protecting resources with OAuth (a.k.a your API endpoint)](#protecting-resources-with-oauth-aka-your-api-endpoint)
36
- - [Protect your API with OAuth when using Grape](#protect-your-api-with-oauth-when-using-grape)
55
+ - [Ruby on Rails controllers](#ruby-on-rails-controllers)
56
+ - [Grape endpoints](#grape-endpoints)
37
57
  - [Route Constraints and other integrations](#route-constraints-and-other-integrations)
38
58
  - [Access Token Scopes](#access-token-scopes)
39
59
  - [Custom Access Token Generator](#custom-access-token-generator)
40
60
  - [Authenticated resource owner](#authenticated-resource-owner)
41
61
  - [Applications list](#applications-list)
42
62
  - [Other customizations](#other-customizations)
63
+ - [Testing](#testing)
43
64
  - [Upgrading](#upgrading)
44
65
  - [Development](#development)
45
66
  - [Contributing](#contributing)
@@ -69,10 +90,12 @@ This will install the doorkeeper initializer into `config/initializers/doorkeepe
69
90
 
70
91
  ## Configuration
71
92
 
72
- ### Active Record
93
+ ### ORM
73
94
 
74
- By default doorkeeper is configured to use active record, so to start you have
75
- to generate the migration tables:
95
+ #### Active Record
96
+
97
+ By default doorkeeper is configured to use Active Record, so to start you have
98
+ to generate the migration tables (supports Rails >= 5 migrations versioning):
76
99
 
77
100
  rails generate doorkeeper:migration
78
101
 
@@ -84,25 +107,82 @@ for each table that includes a `resource_owner_id` column:
84
107
  add_foreign_key :table_name, :users, column: :resource_owner_id
85
108
  ```
86
109
 
110
+ If you want to enable [PKCE flow] for mobile apps, you need to generate another
111
+ migration:
112
+
113
+ [PKCE flow]: https://tools.ietf.org/html/rfc7636
114
+
115
+ ```sh
116
+ rails generate doorkeeper:pkce
117
+ ```
118
+
87
119
  Then run migrations:
88
120
 
89
121
  ```sh
90
122
  rake db:migrate
91
123
  ```
92
124
 
93
- ### Other ORMs
125
+ Ensure to use non-confidential apps for pkce. PKCE is created, because
126
+ you cannot trust its apps' secret. So whatever app needs pkce: it means, it cannot
127
+ be a confidential app by design.
128
+
129
+
130
+ Remember to add associations to your model so the related records are deleted.
131
+ If you don't do this an `ActiveRecord::InvalidForeignKey`-error will be raised
132
+ when you try to destroy a model with related access grants or access tokens.
133
+
134
+ ```ruby
135
+ class User < ApplicationRecord
136
+ has_many :access_grants, class_name: "Doorkeeper::AccessGrant",
137
+ foreign_key: :resource_owner_id,
138
+ dependent: :delete_all # or :destroy if you need callbacks
139
+
140
+ has_many :access_tokens, class_name: "Doorkeeper::AccessToken",
141
+ foreign_key: :resource_owner_id,
142
+ dependent: :delete_all # or :destroy if you need callbacks
143
+ end
144
+ ```
145
+
146
+ #### MongoDB
94
147
 
95
148
  See [doorkeeper-mongodb project] for Mongoid and MongoMapper support. Follow along
96
149
  the implementation in that repository to extend doorkeeper with other ORMs.
97
150
 
98
151
  [doorkeeper-mongodb project]: https://github.com/doorkeeper-gem/doorkeeper-mongodb
99
152
 
153
+ #### Sequel
154
+
100
155
  If you are using [Sequel gem] then you can add [doorkeeper-sequel extension] to your project.
101
156
  Follow configuration instructions for setting up the necessary Doorkeeper ORM.
102
157
 
103
158
  [Sequel gem]: https://github.com/jeremyevans/sequel/
104
159
  [doorkeeper-sequel extension]: https://github.com/nbulaj/doorkeeper-sequel
105
160
 
161
+ #### Couchbase
162
+
163
+ Use [doorkeeper-couchbase] extension if you are using Couchbase database.
164
+
165
+ [doorkeeper-couchbase]: https://github.com/acaprojects/doorkeeper-couchbase
166
+
167
+ ### API mode
168
+
169
+ By default Doorkeeper uses full Rails stack to provide all the OAuth 2 functionality
170
+ with additional features like administration area for managing applications. By the
171
+ way, starting from Doorkeeper 5 you can use API mode for your [API only Rails 5 applications](http://edgeguides.rubyonrails.org/api_app.html).
172
+ All you need is just to configure the gem to work in desired mode:
173
+
174
+ ``` ruby
175
+ Doorkeeper.configure do
176
+ # ...
177
+
178
+ api_only
179
+ end
180
+ ```
181
+
182
+ Keep in mind, that in this mode you will not be able to access `Applications` or
183
+ `Authorized Applications` controllers because they will be skipped. Also all the
184
+ redirects will be returned as JSON response with corresponding locations.
185
+
106
186
  ### Routes
107
187
 
108
188
  The installation script will also automatically add the Doorkeeper routes into
@@ -117,12 +197,13 @@ end
117
197
 
118
198
  This will mount following routes:
119
199
 
120
- GET /oauth/authorize/:code
200
+ GET /oauth/authorize/native?code
121
201
  GET /oauth/authorize
122
202
  POST /oauth/authorize
123
203
  DELETE /oauth/authorize
124
204
  POST /oauth/token
125
205
  POST /oauth/revoke
206
+ POST /oauth/introspect
126
207
  resources /oauth/applications
127
208
  GET /oauth/authorized_applications
128
209
  DELETE /oauth/authorized_applications/:id
@@ -139,7 +220,7 @@ and authentication block in `config/initializers/doorkeeper.rb`:
139
220
  ``` ruby
140
221
  Doorkeeper.configure do
141
222
  resource_owner_authenticator do
142
- User.find_by_id(session[:current_user_id]) || redirect_to(login_url)
223
+ User.find_by(id: session[:current_user_id]) || redirect_to(login_url)
143
224
  end
144
225
  end
145
226
  ```
@@ -152,16 +233,46 @@ the methods defined over there.
152
233
  You may want to check other ways of authentication
153
234
  [here](https://github.com/doorkeeper-gem/doorkeeper/wiki/Authenticating-using-Clearance-or-DIY).
154
235
 
155
-
156
236
  ### Internationalization (I18n)
157
237
 
158
- See language files in [the I18n repository](https://github.com/doorkeeper-gem/doorkeeper-i18n).
238
+ Doorkeeper support multiple languages. See language files in
239
+ [the I18n repository](https://github.com/doorkeeper-gem/doorkeeper-i18n).
240
+
241
+ ### Rake Tasks
242
+
243
+ If you are using `rake`, you can load rake tasks provided by this gem, by adding
244
+ the following line to your `Rakefile`:
245
+
246
+ ```ruby
247
+ Doorkeeper::Rake.load_tasks
248
+ ```
249
+
250
+ #### Cleaning up
159
251
 
252
+ By default Doorkeeper is retaining expired and revoked access tokens and grants.
253
+ This allows to keep an audit log of those records, but it also leads to the
254
+ corresponding tables to grow large over the lifetime of your application.
255
+
256
+ If you are concerned about those tables growing too large,
257
+ you can regularly run the following rake task to remove stale entries
258
+ from the database:
259
+
260
+ ```rake
261
+ rake doorkeeper:db:cleanup
262
+ ```
263
+
264
+ Note that this will remove tokens that are expired according to the configured TTL
265
+ in `Doorkeeper.configuration.access_token_expires_in`. The specific `expires_in`
266
+ value of each access token **is not considered**. The same is true for access
267
+ grants.
160
268
 
161
269
  ## Protecting resources with OAuth (a.k.a your API endpoint)
162
270
 
163
- To protect your API with OAuth, you just need to setup `before_action`s
164
- specifying the actions you want to protect. For example:
271
+ ### Ruby on Rails controllers
272
+
273
+ To protect your controllers (usual one or `ActionController::API`) with OAuth,
274
+ you just need to setup `before_action`s specifying the actions you want to
275
+ protect. For example:
165
276
 
166
277
  ``` ruby
167
278
  class Api::V1::ProductsController < Api::V1::ApiController
@@ -174,16 +285,17 @@ end
174
285
  You can pass any option `before_action` accepts, such as `if`, `only`,
175
286
  `except`, and others.
176
287
 
177
- ### Protect your API with OAuth when using Grape
288
+ ### Grape endpoints
178
289
 
179
- As of [PR 567] doorkeeper has helpers for Grape >= 0.10. One of them is
180
- `doorkeeper_authorize!` and can be used in a similar way as an example above.
181
- Note that you have to use `require 'doorkeeper/grape/helpers'` and
182
- `helpers Doorkeeper::Grape::Helpers`.
290
+ Starting from version 2.2 Doorkeeper provides helpers for the
291
+ [Grape framework] >= 0.10. One of them is `doorkeeper_authorize!` that
292
+ can be used in a similar way as an example above to protect your API
293
+ with OAuth. Note that you have to use `require 'doorkeeper/grape/helpers'`
294
+ and `helpers Doorkeeper::Grape::Helpers` in your Grape API class.
183
295
 
184
296
  For more information about integration with Grape see the [Wiki].
185
297
 
186
- [PR 567]: https://github.com/doorkeeper-gem/doorkeeper/pull/567
298
+ [Grape framework]: https://github.com/ruby-grape/grape
187
299
  [Wiki]: https://github.com/doorkeeper-gem/doorkeeper/wiki/Grape-Integration
188
300
 
189
301
  ``` ruby
@@ -198,8 +310,8 @@ module API
198
310
  doorkeeper_authorize!
199
311
  end
200
312
 
201
- route_setting :scopes, ['user:email']
202
- get :emails do
313
+ # route_setting :scopes, ['user:email'] - for old versions of Grape
314
+ get :emails, scopes: [:user, :write] do
203
315
  [{'email' => current_user.email}]
204
316
  end
205
317
 
@@ -209,7 +321,6 @@ module API
209
321
  end
210
322
  ```
211
323
 
212
-
213
324
  ### Route Constraints and other integrations
214
325
 
215
326
  You can leverage the `Doorkeeper.authenticate` facade to easily extract a
@@ -224,7 +335,6 @@ module Constraint
224
335
  token = Doorkeeper.authenticate(request)
225
336
  token && token.accessible?
226
337
  end
227
-
228
338
  end
229
339
  end
230
340
  ```
@@ -296,8 +406,10 @@ JWT token support is available with
296
406
 
297
407
  ### Custom Base Controller
298
408
 
299
- By default Doorkeeper's main controller `Doorkeeper::ApplicationController` inherits from `ActionController::Base`.
300
- You may want to use your own controller to inherit from, to keep Doorkeeper controllers in the same context than the rest your app:
409
+ By default Doorkeeper's main controller `Doorkeeper::ApplicationController`
410
+ inherits from `ActionController::Base`. You may want to use your own
411
+ controller to inherit from, to keep Doorkeeper controllers in the same
412
+ context than the rest your app:
301
413
 
302
414
  ```ruby
303
415
  Doorkeeper.configure do
@@ -342,7 +454,7 @@ To protect the endpoint you should uncomment these lines:
342
454
  # config/initializers/doorkeeper.rb
343
455
  Doorkeeper.configure do
344
456
  admin_authenticator do |routes|
345
- Admin.find_by_id(session[:admin_id]) || redirect_to(routes.new_admin_session_url)
457
+ Admin.find_by(id: session[:admin_id]) || redirect_to(routes.new_admin_session_url)
346
458
  end
347
459
  end
348
460
  ```
@@ -353,10 +465,36 @@ customize the controller used by the list or skip the controller all together.
353
465
  For more information see the page
354
466
  [in the wiki](https://github.com/doorkeeper-gem/doorkeeper/wiki/Customizing-routes).
355
467
 
468
+ By default, everybody can create application with any scopes. However,
469
+ you can enforce users to create applications only with configured scopes
470
+ (`default_scopes` and `optional_scopes` from the Doorkeeper initializer):
471
+
472
+ ```ruby
473
+ # config/initializers/doorkeeper.rb
474
+ Doorkeeper.configure do
475
+ # ...
476
+
477
+ default_scopes :read, :write
478
+ optional_scopes :create, :update
479
+
480
+ enforce_configured_scopes
481
+ end
482
+ ```
483
+
356
484
  ## Other customizations
357
485
 
358
486
  - [Associate users to OAuth applications (ownership)](https://github.com/doorkeeper-gem/doorkeeper/wiki/Associate-users-to-OAuth-applications-%28ownership%29)
359
487
  - [CORS - Cross Origin Resource Sharing](https://github.com/doorkeeper-gem/doorkeeper/wiki/%5BCORS%5D-Cross-Origin-Resource-Sharing)
488
+ - see more on [Wiki page](https://github.com/doorkeeper-gem/doorkeeper/wiki)
489
+
490
+ ## Testing
491
+
492
+ You can use Doorkeeper models in your application test suite. Note that starting from
493
+ Doorkeeper 4.3.0 it uses [ActiveSupport lazy loading hooks](http://api.rubyonrails.org/classes/ActiveSupport/LazyLoadHooks.html)
494
+ to load models. There are [known issue](https://github.com/doorkeeper-gem/doorkeeper/issues/1043)
495
+ with the `factory_bot_rails` gem (it executes factories building before `ActiveRecord::Base`
496
+ is initialized using hooks in gem railtie, so you can catch a `uninitialized constant` error).
497
+ It is recommended to use pure `factory_bot` gem to solve this problem.
360
498
 
361
499
  ## Upgrading
362
500
 
@@ -373,7 +511,7 @@ To run the local engine server:
373
511
 
374
512
  ```
375
513
  bundle install
376
- bundle exec rails server
514
+ bundle exec rake doorkeeper:server
377
515
  ````
378
516
 
379
517
  By default, it uses the latest Rails version with ActiveRecord. To run the
@@ -383,8 +521,6 @@ tests with a specific ORM and Rails version:
383
521
  rails=4.2.0 orm=active_record bundle exec rake
384
522
  ```
385
523
 
386
- Or you might prefer to run `script/run_all` to integrate against all ORMs.
387
-
388
524
  ## Contributing
389
525
 
390
526
  Want to contribute and don't know where to start? Check out [features we're
@@ -400,7 +536,7 @@ page](https://github.com/doorkeeper-gem/doorkeeper/wiki/Contributing).
400
536
 
401
537
  ### Wiki
402
538
 
403
- You can find everything about doorkeeper in our [wiki
539
+ You can find everything about Doorkeeper in our [wiki
404
540
  here](https://github.com/doorkeeper-gem/doorkeeper/wiki).
405
541
 
406
542
  ### Screencast
@@ -422,7 +558,6 @@ here](https://github.com/doorkeeper-gem/doorkeeper/wiki/Testing-your-provider-wi
422
558
  Thanks to all our [awesome
423
559
  contributors](https://github.com/doorkeeper-gem/doorkeeper/graphs/contributors)!
424
560
 
425
-
426
561
  ### IETF Standards
427
562
 
428
563
  * [The OAuth 2.0 Authorization Framework](http://tools.ietf.org/html/rfc6749)
data/Rakefile CHANGED
@@ -15,6 +15,12 @@ namespace :doorkeeper do
15
15
  cd 'spec/dummy'
16
16
  system 'bundle exec rails g doorkeeper:install --force'
17
17
  end
18
+
19
+ desc 'Runs local test server'
20
+ task :server do
21
+ cd 'spec/dummy'
22
+ system 'bundle exec rails server'
23
+ end
18
24
  end
19
25
 
20
26
  Bundler::GemHelper.install_tasks
data/SECURITY.md ADDED
@@ -0,0 +1,15 @@
1
+ # Reporting security issues in Doorkeeper
2
+
3
+ Hello! Thank you for wanting to disclose a possible security
4
+ vulnerability within the Doorkeeper gem! Please follow our disclosure
5
+ policy as outlined below:
6
+
7
+ 1. Do NOT open up a GitHub issue with your report. Security reports
8
+ should be kept private until a possible fix is determined.
9
+ 2. Send an email to Nikita Bulai at bulaj.nikita AT gmail.com or one of
10
+ the others Doorkeeper maintainers listed in gemspec. You should receive
11
+ a prompt response.
12
+ 3. Be patient. Since Doorkeeper is in a stable maintenance phase, we want to
13
+ do as little as possible to rock the boat of the project.
14
+
15
+ Thank you very much for adhering for these policies!
@@ -5,6 +5,6 @@
5
5
  *= require_tree .
6
6
  */
7
7
 
8
- td {
9
- vertical-align: middle !important;
8
+ .doorkeeper-admin .form-group > .field_with_errors {
9
+ width: 16.66667%;
10
10
  }
@@ -4,12 +4,9 @@ module Doorkeeper
4
4
 
5
5
  include Helpers::Controller
6
6
 
7
- if ::Rails.version.to_i < 4
8
- protect_from_forgery
9
- else
7
+ unless Doorkeeper.configuration.api_only
10
8
  protect_from_forgery with: :exception
9
+ helper 'doorkeeper/dashboard'
11
10
  end
12
-
13
- helper 'doorkeeper/dashboard'
14
11
  end
15
12
  end
@@ -5,6 +5,7 @@ module Doorkeeper
5
5
  AbstractController::Rendering,
6
6
  ActionController::Rendering,
7
7
  ActionController::Renderers::All,
8
+ AbstractController::Callbacks,
8
9
  Helpers::Controller
9
10
  ].freeze
10
11
 
@@ -12,6 +13,9 @@ module Doorkeeper
12
13
  include mod
13
14
  end
14
15
 
16
+ before_action :enforce_content_type,
17
+ if: -> { Doorkeeper.configuration.enforce_content_type }
18
+
15
19
  ActiveSupport.run_load_hooks(:doorkeeper_metal_controller, self)
16
20
  end
17
21
  end
@@ -1,12 +1,24 @@
1
1
  module Doorkeeper
2
2
  class ApplicationsController < Doorkeeper::ApplicationController
3
- layout 'doorkeeper/admin'
3
+ layout 'doorkeeper/admin' unless Doorkeeper.configuration.api_only
4
4
 
5
5
  before_action :authenticate_admin!
6
- before_action :set_application, only: [:show, :edit, :update, :destroy]
6
+ before_action :set_application, only: %i[show edit update destroy]
7
7
 
8
8
  def index
9
- @applications = Application.all
9
+ @applications = Application.ordered_by(:created_at)
10
+
11
+ respond_to do |format|
12
+ format.html
13
+ format.json { head :no_content }
14
+ end
15
+ end
16
+
17
+ def show
18
+ respond_to do |format|
19
+ format.html
20
+ format.json { render json: @application }
21
+ end
10
22
  end
11
23
 
12
24
  def new
@@ -15,26 +27,47 @@ module Doorkeeper
15
27
 
16
28
  def create
17
29
  @application = Application.new(application_params)
30
+
18
31
  if @application.save
19
- flash[:notice] = I18n.t(:notice, scope: [:doorkeeper, :flash, :applications, :create])
20
- redirect_to oauth_application_url(@application)
32
+ flash[:notice] = I18n.t(:notice, scope: %i[doorkeeper flash applications create])
33
+
34
+ respond_to do |format|
35
+ format.html { redirect_to oauth_application_url(@application) }
36
+ format.json { render json: @application }
37
+ end
21
38
  else
22
- render :new
39
+ respond_to do |format|
40
+ format.html { render :new }
41
+ format.json { render json: { errors: @application.errors.full_messages }, status: :unprocessable_entity }
42
+ end
23
43
  end
24
44
  end
25
45
 
46
+ def edit; end
47
+
26
48
  def update
27
- if @application.update_attributes(application_params)
28
- flash[:notice] = I18n.t(:notice, scope: [:doorkeeper, :flash, :applications, :update])
29
- redirect_to oauth_application_url(@application)
49
+ if @application.update(application_params)
50
+ flash[:notice] = I18n.t(:notice, scope: %i[doorkeeper flash applications update])
51
+
52
+ respond_to do |format|
53
+ format.html { redirect_to oauth_application_url(@application) }
54
+ format.json { render json: @application }
55
+ end
30
56
  else
31
- render :edit
57
+ respond_to do |format|
58
+ format.html { render :edit }
59
+ format.json { render json: { errors: @application.errors.full_messages }, status: :unprocessable_entity }
60
+ end
32
61
  end
33
62
  end
34
63
 
35
64
  def destroy
36
- flash[:notice] = I18n.t(:notice, scope: [:doorkeeper, :flash, :applications, :destroy]) if @application.destroy
37
- redirect_to oauth_applications_url
65
+ flash[:notice] = I18n.t(:notice, scope: %i[doorkeeper flash applications destroy]) if @application.destroy
66
+
67
+ respond_to do |format|
68
+ format.html { redirect_to oauth_applications_url }
69
+ format.json { head :no_content }
70
+ end
38
71
  end
39
72
 
40
73
  private
@@ -44,7 +77,8 @@ module Doorkeeper
44
77
  end
45
78
 
46
79
  def application_params
47
- params.require(:doorkeeper_application).permit(:name, :redirect_uri, :scopes)
80
+ params.require(:doorkeeper_application).
81
+ permit(:name, :redirect_uri, :scopes, :confidential)
48
82
  end
49
83
  end
50
84
  end
@@ -4,20 +4,15 @@ module Doorkeeper
4
4
 
5
5
  def new
6
6
  if pre_auth.authorizable?
7
- if skip_authorization? || matching_token?
8
- auth = authorization.authorize
9
- redirect_to auth.redirect_uri
10
- else
11
- render :new
12
- end
7
+ render_success
13
8
  else
14
- render :error
9
+ render_error
15
10
  end
16
11
  end
17
12
 
18
13
  # TODO: Handle raise invalid authorization
19
14
  def create
20
- redirect_or_render authorization.authorize
15
+ redirect_or_render authorize_response
21
16
  end
22
17
 
23
18
  def destroy
@@ -26,15 +21,45 @@ module Doorkeeper
26
21
 
27
22
  private
28
23
 
24
+ def render_success
25
+ if skip_authorization? || matching_token?
26
+ redirect_or_render authorize_response
27
+ elsif Doorkeeper.configuration.api_only
28
+ render json: pre_auth
29
+ else
30
+ render :new
31
+ end
32
+ end
33
+
34
+ def render_error
35
+ if Doorkeeper.configuration.api_only
36
+ render json: pre_auth.error_response.body[:error_description],
37
+ status: :bad_request
38
+ else
39
+ render :error
40
+ end
41
+ end
42
+
29
43
  def matching_token?
30
- AccessToken.matching_token_for pre_auth.client,
31
- current_resource_owner.id,
32
- pre_auth.scopes
44
+ token = AccessToken.matching_token_for(
45
+ pre_auth.client,
46
+ current_resource_owner.id,
47
+ pre_auth.scopes
48
+ )
49
+
50
+ token && token.accessible?
33
51
  end
34
52
 
35
53
  def redirect_or_render(auth)
36
54
  if auth.redirectable?
37
- redirect_to auth.redirect_uri
55
+ if Doorkeeper.configuration.api_only
56
+ render(
57
+ json: { status: :redirect, redirect_uri: auth.redirect_uri },
58
+ status: auth.status
59
+ )
60
+ else
61
+ redirect_to auth.redirect_uri
62
+ end
38
63
  else
39
64
  render json: auth.body, status: auth.status
40
65
  end
@@ -53,5 +78,23 @@ module Doorkeeper
53
78
  def strategy
54
79
  @strategy ||= server.authorization_request pre_auth.response_type
55
80
  end
81
+
82
+ def authorize_response
83
+ @authorize_response ||= begin
84
+ authorizable = pre_auth.authorizable?
85
+ before_successful_authorization if authorizable
86
+ auth = strategy.authorize
87
+ after_successful_authorization if authorizable
88
+ auth
89
+ end
90
+ end
91
+
92
+ def after_successful_authorization
93
+ Doorkeeper.configuration.after_successful_authorization.call(self)
94
+ end
95
+
96
+ def before_successful_authorization
97
+ Doorkeeper.configuration.before_successful_authorization.call(self)
98
+ end
56
99
  end
57
100
  end
@@ -4,11 +4,25 @@ module Doorkeeper
4
4
 
5
5
  def index
6
6
  @applications = Application.authorized_for(current_resource_owner)
7
+
8
+ respond_to do |format|
9
+ format.html
10
+ format.json { render json: @applications }
11
+ end
7
12
  end
8
13
 
9
14
  def destroy
10
15
  AccessToken.revoke_all_for params[:id], current_resource_owner
11
- redirect_to oauth_authorized_applications_url, notice: I18n.t(:notice, scope: [:doorkeeper, :flash, :authorized_applications, :destroy])
16
+
17
+ respond_to do |format|
18
+ format.html do
19
+ redirect_to oauth_authorized_applications_url, notice: I18n.t(
20
+ :notice, scope: %i[doorkeeper flash authorized_applications destroy]
21
+ )
22
+ end
23
+
24
+ format.json { render :no_content }
25
+ end
12
26
  end
13
27
  end
14
28
  end