doorkeeper 3.1.0 → 4.4.3

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 (195) hide show
  1. checksums.yaml +4 -4
  2. data/.coveralls.yml +1 -0
  3. data/.github/ISSUE_TEMPLATE.md +25 -0
  4. data/.github/PULL_REQUEST_TEMPLATE.md +17 -0
  5. data/.gitignore +6 -1
  6. data/.hound.yml +2 -13
  7. data/.rubocop.yml +17 -0
  8. data/.travis.yml +26 -10
  9. data/Appraisals +18 -0
  10. data/CODE_OF_CONDUCT.md +46 -0
  11. data/CONTRIBUTING.md +2 -0
  12. data/Gemfile +5 -5
  13. data/NEWS.md +141 -2
  14. data/README.md +149 -66
  15. data/RELEASING.md +5 -12
  16. data/Rakefile +1 -1
  17. data/SECURITY.md +15 -0
  18. data/app/controllers/doorkeeper/application_controller.rb +4 -6
  19. data/app/controllers/doorkeeper/application_metal_controller.rb +3 -2
  20. data/app/controllers/doorkeeper/applications_controller.rb +18 -8
  21. data/app/controllers/doorkeeper/authorizations_controller.rb +1 -1
  22. data/app/controllers/doorkeeper/authorized_applications_controller.rb +1 -1
  23. data/app/controllers/doorkeeper/tokens_controller.rb +62 -15
  24. data/app/helpers/doorkeeper/dashboard_helper.rb +14 -10
  25. data/app/validators/redirect_uri_validator.rb +12 -2
  26. data/app/views/doorkeeper/applications/_delete_form.html.erb +1 -2
  27. data/app/views/doorkeeper/applications/_form.html.erb +13 -2
  28. data/app/views/doorkeeper/applications/index.html.erb +2 -0
  29. data/app/views/doorkeeper/applications/show.html.erb +4 -1
  30. data/app/views/doorkeeper/authorizations/new.html.erb +1 -1
  31. data/app/views/doorkeeper/authorized_applications/_delete_form.html.erb +1 -2
  32. data/app/views/doorkeeper/authorized_applications/index.html.erb +0 -1
  33. data/app/views/layouts/doorkeeper/admin.html.erb +1 -1
  34. data/config/locales/en.yml +12 -7
  35. data/doorkeeper.gemspec +16 -11
  36. data/gemfiles/rails_4_2.gemfile +13 -0
  37. data/gemfiles/rails_5_0.gemfile +12 -0
  38. data/gemfiles/rails_5_1.gemfile +12 -0
  39. data/gemfiles/rails_5_2.gemfile +12 -0
  40. data/gemfiles/rails_master.gemfile +14 -0
  41. data/lib/doorkeeper/config.rb +119 -46
  42. data/lib/doorkeeper/engine.rb +11 -7
  43. data/lib/doorkeeper/errors.rb +18 -0
  44. data/lib/doorkeeper/grape/helpers.rb +14 -8
  45. data/lib/doorkeeper/helpers/controller.rb +8 -19
  46. data/lib/doorkeeper/models/access_grant_mixin.rb +10 -21
  47. data/lib/doorkeeper/models/access_token_mixin.rb +147 -43
  48. data/lib/doorkeeper/models/application_mixin.rb +33 -35
  49. data/lib/doorkeeper/models/concerns/accessible.rb +4 -0
  50. data/lib/doorkeeper/models/concerns/expirable.rb +15 -5
  51. data/lib/doorkeeper/models/concerns/orderable.rb +13 -0
  52. data/lib/doorkeeper/models/concerns/ownership.rb +6 -1
  53. data/lib/doorkeeper/models/concerns/revocable.rb +37 -2
  54. data/lib/doorkeeper/oauth/authorization/token.rb +22 -18
  55. data/lib/doorkeeper/oauth/authorization/uri_builder.rb +20 -18
  56. data/lib/doorkeeper/oauth/authorization_code_request.rb +7 -5
  57. data/lib/doorkeeper/oauth/{request_concern.rb → base_request.rb} +9 -2
  58. data/lib/doorkeeper/oauth/base_response.rb +29 -0
  59. data/lib/doorkeeper/oauth/client/credentials.rb +21 -8
  60. data/lib/doorkeeper/oauth/client.rb +2 -3
  61. data/lib/doorkeeper/oauth/client_credentials/creator.rb +1 -1
  62. data/lib/doorkeeper/oauth/client_credentials/issuer.rb +3 -2
  63. data/lib/doorkeeper/oauth/client_credentials/validation.rb +1 -1
  64. data/lib/doorkeeper/oauth/client_credentials_request.rb +8 -8
  65. data/lib/doorkeeper/oauth/code_response.rb +16 -16
  66. data/lib/doorkeeper/oauth/error.rb +2 -2
  67. data/lib/doorkeeper/oauth/error_response.rb +10 -10
  68. data/lib/doorkeeper/oauth/forbidden_token_response.rb +1 -1
  69. data/lib/doorkeeper/oauth/helpers/scope_checker.rb +1 -1
  70. data/lib/doorkeeper/oauth/helpers/uri_checker.rb +17 -1
  71. data/lib/doorkeeper/oauth/invalid_token_response.rb +5 -4
  72. data/lib/doorkeeper/oauth/password_access_token_request.rb +8 -13
  73. data/lib/doorkeeper/oauth/pre_authorization.rb +5 -3
  74. data/lib/doorkeeper/oauth/refresh_token_request.rb +23 -14
  75. data/lib/doorkeeper/oauth/scopes.rb +18 -8
  76. data/lib/doorkeeper/oauth/token.rb +20 -21
  77. data/lib/doorkeeper/oauth/token_introspection.rb +128 -0
  78. data/lib/doorkeeper/oauth/token_request.rb +1 -2
  79. data/lib/doorkeeper/oauth/token_response.rb +1 -1
  80. data/lib/doorkeeper/orm/active_record/access_grant.rb +27 -0
  81. data/lib/doorkeeper/orm/active_record/access_token.rb +34 -8
  82. data/lib/doorkeeper/orm/active_record/application.rb +48 -11
  83. data/lib/doorkeeper/orm/active_record.rb +17 -22
  84. data/lib/doorkeeper/rails/helpers.rb +6 -9
  85. data/lib/doorkeeper/rails/routes/mapper.rb +4 -4
  86. data/lib/doorkeeper/rails/routes/mapping.rb +1 -1
  87. data/lib/doorkeeper/rails/routes.rb +17 -11
  88. data/lib/doorkeeper/request/authorization_code.rb +7 -1
  89. data/lib/doorkeeper/request/password.rb +2 -2
  90. data/lib/doorkeeper/request/refresh_token.rb +1 -1
  91. data/lib/doorkeeper/request.rb +7 -1
  92. data/lib/doorkeeper/server.rb +0 -8
  93. data/lib/doorkeeper/validations.rb +3 -2
  94. data/lib/doorkeeper/version.rb +34 -1
  95. data/lib/doorkeeper.rb +10 -2
  96. data/lib/generators/doorkeeper/add_client_confidentiality_generator.rb +31 -0
  97. data/lib/generators/doorkeeper/application_owner_generator.rb +11 -2
  98. data/lib/generators/doorkeeper/migration_generator.rb +13 -1
  99. data/lib/generators/doorkeeper/previous_refresh_token_generator.rb +35 -0
  100. data/lib/generators/doorkeeper/templates/add_confidential_to_application_migration.rb.erb +11 -0
  101. data/{spec/dummy/db/migrate/20130902175349_add_owner_to_application.rb → lib/generators/doorkeeper/templates/add_owner_to_application_migration.rb.erb} +1 -1
  102. data/lib/generators/doorkeeper/templates/add_previous_refresh_token_to_access_tokens.rb.erb +11 -0
  103. data/lib/generators/doorkeeper/templates/initializer.rb +38 -6
  104. data/lib/generators/doorkeeper/templates/migration.rb.erb +69 -0
  105. data/spec/controllers/application_metal_controller.rb +10 -0
  106. data/spec/controllers/applications_controller_spec.rb +15 -4
  107. data/spec/controllers/authorizations_controller_spec.rb +74 -27
  108. data/spec/controllers/protected_resources_controller_spec.rb +70 -32
  109. data/spec/controllers/token_info_controller_spec.rb +17 -13
  110. data/spec/controllers/tokens_controller_spec.rb +198 -12
  111. data/spec/dummy/app/controllers/full_protected_resources_controller.rb +4 -4
  112. data/spec/dummy/app/controllers/home_controller.rb +1 -1
  113. data/spec/dummy/app/controllers/metal_controller.rb +1 -1
  114. data/spec/dummy/app/controllers/semi_protected_resources_controller.rb +3 -3
  115. data/spec/dummy/app/models/user.rb +0 -4
  116. data/spec/dummy/config/application.rb +2 -36
  117. data/spec/dummy/config/environment.rb +1 -1
  118. data/spec/dummy/config/environments/test.rb +4 -15
  119. data/spec/dummy/config/initializers/doorkeeper.rb +19 -3
  120. data/spec/dummy/config/initializers/new_framework_defaults.rb +6 -0
  121. data/spec/dummy/config/initializers/secret_token.rb +0 -1
  122. data/spec/dummy/db/migrate/20111122132257_create_users.rb +3 -1
  123. data/spec/dummy/db/migrate/20120312140401_add_password_to_users.rb +3 -1
  124. data/{lib/generators/doorkeeper/templates/migration.rb → spec/dummy/db/migrate/20151223192035_create_doorkeeper_tables.rb} +16 -4
  125. data/{lib/generators/doorkeeper/templates/add_owner_to_application_migration.rb → spec/dummy/db/migrate/20151223200000_add_owner_to_application.rb} +4 -2
  126. data/spec/dummy/db/migrate/20160320211015_add_previous_refresh_token_to_access_tokens.rb +13 -0
  127. data/spec/dummy/db/migrate/20180210183654_add_confidential_to_application.rb +13 -0
  128. data/spec/dummy/db/schema.rb +24 -22
  129. data/spec/factories.rb +4 -2
  130. data/spec/generators/application_owner_generator_spec.rb +24 -5
  131. data/spec/generators/migration_generator_spec.rb +24 -3
  132. data/spec/generators/previous_refresh_token_generator_spec.rb +57 -0
  133. data/spec/grape/grape_integration_spec.rb +135 -0
  134. data/spec/helpers/doorkeeper/dashboard_helper_spec.rb +1 -1
  135. data/spec/lib/config_spec.rb +159 -14
  136. data/spec/lib/doorkeeper_spec.rb +135 -13
  137. data/spec/lib/models/expirable_spec.rb +0 -1
  138. data/spec/lib/models/revocable_spec.rb +27 -4
  139. data/spec/lib/oauth/authorization/uri_builder_spec.rb +1 -2
  140. data/spec/lib/oauth/authorization_code_request_spec.rb +55 -12
  141. data/spec/lib/oauth/base_request_spec.rb +155 -0
  142. data/spec/lib/oauth/base_response_spec.rb +45 -0
  143. data/spec/lib/oauth/client/credentials_spec.rb +45 -2
  144. data/spec/lib/oauth/client_credentials/creator_spec.rb +1 -1
  145. data/spec/lib/oauth/client_credentials_integration_spec.rb +1 -1
  146. data/spec/lib/oauth/client_credentials_request_spec.rb +1 -0
  147. data/spec/lib/oauth/code_request_spec.rb +1 -3
  148. data/spec/lib/oauth/code_response_spec.rb +34 -0
  149. data/spec/lib/oauth/error_response_spec.rb +9 -9
  150. data/spec/lib/oauth/error_spec.rb +1 -1
  151. data/spec/lib/oauth/helpers/uri_checker_spec.rb +115 -1
  152. data/spec/lib/oauth/invalid_token_response_spec.rb +36 -8
  153. data/spec/lib/oauth/password_access_token_request_spec.rb +14 -8
  154. data/spec/lib/oauth/pre_authorization_spec.rb +12 -7
  155. data/spec/lib/oauth/refresh_token_request_spec.rb +52 -9
  156. data/spec/lib/oauth/scopes_spec.rb +28 -2
  157. data/spec/lib/oauth/token_request_spec.rb +6 -8
  158. data/spec/lib/oauth/token_spec.rb +12 -5
  159. data/spec/lib/server_spec.rb +10 -3
  160. data/spec/models/doorkeeper/access_grant_spec.rb +1 -1
  161. data/spec/models/doorkeeper/access_token_spec.rb +116 -48
  162. data/spec/models/doorkeeper/application_spec.rb +145 -29
  163. data/spec/requests/applications/applications_request_spec.rb +5 -5
  164. data/spec/requests/endpoints/authorization_spec.rb +5 -6
  165. data/spec/requests/endpoints/token_spec.rb +8 -1
  166. data/spec/requests/flows/authorization_code_errors_spec.rb +11 -1
  167. data/spec/requests/flows/authorization_code_spec.rb +6 -13
  168. data/spec/requests/flows/client_credentials_spec.rb +29 -1
  169. data/spec/requests/flows/implicit_grant_errors_spec.rb +2 -2
  170. data/spec/requests/flows/password_spec.rb +118 -15
  171. data/spec/requests/flows/refresh_token_spec.rb +89 -19
  172. data/spec/requests/flows/revoke_token_spec.rb +105 -91
  173. data/spec/requests/protected_resources/metal_spec.rb +1 -1
  174. data/spec/requests/protected_resources/private_api_spec.rb +1 -1
  175. data/spec/routing/custom_controller_routes_spec.rb +4 -0
  176. data/spec/routing/default_routes_spec.rb +5 -1
  177. data/spec/spec_helper.rb +2 -0
  178. data/spec/spec_helper_integration.rb +22 -4
  179. data/spec/support/dependencies/factory_girl.rb +2 -2
  180. data/spec/support/helpers/access_token_request_helper.rb +1 -1
  181. data/spec/support/helpers/model_helper.rb +34 -7
  182. data/spec/support/helpers/request_spec_helper.rb +17 -5
  183. data/spec/support/helpers/url_helper.rb +9 -8
  184. data/spec/support/http_method_shim.rb +38 -0
  185. data/spec/support/shared/controllers_shared_context.rb +15 -10
  186. data/spec/support/shared/models_shared_examples.rb +5 -5
  187. data/spec/validators/redirect_uri_validator_spec.rb +51 -6
  188. data/spec/version/version_spec.rb +15 -0
  189. metadata +128 -46
  190. data/lib/doorkeeper/oauth/client/methods.rb +0 -18
  191. data/lib/generators/doorkeeper/application_scopes_generator.rb +0 -34
  192. data/lib/generators/doorkeeper/templates/add_scopes_to_oauth_applications.rb +0 -5
  193. data/spec/dummy/db/migrate/20130902165751_create_doorkeeper_tables.rb +0 -41
  194. data/spec/dummy/db/migrate/20141209001746_add_scopes_to_oauth_applications.rb +0 -5
  195. data/spec/lib/oauth/client/methods_spec.rb +0 -54
@@ -1,15 +1,19 @@
1
- module Doorkeeper::DashboardHelper
2
- def doorkeeper_errors_for(object, method)
3
- if object.errors[method].present?
4
- object.errors[method].map do |msg|
5
- content_tag(:span, class: 'help-block') do
6
- msg.capitalize
1
+ module Doorkeeper
2
+ module DashboardHelper
3
+ def doorkeeper_errors_for(object, method)
4
+ if object.errors[method].present?
5
+ output = object.errors[method].map do |msg|
6
+ content_tag(:span, class: 'help-block') do
7
+ msg.capitalize
8
+ end
7
9
  end
8
- end.join.html_safe
10
+
11
+ safe_join(output)
12
+ end
9
13
  end
10
- end
11
14
 
12
- def doorkeeper_submit_path(application)
13
- application.persisted? ? oauth_application_path(application) : oauth_applications_path
15
+ def doorkeeper_submit_path(application)
16
+ application.persisted? ? oauth_application_path(application) : oauth_applications_path
17
+ end
14
18
  end
15
19
  end
@@ -11,7 +11,8 @@ class RedirectUriValidator < ActiveModel::EachValidator
11
11
  else
12
12
  value.split.each do |val|
13
13
  uri = ::URI.parse(val)
14
- return if native_redirect_uri?(uri)
14
+ next if native_redirect_uri?(uri)
15
+ record.errors.add(attribute, :forbidden_uri) if forbidden_uri?(uri)
15
16
  record.errors.add(attribute, :fragment_present) unless uri.fragment.nil?
16
17
  record.errors.add(attribute, :relative_uri) if uri.scheme.nil? || uri.host.nil?
17
18
  record.errors.add(attribute, :secured_uri) if invalid_ssl_uri?(uri)
@@ -27,8 +28,17 @@ class RedirectUriValidator < ActiveModel::EachValidator
27
28
  self.class.native_redirect_uri.present? && uri.to_s == self.class.native_redirect_uri.to_s
28
29
  end
29
30
 
31
+ def forbidden_uri?(uri)
32
+ Doorkeeper.configuration.forbid_redirect_uri.call(uri)
33
+ end
34
+
30
35
  def invalid_ssl_uri?(uri)
31
36
  forces_ssl = Doorkeeper.configuration.force_ssl_in_redirect_uri
32
- forces_ssl && uri.try(:scheme) == 'http'
37
+
38
+ if forces_ssl.respond_to?(:call)
39
+ forces_ssl.call(uri)
40
+ else
41
+ forces_ssl && uri.try(:scheme) == 'http'
42
+ end
33
43
  end
34
44
  end
@@ -1,5 +1,4 @@
1
1
  <%- submit_btn_css ||= 'btn btn-link' %>
2
- <%= form_tag oauth_application_path(application) do %>
3
- <input type="hidden" name="_method" value="delete">
2
+ <%= form_tag oauth_application_path(application), method: :delete do %>
4
3
  <%= submit_tag t('doorkeeper.applications.buttons.destroy'), onclick: "return confirm('#{ t('doorkeeper.applications.confirmations.destroy') }')", class: submit_btn_css %>
5
4
  <% end %>
@@ -21,12 +21,23 @@
21
21
  </span>
22
22
  <% if Doorkeeper.configuration.native_redirect_uri %>
23
23
  <span class="help-block">
24
- <%= raw t('doorkeeper.applications.help.native_redirect_uri', native_redirect_uri: "<code>#{ Doorkeeper.configuration.native_redirect_uri }</code>") %>
24
+ <%= raw t('doorkeeper.applications.help.native_redirect_uri', native_redirect_uri: content_tag(:code) { Doorkeeper.configuration.native_redirect_uri }) %>
25
25
  </span>
26
26
  <% end %>
27
27
  </div>
28
28
  <% end %>
29
29
 
30
+ <%= content_tag :div, class: "form-group#{' has-error' if application.errors[:confidential].present?}" do %>
31
+ <%= f.label :confidential, class: 'col-sm-2 control-label' %>
32
+ <div class="col-sm-10">
33
+ <%= f.check_box :confidential, class: 'form-control', disabled: !Doorkeeper::Application.supports_confidentiality? %>
34
+ <%= doorkeeper_errors_for application, :confidential %>
35
+ <span class="help-block">
36
+ <%= t('doorkeeper.applications.help.confidential') %>
37
+ </span>
38
+ </div>
39
+ <% end %>
40
+
30
41
  <%= content_tag :div, class: "form-group#{' has-error' if application.errors[:scopes].present?}" do %>
31
42
  <%= f.label :scopes, class: 'col-sm-2 control-label' %>
32
43
  <div class="col-sm-10">
@@ -41,7 +52,7 @@
41
52
  <div class="form-group">
42
53
  <div class="col-sm-offset-2 col-sm-10">
43
54
  <%= f.submit t('doorkeeper.applications.buttons.submit'), class: "btn btn-primary" %>
44
- <%= link_to t('doorkeeper.applications.buttons.cancel'), oauth_applications_path, :class => "btn btn-default" %>
55
+ <%= link_to t('doorkeeper.applications.buttons.cancel'), oauth_applications_path, class: "btn btn-default" %>
45
56
  </div>
46
57
  </div>
47
58
  <% end %>
@@ -9,6 +9,7 @@
9
9
  <tr>
10
10
  <th><%= t('.name') %></th>
11
11
  <th><%= t('.callback_url') %></th>
12
+ <th><%= t('.confidential') %></th>
12
13
  <th></th>
13
14
  <th></th>
14
15
  </tr>
@@ -18,6 +19,7 @@
18
19
  <tr id="application_<%= application.id %>">
19
20
  <td><%= link_to application.name, oauth_application_path(application) %></td>
20
21
  <td><%= application.redirect_uri %></td>
22
+ <td><%= application.confidential? ? t('doorkeeper.applications.index.confidentiality.yes') : t('doorkeeper.applications.index.confidentiality.no') %></td>
21
23
  <td><%= link_to t('doorkeeper.applications.buttons.edit'), edit_oauth_application_path(application), class: 'btn btn-link' %></td>
22
24
  <td><%= render 'delete_form', application: application %></td>
23
25
  </tr>
@@ -13,6 +13,9 @@
13
13
  <h4><%= t('.scopes') %>:</h4>
14
14
  <p><code id="scopes"><%= @application.scopes %></code></p>
15
15
 
16
+ <h4><%= t('.confidential') %>:</h4>
17
+ <p><code id="confidential"><%= @application.confidential? %></code></p>
18
+
16
19
  <h4><%= t('.callback_urls') %>:</h4>
17
20
 
18
21
  <table>
@@ -22,7 +25,7 @@
22
25
  <code><%= uri %></code>
23
26
  </td>
24
27
  <td>
25
- <%= link_to t('doorkeeper.applications.buttons.authorize'), oauth_authorization_path(client_id: @application.uid, redirect_uri: uri, response_type: 'code'), class: 'btn btn-success', target: '_blank' %>
28
+ <%= link_to t('doorkeeper.applications.buttons.authorize'), oauth_authorization_path(client_id: @application.uid, redirect_uri: uri, response_type: 'code', scope: @application.scopes), class: 'btn btn-success', target: '_blank' %>
26
29
  </td>
27
30
  </tr>
28
31
  <% end %>
@@ -4,7 +4,7 @@
4
4
 
5
5
  <main role="main">
6
6
  <p class="h4">
7
- <%= raw t('.prompt', client_name: "<strong class=\"text-info\">#{ @pre_auth.client.name }</strong>") %>
7
+ <%= raw t('.prompt', client_name: content_tag(:strong, class: 'text-info') { @pre_auth.client.name }) %>
8
8
  </p>
9
9
 
10
10
  <% if @pre_auth.scopes.count > 0 %>
@@ -1,5 +1,4 @@
1
1
  <%- submit_btn_css ||= 'btn btn-link' %>
2
- <%= form_tag oauth_authorized_application_path(application) do %>
3
- <input type="hidden" name="_method" value="delete">
2
+ <%= form_tag oauth_authorized_application_path(application), method: :delete do %>
4
3
  <%= submit_tag t('doorkeeper.authorized_applications.buttons.revoke'), onclick: "return confirm('#{ t('doorkeeper.authorized_applications.confirmations.revoke') }')", class: submit_btn_css %>
5
4
  <% end %>
@@ -9,7 +9,6 @@
9
9
  <th><%= t('doorkeeper.authorized_applications.index.application') %></th>
10
10
  <th><%= t('doorkeeper.authorized_applications.index.created_at') %></th>
11
11
  <th></th>
12
- <th></th>
13
12
  </tr>
14
13
  </thead>
15
14
  <tbody>
@@ -19,7 +19,7 @@
19
19
  <%= link_to t('doorkeeper.layouts.admin.nav.applications'), oauth_applications_path %>
20
20
  <% end %>
21
21
  <%= content_tag :li do %>
22
- <%= link_to 'Home', root_path %>
22
+ <%= link_to t('doorkeeper.layouts.admin.nav.home'), root_path %>
23
23
  <% end %>
24
24
  </ul>
25
25
  </div>
@@ -13,6 +13,7 @@ en:
13
13
  invalid_uri: 'must be a valid URI.'
14
14
  relative_uri: 'must be an absolute URI.'
15
15
  secured_uri: 'must be an HTTPS/SSL URI.'
16
+ forbidden_uri: 'is forbidden by the server.'
16
17
 
17
18
  doorkeeper:
18
19
  applications:
@@ -27,8 +28,9 @@ en:
27
28
  form:
28
29
  error: 'Whoops! Check your form for possible errors'
29
30
  help:
31
+ confidential: 'Application will be used where the client secret can be kept confidential. Native mobile apps and Single Page Apps are considered non-confidential.'
30
32
  redirect_uri: 'Use one line per URI'
31
- native_redirect_uri: 'Use %{native_redirect_uri} for local tests'
33
+ native_redirect_uri: 'Use %{native_redirect_uri} if you want to add localhost URIs for development purposes'
32
34
  scopes: 'Separate scopes with spaces. Leave blank to use the default scopes.'
33
35
  edit:
34
36
  title: 'Edit application'
@@ -37,6 +39,10 @@ en:
37
39
  new: 'New Application'
38
40
  name: 'Name'
39
41
  callback_url: 'Callback URL'
42
+ confidential: 'Confidential?'
43
+ confidentiality:
44
+ 'yes': 'Yes'
45
+ 'no': 'No'
40
46
  new:
41
47
  title: 'New Application'
42
48
  show:
@@ -44,6 +50,7 @@ en:
44
50
  application_id: 'Application Id'
45
51
  secret: 'Secret'
46
52
  scopes: 'Scopes'
53
+ confidential: 'Confidential'
47
54
  callback_urls: 'Callback urls'
48
55
  actions: 'Actions'
49
56
 
@@ -75,16 +82,16 @@ en:
75
82
  messages:
76
83
  # Common error messages
77
84
  invalid_request: 'The request is missing a required parameter, includes an unsupported parameter value, or is otherwise malformed.'
78
- invalid_redirect_uri: 'The redirect uri included is not valid.'
85
+ invalid_redirect_uri: "The requested redirect uri is malformed or doesn't match client redirect URI."
79
86
  unauthorized_client: 'The client is not authorized to perform this request using this method.'
80
87
  access_denied: 'The resource owner or authorization server denied the request.'
81
88
  invalid_scope: 'The requested scope is invalid, unknown, or malformed.'
82
89
  server_error: 'The authorization server encountered an unexpected condition which prevented it from fulfilling the request.'
83
90
  temporarily_unavailable: 'The authorization server is currently unable to handle the request due to a temporary overloading or maintenance of the server.'
84
91
 
85
- #configuration error messages
92
+ # Configuration error messages
86
93
  credential_flow_not_configured: 'Resource Owner Password Credentials flow failed due to Doorkeeper.configure.resource_owner_from_credentials being unconfigured.'
87
- resource_owner_authenticator_not_configured: 'Resource Owner find failed due to Doorkeeper.configure.resource_owner_authenticator being unconfiged.'
94
+ resource_owner_authenticator_not_configured: 'Resource Owner find failed due to Doorkeeper.configure.resource_owner_authenticator being unconfigured.'
88
95
 
89
96
  # Access grant errors
90
97
  unsupported_response_type: 'The authorization server does not support this response type.'
@@ -94,9 +101,6 @@ en:
94
101
  invalid_grant: 'The provided authorization grant is invalid, expired, revoked, does not match the redirection URI used in the authorization request, or was issued to another client.'
95
102
  unsupported_grant_type: 'The authorization grant type is not supported by the authorization server.'
96
103
 
97
- # Password Access token errors
98
- invalid_resource_owner: 'The provided resource owner credentials are not valid, or resource owner cannot be found'
99
-
100
104
  invalid_token:
101
105
  revoked: "The access token was revoked"
102
106
  expired: "The access token expired"
@@ -119,5 +123,6 @@ en:
119
123
  nav:
120
124
  oauth2_provider: 'OAuth2 Provider'
121
125
  applications: 'Applications'
126
+ home: 'Home'
122
127
  application:
123
128
  title: 'OAuth authorization required'
data/doorkeeper.gemspec CHANGED
@@ -1,12 +1,12 @@
1
- $:.push File.expand_path("../lib", __FILE__)
1
+ $LOAD_PATH.push File.expand_path("../lib", __FILE__)
2
2
 
3
3
  require "doorkeeper/version"
4
4
 
5
5
  Gem::Specification.new do |s|
6
6
  s.name = "doorkeeper"
7
- s.version = Doorkeeper::VERSION
8
- s.authors = ["Felipe Elias Philipp", "Tute Costa"]
9
- s.email = %w(tutecosta@gmail.com)
7
+ s.version = Doorkeeper.gem_version
8
+ s.authors = ["Felipe Elias Philipp", "Tute Costa", "Jon Moss", "Nikita Bulai"]
9
+ s.email = %w(bulaj.nikita@gmail.com)
10
10
  s.homepage = "https://github.com/doorkeeper-gem/doorkeeper"
11
11
  s.summary = "OAuth 2 provider for Rails and Grape"
12
12
  s.description = "Doorkeeper is an OAuth 2 provider for Rails and Grape."
@@ -16,12 +16,17 @@ Gem::Specification.new do |s|
16
16
  s.test_files = `git ls-files -- spec/*`.split("\n")
17
17
  s.require_paths = ["lib"]
18
18
 
19
- s.add_dependency "railties", ">= 3.2"
19
+ s.add_dependency "railties", ">= 4.2"
20
+ s.required_ruby_version = ">= 2.1"
20
21
 
21
- s.add_development_dependency "rspec-rails", "~> 3.4.0"
22
- s.add_development_dependency "capybara", "~> 2.3.0"
23
- s.add_development_dependency "generator_spec", "~> 0.9.0"
24
- s.add_development_dependency "factory_girl", "~> 4.5.0"
25
- s.add_development_dependency "timecop", "~> 0.7.0"
26
- s.add_development_dependency "database_cleaner", "~> 1.3.0"
22
+ s.add_development_dependency "capybara"
23
+ s.add_development_dependency "coveralls"
24
+ s.add_development_dependency "grape"
25
+ s.add_development_dependency "database_cleaner", "~> 1.6"
26
+ s.add_development_dependency "factory_bot", "~> 4.8"
27
+ s.add_development_dependency "generator_spec", "~> 0.9.3"
28
+ s.add_development_dependency "rake", ">= 11.3.0"
29
+ s.add_development_dependency "rspec-rails"
30
+
31
+ s.post_install_message = Doorkeeper::CVE_2018_1000211_WARNING
27
32
  end
@@ -0,0 +1,13 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "rails", "~> 4.2.0"
6
+ gem "appraisal"
7
+ gem "activerecord-jdbcsqlite3-adapter", platform: :jruby
8
+ gem "sqlite3", platform: [:ruby, :mswin, :mingw, :x64_mingw]
9
+ gem "tzinfo-data", platforms: [:mingw, :mswin, :x64_mingw]
10
+ # Older Grape requires Ruby >= 2.2.2
11
+ gem "grape", '~> 0.16', '< 0.19.2'
12
+
13
+ gemspec path: "../"
@@ -0,0 +1,12 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "rails", "~> 5.0.0"
6
+ gem "appraisal"
7
+ gem "activerecord-jdbcsqlite3-adapter", platforms: :jruby
8
+ gem "sqlite3", platforms: [:ruby, :mswin, :mingw, :x64_mingw]
9
+ gem "tzinfo-data", platforms: [:mingw, :mswin, :x64_mingw]
10
+ gem "rspec-rails", "~> 3.5"
11
+
12
+ gemspec path: "../"
@@ -0,0 +1,12 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "rails", "~> 5.1.0"
6
+ gem "appraisal"
7
+ gem "activerecord-jdbcsqlite3-adapter", platforms: :jruby
8
+ gem "sqlite3", platforms: [:ruby, :mswin, :mingw, :x64_mingw]
9
+ gem "tzinfo-data", platforms: [:mingw, :mswin, :x64_mingw]
10
+ gem "rspec-rails", "~> 3.7"
11
+
12
+ gemspec path: "../"
@@ -0,0 +1,12 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "rails", "5.2.0.rc1"
6
+ gem "appraisal"
7
+ gem "activerecord-jdbcsqlite3-adapter", platforms: :jruby
8
+ gem "sqlite3", platforms: [:ruby, :mswin, :mingw, :x64_mingw]
9
+ gem "tzinfo-data", platforms: [:mingw, :mswin, :x64_mingw]
10
+ gem "rspec-rails", "~> 3.7"
11
+
12
+ gemspec path: "../"
@@ -0,0 +1,14 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "rails", git: 'https://github.com/rails/rails'
6
+ gem "arel", git: 'https://github.com/rails/arel'
7
+
8
+ gem "appraisal"
9
+ gem "activerecord-jdbcsqlite3-adapter", platform: :jruby
10
+ gem "sqlite3", platform: [:ruby, :mswin, :mingw, :x64_mingw]
11
+ gem "tzinfo-data", platforms: [:mingw, :mswin, :x64_mingw]
12
+ gem "rspec-rails", "~> 3.7"
13
+
14
+ gemspec path: "../"
@@ -1,5 +1,7 @@
1
1
  module Doorkeeper
2
2
  class MissingConfiguration < StandardError
3
+ # Defines a MissingConfiguration error for a missing Doorkeeper
4
+ # configuration
3
5
  def initialize
4
6
  super('Configuration for doorkeeper missing. Do you have doorkeeper initializer?')
5
7
  end
@@ -10,15 +12,10 @@ module Doorkeeper
10
12
  setup_orm_adapter
11
13
  setup_orm_models
12
14
  setup_application_owner if @config.enable_application_owner?
13
- check_requirements
14
15
  end
15
16
 
16
17
  def self.configuration
17
- @config || (fail MissingConfiguration.new)
18
- end
19
-
20
- def self.check_requirements
21
- @orm_adapter.check_requirements!(configuration)
18
+ @config || (fail MissingConfiguration)
22
19
  end
23
20
 
24
21
  def self.setup_orm_adapter
@@ -52,51 +49,79 @@ doorkeeper.
52
49
  @config
53
50
  end
54
51
 
52
+ # Provide support for an owner to be assigned to each registered
53
+ # application (disabled by default)
54
+ # Optional parameter confirmation: true (default false) if you want
55
+ # to enforce ownership of a registered application
56
+ #
57
+ # @param opts [Hash] the options to confirm if an application owner
58
+ # is present
59
+ # @option opts[Boolean] :confirmation (false)
60
+ # Set confirm_application_owner variable
55
61
  def enable_application_owner(opts = {})
56
- @config.instance_variable_set('@enable_application_owner', true)
62
+ @config.instance_variable_set(:@enable_application_owner, true)
57
63
  confirm_application_owner if opts[:confirmation].present? && opts[:confirmation]
58
64
  end
59
65
 
60
66
  def confirm_application_owner
61
- @config.instance_variable_set('@confirm_application_owner', true)
67
+ @config.instance_variable_set(:@confirm_application_owner, true)
62
68
  end
63
69
 
70
+ # Define default access token scopes for your provider
71
+ #
72
+ # @param scopes [Array] Default set of access (OAuth::Scopes.new)
73
+ # token scopes
64
74
  def default_scopes(*scopes)
65
- @config.instance_variable_set('@default_scopes', OAuth::Scopes.from_array(scopes))
75
+ @config.instance_variable_set(:@default_scopes, OAuth::Scopes.from_array(scopes))
66
76
  end
67
77
 
78
+ # Define default access token scopes for your provider
79
+ #
80
+ # @param scopes [Array] Optional set of access (OAuth::Scopes.new)
81
+ # token scopes
68
82
  def optional_scopes(*scopes)
69
- @config.instance_variable_set('@optional_scopes', OAuth::Scopes.from_array(scopes))
83
+ @config.instance_variable_set(:@optional_scopes, OAuth::Scopes.from_array(scopes))
70
84
  end
71
85
 
86
+ # Change the way client credentials are retrieved from the request object.
87
+ # By default it retrieves first from the `HTTP_AUTHORIZATION` header, then
88
+ # falls back to the `:client_id` and `:client_secret` params from the
89
+ # `params` object.
90
+ #
91
+ # @param methods [Array] Define client credentials
72
92
  def client_credentials(*methods)
73
- @config.instance_variable_set('@client_credentials', methods)
93
+ @config.instance_variable_set(:@client_credentials, methods)
74
94
  end
75
95
 
96
+ # Change the way access token is authenticated from the request object.
97
+ # By default it retrieves first from the `HTTP_AUTHORIZATION` header, then
98
+ # falls back to the `:access_token` or `:bearer_token` params from the
99
+ # `params` object.
100
+ #
101
+ # @param methods [Array] Define access token methods
76
102
  def access_token_methods(*methods)
77
- @config.instance_variable_set('@access_token_methods', methods)
103
+ @config.instance_variable_set(:@access_token_methods, methods)
78
104
  end
79
105
 
106
+ # Issue access tokens with refresh token (disabled by default)
80
107
  def use_refresh_token
81
- @config.instance_variable_set('@refresh_token_enabled', true)
82
- end
83
-
84
- def realm(realm)
85
- @config.instance_variable_set('@realm', realm)
108
+ @config.instance_variable_set(:@refresh_token_enabled, true)
86
109
  end
87
110
 
111
+ # Reuse access token for the same resource owner within an application
112
+ # (disabled by default)
113
+ # Rationale: https://github.com/doorkeeper-gem/doorkeeper/issues/383
88
114
  def reuse_access_token
89
- @config.instance_variable_set("@reuse_access_token", true)
90
- end
91
-
92
- def force_ssl_in_redirect_uri(boolean)
93
- @config.instance_variable_set("@force_ssl_in_redirect_uri", boolean)
115
+ @config.instance_variable_set(:@reuse_access_token, true)
94
116
  end
95
117
 
96
- def access_token_generator(access_token_generator)
97
- @config.instance_variable_set(
98
- '@access_token_generator', access_token_generator
99
- )
118
+ # Opt out of breaking api change to the native authorization code flow.
119
+ # Opting out sets the authorization code response route for native
120
+ # redirect uris to oauth/authorize/<code>. The default is
121
+ # oauth/authorize/native?code=<code>.
122
+ # Rationale: https://github.com/doorkeeper-gem/doorkeeper/issues/1143
123
+ def opt_out_native_route_change
124
+ @config.instance_variable_set(:@opt_out_native_route_change, true)
100
125
  end
101
126
  end
102
127
 
@@ -133,19 +158,20 @@ doorkeeper.
133
158
  attribute_builder = options[:builder_class]
134
159
 
135
160
  Builder.instance_eval do
161
+ remove_method name if method_defined?(name)
136
162
  define_method name do |*args, &block|
137
163
  # TODO: is builder_class option being used?
138
- value = unless attribute_builder
139
- block ? block : args.first
140
- else
164
+ value = if attribute_builder
141
165
  attribute_builder.new(&block).build
166
+ else
167
+ block ? block : args.first
142
168
  end
143
169
 
144
170
  @config.instance_variable_set(:"@#{attribute}", value)
145
171
  end
146
172
  end
147
173
 
148
- define_method attribute do |*args|
174
+ define_method attribute do |*_args|
149
175
  if instance_variable_defined?(:"@#{attribute}")
150
176
  instance_variable_get(:"@#{attribute}")
151
177
  else
@@ -155,10 +181,6 @@ doorkeeper.
155
181
 
156
182
  public attribute
157
183
  end
158
-
159
- def extended(base)
160
- base.send(:private, :option)
161
- end
162
184
  end
163
185
 
164
186
  extend Option
@@ -166,41 +188,91 @@ doorkeeper.
166
188
  option :resource_owner_authenticator,
167
189
  as: :authenticate_resource_owner,
168
190
  default: (lambda do |_routes|
169
- logger.warn(I18n.translate('doorkeeper.errors.messages.resource_owner_authenticator_not_configured'))
191
+ ::Rails.logger.warn(I18n.t('doorkeeper.errors.messages.resource_owner_authenticator_not_configured'))
170
192
  nil
171
193
  end)
194
+
172
195
  option :admin_authenticator,
173
196
  as: :authenticate_admin,
174
197
  default: ->(_routes) {}
198
+
175
199
  option :resource_owner_from_credentials,
176
200
  default: (lambda do |_routes|
177
- warn(I18n.translate('doorkeeper.errors.messages.credential_flow_not_configured'))
201
+ ::Rails.logger.warn(I18n.t('doorkeeper.errors.messages.credential_flow_not_configured'))
178
202
  nil
179
203
  end)
180
-
204
+ option :before_successful_strategy_response, default: ->(_request) {}
205
+ option :after_successful_strategy_response,
206
+ default: ->(_request, _response) {}
181
207
  option :skip_authorization, default: ->(_routes) {}
182
208
  option :access_token_expires_in, default: 7200
183
- option :custom_access_token_expires_in, default: lambda { |_app| nil }
209
+ option :custom_access_token_expires_in, default: ->(_app) { nil }
184
210
  option :authorization_code_expires_in, default: 600
185
211
  option :orm, default: :active_record
186
212
  option :native_redirect_uri, default: 'urn:ietf:wg:oauth:2.0:oob'
187
213
  option :active_record_options, default: {}
214
+ option :grant_flows, default: %w[authorization_code client_credentials]
215
+
216
+ # Allows to forbid specific Application redirect URI's by custom rules.
217
+ # Doesn't forbid any URI by default.
218
+ #
219
+ # @param forbid_redirect_uri [Proc] Block or any object respond to #call
220
+ #
221
+ option :forbid_redirect_uri, default: ->(_uri) { false }
222
+
223
+ # WWW-Authenticate Realm (default "Doorkeeper").
224
+ #
225
+ # @param realm [String] ("Doorkeeper") Authentication realm
226
+ #
188
227
  option :realm, default: 'Doorkeeper'
228
+
229
+ # Forces the usage of the HTTPS protocol in non-native redirect uris
230
+ # (enabled by default in non-development environments). OAuth2
231
+ # delegates security in communication to the HTTPS protocol so it is
232
+ # wise to keep this enabled.
233
+ #
234
+ # @param [Boolean] boolean_or_block value for the parameter, true by default in
235
+ # non-development environment
236
+ #
237
+ # @yield [uri] Conditional usage of SSL redirect uris.
238
+ # @yieldparam [URI] Redirect URI
239
+ # @yieldreturn [Boolean] Indicates necessity of usage of the HTTPS protocol
240
+ # in non-native redirect uris
241
+ #
189
242
  option :force_ssl_in_redirect_uri, default: !Rails.env.development?
190
- option :grant_flows, default: %w(authorization_code client_credentials)
191
- option :access_token_generator, default: "Doorkeeper::OAuth::Helpers::UniqueToken"
243
+
244
+
245
+ # Use a custom class for generating the access token.
246
+ # https://github.com/doorkeeper-gem/doorkeeper#custom-access-token-generator
247
+ #
248
+ # @param access_token_generator [String]
249
+ # the name of the access token generator class
250
+ #
251
+ option :access_token_generator,
252
+ default: 'Doorkeeper::OAuth::Helpers::UniqueToken'
253
+
254
+ # The controller Doorkeeper::ApplicationController inherits from.
255
+ # Defaults to ActionController::Base.
256
+ # https://github.com/doorkeeper-gem/doorkeeper#custom-base-controller
257
+ #
258
+ # @param base_controller [String] the name of the base controller
259
+ option :base_controller,
260
+ default: 'ActionController::Base'
192
261
 
193
262
  attr_reader :reuse_access_token
194
263
 
195
264
  def refresh_token_enabled?
265
+ @refresh_token_enabled ||= false
196
266
  !!@refresh_token_enabled
197
267
  end
198
268
 
199
269
  def enable_application_owner?
270
+ @enable_application_owner ||= false
200
271
  !!@enable_application_owner
201
272
  end
202
273
 
203
274
  def confirm_application_owner?
275
+ @confirm_application_owner ||= false
204
276
  !!@confirm_application_owner
205
277
  end
206
278
 
@@ -217,15 +289,11 @@ doorkeeper.
217
289
  end
218
290
 
219
291
  def client_credentials_methods
220
- @client_credentials ||= [:from_basic, :from_params]
292
+ @client_credentials ||= %i[from_basic from_params]
221
293
  end
222
294
 
223
295
  def access_token_methods
224
- @access_token_methods ||= [:from_bearer_authorization, :from_access_token_param, :from_bearer_param]
225
- end
226
-
227
- def realm
228
- @realm ||= 'Doorkeeper'
296
+ @access_token_methods ||= %i[from_bearer_authorization from_access_token_param from_bearer_param]
229
297
  end
230
298
 
231
299
  def authorization_response_types
@@ -236,6 +304,11 @@ doorkeeper.
236
304
  @token_grant_types ||= calculate_token_grant_types
237
305
  end
238
306
 
307
+ def native_authorization_code_route
308
+ @opt_out_native_route_change ||= false
309
+ @opt_out_native_route_change ? '/:code' : '/native'
310
+ end
311
+
239
312
  private
240
313
 
241
314
  # Determines what values are acceptable for 'response_type' param in