doorkeeper 4.4.0 → 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 (170) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.travis.yml +2 -0
  4. data/Appraisals +2 -2
  5. data/Gemfile +1 -1
  6. data/NEWS.md +36 -4
  7. data/README.md +85 -3
  8. data/Rakefile +6 -0
  9. data/app/assets/stylesheets/doorkeeper/admin/application.css +2 -2
  10. data/app/controllers/doorkeeper/application_controller.rb +4 -3
  11. data/app/controllers/doorkeeper/application_metal_controller.rb +4 -0
  12. data/app/controllers/doorkeeper/applications_controller.rb +42 -22
  13. data/app/controllers/doorkeeper/authorizations_controller.rb +55 -12
  14. data/app/controllers/doorkeeper/authorized_applications_controller.rb +15 -1
  15. data/app/controllers/doorkeeper/tokens_controller.rb +12 -15
  16. data/app/helpers/doorkeeper/dashboard_helper.rb +7 -7
  17. data/app/validators/redirect_uri_validator.rb +3 -2
  18. data/app/views/doorkeeper/applications/_delete_form.html.erb +3 -1
  19. data/app/views/doorkeeper/applications/_form.html.erb +25 -24
  20. data/app/views/doorkeeper/applications/edit.html.erb +1 -1
  21. data/app/views/doorkeeper/applications/index.html.erb +17 -7
  22. data/app/views/doorkeeper/applications/new.html.erb +1 -1
  23. data/app/views/doorkeeper/applications/show.html.erb +6 -6
  24. data/app/views/doorkeeper/authorizations/error.html.erb +1 -1
  25. data/app/views/doorkeeper/authorizations/new.html.erb +4 -0
  26. data/app/views/layouts/doorkeeper/admin.html.erb +15 -15
  27. data/config/locales/en.yml +11 -3
  28. data/doorkeeper.gemspec +0 -2
  29. data/gemfiles/rails_5_2.gemfile +1 -1
  30. data/lib/doorkeeper/config.rb +60 -23
  31. data/lib/doorkeeper/engine.rb +4 -0
  32. data/lib/doorkeeper/errors.rb +2 -5
  33. data/lib/doorkeeper/grape/helpers.rb +1 -1
  34. data/lib/doorkeeper/helpers/controller.rb +7 -2
  35. data/lib/doorkeeper/models/access_grant_mixin.rb +56 -0
  36. data/lib/doorkeeper/models/access_token_mixin.rb +37 -20
  37. data/lib/doorkeeper/models/concerns/scopes.rb +1 -1
  38. data/lib/doorkeeper/oauth/authorization/code.rb +31 -8
  39. data/lib/doorkeeper/oauth/authorization/context.rb +15 -0
  40. data/lib/doorkeeper/oauth/authorization/token.rb +23 -6
  41. data/lib/doorkeeper/oauth/authorization_code_request.rb +27 -2
  42. data/lib/doorkeeper/oauth/base_request.rb +18 -8
  43. data/lib/doorkeeper/oauth/client/credentials.rb +1 -1
  44. data/lib/doorkeeper/oauth/client_credentials/issuer.rb +6 -1
  45. data/lib/doorkeeper/oauth/client_credentials/validation.rb +4 -2
  46. data/lib/doorkeeper/oauth/error_response.rb +11 -3
  47. data/lib/doorkeeper/oauth/helpers/scope_checker.rb +0 -8
  48. data/lib/doorkeeper/oauth/helpers/uri_checker.rb +1 -0
  49. data/lib/doorkeeper/oauth/password_access_token_request.rb +7 -4
  50. data/lib/doorkeeper/oauth/pre_authorization.rb +45 -13
  51. data/lib/doorkeeper/oauth/refresh_token_request.rb +6 -1
  52. data/lib/doorkeeper/oauth/scopes.rb +1 -1
  53. data/lib/doorkeeper/oauth/token.rb +5 -2
  54. data/lib/doorkeeper/oauth/token_introspection.rb +2 -2
  55. data/lib/doorkeeper/oauth/token_response.rb +4 -2
  56. data/lib/doorkeeper/oauth.rb +13 -0
  57. data/lib/doorkeeper/orm/active_record/application.rb +13 -16
  58. data/lib/doorkeeper/orm/active_record/stale_records_cleaner.rb +26 -0
  59. data/lib/doorkeeper/orm/active_record.rb +2 -0
  60. data/lib/doorkeeper/rails/helpers.rb +2 -4
  61. data/lib/doorkeeper/rails/routes.rb +13 -1
  62. data/lib/doorkeeper/rake/db.rake +40 -0
  63. data/lib/doorkeeper/rake/setup.rake +6 -0
  64. data/lib/doorkeeper/rake.rb +14 -0
  65. data/lib/doorkeeper/request.rb +28 -28
  66. data/lib/doorkeeper/version.rb +4 -24
  67. data/lib/doorkeeper.rb +4 -17
  68. data/lib/generators/doorkeeper/application_owner_generator.rb +23 -18
  69. data/lib/generators/doorkeeper/confidential_applications_generator.rb +32 -0
  70. data/lib/generators/doorkeeper/install_generator.rb +17 -9
  71. data/lib/generators/doorkeeper/migration_generator.rb +23 -18
  72. data/lib/generators/doorkeeper/pkce_generator.rb +32 -0
  73. data/lib/generators/doorkeeper/previous_refresh_token_generator.rb +29 -24
  74. data/lib/generators/doorkeeper/templates/add_confidential_to_applications.rb.erb +13 -0
  75. data/lib/generators/doorkeeper/templates/enable_pkce_migration.rb.erb +6 -0
  76. data/lib/generators/doorkeeper/templates/initializer.rb +60 -9
  77. data/lib/generators/doorkeeper/views_generator.rb +3 -1
  78. data/spec/controllers/application_metal_controller_spec.rb +50 -0
  79. data/spec/controllers/applications_controller_spec.rb +126 -13
  80. data/spec/controllers/authorizations_controller_spec.rb +250 -15
  81. data/spec/controllers/protected_resources_controller_spec.rb +16 -16
  82. data/spec/controllers/token_info_controller_spec.rb +4 -12
  83. data/spec/controllers/tokens_controller_spec.rb +19 -73
  84. data/spec/dummy/app/assets/config/manifest.js +2 -0
  85. data/spec/dummy/config/environments/test.rb +4 -5
  86. data/spec/dummy/config/initializers/doorkeeper.rb +6 -0
  87. data/spec/dummy/config/initializers/new_framework_defaults.rb +4 -0
  88. data/spec/dummy/config/routes.rb +3 -42
  89. data/spec/dummy/db/migrate/20170822064514_enable_pkce.rb +6 -0
  90. data/spec/dummy/db/migrate/{20180210183654_add_confidential_to_application.rb → 20180210183654_add_confidential_to_applications.rb} +1 -1
  91. data/spec/dummy/db/schema.rb +36 -36
  92. data/spec/generators/application_owner_generator_spec.rb +1 -1
  93. data/spec/generators/confidential_applications_generator_spec.rb +45 -0
  94. data/spec/generators/install_generator_spec.rb +1 -1
  95. data/spec/generators/migration_generator_spec.rb +1 -1
  96. data/spec/generators/pkce_generator_spec.rb +43 -0
  97. data/spec/generators/previous_refresh_token_generator_spec.rb +1 -1
  98. data/spec/generators/views_generator_spec.rb +1 -1
  99. data/spec/grape/grape_integration_spec.rb +1 -1
  100. data/spec/helpers/doorkeeper/dashboard_helper_spec.rb +1 -1
  101. data/spec/lib/config_spec.rb +59 -14
  102. data/spec/lib/doorkeeper_spec.rb +1 -126
  103. data/spec/lib/models/expirable_spec.rb +0 -3
  104. data/spec/lib/models/revocable_spec.rb +0 -2
  105. data/spec/lib/models/scopes_spec.rb +0 -4
  106. data/spec/lib/oauth/authorization/uri_builder_spec.rb +0 -4
  107. data/spec/lib/oauth/authorization_code_request_spec.rb +24 -2
  108. data/spec/lib/oauth/base_request_spec.rb +16 -2
  109. data/spec/lib/oauth/base_response_spec.rb +1 -1
  110. data/spec/lib/oauth/client/credentials_spec.rb +1 -3
  111. data/spec/lib/oauth/client_credentials/creator_spec.rb +5 -1
  112. data/spec/lib/oauth/client_credentials/issuer_spec.rb +26 -7
  113. data/spec/lib/oauth/client_credentials/validation_spec.rb +2 -3
  114. data/spec/lib/oauth/client_credentials_integration_spec.rb +1 -1
  115. data/spec/lib/oauth/client_credentials_request_spec.rb +3 -5
  116. data/spec/lib/oauth/client_spec.rb +0 -3
  117. data/spec/lib/oauth/code_request_spec.rb +4 -2
  118. data/spec/lib/oauth/error_response_spec.rb +0 -3
  119. data/spec/lib/oauth/error_spec.rb +0 -2
  120. data/spec/lib/oauth/forbidden_token_response_spec.rb +1 -4
  121. data/spec/lib/oauth/helpers/scope_checker_spec.rb +0 -3
  122. data/spec/lib/oauth/helpers/unique_token_spec.rb +0 -1
  123. data/spec/lib/oauth/helpers/uri_checker_spec.rb +5 -2
  124. data/spec/lib/oauth/invalid_token_response_spec.rb +1 -4
  125. data/spec/lib/oauth/password_access_token_request_spec.rb +37 -2
  126. data/spec/lib/oauth/pre_authorization_spec.rb +40 -6
  127. data/spec/lib/oauth/refresh_token_request_spec.rb +11 -7
  128. data/spec/lib/oauth/scopes_spec.rb +0 -3
  129. data/spec/lib/oauth/token_request_spec.rb +4 -5
  130. data/spec/lib/oauth/token_response_spec.rb +0 -1
  131. data/spec/lib/oauth/token_spec.rb +37 -14
  132. data/spec/lib/orm/active_record/stale_records_cleaner_spec.rb +79 -0
  133. data/spec/lib/request/strategy_spec.rb +0 -1
  134. data/spec/lib/server_spec.rb +1 -1
  135. data/spec/models/doorkeeper/access_grant_spec.rb +1 -1
  136. data/spec/models/doorkeeper/access_token_spec.rb +50 -16
  137. data/spec/models/doorkeeper/application_spec.rb +1 -30
  138. data/spec/requests/applications/applications_request_spec.rb +89 -1
  139. data/spec/requests/applications/authorized_applications_spec.rb +1 -1
  140. data/spec/requests/endpoints/authorization_spec.rb +1 -1
  141. data/spec/requests/endpoints/token_spec.rb +7 -5
  142. data/spec/requests/flows/authorization_code_errors_spec.rb +1 -1
  143. data/spec/requests/flows/authorization_code_spec.rb +197 -1
  144. data/spec/requests/flows/client_credentials_spec.rb +46 -6
  145. data/spec/requests/flows/implicit_grant_errors_spec.rb +1 -1
  146. data/spec/requests/flows/implicit_grant_spec.rb +38 -11
  147. data/spec/requests/flows/password_spec.rb +56 -2
  148. data/spec/requests/flows/refresh_token_spec.rb +2 -2
  149. data/spec/requests/flows/revoke_token_spec.rb +11 -11
  150. data/spec/requests/flows/skip_authorization_spec.rb +16 -11
  151. data/spec/requests/protected_resources/metal_spec.rb +1 -1
  152. data/spec/requests/protected_resources/private_api_spec.rb +1 -1
  153. data/spec/routing/custom_controller_routes_spec.rb +59 -7
  154. data/spec/routing/default_routes_spec.rb +2 -2
  155. data/spec/routing/scoped_routes_spec.rb +16 -2
  156. data/spec/spec_helper.rb +54 -3
  157. data/spec/spec_helper_integration.rb +2 -74
  158. data/spec/support/doorkeeper_rspec.rb +19 -0
  159. data/spec/support/helpers/authorization_request_helper.rb +4 -4
  160. data/spec/support/helpers/request_spec_helper.rb +2 -2
  161. data/spec/support/helpers/url_helper.rb +7 -3
  162. data/spec/support/http_method_shim.rb +12 -16
  163. data/spec/validators/redirect_uri_validator_spec.rb +7 -1
  164. data/spec/version/version_spec.rb +3 -3
  165. data/vendor/assets/stylesheets/doorkeeper/bootstrap.min.css +4 -5
  166. metadata +33 -31
  167. data/lib/generators/doorkeeper/add_client_confidentiality_generator.rb +0 -31
  168. data/lib/generators/doorkeeper/templates/add_confidential_to_application_migration.rb.erb +0 -11
  169. data/spec/controllers/application_metal_controller.rb +0 -10
  170. /data/spec/support/dependencies/{factory_girl.rb → factory_bot.rb} +0 -0
@@ -1,58 +1,59 @@
1
- <%= form_for application, url: doorkeeper_submit_path(application), html: {class: 'form-horizontal', role: 'form'} do |f| %>
1
+ <%= form_for application, url: doorkeeper_submit_path(application), html: { role: 'form' } do |f| %>
2
2
  <% if application.errors.any? %>
3
3
  <div class="alert alert-danger" data-alert><p><%= t('doorkeeper.applications.form.error') %></p></div>
4
4
  <% end %>
5
5
 
6
- <%= content_tag :div, class: "form-group#{' has-error' if application.errors[:name].present?}" do %>
7
- <%= f.label :name, class: 'col-sm-2 control-label' %>
6
+ <div class="form-group row">
7
+ <%= f.label :name, class: 'col-sm-2 col-form-label font-weight-bold' %>
8
8
  <div class="col-sm-10">
9
- <%= f.text_field :name, class: 'form-control' %>
9
+ <%= f.text_field :name, class: "form-control #{ 'is-invalid' if application.errors[:name].present? }", required: true %>
10
10
  <%= doorkeeper_errors_for application, :name %>
11
11
  </div>
12
- <% end %>
12
+ </div>
13
13
 
14
- <%= content_tag :div, class: "form-group#{' has-error' if application.errors[:redirect_uri].present?}" do %>
15
- <%= f.label :redirect_uri, class: 'col-sm-2 control-label' %>
14
+ <div class="form-group row">
15
+ <%= f.label :redirect_uri, class: 'col-sm-2 col-form-label font-weight-bold' %>
16
16
  <div class="col-sm-10">
17
- <%= f.text_area :redirect_uri, class: 'form-control' %>
17
+ <%= f.text_area :redirect_uri, class: "form-control #{ 'is-invalid' if application.errors[:redirect_uri].present? }" %>
18
18
  <%= doorkeeper_errors_for application, :redirect_uri %>
19
- <span class="help-block">
19
+ <span class="form-text text-secondary">
20
20
  <%= t('doorkeeper.applications.help.redirect_uri') %>
21
21
  </span>
22
+
22
23
  <% if Doorkeeper.configuration.native_redirect_uri %>
23
- <span class="help-block">
24
- <%= raw t('doorkeeper.applications.help.native_redirect_uri', native_redirect_uri: content_tag(:code) { Doorkeeper.configuration.native_redirect_uri }) %>
24
+ <span class="form-text text-secondary">
25
+ <%= raw t('doorkeeper.applications.help.native_redirect_uri', native_redirect_uri: content_tag(:code, class: 'bg-light') { Doorkeeper.configuration.native_redirect_uri }) %>
25
26
  </span>
26
27
  <% end %>
27
28
  </div>
28
- <% end %>
29
+ </div>
29
30
 
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' %>
31
+ <div class="form-group row">
32
+ <%= f.label :confidential, class: 'col-sm-2 form-check-label font-weight-bold' %>
32
33
  <div class="col-sm-10">
33
- <%= f.check_box :confidential, class: 'form-control', disabled: !Doorkeeper::Application.supports_confidentiality? %>
34
+ <%= f.check_box :confidential, class: "checkbox #{ 'is-invalid' if application.errors[:confidential].present? }" %>
34
35
  <%= doorkeeper_errors_for application, :confidential %>
35
- <span class="help-block">
36
+ <span class="form-text text-secondary">
36
37
  <%= t('doorkeeper.applications.help.confidential') %>
37
38
  </span>
38
39
  </div>
39
- <% end %>
40
+ </div>
40
41
 
41
- <%= content_tag :div, class: "form-group#{' has-error' if application.errors[:scopes].present?}" do %>
42
- <%= f.label :scopes, class: 'col-sm-2 control-label' %>
42
+ <div class="form-group row">
43
+ <%= f.label :scopes, class: 'col-sm-2 col-form-label font-weight-bold' %>
43
44
  <div class="col-sm-10">
44
- <%= f.text_field :scopes, class: 'form-control' %>
45
+ <%= f.text_field :scopes, class: "form-control #{ 'has-error' if application.errors[:scopes].present? }" %>
45
46
  <%= doorkeeper_errors_for application, :scopes %>
46
- <span class="help-block">
47
+ <span class="form-text text-secondary">
47
48
  <%= t('doorkeeper.applications.help.scopes') %>
48
49
  </span>
49
50
  </div>
50
- <% end %>
51
+ </div>
51
52
 
52
53
  <div class="form-group">
53
54
  <div class="col-sm-offset-2 col-sm-10">
54
- <%= f.submit t('doorkeeper.applications.buttons.submit'), class: "btn btn-primary" %>
55
- <%= link_to t('doorkeeper.applications.buttons.cancel'), oauth_applications_path, class: "btn btn-default" %>
55
+ <%= f.submit t('doorkeeper.applications.buttons.submit'), class: 'btn btn-primary' %>
56
+ <%= link_to t('doorkeeper.applications.buttons.cancel'), oauth_applications_path, class: 'btn btn-secondary' %>
56
57
  </div>
57
58
  </div>
58
59
  <% end %>
@@ -1,4 +1,4 @@
1
- <div class="page-header">
1
+ <div class="border-bottom mb-4">
2
2
  <h1><%= t('.title') %></h1>
3
3
  </div>
4
4
 
@@ -1,4 +1,4 @@
1
- <div class="page-header">
1
+ <div class="border-bottom mb-4">
2
2
  <h1><%= t('.title') %></h1>
3
3
  </div>
4
4
 
@@ -10,18 +10,28 @@
10
10
  <th><%= t('.name') %></th>
11
11
  <th><%= t('.callback_url') %></th>
12
12
  <th><%= t('.confidential') %></th>
13
- <th></th>
13
+ <th><%= t('.actions') %></th>
14
14
  <th></th>
15
15
  </tr>
16
16
  </thead>
17
17
  <tbody>
18
18
  <% @applications.each do |application| %>
19
19
  <tr id="application_<%= application.id %>">
20
- <td><%= link_to application.name, oauth_application_path(application) %></td>
21
- <td><%= application.redirect_uri %></td>
22
- <td><%= application.confidential? ? t('doorkeeper.applications.index.confidentiality.yes') : t('doorkeeper.applications.index.confidentiality.no') %></td>
23
- <td><%= link_to t('doorkeeper.applications.buttons.edit'), edit_oauth_application_path(application), class: 'btn btn-link' %></td>
24
- <td><%= render 'delete_form', application: application %></td>
20
+ <td class="align-middle">
21
+ <%= link_to application.name, oauth_application_path(application) %>
22
+ </td>
23
+ <td class="align-middle">
24
+ <%= application.redirect_uri %>
25
+ </td>
26
+ <td class="align-middle">
27
+ <%= application.confidential? ? t('doorkeeper.applications.index.confidentiality.yes') : t('doorkeeper.applications.index.confidentiality.no') %>
28
+ </td>
29
+ <td class="align-middle">
30
+ <%= link_to t('doorkeeper.applications.buttons.edit'), edit_oauth_application_path(application), class: 'btn btn-link' %>
31
+ </td>
32
+ <td class="align-middle">
33
+ <%= render 'delete_form', application: application %>
34
+ </td>
25
35
  </tr>
26
36
  <% end %>
27
37
  </tbody>
@@ -1,4 +1,4 @@
1
- <div class="page-header">
1
+ <div class="border-bottom mb-4">
2
2
  <h1><%= t('.title') %></h1>
3
3
  </div>
4
4
 
@@ -1,20 +1,20 @@
1
- <div class="page-header">
1
+ <div class="border-bottom mb-4">
2
2
  <h1><%= t('.title', name: @application.name) %></h1>
3
3
  </div>
4
4
 
5
5
  <div class="row">
6
6
  <div class="col-md-8">
7
7
  <h4><%= t('.application_id') %>:</h4>
8
- <p><code id="application_id"><%= @application.uid %></code></p>
8
+ <p><code class="bg-light" id="application_id"><%= @application.uid %></code></p>
9
9
 
10
10
  <h4><%= t('.secret') %>:</h4>
11
- <p><code id="secret"><%= @application.secret %></code></p>
11
+ <p><code class="bg-light" id="secret"><%= @application.secret %></code></p>
12
12
 
13
13
  <h4><%= t('.scopes') %>:</h4>
14
- <p><code id="scopes"><%= @application.scopes %></code></p>
14
+ <p><code class="bg-light" id="scopes"><%= @application.scopes.presence || raw('&nbsp;') %></code></p>
15
15
 
16
16
  <h4><%= t('.confidential') %>:</h4>
17
- <p><code id="confidential"><%= @application.confidential? %></code></p>
17
+ <p><code class="bg-light" id="confidential"><%= @application.confidential? %></code></p>
18
18
 
19
19
  <h4><%= t('.callback_urls') %>:</h4>
20
20
 
@@ -22,7 +22,7 @@
22
22
  <% @application.redirect_uri.split.each do |uri| %>
23
23
  <tr>
24
24
  <td>
25
- <code><%= uri %></code>
25
+ <code class="bg-light"><%= uri %></code>
26
26
  </td>
27
27
  <td>
28
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' %>
@@ -1,4 +1,4 @@
1
- <div class="page-header">
1
+ <div class="border-bottom mb-4">
2
2
  <h1><%= t('doorkeeper.authorizations.error.title') %></h1>
3
3
  </div>
4
4
 
@@ -26,6 +26,8 @@
26
26
  <%= hidden_field_tag :state, @pre_auth.state %>
27
27
  <%= hidden_field_tag :response_type, @pre_auth.response_type %>
28
28
  <%= hidden_field_tag :scope, @pre_auth.scope %>
29
+ <%= hidden_field_tag :code_challenge, @pre_auth.code_challenge %>
30
+ <%= hidden_field_tag :code_challenge_method, @pre_auth.code_challenge_method %>
29
31
  <%= submit_tag t('doorkeeper.authorizations.buttons.authorize'), class: "btn btn-success btn-lg btn-block" %>
30
32
  <% end %>
31
33
  <%= form_tag oauth_authorization_path, method: :delete do %>
@@ -34,6 +36,8 @@
34
36
  <%= hidden_field_tag :state, @pre_auth.state %>
35
37
  <%= hidden_field_tag :response_type, @pre_auth.response_type %>
36
38
  <%= hidden_field_tag :scope, @pre_auth.scope %>
39
+ <%= hidden_field_tag :code_challenge, @pre_auth.code_challenge %>
40
+ <%= hidden_field_tag :code_challenge_method, @pre_auth.code_challenge_method %>
37
41
  <%= submit_tag t('doorkeeper.authorizations.buttons.deny'), class: "btn btn-danger btn-lg btn-block" %>
38
42
  <% end %>
39
43
  </div>
@@ -4,27 +4,27 @@
4
4
  <meta charset="utf-8">
5
5
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
- <title>Doorkeeper</title>
7
+ <title><%= t('doorkeeper.layouts.admin.title') %></title>
8
8
  <%= stylesheet_link_tag "doorkeeper/admin/application" %>
9
9
  <%= csrf_meta_tags %>
10
10
  </head>
11
11
  <body>
12
- <div class="navbar navbar-inverse navbar-static-top" role="navigation">
13
- <div class="container-fluid">
14
- <div class="navbar-header">
15
- <%= link_to t('doorkeeper.layouts.admin.nav.oauth2_provider'), oauth_applications_path, class: 'navbar-brand' %>
16
- </div>
17
- <ul class="nav navbar-nav">
18
- <%= content_tag :li, class: "#{'active' if request.path == oauth_applications_path}" do %>
19
- <%= link_to t('doorkeeper.layouts.admin.nav.applications'), oauth_applications_path %>
20
- <% end %>
21
- <%= content_tag :li do %>
22
- <%= link_to t('doorkeeper.layouts.admin.nav.home'), root_path %>
23
- <% end %>
12
+ <nav class="navbar navbar-expand-lg navbar-dark bg-dark mb-5">
13
+ <%= link_to t('doorkeeper.layouts.admin.nav.oauth2_provider'), oauth_applications_path, class: 'navbar-brand' %>
14
+
15
+ <div class="collapse navbar-collapse">
16
+ <ul class="navbar-nav mr-auto">
17
+ <li class="nav-item <%= 'active' if request.path == oauth_applications_path %>">
18
+ <%= link_to t('doorkeeper.layouts.admin.nav.applications'), oauth_applications_path, class: 'nav-link' %>
19
+ </li>
20
+ <li class="nav-item">
21
+ <%= link_to t('doorkeeper.layouts.admin.nav.home'), root_path, class: 'nav-link' %>
22
+ </li>
24
23
  </ul>
25
24
  </div>
26
- </div>
27
- <div class="container">
25
+ </nav>
26
+
27
+ <div class="doorkeeper-admin container">
28
28
  <%- if flash[:notice].present? %>
29
29
  <div class="alert alert-info">
30
30
  <%= flash[:notice] %>
@@ -14,6 +14,8 @@ en:
14
14
  relative_uri: 'must be an absolute URI.'
15
15
  secured_uri: 'must be an HTTPS/SSL URI.'
16
16
  forbidden_uri: 'is forbidden by the server.'
17
+ scopes:
18
+ not_match_configured: "doesn't match configured on the server."
17
19
 
18
20
  doorkeeper:
19
21
  applications:
@@ -40,14 +42,15 @@ en:
40
42
  name: 'Name'
41
43
  callback_url: 'Callback URL'
42
44
  confidential: 'Confidential?'
45
+ actions: 'Actions'
43
46
  confidentiality:
44
- yes: 'Yes'
45
- no: 'No'
47
+ 'yes': 'Yes'
48
+ 'no': 'No'
46
49
  new:
47
50
  title: 'New Application'
48
51
  show:
49
52
  title: 'Application: %{name}'
50
- application_id: 'Application Id'
53
+ application_id: 'Application UID'
51
54
  secret: 'Secret'
52
55
  scopes: 'Scopes'
53
56
  confidential: 'Confidential'
@@ -78,6 +81,9 @@ en:
78
81
  created_at: 'Created At'
79
82
  date_format: '%Y-%m-%d %H:%M:%S'
80
83
 
84
+ pre_authorization:
85
+ status: 'Pre-authorization'
86
+
81
87
  errors:
82
88
  messages:
83
89
  # Common error messages
@@ -86,6 +92,7 @@ en:
86
92
  unauthorized_client: 'The client is not authorized to perform this request using this method.'
87
93
  access_denied: 'The resource owner or authorization server denied the request.'
88
94
  invalid_scope: 'The requested scope is invalid, unknown, or malformed.'
95
+ invalid_code_challenge_method: 'The code challenge method must be plain or S256.'
89
96
  server_error: 'The authorization server encountered an unexpected condition which prevented it from fulfilling the request.'
90
97
  temporarily_unavailable: 'The authorization server is currently unable to handle the request due to a temporary overloading or maintenance of the server.'
91
98
 
@@ -120,6 +127,7 @@ en:
120
127
 
121
128
  layouts:
122
129
  admin:
130
+ title: 'Doorkeeper'
123
131
  nav:
124
132
  oauth2_provider: 'OAuth2 Provider'
125
133
  applications: 'Applications'
data/doorkeeper.gemspec CHANGED
@@ -27,6 +27,4 @@ Gem::Specification.new do |s|
27
27
  s.add_development_dependency "generator_spec", "~> 0.9.3"
28
28
  s.add_development_dependency "rake", ">= 11.3.0"
29
29
  s.add_development_dependency "rspec-rails"
30
-
31
- s.post_install_message = Doorkeeper::CVE_2018_1000211_WARNING
32
30
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
- gem "rails", "5.2.0.rc1"
5
+ gem "rails", "5.2.0"
6
6
  gem "appraisal"
7
7
  gem "activerecord-jdbcsqlite3-adapter", platforms: :jruby
8
8
  gem "sqlite3", platforms: [:ruby, :mswin, :mingw, :x64_mingw]
@@ -15,19 +15,19 @@ module Doorkeeper
15
15
  end
16
16
 
17
17
  def self.configuration
18
- @config || (fail MissingConfiguration)
18
+ @config || (raise MissingConfiguration)
19
19
  end
20
20
 
21
21
  def self.setup_orm_adapter
22
22
  @orm_adapter = "doorkeeper/orm/#{configuration.orm}".classify.constantize
23
- rescue NameError => e
24
- fail e, "ORM adapter not found (#{configuration.orm})", <<-ERROR_MSG.squish
25
- [doorkeeper] ORM adapter not found (#{configuration.orm}), or there was an error
26
- trying to load it.
27
-
28
- You probably need to add the related gem for this adapter to work with
29
- doorkeeper.
30
- ERROR_MSG
23
+ rescue NameError => error
24
+ raise error, "ORM adapter not found (#{configuration.orm})", <<-ERROR_MSG.strip_heredoc
25
+ [doorkeeper] ORM adapter not found (#{configuration.orm}), or there was an error
26
+ trying to load it.
27
+
28
+ You probably need to add the related gem for this adapter to work with
29
+ doorkeeper.
30
+ ERROR_MSG
31
31
  end
32
32
 
33
33
  def self.setup_orm_models
@@ -90,7 +90,7 @@ doorkeeper.
90
90
  #
91
91
  # @param methods [Array] Define client credentials
92
92
  def client_credentials(*methods)
93
- @config.instance_variable_set(:@client_credentials, methods)
93
+ @config.instance_variable_set(:@client_credentials_methods, methods)
94
94
  end
95
95
 
96
96
  # Change the way access token is authenticated from the request object.
@@ -114,6 +114,25 @@ doorkeeper.
114
114
  def reuse_access_token
115
115
  @config.instance_variable_set(:@reuse_access_token, true)
116
116
  end
117
+
118
+ # Use an API mode for applications generated with --api argument
119
+ # It will skip applications controller, disable forgery protection
120
+ def api_only
121
+ @config.instance_variable_set(:@api_only, true)
122
+ end
123
+
124
+ # Forbids creating/updating applications with arbitrary scopes that are
125
+ # not in configuration, i.e. `default_scopes` or `optional_scopes`.
126
+ # (disabled by default)
127
+ def enforce_configured_scopes
128
+ @config.instance_variable_set(:@enforce_configured_scopes, true)
129
+ end
130
+
131
+ # Enforce request content type as the spec requires:
132
+ # disabled by default for backward compatibility.
133
+ def enforce_content_type
134
+ @config.instance_variable_set(:@enforce_content_type, true)
135
+ end
117
136
  end
118
137
 
119
138
  module Option
@@ -179,7 +198,10 @@ doorkeeper.
179
198
  option :resource_owner_authenticator,
180
199
  as: :authenticate_resource_owner,
181
200
  default: (lambda do |_routes|
182
- ::Rails.logger.warn(I18n.t('doorkeeper.errors.messages.resource_owner_authenticator_not_configured'))
201
+ ::Rails.logger.warn(
202
+ I18n.t('doorkeeper.errors.messages.resource_owner_authenticator_not_configured')
203
+ )
204
+
183
205
  nil
184
206
  end)
185
207
 
@@ -189,15 +211,20 @@ doorkeeper.
189
211
 
190
212
  option :resource_owner_from_credentials,
191
213
  default: (lambda do |_routes|
192
- ::Rails.logger.warn(I18n.t('doorkeeper.errors.messages.credential_flow_not_configured'))
214
+ ::Rails.logger.warn(
215
+ I18n.t('doorkeeper.errors.messages.credential_flow_not_configured')
216
+ )
217
+
193
218
  nil
194
219
  end)
220
+ option :before_successful_authorization, default: ->(_context) {}
221
+ option :after_successful_authorization, default: ->(_context) {}
195
222
  option :before_successful_strategy_response, default: ->(_request) {}
196
223
  option :after_successful_strategy_response,
197
224
  default: ->(_request, _response) {}
198
225
  option :skip_authorization, default: ->(_routes) {}
199
226
  option :access_token_expires_in, default: 7200
200
- option :custom_access_token_expires_in, default: ->(_app) { nil }
227
+ option :custom_access_token_expires_in, default: ->(_context) { nil }
201
228
  option :authorization_code_expires_in, default: 600
202
229
  option :orm, default: :active_record
203
230
  option :native_redirect_uri, default: 'urn:ietf:wg:oauth:2.0:oob'
@@ -232,7 +259,6 @@ doorkeeper.
232
259
  #
233
260
  option :force_ssl_in_redirect_uri, default: !Rails.env.development?
234
261
 
235
-
236
262
  # Use a custom class for generating the access token.
237
263
  # https://github.com/doorkeeper-gem/doorkeeper#custom-access-token-generator
238
264
  #
@@ -251,20 +277,31 @@ doorkeeper.
251
277
  default: 'ActionController::Base'
252
278
 
253
279
  attr_reader :reuse_access_token
280
+ attr_reader :api_only
281
+ attr_reader :enforce_content_type
282
+
283
+ def api_only
284
+ @api_only ||= false
285
+ end
286
+
287
+ def enforce_content_type
288
+ @enforce_content_type ||= false
289
+ end
254
290
 
255
291
  def refresh_token_enabled?
256
- @refresh_token_enabled ||= false
257
- !!@refresh_token_enabled
292
+ !!(defined?(@refresh_token_enabled) && @refresh_token_enabled)
293
+ end
294
+
295
+ def enforce_configured_scopes?
296
+ !!(defined?(@enforce_configured_scopes) && @enforce_configured_scopes)
258
297
  end
259
298
 
260
299
  def enable_application_owner?
261
- @enable_application_owner ||= false
262
- !!@enable_application_owner
300
+ !!(defined?(@enable_application_owner) && @enable_application_owner)
263
301
  end
264
302
 
265
303
  def confirm_application_owner?
266
- @confirm_application_owner ||= false
267
- !!@confirm_application_owner
304
+ !!(defined?(@confirm_application_owner) && @confirm_application_owner)
268
305
  end
269
306
 
270
307
  def default_scopes
@@ -280,7 +317,7 @@ doorkeeper.
280
317
  end
281
318
 
282
319
  def client_credentials_methods
283
- @client_credentials ||= %i[from_basic from_params]
320
+ @client_credentials_methods ||= %i[from_basic from_params]
284
321
  end
285
322
 
286
323
  def access_token_methods
@@ -288,11 +325,11 @@ doorkeeper.
288
325
  end
289
326
 
290
327
  def authorization_response_types
291
- @authorization_response_types ||= calculate_authorization_response_types
328
+ @authorization_response_types ||= calculate_authorization_response_types.freeze
292
329
  end
293
330
 
294
331
  def token_grant_types
295
- @token_grant_types ||= calculate_token_grant_types
332
+ @token_grant_types ||= calculate_token_grant_types.freeze
296
333
  end
297
334
 
298
335
  private
@@ -17,6 +17,10 @@ module Doorkeeper
17
17
 
18
18
  if defined?(Sprockets) && Sprockets::VERSION.chr.to_i >= 4
19
19
  initializer 'doorkeeper.assets.precompile' do |app|
20
+ # Force users to use:
21
+ # //= link doorkeeper/admin/application.css
22
+ # in Doorkeeper 5 for Sprockets 4 instead of precompile.
23
+ # Add note to official docs & Wiki
20
24
  app.config.assets.precompile += %w[
21
25
  doorkeeper/application.css
22
26
  doorkeeper/admin/application.css
@@ -36,10 +36,7 @@ module Doorkeeper
36
36
  end
37
37
  end
38
38
 
39
- class UnableToGenerateToken < DoorkeeperError
40
- end
41
-
42
- class TokenGeneratorNotFound < DoorkeeperError
43
- end
39
+ UnableToGenerateToken = Class.new(DoorkeeperError)
40
+ TokenGeneratorNotFound = Class.new(DoorkeeperError)
44
41
  end
45
42
  end
@@ -31,7 +31,7 @@ module Doorkeeper
31
31
  end
32
32
 
33
33
  def doorkeeper_token
34
- @_doorkeeper_token ||= OAuth::Token.authenticate(
34
+ @doorkeeper_token ||= OAuth::Token.authenticate(
35
35
  decorated_request,
36
36
  *Doorkeeper.configuration.access_token_methods
37
37
  )
@@ -30,11 +30,11 @@ module Doorkeeper
30
30
 
31
31
  # :doc:
32
32
  def doorkeeper_token
33
- @token ||= OAuth::Token.authenticate request, *config_methods
33
+ @doorkeeper_token ||= OAuth::Token.authenticate request, *config_methods
34
34
  end
35
35
 
36
36
  def config_methods
37
- @methods ||= Doorkeeper.configuration.access_token_methods
37
+ @config_methods ||= Doorkeeper.configuration.access_token_methods
38
38
  end
39
39
 
40
40
  def get_error_response_from_exception(exception)
@@ -51,6 +51,11 @@ module Doorkeeper
51
51
  def skip_authorization?
52
52
  !!instance_exec([@server.current_resource_owner, @pre_auth.client], &Doorkeeper.configuration.skip_authorization)
53
53
  end
54
+
55
+ def enforce_content_type
56
+ return if request.content_type == 'application/x-www-form-urlencoded'
57
+ render json: {}, status: :unsupported_media_type
58
+ end
54
59
  end
55
60
  end
56
61
  end
@@ -9,6 +9,15 @@ module Doorkeeper
9
9
  include Models::Orderable
10
10
  include Models::Scopes
11
11
 
12
+ # never uses pkce, if pkce migrations were not generated
13
+ def uses_pkce?
14
+ pkce_supported? && code_challenge.present?
15
+ end
16
+
17
+ def pkce_supported?
18
+ respond_to? :code_challenge
19
+ end
20
+
12
21
  module ClassMethods
13
22
  # Searches for Doorkeeper::AccessGrant record with the
14
23
  # specific token value.
@@ -21,6 +30,53 @@ module Doorkeeper
21
30
  def by_token(token)
22
31
  find_by(token: token.to_s)
23
32
  end
33
+
34
+ # Implements PKCE code_challenge encoding without base64 padding as described in the spec.
35
+ # https://tools.ietf.org/html/rfc7636#appendix-A
36
+ # Appendix A. Notes on Implementing Base64url Encoding without Padding
37
+ #
38
+ # This appendix describes how to implement a base64url-encoding
39
+ # function without padding, based upon the standard base64-encoding
40
+ # function that uses padding.
41
+ #
42
+ # To be concrete, example C# code implementing these functions is shown
43
+ # below. Similar code could be used in other languages.
44
+ #
45
+ # static string base64urlencode(byte [] arg)
46
+ # {
47
+ # string s = Convert.ToBase64String(arg); // Regular base64 encoder
48
+ # s = s.Split('=')[0]; // Remove any trailing '='s
49
+ # s = s.Replace('+', '-'); // 62nd char of encoding
50
+ # s = s.Replace('/', '_'); // 63rd char of encoding
51
+ # return s;
52
+ # }
53
+ #
54
+ # An example correspondence between unencoded and encoded values
55
+ # follows. The octet sequence below encodes into the string below,
56
+ # which when decoded, reproduces the octet sequence.
57
+ #
58
+ # 3 236 255 224 193
59
+ #
60
+ # A-z_4ME
61
+ #
62
+ # https://ruby-doc.org/stdlib-2.1.3/libdoc/base64/rdoc/Base64.html#method-i-urlsafe_encode64
63
+ #
64
+ # urlsafe_encode64(bin)
65
+ # Returns the Base64-encoded version of bin. This method complies with
66
+ # “Base 64 Encoding with URL and Filename Safe Alphabet” in RFC 4648.
67
+ # The alphabet uses '-' instead of '+' and '_' instead of '/'.
68
+
69
+ # @param code_verifier [#to_s] a one time use value (any object that responds to `#to_s`)
70
+ #
71
+ # @return [#to_s] An encoded code challenge based on the provided verifier suitable for PKCE validation
72
+ def generate_code_challenge(code_verifier)
73
+ padded_result = Base64.urlsafe_encode64(Digest::SHA256.digest(code_verifier))
74
+ padded_result.split('=')[0] # Remove any trailing '='
75
+ end
76
+
77
+ def pkce_supported?
78
+ new.pkce_supported?
79
+ end
24
80
  end
25
81
  end
26
82
  end