doorkeeper 4.4.3 → 5.0.0.rc1

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 (169) 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 -17
  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 +9 -1
  28. data/doorkeeper.gemspec +0 -2
  29. data/gemfiles/rails_5_2.gemfile +1 -1
  30. data/lib/doorkeeper/config.rb +58 -35
  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 +38 -21
  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/password_access_token_request.rb +7 -4
  49. data/lib/doorkeeper/oauth/pre_authorization.rb +41 -11
  50. data/lib/doorkeeper/oauth/refresh_token_request.rb +6 -1
  51. data/lib/doorkeeper/oauth/scopes.rb +1 -1
  52. data/lib/doorkeeper/oauth/token.rb +5 -2
  53. data/lib/doorkeeper/oauth/token_introspection.rb +2 -2
  54. data/lib/doorkeeper/oauth/token_response.rb +4 -2
  55. data/lib/doorkeeper/oauth.rb +13 -0
  56. data/lib/doorkeeper/orm/active_record/application.rb +13 -16
  57. data/lib/doorkeeper/orm/active_record/stale_records_cleaner.rb +26 -0
  58. data/lib/doorkeeper/orm/active_record.rb +2 -0
  59. data/lib/doorkeeper/rails/helpers.rb +2 -4
  60. data/lib/doorkeeper/rails/routes.rb +14 -6
  61. data/lib/doorkeeper/rake/db.rake +40 -0
  62. data/lib/doorkeeper/rake/setup.rake +6 -0
  63. data/lib/doorkeeper/rake.rb +14 -0
  64. data/lib/doorkeeper/request.rb +28 -28
  65. data/lib/doorkeeper/version.rb +5 -25
  66. data/lib/doorkeeper.rb +4 -17
  67. data/lib/generators/doorkeeper/application_owner_generator.rb +23 -18
  68. data/lib/generators/doorkeeper/confidential_applications_generator.rb +32 -0
  69. data/lib/generators/doorkeeper/install_generator.rb +17 -9
  70. data/lib/generators/doorkeeper/migration_generator.rb +23 -18
  71. data/lib/generators/doorkeeper/pkce_generator.rb +32 -0
  72. data/lib/generators/doorkeeper/previous_refresh_token_generator.rb +29 -24
  73. data/lib/generators/doorkeeper/templates/add_confidential_to_applications.rb.erb +13 -0
  74. data/lib/generators/doorkeeper/templates/enable_pkce_migration.rb.erb +6 -0
  75. data/lib/generators/doorkeeper/templates/initializer.rb +60 -9
  76. data/lib/generators/doorkeeper/views_generator.rb +3 -1
  77. data/spec/controllers/application_metal_controller_spec.rb +50 -0
  78. data/spec/controllers/applications_controller_spec.rb +126 -13
  79. data/spec/controllers/authorizations_controller_spec.rb +252 -49
  80. data/spec/controllers/protected_resources_controller_spec.rb +16 -16
  81. data/spec/controllers/token_info_controller_spec.rb +4 -12
  82. data/spec/controllers/tokens_controller_spec.rb +19 -73
  83. data/spec/dummy/app/assets/config/manifest.js +2 -0
  84. data/spec/dummy/config/environments/test.rb +4 -5
  85. data/spec/dummy/config/initializers/doorkeeper.rb +5 -4
  86. data/spec/dummy/config/initializers/new_framework_defaults.rb +4 -0
  87. data/spec/dummy/config/routes.rb +3 -42
  88. data/spec/dummy/db/migrate/20170822064514_enable_pkce.rb +6 -0
  89. data/spec/dummy/db/migrate/{20180210183654_add_confidential_to_application.rb → 20180210183654_add_confidential_to_applications.rb} +1 -1
  90. data/spec/dummy/db/schema.rb +36 -36
  91. data/spec/generators/application_owner_generator_spec.rb +1 -1
  92. data/spec/generators/confidential_applications_generator_spec.rb +45 -0
  93. data/spec/generators/install_generator_spec.rb +1 -1
  94. data/spec/generators/migration_generator_spec.rb +1 -1
  95. data/spec/generators/pkce_generator_spec.rb +43 -0
  96. data/spec/generators/previous_refresh_token_generator_spec.rb +1 -1
  97. data/spec/generators/views_generator_spec.rb +1 -1
  98. data/spec/grape/grape_integration_spec.rb +1 -1
  99. data/spec/helpers/doorkeeper/dashboard_helper_spec.rb +1 -1
  100. data/spec/lib/config_spec.rb +51 -31
  101. data/spec/lib/doorkeeper_spec.rb +1 -126
  102. data/spec/lib/models/expirable_spec.rb +0 -3
  103. data/spec/lib/models/revocable_spec.rb +0 -2
  104. data/spec/lib/models/scopes_spec.rb +0 -4
  105. data/spec/lib/oauth/authorization/uri_builder_spec.rb +0 -4
  106. data/spec/lib/oauth/authorization_code_request_spec.rb +9 -2
  107. data/spec/lib/oauth/base_request_spec.rb +16 -2
  108. data/spec/lib/oauth/base_response_spec.rb +1 -1
  109. data/spec/lib/oauth/client/credentials_spec.rb +1 -3
  110. data/spec/lib/oauth/client_credentials/creator_spec.rb +5 -1
  111. data/spec/lib/oauth/client_credentials/issuer_spec.rb +26 -7
  112. data/spec/lib/oauth/client_credentials/validation_spec.rb +2 -3
  113. data/spec/lib/oauth/client_credentials_integration_spec.rb +1 -1
  114. data/spec/lib/oauth/client_credentials_request_spec.rb +3 -5
  115. data/spec/lib/oauth/client_spec.rb +0 -3
  116. data/spec/lib/oauth/code_request_spec.rb +4 -2
  117. data/spec/lib/oauth/error_response_spec.rb +0 -3
  118. data/spec/lib/oauth/error_spec.rb +0 -2
  119. data/spec/lib/oauth/forbidden_token_response_spec.rb +1 -4
  120. data/spec/lib/oauth/helpers/scope_checker_spec.rb +0 -3
  121. data/spec/lib/oauth/helpers/unique_token_spec.rb +0 -1
  122. data/spec/lib/oauth/helpers/uri_checker_spec.rb +5 -7
  123. data/spec/lib/oauth/invalid_token_response_spec.rb +1 -4
  124. data/spec/lib/oauth/password_access_token_request_spec.rb +37 -2
  125. data/spec/lib/oauth/pre_authorization_spec.rb +33 -4
  126. data/spec/lib/oauth/refresh_token_request_spec.rb +11 -7
  127. data/spec/lib/oauth/scopes_spec.rb +0 -3
  128. data/spec/lib/oauth/token_request_spec.rb +4 -5
  129. data/spec/lib/oauth/token_response_spec.rb +0 -1
  130. data/spec/lib/oauth/token_spec.rb +37 -14
  131. data/spec/lib/orm/active_record/stale_records_cleaner_spec.rb +79 -0
  132. data/spec/lib/request/strategy_spec.rb +0 -1
  133. data/spec/lib/server_spec.rb +1 -1
  134. data/spec/models/doorkeeper/access_grant_spec.rb +1 -1
  135. data/spec/models/doorkeeper/access_token_spec.rb +50 -16
  136. data/spec/models/doorkeeper/application_spec.rb +1 -47
  137. data/spec/requests/applications/applications_request_spec.rb +89 -1
  138. data/spec/requests/applications/authorized_applications_spec.rb +1 -1
  139. data/spec/requests/endpoints/authorization_spec.rb +1 -1
  140. data/spec/requests/endpoints/token_spec.rb +7 -5
  141. data/spec/requests/flows/authorization_code_errors_spec.rb +1 -1
  142. data/spec/requests/flows/authorization_code_spec.rb +198 -2
  143. data/spec/requests/flows/client_credentials_spec.rb +46 -6
  144. data/spec/requests/flows/implicit_grant_errors_spec.rb +1 -1
  145. data/spec/requests/flows/implicit_grant_spec.rb +38 -11
  146. data/spec/requests/flows/password_spec.rb +56 -2
  147. data/spec/requests/flows/refresh_token_spec.rb +2 -2
  148. data/spec/requests/flows/revoke_token_spec.rb +11 -11
  149. data/spec/requests/flows/skip_authorization_spec.rb +16 -11
  150. data/spec/requests/protected_resources/metal_spec.rb +1 -1
  151. data/spec/requests/protected_resources/private_api_spec.rb +1 -1
  152. data/spec/routing/custom_controller_routes_spec.rb +59 -7
  153. data/spec/routing/default_routes_spec.rb +2 -2
  154. data/spec/routing/scoped_routes_spec.rb +16 -2
  155. data/spec/spec_helper.rb +54 -3
  156. data/spec/spec_helper_integration.rb +2 -74
  157. data/spec/support/dependencies/{factory_girl.rb → factory_bot.rb} +0 -0
  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
@@ -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,6 +42,7 @@ en:
40
42
  name: 'Name'
41
43
  callback_url: 'Callback URL'
42
44
  confidential: 'Confidential?'
45
+ actions: 'Actions'
43
46
  confidentiality:
44
47
  'yes': 'Yes'
45
48
  'no': 'No'
@@ -47,7 +50,7 @@ en:
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.
@@ -115,13 +115,23 @@ doorkeeper.
115
115
  @config.instance_variable_set(:@reuse_access_token, true)
116
116
  end
117
117
 
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)
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)
125
135
  end
126
136
  end
127
137
 
@@ -188,7 +198,10 @@ doorkeeper.
188
198
  option :resource_owner_authenticator,
189
199
  as: :authenticate_resource_owner,
190
200
  default: (lambda do |_routes|
191
- ::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
+
192
205
  nil
193
206
  end)
194
207
 
@@ -198,15 +211,20 @@ doorkeeper.
198
211
 
199
212
  option :resource_owner_from_credentials,
200
213
  default: (lambda do |_routes|
201
- ::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
+
202
218
  nil
203
219
  end)
220
+ option :before_successful_authorization, default: ->(_context) {}
221
+ option :after_successful_authorization, default: ->(_context) {}
204
222
  option :before_successful_strategy_response, default: ->(_request) {}
205
223
  option :after_successful_strategy_response,
206
224
  default: ->(_request, _response) {}
207
225
  option :skip_authorization, default: ->(_routes) {}
208
226
  option :access_token_expires_in, default: 7200
209
- option :custom_access_token_expires_in, default: ->(_app) { nil }
227
+ option :custom_access_token_expires_in, default: ->(_context) { nil }
210
228
  option :authorization_code_expires_in, default: 600
211
229
  option :orm, default: :active_record
212
230
  option :native_redirect_uri, default: 'urn:ietf:wg:oauth:2.0:oob'
@@ -241,7 +259,6 @@ doorkeeper.
241
259
  #
242
260
  option :force_ssl_in_redirect_uri, default: !Rails.env.development?
243
261
 
244
-
245
262
  # Use a custom class for generating the access token.
246
263
  # https://github.com/doorkeeper-gem/doorkeeper#custom-access-token-generator
247
264
  #
@@ -260,20 +277,31 @@ doorkeeper.
260
277
  default: 'ActionController::Base'
261
278
 
262
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
263
290
 
264
291
  def refresh_token_enabled?
265
- @refresh_token_enabled ||= false
266
- !!@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)
267
297
  end
268
298
 
269
299
  def enable_application_owner?
270
- @enable_application_owner ||= false
271
- !!@enable_application_owner
300
+ !!(defined?(@enable_application_owner) && @enable_application_owner)
272
301
  end
273
302
 
274
303
  def confirm_application_owner?
275
- @confirm_application_owner ||= false
276
- !!@confirm_application_owner
304
+ !!(defined?(@confirm_application_owner) && @confirm_application_owner)
277
305
  end
278
306
 
279
307
  def default_scopes
@@ -289,7 +317,7 @@ doorkeeper.
289
317
  end
290
318
 
291
319
  def client_credentials_methods
292
- @client_credentials ||= %i[from_basic from_params]
320
+ @client_credentials_methods ||= %i[from_basic from_params]
293
321
  end
294
322
 
295
323
  def access_token_methods
@@ -297,16 +325,11 @@ doorkeeper.
297
325
  end
298
326
 
299
327
  def authorization_response_types
300
- @authorization_response_types ||= calculate_authorization_response_types
328
+ @authorization_response_types ||= calculate_authorization_response_types.freeze
301
329
  end
302
330
 
303
331
  def token_grant_types
304
- @token_grant_types ||= calculate_token_grant_types
305
- end
306
-
307
- def native_authorization_code_route
308
- @opt_out_native_route_change ||= false
309
- @opt_out_native_route_change ? '/:code' : '/native'
332
+ @token_grant_types ||= calculate_token_grant_types.freeze
310
333
  end
311
334
 
312
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