doorkeeper 4.2.5 → 5.0.0

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 (215) hide show
  1. checksums.yaml +4 -4
  2. data/.github/ISSUE_TEMPLATE.md +25 -0
  3. data/.github/PULL_REQUEST_TEMPLATE.md +17 -0
  4. data/.gitignore +2 -1
  5. data/.gitlab-ci.yml +16 -0
  6. data/.hound.yml +2 -13
  7. data/.rubocop.yml +17 -0
  8. data/.travis.yml +19 -4
  9. data/Appraisals +8 -4
  10. data/CODE_OF_CONDUCT.md +46 -0
  11. data/Gemfile +1 -1
  12. data/NEWS.md +115 -0
  13. data/README.md +175 -39
  14. data/RELEASING.md +5 -12
  15. data/Rakefile +6 -0
  16. data/SECURITY.md +15 -0
  17. data/UPGRADE.md +2 -0
  18. data/app/assets/stylesheets/doorkeeper/admin/application.css +2 -2
  19. data/app/controllers/doorkeeper/application_controller.rb +2 -5
  20. data/app/controllers/doorkeeper/application_metal_controller.rb +4 -0
  21. data/app/controllers/doorkeeper/applications_controller.rb +47 -13
  22. data/app/controllers/doorkeeper/authorizations_controller.rb +55 -12
  23. data/app/controllers/doorkeeper/authorized_applications_controller.rb +19 -2
  24. data/app/controllers/doorkeeper/tokens_controller.rb +24 -17
  25. data/app/helpers/doorkeeper/dashboard_helper.rb +8 -6
  26. data/app/validators/redirect_uri_validator.rb +13 -2
  27. data/app/views/doorkeeper/applications/_delete_form.html.erb +3 -1
  28. data/app/views/doorkeeper/applications/_form.html.erb +31 -19
  29. data/app/views/doorkeeper/applications/edit.html.erb +1 -1
  30. data/app/views/doorkeeper/applications/index.html.erb +18 -6
  31. data/app/views/doorkeeper/applications/new.html.erb +1 -1
  32. data/app/views/doorkeeper/applications/show.html.erb +8 -5
  33. data/app/views/doorkeeper/authorizations/error.html.erb +1 -1
  34. data/app/views/doorkeeper/authorizations/new.html.erb +5 -1
  35. data/app/views/doorkeeper/authorized_applications/index.html.erb +0 -1
  36. data/app/views/layouts/doorkeeper/admin.html.erb +15 -15
  37. data/config/locales/en.yml +19 -6
  38. data/doorkeeper.gemspec +20 -20
  39. data/gemfiles/rails_4_2.gemfile +6 -4
  40. data/gemfiles/rails_5_0.gemfile +4 -4
  41. data/gemfiles/rails_5_1.gemfile +6 -7
  42. data/gemfiles/rails_5_2.gemfile +12 -0
  43. data/gemfiles/rails_master.gemfile +17 -0
  44. data/lib/doorkeeper/config.rb +123 -71
  45. data/lib/doorkeeper/engine.rb +7 -3
  46. data/lib/doorkeeper/errors.rb +20 -5
  47. data/lib/doorkeeper/grape/helpers.rb +14 -9
  48. data/lib/doorkeeper/helpers/controller.rb +16 -22
  49. data/lib/doorkeeper/models/access_grant_mixin.rb +67 -23
  50. data/lib/doorkeeper/models/access_token_mixin.rb +54 -55
  51. data/lib/doorkeeper/models/application_mixin.rb +16 -30
  52. data/lib/doorkeeper/models/concerns/expirable.rb +7 -5
  53. data/lib/doorkeeper/models/concerns/orderable.rb +13 -0
  54. data/lib/doorkeeper/models/concerns/scopes.rb +1 -1
  55. data/lib/doorkeeper/oauth/authorization/code.rb +31 -8
  56. data/lib/doorkeeper/oauth/authorization/context.rb +15 -0
  57. data/lib/doorkeeper/oauth/authorization/token.rb +46 -20
  58. data/lib/doorkeeper/oauth/authorization_code_request.rb +33 -3
  59. data/lib/doorkeeper/oauth/base_request.rb +23 -7
  60. data/lib/doorkeeper/oauth/client/credentials.rb +6 -4
  61. data/lib/doorkeeper/oauth/client.rb +2 -4
  62. data/lib/doorkeeper/oauth/client_credentials/creator.rb +2 -1
  63. data/lib/doorkeeper/oauth/client_credentials/issuer.rb +6 -3
  64. data/lib/doorkeeper/oauth/client_credentials/validation.rb +4 -6
  65. data/lib/doorkeeper/oauth/client_credentials_request.rb +0 -4
  66. data/lib/doorkeeper/oauth/error.rb +2 -2
  67. data/lib/doorkeeper/oauth/error_response.rb +11 -4
  68. data/lib/doorkeeper/oauth/forbidden_token_response.rb +1 -1
  69. data/lib/doorkeeper/oauth/helpers/scope_checker.rb +0 -8
  70. data/lib/doorkeeper/oauth/helpers/uri_checker.rb +15 -0
  71. data/lib/doorkeeper/oauth/invalid_token_response.rb +3 -4
  72. data/lib/doorkeeper/oauth/password_access_token_request.rb +8 -4
  73. data/lib/doorkeeper/oauth/pre_authorization.rb +45 -13
  74. data/lib/doorkeeper/oauth/refresh_token_request.rb +7 -1
  75. data/lib/doorkeeper/oauth/scopes.rb +19 -9
  76. data/lib/doorkeeper/oauth/token.rb +6 -3
  77. data/lib/doorkeeper/oauth/token_introspection.rb +128 -0
  78. data/lib/doorkeeper/oauth/token_response.rb +4 -2
  79. data/lib/doorkeeper/oauth.rb +13 -0
  80. data/lib/doorkeeper/orm/active_record/access_grant.rb +27 -0
  81. data/lib/doorkeeper/orm/active_record/access_token.rb +21 -20
  82. data/lib/doorkeeper/orm/active_record/application.rb +45 -0
  83. data/lib/doorkeeper/orm/active_record/stale_records_cleaner.rb +26 -0
  84. data/lib/doorkeeper/orm/active_record.rb +21 -8
  85. data/lib/doorkeeper/rails/helpers.rb +7 -10
  86. data/lib/doorkeeper/rails/routes.rb +21 -7
  87. data/lib/doorkeeper/rake/db.rake +40 -0
  88. data/lib/doorkeeper/rake/setup.rake +6 -0
  89. data/lib/doorkeeper/rake.rb +14 -0
  90. data/lib/doorkeeper/request/authorization_code.rb +0 -2
  91. data/lib/doorkeeper/request/client_credentials.rb +0 -2
  92. data/lib/doorkeeper/request/code.rb +0 -2
  93. data/lib/doorkeeper/request/password.rb +1 -13
  94. data/lib/doorkeeper/request/refresh_token.rb +0 -2
  95. data/lib/doorkeeper/request/token.rb +0 -2
  96. data/lib/doorkeeper/request.rb +29 -30
  97. data/lib/doorkeeper/validations.rb +3 -2
  98. data/lib/doorkeeper/version.rb +14 -1
  99. data/lib/doorkeeper.rb +21 -17
  100. data/lib/generators/doorkeeper/application_owner_generator.rb +26 -12
  101. data/lib/generators/doorkeeper/confidential_applications_generator.rb +32 -0
  102. data/lib/generators/doorkeeper/install_generator.rb +17 -9
  103. data/lib/generators/doorkeeper/migration_generator.rb +26 -9
  104. data/lib/generators/doorkeeper/pkce_generator.rb +32 -0
  105. data/lib/generators/doorkeeper/previous_refresh_token_generator.rb +31 -20
  106. data/lib/generators/doorkeeper/templates/add_confidential_to_applications.rb.erb +13 -0
  107. data/lib/generators/doorkeeper/templates/{add_owner_to_application_migration.rb → add_owner_to_application_migration.rb.erb} +1 -1
  108. data/lib/generators/doorkeeper/templates/{add_previous_refresh_token_to_access_tokens.rb → add_previous_refresh_token_to_access_tokens.rb.erb} +1 -1
  109. data/lib/generators/doorkeeper/templates/enable_pkce_migration.rb.erb +6 -0
  110. data/lib/generators/doorkeeper/templates/initializer.rb +104 -12
  111. data/lib/generators/doorkeeper/templates/{migration.rb → migration.rb.erb} +2 -1
  112. data/lib/generators/doorkeeper/views_generator.rb +3 -1
  113. data/spec/controllers/application_metal_controller_spec.rb +50 -0
  114. data/spec/controllers/applications_controller_spec.rb +141 -17
  115. data/spec/controllers/authorizations_controller_spec.rb +304 -27
  116. data/spec/controllers/protected_resources_controller_spec.rb +44 -35
  117. data/spec/controllers/token_info_controller_spec.rb +17 -21
  118. data/spec/controllers/tokens_controller_spec.rb +201 -17
  119. data/spec/dummy/app/assets/config/manifest.js +2 -0
  120. data/spec/dummy/config/environments/test.rb +4 -5
  121. data/spec/dummy/config/initializers/doorkeeper.rb +23 -2
  122. data/spec/dummy/config/initializers/{active_record_belongs_to_required_by_default.rb → new_framework_defaults.rb} +5 -1
  123. data/spec/dummy/config/initializers/secret_token.rb +0 -1
  124. data/spec/dummy/config/routes.rb +3 -42
  125. data/spec/dummy/db/migrate/20111122132257_create_users.rb +3 -1
  126. data/spec/dummy/db/migrate/20120312140401_add_password_to_users.rb +3 -1
  127. data/spec/dummy/db/migrate/20151223192035_create_doorkeeper_tables.rb +3 -1
  128. data/spec/dummy/db/migrate/20151223200000_add_owner_to_application.rb +3 -1
  129. data/spec/dummy/db/migrate/20160320211015_add_previous_refresh_token_to_access_tokens.rb +3 -1
  130. data/spec/dummy/db/migrate/20170822064514_enable_pkce.rb +6 -0
  131. data/spec/dummy/db/migrate/20180210183654_add_confidential_to_applications.rb +13 -0
  132. data/spec/dummy/db/schema.rb +38 -37
  133. data/spec/factories.rb +1 -1
  134. data/spec/generators/application_owner_generator_spec.rb +25 -6
  135. data/spec/generators/confidential_applications_generator_spec.rb +45 -0
  136. data/spec/generators/install_generator_spec.rb +1 -1
  137. data/spec/generators/migration_generator_spec.rb +25 -4
  138. data/spec/generators/pkce_generator_spec.rb +43 -0
  139. data/spec/generators/previous_refresh_token_generator_spec.rb +57 -0
  140. data/spec/generators/views_generator_spec.rb +1 -1
  141. data/spec/grape/grape_integration_spec.rb +135 -0
  142. data/spec/helpers/doorkeeper/dashboard_helper_spec.rb +2 -2
  143. data/spec/lib/config_spec.rb +199 -22
  144. data/spec/lib/doorkeeper_spec.rb +1 -126
  145. data/spec/lib/models/expirable_spec.rb +0 -4
  146. data/spec/lib/models/revocable_spec.rb +2 -4
  147. data/spec/lib/models/scopes_spec.rb +0 -4
  148. data/spec/lib/oauth/authorization/uri_builder_spec.rb +0 -4
  149. data/spec/lib/oauth/authorization_code_request_spec.rb +63 -13
  150. data/spec/lib/oauth/base_request_spec.rb +43 -10
  151. data/spec/lib/oauth/base_response_spec.rb +1 -1
  152. data/spec/lib/oauth/client/credentials_spec.rb +5 -5
  153. data/spec/lib/oauth/client_credentials/creator_spec.rb +6 -2
  154. data/spec/lib/oauth/client_credentials/issuer_spec.rb +26 -7
  155. data/spec/lib/oauth/client_credentials/validation_spec.rb +2 -3
  156. data/spec/lib/oauth/client_credentials_integration_spec.rb +2 -2
  157. data/spec/lib/oauth/client_credentials_request_spec.rb +4 -5
  158. data/spec/lib/oauth/client_spec.rb +0 -3
  159. data/spec/lib/oauth/code_request_spec.rb +5 -5
  160. data/spec/lib/oauth/error_response_spec.rb +0 -3
  161. data/spec/lib/oauth/error_spec.rb +1 -3
  162. data/spec/lib/oauth/forbidden_token_response_spec.rb +1 -4
  163. data/spec/lib/oauth/helpers/scope_checker_spec.rb +0 -3
  164. data/spec/lib/oauth/helpers/unique_token_spec.rb +0 -1
  165. data/spec/lib/oauth/helpers/uri_checker_spec.rb +115 -3
  166. data/spec/lib/oauth/invalid_token_response_spec.rb +2 -5
  167. data/spec/lib/oauth/password_access_token_request_spec.rb +46 -5
  168. data/spec/lib/oauth/pre_authorization_spec.rb +40 -6
  169. data/spec/lib/oauth/refresh_token_request_spec.rb +30 -14
  170. data/spec/lib/oauth/scopes_spec.rb +28 -4
  171. data/spec/lib/oauth/token_request_spec.rb +10 -13
  172. data/spec/lib/oauth/token_response_spec.rb +0 -1
  173. data/spec/lib/oauth/token_spec.rb +37 -14
  174. data/spec/lib/orm/active_record/stale_records_cleaner_spec.rb +79 -0
  175. data/spec/lib/request/strategy_spec.rb +0 -1
  176. data/spec/lib/server_spec.rb +10 -0
  177. data/spec/models/doorkeeper/access_grant_spec.rb +45 -2
  178. data/spec/models/doorkeeper/access_token_spec.rb +132 -64
  179. data/spec/models/doorkeeper/application_spec.rb +114 -23
  180. data/spec/requests/applications/applications_request_spec.rb +139 -6
  181. data/spec/requests/applications/authorized_applications_spec.rb +1 -1
  182. data/spec/requests/endpoints/authorization_spec.rb +1 -1
  183. data/spec/requests/endpoints/token_spec.rb +15 -6
  184. data/spec/requests/flows/authorization_code_errors_spec.rb +12 -2
  185. data/spec/requests/flows/authorization_code_spec.rb +199 -2
  186. data/spec/requests/flows/client_credentials_spec.rb +73 -5
  187. data/spec/requests/flows/implicit_grant_errors_spec.rb +3 -3
  188. data/spec/requests/flows/implicit_grant_spec.rb +38 -11
  189. data/spec/requests/flows/password_spec.rb +160 -24
  190. data/spec/requests/flows/refresh_token_spec.rb +6 -6
  191. data/spec/requests/flows/revoke_token_spec.rb +26 -26
  192. data/spec/requests/flows/skip_authorization_spec.rb +16 -11
  193. data/spec/requests/protected_resources/metal_spec.rb +2 -2
  194. data/spec/requests/protected_resources/private_api_spec.rb +2 -2
  195. data/spec/routing/custom_controller_routes_spec.rb +63 -7
  196. data/spec/routing/default_routes_spec.rb +6 -2
  197. data/spec/routing/scoped_routes_spec.rb +16 -2
  198. data/spec/spec_helper.rb +54 -3
  199. data/spec/spec_helper_integration.rb +2 -64
  200. data/spec/support/dependencies/factory_bot.rb +2 -0
  201. data/spec/support/doorkeeper_rspec.rb +19 -0
  202. data/spec/support/helpers/access_token_request_helper.rb +1 -1
  203. data/spec/support/helpers/authorization_request_helper.rb +4 -4
  204. data/spec/support/helpers/model_helper.rb +9 -4
  205. data/spec/support/helpers/request_spec_helper.rb +18 -6
  206. data/spec/support/helpers/url_helper.rb +15 -10
  207. data/spec/support/http_method_shim.rb +12 -16
  208. data/spec/support/shared/controllers_shared_context.rb +2 -6
  209. data/spec/support/shared/models_shared_examples.rb +4 -4
  210. data/spec/validators/redirect_uri_validator_spec.rb +58 -7
  211. data/spec/version/version_spec.rb +15 -0
  212. data/vendor/assets/stylesheets/doorkeeper/bootstrap.min.css +4 -5
  213. metadata +75 -33
  214. data/spec/controllers/application_metal_controller.rb +0 -10
  215. data/spec/support/dependencies/factory_girl.rb +0 -2
@@ -4,20 +4,15 @@ module Doorkeeper
4
4
 
5
5
  def new
6
6
  if pre_auth.authorizable?
7
- if skip_authorization? || matching_token?
8
- auth = authorization.authorize
9
- redirect_to auth.redirect_uri
10
- else
11
- render :new
12
- end
7
+ render_success
13
8
  else
14
- render :error
9
+ render_error
15
10
  end
16
11
  end
17
12
 
18
13
  # TODO: Handle raise invalid authorization
19
14
  def create
20
- redirect_or_render authorization.authorize
15
+ redirect_or_render authorize_response
21
16
  end
22
17
 
23
18
  def destroy
@@ -26,15 +21,45 @@ module Doorkeeper
26
21
 
27
22
  private
28
23
 
24
+ def render_success
25
+ if skip_authorization? || matching_token?
26
+ redirect_or_render authorize_response
27
+ elsif Doorkeeper.configuration.api_only
28
+ render json: pre_auth
29
+ else
30
+ render :new
31
+ end
32
+ end
33
+
34
+ def render_error
35
+ if Doorkeeper.configuration.api_only
36
+ render json: pre_auth.error_response.body,
37
+ status: :bad_request
38
+ else
39
+ render :error
40
+ end
41
+ end
42
+
29
43
  def matching_token?
30
- AccessToken.matching_token_for pre_auth.client,
31
- current_resource_owner.id,
32
- pre_auth.scopes
44
+ token = AccessToken.matching_token_for(
45
+ pre_auth.client,
46
+ current_resource_owner.id,
47
+ pre_auth.scopes
48
+ )
49
+
50
+ token && token.accessible?
33
51
  end
34
52
 
35
53
  def redirect_or_render(auth)
36
54
  if auth.redirectable?
37
- redirect_to auth.redirect_uri
55
+ if Doorkeeper.configuration.api_only
56
+ render(
57
+ json: { status: :redirect, redirect_uri: auth.redirect_uri },
58
+ status: auth.status
59
+ )
60
+ else
61
+ redirect_to auth.redirect_uri
62
+ end
38
63
  else
39
64
  render json: auth.body, status: auth.status
40
65
  end
@@ -53,5 +78,23 @@ module Doorkeeper
53
78
  def strategy
54
79
  @strategy ||= server.authorization_request pre_auth.response_type
55
80
  end
81
+
82
+ def authorize_response
83
+ @authorize_response ||= begin
84
+ authorizable = pre_auth.authorizable?
85
+ before_successful_authorization if authorizable
86
+ auth = strategy.authorize
87
+ after_successful_authorization if authorizable
88
+ auth
89
+ end
90
+ end
91
+
92
+ def after_successful_authorization
93
+ Doorkeeper.configuration.after_successful_authorization.call(self)
94
+ end
95
+
96
+ def before_successful_authorization
97
+ Doorkeeper.configuration.before_successful_authorization.call(self)
98
+ end
56
99
  end
57
100
  end
@@ -4,11 +4,28 @@ module Doorkeeper
4
4
 
5
5
  def index
6
6
  @applications = Application.authorized_for(current_resource_owner)
7
+
8
+ respond_to do |format|
9
+ format.html
10
+ format.json { render json: @applications }
11
+ end
7
12
  end
8
13
 
9
14
  def destroy
10
- AccessToken.revoke_all_for params[:id], current_resource_owner
11
- redirect_to oauth_authorized_applications_url, notice: I18n.t(:notice, scope: [:doorkeeper, :flash, :authorized_applications, :destroy])
15
+ Application.revoke_tokens_and_grants_for(
16
+ params[:id],
17
+ current_resource_owner
18
+ )
19
+
20
+ respond_to do |format|
21
+ format.html do
22
+ redirect_to oauth_authorized_applications_url, notice: I18n.t(
23
+ :notice, scope: %i[doorkeeper flash authorized_applications destroy]
24
+ )
25
+ end
26
+
27
+ format.json { render :no_content }
28
+ end
12
29
  end
13
30
  end
14
31
  end
@@ -4,7 +4,7 @@ module Doorkeeper
4
4
  response = authorize_response
5
5
  headers.merge! response.headers
6
6
  self.response_body = response.body.to_json
7
- self.status = response.status
7
+ self.status = response.status
8
8
  rescue Errors::DoorkeeperError => e
9
9
  handle_token_exception e
10
10
  end
@@ -17,9 +17,7 @@ module Doorkeeper
17
17
  # Doorkeeper does not use the token_type_hint logic described in the
18
18
  # RFC 7009 due to the refresh token implementation that is a field in
19
19
  # the access token model.
20
- if authorized?
21
- revoke_token
22
- end
20
+ revoke_token if authorized?
23
21
 
24
22
  # The authorization server responds with HTTP status code 200 if the token
25
23
  # has been revoked successfully or if the client submitted an invalid
@@ -27,6 +25,18 @@ module Doorkeeper
27
25
  render json: {}, status: 200
28
26
  end
29
27
 
28
+ def introspect
29
+ introspection = OAuth::TokenIntrospection.new(server, token)
30
+
31
+ if introspection.authorized?
32
+ render json: introspection.to_json, status: 200
33
+ else
34
+ error = OAuth::ErrorResponse.new(name: introspection.error)
35
+ response.headers.merge!(error.headers)
36
+ render json: error.body, status: error.status
37
+ end
38
+ end
39
+
30
40
  private
31
41
 
32
42
  # OAuth 2.0 Section 2.1 defines two client types, "public" & "confidential".
@@ -46,23 +56,20 @@ module Doorkeeper
46
56
  # https://tools.ietf.org/html/rfc6749#section-2.1
47
57
  # https://tools.ietf.org/html/rfc7009
48
58
  def authorized?
49
- if token.present?
50
- # Client is confidential, therefore client authentication & authorization
51
- # is required
52
- if token.application_id?
53
- # We authorize client by checking token's application
54
- server.client && server.client.application == token.application
55
- else
56
- # Client is public, authentication unnecessary
57
- true
58
- end
59
+ return unless token.present?
60
+ # Client is confidential, therefore client authentication & authorization
61
+ # is required
62
+ if token.application_id? && token.application.confidential?
63
+ # We authorize client by checking token's application
64
+ server.client && server.client.application == token.application
65
+ else
66
+ # Client is public, authentication unnecessary
67
+ true
59
68
  end
60
69
  end
61
70
 
62
71
  def revoke_token
63
- if token.accessible?
64
- token.revoke
65
- end
72
+ token.revoke if token.accessible?
66
73
  end
67
74
 
68
75
  def token
@@ -1,13 +1,15 @@
1
1
  module Doorkeeper
2
2
  module DashboardHelper
3
3
  def doorkeeper_errors_for(object, method)
4
- if object.errors[method].present?
5
- object.errors[method].map do |msg|
6
- content_tag(:span, class: 'help-block') do
7
- msg.capitalize
8
- end
9
- end.join.html_safe
4
+ return if object.errors[method].blank?
5
+
6
+ output = object.errors[method].map do |msg|
7
+ content_tag(:span, class: 'form-text') do
8
+ msg.capitalize
9
+ end
10
10
  end
11
+
12
+ safe_join(output)
11
13
  end
12
14
 
13
15
  def doorkeeper_submit_path(application)
@@ -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,18 @@ 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
+ non_https = uri.try(:scheme) == 'http'
38
+
39
+ if forces_ssl.respond_to?(:call)
40
+ forces_ssl.call(uri) && non_https
41
+ else
42
+ forces_ssl && non_https
43
+ end
33
44
  end
34
45
  end
@@ -1,4 +1,6 @@
1
1
  <%- submit_btn_css ||= 'btn btn-link' %>
2
2
  <%= form_tag oauth_application_path(application), method: :delete do %>
3
- <%= submit_tag t('doorkeeper.applications.buttons.destroy'), onclick: "return confirm('#{ t('doorkeeper.applications.confirmations.destroy') }')", class: submit_btn_css %>
3
+ <%= submit_tag t('doorkeeper.applications.buttons.destroy'),
4
+ onclick: "return confirm('#{ t('doorkeeper.applications.confirmations.destroy') }')",
5
+ class: submit_btn_css %>
4
6
  <% end %>
@@ -1,47 +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: "<code>#{ Doorkeeper.configuration.native_redirect_uri }</code>") %>
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>
30
+
31
+ <div class="form-group row">
32
+ <%= f.label :confidential, class: 'col-sm-2 form-check-label font-weight-bold' %>
33
+ <div class="col-sm-10">
34
+ <%= f.check_box :confidential, class: "checkbox #{ 'is-invalid' if application.errors[:confidential].present? }" %>
35
+ <%= doorkeeper_errors_for application, :confidential %>
36
+ <span class="form-text text-secondary">
37
+ <%= t('doorkeeper.applications.help.confidential') %>
38
+ </span>
39
+ </div>
40
+ </div>
29
41
 
30
- <%= content_tag :div, class: "form-group#{' has-error' if application.errors[:scopes].present?}" do %>
31
- <%= 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' %>
32
44
  <div class="col-sm-10">
33
- <%= f.text_field :scopes, class: 'form-control' %>
45
+ <%= f.text_field :scopes, class: "form-control #{ 'has-error' if application.errors[:scopes].present? }" %>
34
46
  <%= doorkeeper_errors_for application, :scopes %>
35
- <span class="help-block">
47
+ <span class="form-text text-secondary">
36
48
  <%= t('doorkeeper.applications.help.scopes') %>
37
49
  </span>
38
50
  </div>
39
- <% end %>
51
+ </div>
40
52
 
41
53
  <div class="form-group">
42
54
  <div class="col-sm-offset-2 col-sm-10">
43
- <%= 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
+ <%= 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' %>
45
57
  </div>
46
58
  </div>
47
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
 
@@ -9,17 +9,29 @@
9
9
  <tr>
10
10
  <th><%= t('.name') %></th>
11
11
  <th><%= t('.callback_url') %></th>
12
- <th></th>
12
+ <th><%= t('.confidential') %></th>
13
+ <th><%= t('.actions') %></th>
13
14
  <th></th>
14
15
  </tr>
15
16
  </thead>
16
17
  <tbody>
17
18
  <% @applications.each do |application| %>
18
19
  <tr id="application_<%= application.id %>">
19
- <td><%= link_to application.name, oauth_application_path(application) %></td>
20
- <td><%= application.redirect_uri %></td>
21
- <td><%= link_to t('doorkeeper.applications.buttons.edit'), edit_oauth_application_path(application), class: 'btn btn-link' %></td>
22
- <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
+ <%= simple_format(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>
23
35
  </tr>
24
36
  <% end %>
25
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,17 +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
+
16
+ <h4><%= t('.confidential') %>:</h4>
17
+ <p><code class="bg-light" id="confidential"><%= @application.confidential? %></code></p>
15
18
 
16
19
  <h4><%= t('.callback_urls') %>:</h4>
17
20
 
@@ -19,7 +22,7 @@
19
22
  <% @application.redirect_uri.split.each do |uri| %>
20
23
  <tr>
21
24
  <td>
22
- <code><%= uri %></code>
25
+ <code class="bg-light"><%= uri %></code>
23
26
  </td>
24
27
  <td>
25
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
 
@@ -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 %>
@@ -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>
@@ -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>
@@ -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] %>
@@ -13,6 +13,9 @@ 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.'
17
+ scopes:
18
+ not_match_configured: "doesn't match configured on the server."
16
19
 
17
20
  doorkeeper:
18
21
  applications:
@@ -27,8 +30,9 @@ en:
27
30
  form:
28
31
  error: 'Whoops! Check your form for possible errors'
29
32
  help:
33
+ 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
34
  redirect_uri: 'Use one line per URI'
31
- native_redirect_uri: 'Use %{native_redirect_uri} for local tests'
35
+ native_redirect_uri: 'Use %{native_redirect_uri} if you want to add localhost URIs for development purposes'
32
36
  scopes: 'Separate scopes with spaces. Leave blank to use the default scopes.'
33
37
  edit:
34
38
  title: 'Edit application'
@@ -37,13 +41,19 @@ en:
37
41
  new: 'New Application'
38
42
  name: 'Name'
39
43
  callback_url: 'Callback URL'
44
+ confidential: 'Confidential?'
45
+ actions: 'Actions'
46
+ confidentiality:
47
+ 'yes': 'Yes'
48
+ 'no': 'No'
40
49
  new:
41
50
  title: 'New Application'
42
51
  show:
43
52
  title: 'Application: %{name}'
44
- application_id: 'Application Id'
53
+ application_id: 'Application UID'
45
54
  secret: 'Secret'
46
55
  scopes: 'Scopes'
56
+ confidential: 'Confidential'
47
57
  callback_urls: 'Callback urls'
48
58
  actions: 'Actions'
49
59
 
@@ -71,20 +81,25 @@ en:
71
81
  created_at: 'Created At'
72
82
  date_format: '%Y-%m-%d %H:%M:%S'
73
83
 
84
+ pre_authorization:
85
+ status: 'Pre-authorization'
86
+
74
87
  errors:
75
88
  messages:
76
89
  # Common error messages
77
90
  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.'
91
+ invalid_redirect_uri: "The requested redirect uri is malformed or doesn't match client redirect URI."
79
92
  unauthorized_client: 'The client is not authorized to perform this request using this method.'
80
93
  access_denied: 'The resource owner or authorization server denied the request.'
81
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.'
82
96
  server_error: 'The authorization server encountered an unexpected condition which prevented it from fulfilling the request.'
83
97
  temporarily_unavailable: 'The authorization server is currently unable to handle the request due to a temporary overloading or maintenance of the server.'
84
98
 
85
99
  # Configuration error messages
86
100
  credential_flow_not_configured: 'Resource Owner Password Credentials flow failed due to Doorkeeper.configure.resource_owner_from_credentials being unconfigured.'
87
101
  resource_owner_authenticator_not_configured: 'Resource Owner find failed due to Doorkeeper.configure.resource_owner_authenticator being unconfigured.'
102
+ admin_authenticator_not_configured: 'Access to admin panel is forbidden due to Doorkeeper.configure.admin_authenticator being unconfigured.'
88
103
 
89
104
  # Access grant errors
90
105
  unsupported_response_type: 'The authorization server does not support this response type.'
@@ -94,9 +109,6 @@ en:
94
109
  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
110
  unsupported_grant_type: 'The authorization grant type is not supported by the authorization server.'
96
111
 
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
112
  invalid_token:
101
113
  revoked: "The access token was revoked"
102
114
  expired: "The access token expired"
@@ -116,6 +128,7 @@ en:
116
128
 
117
129
  layouts:
118
130
  admin:
131
+ title: 'Doorkeeper'
119
132
  nav:
120
133
  oauth2_provider: 'OAuth2 Provider'
121
134
  applications: 'Applications'