doorkeeper 5.1.2 → 5.2.2

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 (107) hide show
  1. checksums.yaml +4 -4
  2. data/Appraisals +1 -1
  3. data/CHANGELOG.md +854 -0
  4. data/CONTRIBUTING.md +11 -9
  5. data/Dangerfile +2 -2
  6. data/Dockerfile +29 -0
  7. data/Gemfile +3 -2
  8. data/NEWS.md +1 -819
  9. data/README.md +11 -3
  10. data/RELEASING.md +6 -5
  11. data/app/controllers/doorkeeper/application_controller.rb +1 -1
  12. data/app/controllers/doorkeeper/application_metal_controller.rb +2 -1
  13. data/app/controllers/doorkeeper/applications_controller.rb +5 -3
  14. data/app/controllers/doorkeeper/authorizations_controller.rb +14 -7
  15. data/app/controllers/doorkeeper/authorized_applications_controller.rb +1 -1
  16. data/app/controllers/doorkeeper/tokens_controller.rb +32 -9
  17. data/app/views/doorkeeper/applications/_form.html.erb +0 -6
  18. data/app/views/doorkeeper/applications/show.html.erb +1 -1
  19. data/config/locales/en.yml +8 -2
  20. data/doorkeeper.gemspec +9 -1
  21. data/gemfiles/rails_5_0.gemfile +1 -0
  22. data/gemfiles/rails_5_1.gemfile +1 -0
  23. data/gemfiles/rails_5_2.gemfile +1 -0
  24. data/gemfiles/rails_6_0.gemfile +2 -1
  25. data/gemfiles/rails_master.gemfile +1 -0
  26. data/lib/doorkeeper/config/option.rb +13 -7
  27. data/lib/doorkeeper/config.rb +88 -6
  28. data/lib/doorkeeper/errors.rb +13 -18
  29. data/lib/doorkeeper/grape/helpers.rb +5 -1
  30. data/lib/doorkeeper/helpers/controller.rb +23 -4
  31. data/lib/doorkeeper/models/access_token_mixin.rb +43 -2
  32. data/lib/doorkeeper/oauth/authorization/code.rb +11 -13
  33. data/lib/doorkeeper/oauth/authorization/token.rb +1 -1
  34. data/lib/doorkeeper/oauth/authorization_code_request.rb +18 -9
  35. data/lib/doorkeeper/oauth/base_request.rb +2 -0
  36. data/lib/doorkeeper/oauth/client_credentials/creator.rb +14 -0
  37. data/lib/doorkeeper/oauth/client_credentials/validation.rb +8 -0
  38. data/lib/doorkeeper/oauth/code_request.rb +5 -11
  39. data/lib/doorkeeper/oauth/code_response.rb +2 -2
  40. data/lib/doorkeeper/oauth/error_response.rb +1 -1
  41. data/lib/doorkeeper/oauth/helpers/uri_checker.rb +18 -4
  42. data/lib/doorkeeper/oauth/invalid_request_response.rb +43 -0
  43. data/lib/doorkeeper/oauth/nonstandard.rb +39 -0
  44. data/lib/doorkeeper/oauth/password_access_token_request.rb +7 -2
  45. data/lib/doorkeeper/oauth/pre_authorization.rb +70 -37
  46. data/lib/doorkeeper/oauth/refresh_token_request.rb +13 -10
  47. data/lib/doorkeeper/oauth/token_introspection.rb +23 -13
  48. data/lib/doorkeeper/oauth/token_request.rb +4 -18
  49. data/lib/doorkeeper/orm/active_record/access_grant.rb +1 -1
  50. data/lib/doorkeeper/orm/active_record/access_token.rb +2 -2
  51. data/lib/doorkeeper/orm/active_record/application.rb +15 -69
  52. data/lib/doorkeeper/orm/active_record/redirect_uri_validator.rb +61 -0
  53. data/lib/doorkeeper/orm/active_record.rb +19 -3
  54. data/lib/doorkeeper/request/authorization_code.rb +2 -0
  55. data/lib/doorkeeper/request.rb +6 -11
  56. data/lib/doorkeeper/server.rb +2 -6
  57. data/lib/doorkeeper/stale_records_cleaner.rb +6 -2
  58. data/lib/doorkeeper/version.rb +1 -1
  59. data/lib/doorkeeper.rb +4 -0
  60. data/lib/generators/doorkeeper/previous_refresh_token_generator.rb +6 -6
  61. data/lib/generators/doorkeeper/templates/initializer.rb +110 -33
  62. data/lib/generators/doorkeeper/templates/migration.rb.erb +4 -1
  63. data/spec/controllers/applications_controller_spec.rb +93 -0
  64. data/spec/controllers/authorizations_controller_spec.rb +143 -62
  65. data/spec/controllers/protected_resources_controller_spec.rb +3 -3
  66. data/spec/controllers/tokens_controller_spec.rb +205 -37
  67. data/spec/dummy/config/application.rb +3 -1
  68. data/spec/dummy/config/initializers/doorkeeper.rb +54 -9
  69. data/spec/dummy/db/migrate/20151223192035_create_doorkeeper_tables.rb +1 -1
  70. data/spec/lib/config_spec.rb +43 -1
  71. data/spec/lib/oauth/authorization_code_request_spec.rb +13 -1
  72. data/spec/lib/oauth/base_request_spec.rb +33 -16
  73. data/spec/lib/oauth/client_credentials/creator_spec.rb +3 -0
  74. data/spec/lib/oauth/code_request_spec.rb +27 -28
  75. data/spec/lib/oauth/helpers/uri_checker_spec.rb +17 -2
  76. data/spec/lib/oauth/invalid_request_response_spec.rb +75 -0
  77. data/spec/lib/oauth/pre_authorization_spec.rb +76 -66
  78. data/spec/lib/oauth/refresh_token_request_spec.rb +1 -0
  79. data/spec/lib/oauth/token_request_spec.rb +20 -17
  80. data/spec/lib/server_spec.rb +0 -12
  81. data/spec/models/doorkeeper/access_grant_spec.rb +21 -2
  82. data/spec/models/doorkeeper/access_token_spec.rb +35 -4
  83. data/spec/models/doorkeeper/application_spec.rb +275 -370
  84. data/spec/requests/endpoints/authorization_spec.rb +21 -5
  85. data/spec/requests/endpoints/token_spec.rb +1 -1
  86. data/spec/requests/flows/authorization_code_errors_spec.rb +1 -0
  87. data/spec/requests/flows/authorization_code_spec.rb +93 -27
  88. data/spec/requests/flows/client_credentials_spec.rb +38 -0
  89. data/spec/requests/flows/implicit_grant_errors_spec.rb +22 -10
  90. data/spec/requests/flows/implicit_grant_spec.rb +9 -8
  91. data/spec/requests/flows/password_spec.rb +37 -0
  92. data/spec/requests/flows/refresh_token_spec.rb +1 -1
  93. data/spec/requests/flows/revoke_token_spec.rb +19 -11
  94. data/spec/support/doorkeeper_rspec.rb +1 -1
  95. data/spec/support/helpers/request_spec_helper.rb +14 -2
  96. data/spec/validators/redirect_uri_validator_spec.rb +40 -15
  97. metadata +16 -15
  98. data/.coveralls.yml +0 -1
  99. data/.github/ISSUE_TEMPLATE.md +0 -25
  100. data/.github/PULL_REQUEST_TEMPLATE.md +0 -17
  101. data/.gitignore +0 -20
  102. data/.gitlab-ci.yml +0 -16
  103. data/.hound.yml +0 -3
  104. data/.rspec +0 -1
  105. data/.rubocop.yml +0 -50
  106. data/.travis.yml +0 -35
  107. data/app/validators/redirect_uri_validator.rb +0 -50
data/README.md CHANGED
@@ -21,10 +21,11 @@ Supported features:
21
21
  - [Implicit grant](http://tools.ietf.org/html/draft-ietf-oauth-v2-22#section-4.2)
22
22
  - [Resource Owner Password Credentials](http://tools.ietf.org/html/draft-ietf-oauth-v2-22#section-4.3)
23
23
  - [Client Credentials](http://tools.ietf.org/html/draft-ietf-oauth-v2-22#section-4.4)
24
- - [Proof Key for Code Exchange](https://tools.ietf.org/html/rfc7636)
25
24
  - [OAuth 2.0 Token Revocation](http://tools.ietf.org/html/rfc7009)
26
25
  - [OAuth 2.0 Token Introspection](https://tools.ietf.org/html/rfc7662)
27
26
  - [OAuth 2.0 Threat Model and Security Considerations](http://tools.ietf.org/html/rfc6819)
27
+ - [OAuth 2.0 for Native Apps](https://tools.ietf.org/html/draft-ietf-oauth-native-apps-10)
28
+ - [Proof Key for Code Exchange by OAuth Public Clients](https://tools.ietf.org/html/rfc7636)
28
29
 
29
30
  ## Table of Contents
30
31
 
@@ -93,6 +94,7 @@ Doorkeeper supports Active Record by default, but can be configured to work with
93
94
  | MongoDB | [doorkeeper-gem/doorkeeper-mongodb](https://github.com/doorkeeper-gem/doorkeeper-mongodb) |
94
95
  | Sequel | [nbulaj/doorkeeper-sequel](https://github.com/nbulaj/doorkeeper-sequel) |
95
96
  | Couchbase | [acaprojects/doorkeeper-couchbase](https://github.com/acaprojects/doorkeeper-couchbase) |
97
+ | RethinkDB | [aca-labs/doorkeeper-rethinkdb](https://github.com/aca-labs/doorkeeper-rethinkdb) |
96
98
 
97
99
  ## Extensions
98
100
 
@@ -136,6 +138,12 @@ Support this project by becoming a sponsor. Your logo will show up here with a l
136
138
 
137
139
  > If you prefer not to deal with the gory details of OAuth 2, need dedicated customer support & consulting, try the cloud-based SaaS version: [https://oauth.io](https://oauth.io/?utm_source=doorkeeper-gem)
138
140
 
141
+ <br>
142
+
143
+ <a href="https://www.wealthsimple.com/?utm_source=doorkeeper-gem" target="_blank"><img src="https://wealthsimple.s3.amazonaws.com/branding/medium-black.svg"/></a>
144
+
145
+ > Wealthsimple is a financial company on a mission to help everyone achieve financial freedom by providing products and advice that are accessible and affordable. Using smart technology, Wealthsimple takes financial services that are often confusing, opaque and expensive and makes them simple, transparent, and low-cost. See what Investing on Autopilot is all about: [https://www.wealthsimple.com](https://www.wealthsimple.com/?utm_source=doorkeeper-gem)
146
+
139
147
  ## Development
140
148
 
141
149
  To run the local engine server:
@@ -146,10 +154,10 @@ bundle exec rake doorkeeper:server
146
154
  ````
147
155
 
148
156
  By default, it uses the latest Rails version with ActiveRecord. To run the
149
- tests with a specific ORM and Rails version:
157
+ tests with a specific Rails version:
150
158
 
151
159
  ```
152
- rails=5.2 orm=active_record bundle exec rake
160
+ BUNDLE_GEMFILE=gemfiles/rails_6_0.gemfile bundle exec rake
153
161
  ```
154
162
 
155
163
  ## Contributing
data/RELEASING.md CHANGED
@@ -1,10 +1,11 @@
1
- # Releasing doorkeeper
1
+ # Releasing Doorkeeper
2
2
 
3
- How to release doorkeeper in five easy steps!
3
+ How to release Doorkeeper in five easy steps!
4
4
 
5
5
  1. Update `lib/doorkeeper/version.rb` file accordingly.
6
- 2. Update `NEWS.md` to reflect the changes since last release.
7
- 3. Commit changes: `git commit -am 'Bump to vVERSION'`
8
- 4. Run `rake release`
6
+ 2. Update `CHANGELOG.md` to reflect the changes since last release.
7
+ 3. Commit changes: `git commit -am 'Bump to vVERSION'`.
8
+ 4. Build and publish the gem.
9
+ 4. Create GitHub release.
9
10
  5. Announce the new release, making sure to say “thank you” to the contributors
10
11
  who helped shape this version!
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Doorkeeper
4
4
  class ApplicationController <
5
- Doorkeeper.configuration.base_controller.constantize
5
+ Doorkeeper.configuration.resolve_controller(:base)
6
6
  include Helpers::Controller
7
7
 
8
8
  unless Doorkeeper.configuration.api_only
@@ -1,7 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Doorkeeper
4
- class ApplicationMetalController < ActionController::API
4
+ class ApplicationMetalController <
5
+ Doorkeeper.configuration.resolve_controller(:base_metal)
5
6
  include Helpers::Controller
6
7
 
7
8
  before_action :enforce_content_type,
@@ -4,6 +4,7 @@ module Doorkeeper
4
4
  class ApplicationsController < Doorkeeper::ApplicationController
5
5
  layout "doorkeeper/admin" unless Doorkeeper.configuration.api_only
6
6
 
7
+ add_flash_types :application_secret unless Doorkeeper.configuration.api_only
7
8
  before_action :authenticate_admin!
8
9
  before_action :set_application, only: %i[show edit update destroy]
9
10
 
@@ -19,7 +20,7 @@ module Doorkeeper
19
20
  def show
20
21
  respond_to do |format|
21
22
  format.html
22
- format.json { render json: @application, as_owner: true }
23
+ format.json { render json: @application }
23
24
  end
24
25
  end
25
26
 
@@ -32,10 +33,11 @@ module Doorkeeper
32
33
 
33
34
  if @application.save
34
35
  flash[:notice] = I18n.t(:notice, scope: %i[doorkeeper flash applications create])
36
+ flash[:application_secret] = @application.plaintext_secret
35
37
 
36
38
  respond_to do |format|
37
39
  format.html { redirect_to oauth_application_url(@application) }
38
- format.json { render json: @application, as_owner: true }
40
+ format.json { render json: @application }
39
41
  end
40
42
  else
41
43
  respond_to do |format|
@@ -57,7 +59,7 @@ module Doorkeeper
57
59
 
58
60
  respond_to do |format|
59
61
  format.html { redirect_to oauth_application_url(@application) }
60
- format.json { render json: @application, as_owner: true }
62
+ format.json { render json: @application }
61
63
  end
62
64
  else
63
65
  respond_to do |format|
@@ -12,7 +12,6 @@ module Doorkeeper
12
12
  end
13
13
  end
14
14
 
15
- # TODO: Handle raise invalid authorization
16
15
  def create
17
16
  redirect_or_render authorize_response
18
17
  end
@@ -66,9 +65,16 @@ module Doorkeeper
66
65
  end
67
66
 
68
67
  def pre_auth
69
- @pre_auth ||= OAuth::PreAuthorization.new(Doorkeeper.configuration,
70
- server.client_via_uid,
71
- params)
68
+ @pre_auth ||= OAuth::PreAuthorization.new(Doorkeeper.configuration, pre_auth_params)
69
+ end
70
+
71
+ def pre_auth_params
72
+ params.slice(*pre_auth_param_fields).permit(*pre_auth_param_fields)
73
+ end
74
+
75
+ def pre_auth_param_fields
76
+ %i[client_id response_type redirect_uri scope state code_challenge
77
+ code_challenge_method]
72
78
  end
73
79
 
74
80
  def authorization
@@ -81,10 +87,11 @@ module Doorkeeper
81
87
 
82
88
  def authorize_response
83
89
  @authorize_response ||= begin
84
- authorizable = pre_auth.authorizable?
85
- before_successful_authorization if authorizable
90
+ return pre_auth.error_response unless pre_auth.authorizable?
91
+
92
+ before_successful_authorization
86
93
  auth = strategy.authorize
87
- after_successful_authorization if authorizable
94
+ after_successful_authorization
88
95
  auth
89
96
  end
90
97
  end
@@ -9,7 +9,7 @@ module Doorkeeper
9
9
 
10
10
  respond_to do |format|
11
11
  format.html
12
- format.json { render json: @applications, current_resource_owner: current_resource_owner }
12
+ format.json { render json: @applications }
13
13
  end
14
14
  end
15
15
 
@@ -6,8 +6,8 @@ module Doorkeeper
6
6
  headers.merge!(authorize_response.headers)
7
7
  render json: authorize_response.body,
8
8
  status: authorize_response.status
9
- rescue Errors::DoorkeeperError => error
10
- handle_token_exception(error)
9
+ rescue Errors::DoorkeeperError => e
10
+ handle_token_exception(e)
11
11
  end
12
12
 
13
13
  # OAuth 2.0 Token Revocation - http://tools.ietf.org/html/rfc7009
@@ -18,12 +18,13 @@ module Doorkeeper
18
18
  # Doorkeeper does not use the token_type_hint logic described in the
19
19
  # RFC 7009 due to the refresh token implementation that is a field in
20
20
  # the access token model.
21
- revoke_token if authorized?
22
21
 
23
- # The authorization server responds with HTTP status code 200 if the token
24
- # has been revoked successfully or if the client submitted an invalid
25
- # token
26
- render json: {}, status: 200
22
+ if authorized?
23
+ revoke_token
24
+ render json: {}, status: 200
25
+ else
26
+ render json: revocation_error_response, status: :forbidden
27
+ end
27
28
  end
28
29
 
29
30
  def introspect
@@ -71,7 +72,10 @@ module Doorkeeper
71
72
  end
72
73
 
73
74
  def revoke_token
74
- token.revoke if token.accessible?
75
+ # The authorization server responds with HTTP status code 200 if the token
76
+ # has been revoked successfully or if the client submitted an invalid
77
+ # token
78
+ token.revoke if token&.accessible?
75
79
  end
76
80
 
77
81
  def token
@@ -84,7 +88,26 @@ module Doorkeeper
84
88
  end
85
89
 
86
90
  def authorize_response
87
- @authorize_response ||= strategy.authorize
91
+ @authorize_response ||= begin
92
+ before_successful_authorization
93
+ auth = strategy.authorize
94
+ after_successful_authorization unless auth.is_a?(Doorkeeper::OAuth::ErrorResponse)
95
+ auth
96
+ end
97
+ end
98
+
99
+ def after_successful_authorization
100
+ Doorkeeper.configuration.after_successful_authorization.call(self)
101
+ end
102
+
103
+ def before_successful_authorization
104
+ Doorkeeper.configuration.before_successful_authorization.call(self)
105
+ end
106
+
107
+ def revocation_error_response
108
+ error_description = I18n.t(:unauthorized, scope: %i[doorkeeper errors messages revoke])
109
+
110
+ { error: :unauthorized_client, error_description: error_description }
88
111
  end
89
112
  end
90
113
  end
@@ -20,12 +20,6 @@
20
20
  <%= t('doorkeeper.applications.help.redirect_uri') %>
21
21
  </span>
22
22
 
23
- <% if 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 }) %>
26
- </span>
27
- <% end %>
28
-
29
23
  <% if Doorkeeper.configuration.allow_blank_redirect_uri?(application) %>
30
24
  <span class="form-text text-secondary">
31
25
  <%= t('doorkeeper.applications.help.blank_redirect_uri') %>
@@ -8,7 +8,7 @@
8
8
  <p><code class="bg-light" id="application_id"><%= @application.uid %></code></p>
9
9
 
10
10
  <h4><%= t('.secret') %>:</h4>
11
- <p><code class="bg-light" id="secret"><%= @application.plaintext_secret %></code></p>
11
+ <p><code class="bg-light" id="secret"><%= flash[:application_secret].presence || @application.plaintext_secret %></code></p>
12
12
 
13
13
  <h4><%= t('.scopes') %>:</h4>
14
14
  <p><code class="bg-light" id="scopes"><%= @application.scopes.presence || raw('&nbsp;') %></code></p>
@@ -11,6 +11,7 @@ en:
11
11
  redirect_uri:
12
12
  fragment_present: 'cannot contain a fragment.'
13
13
  invalid_uri: 'must be a valid URI.'
14
+ unspecified_scheme: 'must specify a scheme.'
14
15
  relative_uri: 'must be an absolute URI.'
15
16
  secured_uri: 'must be an HTTPS/SSL URI.'
16
17
  forbidden_uri: 'is forbidden by the server.'
@@ -33,7 +34,6 @@ en:
33
34
  confidential: 'Application will be used where the client secret can be kept confidential. Native mobile apps and Single Page Apps are considered non-confidential.'
34
35
  redirect_uri: 'Use one line per URI'
35
36
  blank_redirect_uri: "Leave it blank if you configured your provider to use Client Credentials, Resource Owner Password Credentials or any other grant type that doesn't require redirect URI."
36
- native_redirect_uri: 'Use %{native_redirect_uri} if you want to add localhost URIs for development purposes'
37
37
  scopes: 'Separate scopes with spaces. Leave blank to use the default scopes.'
38
38
  edit:
39
39
  title: 'Edit application'
@@ -88,7 +88,11 @@ en:
88
88
  errors:
89
89
  messages:
90
90
  # Common error messages
91
- invalid_request: 'The request is missing a required parameter, includes an unsupported parameter value, or is otherwise malformed.'
91
+ invalid_request:
92
+ unknown: 'The request is missing a required parameter, includes an unsupported parameter value, or is otherwise malformed.'
93
+ missing_param: 'Missing required parameter: %{value}.'
94
+ not_support_pkce: 'Invalid code_verifier parameter. Server does not support pkce.'
95
+ request_not_authorized: 'Request need to be authorized. Required parameter for authorizing request is missing or invalid.'
92
96
  invalid_redirect_uri: "The requested redirect uri is malformed or doesn't match client redirect URI."
93
97
  unauthorized_client: 'The client is not authorized to perform this request using this method.'
94
98
  access_denied: 'The resource owner or authorization server denied the request.'
@@ -114,6 +118,8 @@ en:
114
118
  revoked: "The access token was revoked"
115
119
  expired: "The access token expired"
116
120
  unknown: "The access token is invalid"
121
+ revoke:
122
+ unauthorized: "You are not authorized to revoke this token"
117
123
 
118
124
  flash:
119
125
  applications:
data/doorkeeper.gemspec CHANGED
@@ -14,10 +14,18 @@ Gem::Specification.new do |gem|
14
14
  gem.description = "Doorkeeper is an OAuth 2 provider for Rails and Grape."
15
15
  gem.license = "MIT"
16
16
 
17
- gem.files = `git ls-files`.split("\n")
17
+ gem.files = `git ls-files`.split("\n").reject { |file| file.start_with?(".") }
18
18
  gem.test_files = `git ls-files -- spec/*`.split("\n")
19
19
  gem.require_paths = ["lib"]
20
20
 
21
+ gem.metadata = {
22
+ "homepage_uri" => "https://github.com/doorkeeper-gem/doorkeeper",
23
+ "changelog_uri" => "https://github.com/doorkeeper-gem/doorkeeper/blob/master/CHANGELOG.md",
24
+ "source_code_uri" => "https://github.com/doorkeeper-gem/doorkeeper",
25
+ "bug_tracker_uri" => "https://github.com/doorkeeper-gem/doorkeeper/issues",
26
+ "documentation_uri" => "https://doorkeeper.gitbook.io/guides/",
27
+ }
28
+
21
29
  gem.add_dependency "railties", ">= 5"
22
30
  gem.required_ruby_version = ">= 2.4"
23
31
 
@@ -9,6 +9,7 @@ gem "rspec-mocks", git: "https://github.com/rspec/rspec-mocks.git"
9
9
  gem "rspec-rails", branch: "4-0-dev", git: "https://github.com/rspec/rspec-rails.git"
10
10
  gem "rspec-support", git: "https://github.com/rspec/rspec-support.git"
11
11
  gem "rubocop", "~> 0.66"
12
+ gem "rubocop-performance"
12
13
  gem "bcrypt", "~> 3.1", require: false
13
14
  gem "activerecord-jdbcsqlite3-adapter", platform: :jruby
14
15
  gem "sqlite3", "~> 1.3", "< 1.4", platform: [:ruby, :mswin, :mingw, :x64_mingw]
@@ -9,6 +9,7 @@ gem "rspec-mocks", git: "https://github.com/rspec/rspec-mocks.git"
9
9
  gem "rspec-rails", branch: "4-0-dev", git: "https://github.com/rspec/rspec-rails.git"
10
10
  gem "rspec-support", git: "https://github.com/rspec/rspec-support.git"
11
11
  gem "rubocop", "~> 0.66"
12
+ gem "rubocop-performance"
12
13
  gem "bcrypt", "~> 3.1", require: false
13
14
  gem "activerecord-jdbcsqlite3-adapter", platform: :jruby
14
15
  gem "sqlite3", "~> 1.3", "< 1.4", platform: [:ruby, :mswin, :mingw, :x64_mingw]
@@ -9,6 +9,7 @@ gem "rspec-mocks", git: "https://github.com/rspec/rspec-mocks.git"
9
9
  gem "rspec-rails", branch: "4-0-dev", git: "https://github.com/rspec/rspec-rails.git"
10
10
  gem "rspec-support", git: "https://github.com/rspec/rspec-support.git"
11
11
  gem "rubocop", "~> 0.66"
12
+ gem "rubocop-performance"
12
13
  gem "bcrypt", "~> 3.1", require: false
13
14
  gem "activerecord-jdbcsqlite3-adapter", platform: :jruby
14
15
  gem "sqlite3", "~> 1.3", "< 1.4", platform: [:ruby, :mswin, :mingw, :x64_mingw]
@@ -2,13 +2,14 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
- gem "rails", "~> 6.0.0.beta3"
5
+ gem "rails", "~> 6.0.0"
6
6
  gem "rspec-core", git: "https://github.com/rspec/rspec-core.git"
7
7
  gem "rspec-expectations", git: "https://github.com/rspec/rspec-expectations.git"
8
8
  gem "rspec-mocks", git: "https://github.com/rspec/rspec-mocks.git"
9
9
  gem "rspec-rails", branch: "4-0-dev", git: "https://github.com/rspec/rspec-rails.git"
10
10
  gem "rspec-support", git: "https://github.com/rspec/rspec-support.git"
11
11
  gem "rubocop", "~> 0.66"
12
+ gem "rubocop-performance"
12
13
  gem "bcrypt", "~> 3.1", require: false
13
14
  gem "activerecord-jdbcsqlite3-adapter", platform: :jruby
14
15
  gem "sqlite3", "~> 1.4", platform: [:ruby, :mswin, :mingw, :x64_mingw]
@@ -9,6 +9,7 @@ gem "rspec-mocks", git: "https://github.com/rspec/rspec-mocks.git"
9
9
  gem "rspec-rails", branch: "4-0-dev", git: "https://github.com/rspec/rspec-rails.git"
10
10
  gem "rspec-support", git: "https://github.com/rspec/rspec-support.git"
11
11
  gem "rubocop", "~> 0.66"
12
+ gem "rubocop-performance"
12
13
  gem "bcrypt", "~> 3.1", require: false
13
14
  gem "activerecord-jdbcsqlite3-adapter", platform: :jruby
14
15
  gem "sqlite3", "~> 1.4", platform: [:ruby, :mswin, :mingw, :x64_mingw]
@@ -38,14 +38,20 @@ module Doorkeeper
38
38
 
39
39
  Builder.instance_eval do
40
40
  remove_method name if method_defined?(name)
41
- define_method name do |*args, &block|
42
- value = if attribute_builder
43
- attribute_builder.new(&block).build
44
- else
45
- block || args.first
46
- end
41
+ if options[:deprecated]
42
+ define_method name do |*_, &_|
43
+ Kernel.warn "[DOORKEEPER] #{name} has been deprecated and will soon be removed"
44
+ end
45
+ else
46
+ define_method name do |*args, &block|
47
+ value = if attribute_builder
48
+ attribute_builder.new(&block).build
49
+ else
50
+ block || args.first
51
+ end
47
52
 
48
- @config.instance_variable_set(:"@#{attribute}", value)
53
+ @config.instance_variable_set(:"@#{attribute}", value)
54
+ end
49
55
  end
50
56
  end
51
57
 
@@ -25,8 +25,8 @@ module Doorkeeper
25
25
 
26
26
  def self.setup_orm_adapter
27
27
  @orm_adapter = "doorkeeper/orm/#{configuration.orm}".classify.constantize
28
- rescue NameError => error
29
- raise error, "ORM adapter not found (#{configuration.orm})", <<-ERROR_MSG.strip_heredoc
28
+ rescue NameError => e
29
+ raise e, "ORM adapter not found (#{configuration.orm})", <<-ERROR_MSG.strip_heredoc
30
30
  [doorkeeper] ORM adapter not found (#{configuration.orm}), or there was an error
31
31
  trying to load it.
32
32
 
@@ -254,11 +254,37 @@ module Doorkeeper
254
254
  option :custom_access_token_expires_in, default: ->(_context) { nil }
255
255
  option :authorization_code_expires_in, default: 600
256
256
  option :orm, default: :active_record
257
- option :native_redirect_uri, default: "urn:ietf:wg:oauth:2.0:oob"
257
+ option :native_redirect_uri, default: "urn:ietf:wg:oauth:2.0:oob", deprecated: true
258
258
  option :active_record_options, default: {}
259
259
  option :grant_flows, default: %w[authorization_code client_credentials]
260
260
  option :handle_auth_errors, default: :render
261
261
 
262
+ # Allows to customize OAuth grant flows that +each+ application support.
263
+ # You can configure a custom block (or use a class respond to `#call`) that must
264
+ # return `true` in case Application instance supports requested OAuth grant flow
265
+ # during the authorization request to the server. This configuration +doesn't+
266
+ # set flows per application, it only allows to check if application supports
267
+ # specific grant flow.
268
+ #
269
+ # For example you can add an additional database column to `oauth_applications` table,
270
+ # say `t.array :grant_flows, default: []`, and store allowed grant flows that can
271
+ # be used with this application there. Then when authorization requested Doorkeeper
272
+ # will call this block to check if specific Application (passed with client_id and/or
273
+ # client_secret) is allowed to perform the request for the specific grant type
274
+ # (authorization, password, client_credentials, etc).
275
+ #
276
+ # Example of the block:
277
+ #
278
+ # ->(flow, client) { client.grant_flows.include?(flow) }
279
+ #
280
+ # In case this option invocation result is `false`, Doorkeeper server returns
281
+ # :unauthorized_client error and stops the request.
282
+ #
283
+ # @param allow_grant_flow_for_client [Proc] Block or any object respond to #call
284
+ # @return [Boolean] `true` if allow or `false` if forbid the request
285
+ #
286
+ option :allow_grant_flow_for_client, default: ->(_grant_flow, _client) { true }
287
+
262
288
  # Allows to forbid specific Application redirect URI's by custom rules.
263
289
  # Doesn't forbid any URI by default.
264
290
  #
@@ -288,7 +314,7 @@ module Doorkeeper
288
314
  option :force_ssl_in_redirect_uri, default: !Rails.env.development?
289
315
 
290
316
  # Use a custom class for generating the access token.
291
- # https://github.com/doorkeeper-gem/doorkeeper#custom-access-token-generator
317
+ # https://doorkeeper.gitbook.io/guides/configuration/other-configurations#custom-access-token-generator
292
318
  #
293
319
  # @param access_token_generator [String]
294
320
  # the name of the access token generator class
@@ -306,11 +332,20 @@ module Doorkeeper
306
332
 
307
333
  # The controller Doorkeeper::ApplicationController inherits from.
308
334
  # Defaults to ActionController::Base.
309
- # https://github.com/doorkeeper-gem/doorkeeper#custom-base-controller
335
+ # https://doorkeeper.gitbook.io/guides/configuration/other-configurations#custom-base-controller
310
336
  #
311
337
  # @param base_controller [String] the name of the base controller
312
338
  option :base_controller,
313
- default: "ActionController::Base"
339
+ default: (lambda do
340
+ api_only ? "ActionController::API" : "ActionController::Base"
341
+ end)
342
+
343
+ # The controller Doorkeeper::ApplicationMetalController inherits from.
344
+ # Defaults to ActionController::API.
345
+ #
346
+ # @param base_metal_controller [String] the name of the base controller
347
+ option :base_metal_controller,
348
+ default: "ActionController::API"
314
349
 
315
350
  # Allows to set blank redirect URIs for Applications in case
316
351
  # server configured to use URI-less grant flows.
@@ -321,6 +356,36 @@ module Doorkeeper
321
356
  grant_flows.exclude?("implicit")
322
357
  end)
323
358
 
359
+ # Configure protection of token introspection request.
360
+ # By default this configuration allows to introspect a token by
361
+ # another token of the same application, or to introspect the token
362
+ # that belongs to authorized client, or access token has been introspected
363
+ # is a public one (doesn't belong to any client)
364
+ #
365
+ # You can define any custom rule you need or just disable token
366
+ # introspection at all.
367
+ #
368
+ # @param token [Doorkeeper::AccessToken]
369
+ # token to be introspected
370
+ #
371
+ # @param authorized_client [Doorkeeper::Application]
372
+ # authorized client (if request is authorized using Basic auth with
373
+ # Client Credentials for example)
374
+ #
375
+ # @param authorized_token [Doorkeeper::AccessToken]
376
+ # Bearer token used to authorize the request
377
+ #
378
+ option :allow_token_introspection,
379
+ default: (lambda do |token, authorized_client, authorized_token|
380
+ if authorized_token
381
+ authorized_token.application == token&.application
382
+ elsif token.application
383
+ authorized_client == token.application
384
+ else
385
+ true
386
+ end
387
+ end)
388
+
324
389
  attr_reader :api_only,
325
390
  :enforce_content_type,
326
391
  :reuse_access_token,
@@ -354,6 +419,17 @@ module Doorkeeper
354
419
  @token_reuse_limit ||= 100
355
420
  end
356
421
 
422
+ def resolve_controller(name)
423
+ config_option = public_send(:"#{name}_controller")
424
+ controller_name = if config_option.respond_to?(:call)
425
+ instance_exec(&config_option)
426
+ else
427
+ config_option
428
+ end
429
+
430
+ controller_name.constantize
431
+ end
432
+
357
433
  def enforce_configured_scopes?
358
434
  option_set? :enforce_configured_scopes
359
435
  end
@@ -422,6 +498,12 @@ module Doorkeeper
422
498
  end
423
499
  end
424
500
 
501
+ def allow_grant_flow_for_client?(grant_flow, client)
502
+ return true unless option_defined?(:allow_grant_flow_for_client)
503
+
504
+ allow_grant_flow_for_client.call(grant_flow, client)
505
+ end
506
+
425
507
  def option_defined?(name)
426
508
  instance_variable_defined?("@#{name}")
427
509
  end
@@ -8,18 +8,6 @@ module Doorkeeper
8
8
  end
9
9
  end
10
10
 
11
- class InvalidAuthorizationStrategy < DoorkeeperError
12
- def type
13
- :unsupported_response_type
14
- end
15
- end
16
-
17
- class InvalidTokenReuse < DoorkeeperError
18
- def type
19
- :invalid_request
20
- end
21
- end
22
-
23
11
  class InvalidGrantReuse < DoorkeeperError
24
12
  def type
25
13
  :invalid_grant
@@ -32,7 +20,14 @@ module Doorkeeper
32
20
  end
33
21
  end
34
22
 
35
- class MissingRequestStrategy < DoorkeeperError
23
+ class MissingRequiredParameter < DoorkeeperError
24
+ attr_reader :missing_param
25
+
26
+ def initialize(missing_param)
27
+ super
28
+ @missing_param = missing_param
29
+ end
30
+
36
31
  def type
37
32
  :invalid_request
38
33
  end
@@ -50,10 +45,10 @@ module Doorkeeper
50
45
  TokenGeneratorNotFound = Class.new(DoorkeeperError)
51
46
  NoOrmCleaner = Class.new(DoorkeeperError)
52
47
 
53
- InvalidToken = Class.new BaseResponseError
54
- TokenExpired = Class.new InvalidToken
55
- TokenRevoked = Class.new InvalidToken
56
- TokenUnknown = Class.new InvalidToken
57
- TokenForbidden = Class.new InvalidToken
48
+ InvalidToken = Class.new(BaseResponseError)
49
+ TokenExpired = Class.new(InvalidToken)
50
+ TokenRevoked = Class.new(InvalidToken)
51
+ TokenUnknown = Class.new(InvalidToken)
52
+ TokenForbidden = Class.new(InvalidToken)
58
53
  end
59
54
  end
@@ -4,6 +4,8 @@ require "doorkeeper/grape/authorization_decorator"
4
4
 
5
5
  module Doorkeeper
6
6
  module Grape
7
+ # Doorkeeper helpers for Grape applications.
8
+ # Provides helpers for endpoints authorization based on defined set of scopes.
7
9
  module Helpers
8
10
  # These helpers are for grape >= 0.10
9
11
  extend ::Grape::API::Helpers
@@ -11,7 +13,9 @@ module Doorkeeper
11
13
 
12
14
  # endpoint specific scopes > parameter scopes > default scopes
13
15
  def doorkeeper_authorize!(*scopes)
14
- endpoint_scopes = endpoint.route_setting(:scopes) || endpoint.options[:route_options][:scopes]
16
+ endpoint_scopes = endpoint.route_setting(:scopes) ||
17
+ endpoint.options[:route_options][:scopes]
18
+
15
19
  scopes = if endpoint_scopes
16
20
  Doorkeeper::OAuth::Scopes.from_array(endpoint_scopes)
17
21
  elsif scopes && !scopes.empty?