doorkeeper 4.3.2 → 4.4.3
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of doorkeeper might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/.rubocop.yml +4 -0
- data/NEWS.md +17 -0
- data/app/controllers/doorkeeper/applications_controller.rb +2 -1
- data/app/controllers/doorkeeper/tokens_controller.rb +9 -10
- data/app/views/doorkeeper/applications/_form.html.erb +11 -0
- data/app/views/doorkeeper/applications/index.html.erb +2 -0
- data/app/views/doorkeeper/applications/show.html.erb +3 -0
- data/config/locales/en.yml +6 -0
- data/doorkeeper.gemspec +2 -0
- data/lib/doorkeeper/config.rb +14 -0
- data/lib/doorkeeper/models/access_token_mixin.rb +1 -1
- data/lib/doorkeeper/models/application_mixin.rb +8 -1
- data/lib/doorkeeper/oauth/client/credentials.rb +3 -1
- data/lib/doorkeeper/oauth/helpers/uri_checker.rb +1 -0
- data/lib/doorkeeper/oauth/pre_authorization.rb +5 -3
- data/lib/doorkeeper/orm/active_record/application.rb +17 -0
- data/lib/doorkeeper/rails/routes.rb +5 -1
- data/lib/doorkeeper/request/password.rb +1 -11
- data/lib/doorkeeper/version.rb +23 -2
- data/lib/generators/doorkeeper/add_client_confidentiality_generator.rb +31 -0
- data/lib/generators/doorkeeper/templates/add_confidential_to_application_migration.rb.erb +11 -0
- data/lib/generators/doorkeeper/templates/migration.rb.erb +1 -0
- data/spec/controllers/authorizations_controller_spec.rb +34 -2
- data/spec/controllers/tokens_controller_spec.rb +59 -7
- data/spec/dummy/config/initializers/doorkeeper.rb +5 -0
- data/spec/dummy/db/migrate/20111122132257_create_users.rb +3 -1
- data/spec/dummy/db/migrate/20120312140401_add_password_to_users.rb +3 -1
- data/spec/dummy/db/migrate/20151223192035_create_doorkeeper_tables.rb +3 -1
- data/spec/dummy/db/migrate/20151223200000_add_owner_to_application.rb +3 -1
- data/spec/dummy/db/migrate/20160320211015_add_previous_refresh_token_to_access_tokens.rb +3 -1
- data/spec/dummy/db/migrate/20180210183654_add_confidential_to_application.rb +13 -0
- data/spec/dummy/db/schema.rb +2 -1
- data/spec/lib/config_spec.rb +25 -0
- data/spec/lib/oauth/authorization_code_request_spec.rb +15 -0
- data/spec/lib/oauth/client/credentials_spec.rb +4 -2
- data/spec/lib/oauth/helpers/uri_checker_spec.rb +5 -0
- data/spec/lib/oauth/pre_authorization_spec.rb +12 -7
- data/spec/models/doorkeeper/application_spec.rb +96 -5
- data/spec/requests/flows/authorization_code_spec.rb +1 -1
- data/spec/requests/flows/password_spec.rb +64 -21
- metadata +25 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8d8d3550d8406d4abb224c4960d1d6e8a0c4c706
|
4
|
+
data.tar.gz: b12408cb8b0dc2b14ee69b57798943b5c1bfaa30
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0674af950f6070d6457e09f73fc89736b092ae6595e484ca6e67e7f126912ea007509d9249fdc4eb01e66bf981c1e49da33712203d8428d10401a43faabd1cfd
|
7
|
+
data.tar.gz: e447513c202dfde4c622b898da2a98dff64272193136fe399b890bb97488e7915156a2588caa6de3566db411f4c7dfa89e88be3a8b8d0a76511251f2f980c382
|
data/.rubocop.yml
CHANGED
data/NEWS.md
CHANGED
@@ -4,6 +4,23 @@ User-visible changes worth mentioning.
|
|
4
4
|
|
5
5
|
## master
|
6
6
|
|
7
|
+
## 4.4.3
|
8
|
+
- [#1143] Adds a config option opt_out_native_route_change to opt out of the
|
9
|
+
breaking api changed introduced in
|
10
|
+
https://github.com/doorkeeper-gem/doorkeeper/pull/1003
|
11
|
+
|
12
|
+
## 4.4.2
|
13
|
+
- [#1130] Backport fix for native redirect_uri from 5.x.
|
14
|
+
|
15
|
+
## 4.4.1
|
16
|
+
|
17
|
+
- [#1127] Backport token type to comply with the RFC6750 specification.
|
18
|
+
- [#1125] Backport Quote surround I18n yes/no keys
|
19
|
+
|
20
|
+
## 4.4.0
|
21
|
+
|
22
|
+
- [#1120] Backport security fix from 5.x for token revocation when using public clients
|
23
|
+
|
7
24
|
## 4.3.2
|
8
25
|
|
9
26
|
- [#1053] Support authorizing with query params in the request `redirect_uri` if explicitly present in app's `Application#redirect_uri`
|
@@ -58,16 +58,15 @@ module Doorkeeper
|
|
58
58
|
# https://tools.ietf.org/html/rfc6749#section-2.1
|
59
59
|
# https://tools.ietf.org/html/rfc7009
|
60
60
|
def authorized?
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
end
|
61
|
+
return unless token.present?
|
62
|
+
# Client is confidential, therefore client authentication & authorization
|
63
|
+
# is required
|
64
|
+
if token.application_id? && token.application.confidential?
|
65
|
+
# We authorize client by checking token's application
|
66
|
+
server.client && server.client.application == token.application
|
67
|
+
else
|
68
|
+
# Client is public, authentication unnecessary
|
69
|
+
true
|
71
70
|
end
|
72
71
|
end
|
73
72
|
|
@@ -27,6 +27,17 @@
|
|
27
27
|
</div>
|
28
28
|
<% end %>
|
29
29
|
|
30
|
+
<%= content_tag :div, class: "form-group#{' has-error' if application.errors[:confidential].present?}" do %>
|
31
|
+
<%= f.label :confidential, class: 'col-sm-2 control-label' %>
|
32
|
+
<div class="col-sm-10">
|
33
|
+
<%= f.check_box :confidential, class: 'form-control', disabled: !Doorkeeper::Application.supports_confidentiality? %>
|
34
|
+
<%= doorkeeper_errors_for application, :confidential %>
|
35
|
+
<span class="help-block">
|
36
|
+
<%= t('doorkeeper.applications.help.confidential') %>
|
37
|
+
</span>
|
38
|
+
</div>
|
39
|
+
<% end %>
|
40
|
+
|
30
41
|
<%= content_tag :div, class: "form-group#{' has-error' if application.errors[:scopes].present?}" do %>
|
31
42
|
<%= f.label :scopes, class: 'col-sm-2 control-label' %>
|
32
43
|
<div class="col-sm-10">
|
@@ -9,6 +9,7 @@
|
|
9
9
|
<tr>
|
10
10
|
<th><%= t('.name') %></th>
|
11
11
|
<th><%= t('.callback_url') %></th>
|
12
|
+
<th><%= t('.confidential') %></th>
|
12
13
|
<th></th>
|
13
14
|
<th></th>
|
14
15
|
</tr>
|
@@ -18,6 +19,7 @@
|
|
18
19
|
<tr id="application_<%= application.id %>">
|
19
20
|
<td><%= link_to application.name, oauth_application_path(application) %></td>
|
20
21
|
<td><%= application.redirect_uri %></td>
|
22
|
+
<td><%= application.confidential? ? t('doorkeeper.applications.index.confidentiality.yes') : t('doorkeeper.applications.index.confidentiality.no') %></td>
|
21
23
|
<td><%= link_to t('doorkeeper.applications.buttons.edit'), edit_oauth_application_path(application), class: 'btn btn-link' %></td>
|
22
24
|
<td><%= render 'delete_form', application: application %></td>
|
23
25
|
</tr>
|
@@ -13,6 +13,9 @@
|
|
13
13
|
<h4><%= t('.scopes') %>:</h4>
|
14
14
|
<p><code id="scopes"><%= @application.scopes %></code></p>
|
15
15
|
|
16
|
+
<h4><%= t('.confidential') %>:</h4>
|
17
|
+
<p><code id="confidential"><%= @application.confidential? %></code></p>
|
18
|
+
|
16
19
|
<h4><%= t('.callback_urls') %>:</h4>
|
17
20
|
|
18
21
|
<table>
|
data/config/locales/en.yml
CHANGED
@@ -28,6 +28,7 @@ en:
|
|
28
28
|
form:
|
29
29
|
error: 'Whoops! Check your form for possible errors'
|
30
30
|
help:
|
31
|
+
confidential: 'Application will be used where the client secret can be kept confidential. Native mobile apps and Single Page Apps are considered non-confidential.'
|
31
32
|
redirect_uri: 'Use one line per URI'
|
32
33
|
native_redirect_uri: 'Use %{native_redirect_uri} if you want to add localhost URIs for development purposes'
|
33
34
|
scopes: 'Separate scopes with spaces. Leave blank to use the default scopes.'
|
@@ -38,6 +39,10 @@ en:
|
|
38
39
|
new: 'New Application'
|
39
40
|
name: 'Name'
|
40
41
|
callback_url: 'Callback URL'
|
42
|
+
confidential: 'Confidential?'
|
43
|
+
confidentiality:
|
44
|
+
'yes': 'Yes'
|
45
|
+
'no': 'No'
|
41
46
|
new:
|
42
47
|
title: 'New Application'
|
43
48
|
show:
|
@@ -45,6 +50,7 @@ en:
|
|
45
50
|
application_id: 'Application Id'
|
46
51
|
secret: 'Secret'
|
47
52
|
scopes: 'Scopes'
|
53
|
+
confidential: 'Confidential'
|
48
54
|
callback_urls: 'Callback urls'
|
49
55
|
actions: 'Actions'
|
50
56
|
|
data/doorkeeper.gemspec
CHANGED
data/lib/doorkeeper/config.rb
CHANGED
@@ -114,6 +114,15 @@ doorkeeper.
|
|
114
114
|
def reuse_access_token
|
115
115
|
@config.instance_variable_set(:@reuse_access_token, true)
|
116
116
|
end
|
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)
|
125
|
+
end
|
117
126
|
end
|
118
127
|
|
119
128
|
module Option
|
@@ -295,6 +304,11 @@ doorkeeper.
|
|
295
304
|
@token_grant_types ||= calculate_token_grant_types
|
296
305
|
end
|
297
306
|
|
307
|
+
def native_authorization_code_route
|
308
|
+
@opt_out_native_route_change ||= false
|
309
|
+
@opt_out_native_route_change ? '/:code' : '/native'
|
310
|
+
end
|
311
|
+
|
298
312
|
private
|
299
313
|
|
300
314
|
# Determines what values are acceptable for 'response_type' param in
|
@@ -10,6 +10,9 @@ module Doorkeeper
|
|
10
10
|
# Returns an instance of the Doorkeeper::Application with
|
11
11
|
# specific UID and secret.
|
12
12
|
#
|
13
|
+
# Public/Non-confidential applications will only find by uid if secret is
|
14
|
+
# blank.
|
15
|
+
#
|
13
16
|
# @param uid [#to_s] UID (any object that responds to `#to_s`)
|
14
17
|
# @param secret [#to_s] secret (any object that responds to `#to_s`)
|
15
18
|
#
|
@@ -17,7 +20,11 @@ module Doorkeeper
|
|
17
20
|
# if there is no record with such credentials
|
18
21
|
#
|
19
22
|
def by_uid_and_secret(uid, secret)
|
20
|
-
|
23
|
+
app = by_uid(uid)
|
24
|
+
return unless app
|
25
|
+
return app if secret.blank? && !app.confidential?
|
26
|
+
return unless app.secret == secret
|
27
|
+
app
|
21
28
|
end
|
22
29
|
|
23
30
|
# Returns an instance of the Doorkeeper::Application with specific UID.
|
@@ -57,9 +57,11 @@ module Doorkeeper
|
|
57
57
|
|
58
58
|
# TODO: test uri should be matched against the client's one
|
59
59
|
def validate_redirect_uri
|
60
|
-
return false
|
61
|
-
|
62
|
-
|
60
|
+
return false if redirect_uri.blank?
|
61
|
+
|
62
|
+
Helpers::URIChecker.valid_for_authorization?(
|
63
|
+
redirect_uri, client.redirect_uri
|
64
|
+
)
|
63
65
|
end
|
64
66
|
end
|
65
67
|
end
|
@@ -11,6 +11,7 @@ module Doorkeeper
|
|
11
11
|
validates :name, :secret, :uid, presence: true
|
12
12
|
validates :uid, uniqueness: true
|
13
13
|
validates :redirect_uri, redirect_uri: true
|
14
|
+
validates :confidential, inclusion: { in: [true, false] }
|
14
15
|
|
15
16
|
before_validation :generate_uid, :generate_secret, on: :create
|
16
17
|
|
@@ -31,6 +32,22 @@ module Doorkeeper
|
|
31
32
|
where(id: resource_access_tokens.select(:application_id).distinct)
|
32
33
|
end
|
33
34
|
|
35
|
+
# Fallback to existing, default behaviour of assuming all apps to be
|
36
|
+
# confidential if the migration hasn't been run
|
37
|
+
def confidential
|
38
|
+
return super if self.class.supports_confidentiality?
|
39
|
+
ActiveSupport::Deprecation.warn 'You are susceptible to security bug ' \
|
40
|
+
'CVE-2018-1000211. Please follow instructions outlined in ' \
|
41
|
+
'Doorkeeper::CVE_2018_1000211_WARNING'
|
42
|
+
true
|
43
|
+
end
|
44
|
+
|
45
|
+
alias_method :confidential?, :confidential
|
46
|
+
|
47
|
+
def self.supports_confidentiality?
|
48
|
+
column_names.include?('confidential')
|
49
|
+
end
|
50
|
+
|
34
51
|
private
|
35
52
|
|
36
53
|
def generate_uid
|
@@ -47,7 +47,7 @@ module Doorkeeper
|
|
47
47
|
as: mapping[:as],
|
48
48
|
controller: mapping[:controllers]
|
49
49
|
) do
|
50
|
-
routes.get
|
50
|
+
routes.get native_authorization_code_route, action: :show, on: :member
|
51
51
|
routes.get '/', action: :new, on: :member
|
52
52
|
end
|
53
53
|
end
|
@@ -85,6 +85,10 @@ module Doorkeeper
|
|
85
85
|
def authorized_applications_routes(mapping)
|
86
86
|
routes.resources :authorized_applications, only: %i[index destroy], controller: mapping[:controllers]
|
87
87
|
end
|
88
|
+
|
89
|
+
def native_authorization_code_route
|
90
|
+
Doorkeeper.configuration.native_authorization_code_route
|
91
|
+
end
|
88
92
|
end
|
89
93
|
end
|
90
94
|
end
|
@@ -3,7 +3,7 @@ require 'doorkeeper/request/strategy'
|
|
3
3
|
module Doorkeeper
|
4
4
|
module Request
|
5
5
|
class Password < Strategy
|
6
|
-
delegate :credentials, :resource_owner, :parameters, to: :server
|
6
|
+
delegate :credentials, :resource_owner, :parameters, :client, to: :server
|
7
7
|
|
8
8
|
def request
|
9
9
|
@request ||= OAuth::PasswordAccessTokenRequest.new(
|
@@ -13,16 +13,6 @@ module Doorkeeper
|
|
13
13
|
parameters
|
14
14
|
)
|
15
15
|
end
|
16
|
-
|
17
|
-
private
|
18
|
-
|
19
|
-
def client
|
20
|
-
if credentials
|
21
|
-
server.client
|
22
|
-
elsif parameters[:client_id]
|
23
|
-
server.client_via_uid
|
24
|
-
end
|
25
|
-
end
|
26
16
|
end
|
27
17
|
end
|
28
18
|
end
|
data/lib/doorkeeper/version.rb
CHANGED
@@ -1,4 +1,25 @@
|
|
1
1
|
module Doorkeeper
|
2
|
+
CVE_2018_1000211_WARNING = <<-HEREDOC.freeze
|
3
|
+
|
4
|
+
|
5
|
+
WARNING: This is a security release that addresses token revocation not working for public apps (CVE-2018-1000211)
|
6
|
+
|
7
|
+
There is no breaking change in this release, however to take advantage of the security fix you must:
|
8
|
+
|
9
|
+
1. Run `rails generate doorkeeper:add_client_confidentiality` for the migration
|
10
|
+
2. Review your OAuth apps and determine which ones exclusively use public grant flows (eg implicit)
|
11
|
+
3. Update their `confidential` column to `false` for those public apps
|
12
|
+
|
13
|
+
This is a backported security release.
|
14
|
+
|
15
|
+
For more information:
|
16
|
+
|
17
|
+
* https://github.com/doorkeeper-gem/doorkeeper/pull/1119
|
18
|
+
* https://github.com/doorkeeper-gem/doorkeeper/issues/891
|
19
|
+
|
20
|
+
|
21
|
+
HEREDOC
|
22
|
+
|
2
23
|
def self.gem_version
|
3
24
|
Gem::Version.new VERSION::STRING
|
4
25
|
end
|
@@ -6,8 +27,8 @@ module Doorkeeper
|
|
6
27
|
module VERSION
|
7
28
|
# Semantic versioning
|
8
29
|
MAJOR = 4
|
9
|
-
MINOR =
|
10
|
-
TINY =
|
30
|
+
MINOR = 4
|
31
|
+
TINY = 3
|
11
32
|
|
12
33
|
# Full version number
|
13
34
|
STRING = [MAJOR, MINOR, TINY].compact.join('.')
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rails/generators/active_record'
|
4
|
+
|
5
|
+
module Doorkeeper
|
6
|
+
class AddClientConfidentialityGenerator < ::Rails::Generators::Base
|
7
|
+
include ::Rails::Generators::Migration
|
8
|
+
source_root File.expand_path('templates', __dir__)
|
9
|
+
desc 'Adds a migration to fix CVE-2018-1000211.'
|
10
|
+
|
11
|
+
def install
|
12
|
+
migration_template(
|
13
|
+
'add_confidential_to_application_migration.rb.erb',
|
14
|
+
'db/migrate/add_confidential_to_doorkeeper_application.rb',
|
15
|
+
migration_version: migration_version
|
16
|
+
)
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.next_migration_number(dirname)
|
20
|
+
::ActiveRecord::Generators::Base.next_migration_number(dirname)
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def migration_version
|
26
|
+
if ::ActiveRecord::VERSION::MAJOR >= 5
|
27
|
+
"[#{::ActiveRecord::VERSION::MAJOR}.#{::ActiveRecord::VERSION::MINOR}]"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
class AddConfidentialToDoorkeeperApplication < ActiveRecord::Migration<%= migration_version %>
|
2
|
+
def change
|
3
|
+
add_column(
|
4
|
+
:oauth_applications,
|
5
|
+
:confidential,
|
6
|
+
:boolean,
|
7
|
+
null: false,
|
8
|
+
default: true # maintaining backwards compatibility: require secrets
|
9
|
+
)
|
10
|
+
end
|
11
|
+
end
|
@@ -6,6 +6,7 @@ class CreateDoorkeeperTables < ActiveRecord::Migration<%= migration_version %>
|
|
6
6
|
t.string :secret, null: false
|
7
7
|
t.text :redirect_uri, null: false
|
8
8
|
t.string :scopes, null: false, default: ''
|
9
|
+
t.boolean :confidential, null: false, default: true
|
9
10
|
t.timestamps null: false
|
10
11
|
end
|
11
12
|
|
@@ -54,7 +54,7 @@ describe Doorkeeper::AuthorizationsController, 'implicit grant flow' do
|
|
54
54
|
end
|
55
55
|
|
56
56
|
it 'includes token type in fragment' do
|
57
|
-
expect(response.query_params['token_type']).to eq('
|
57
|
+
expect(response.query_params['token_type']).to eq('Bearer')
|
58
58
|
end
|
59
59
|
|
60
60
|
it 'includes token expiration in fragment' do
|
@@ -164,6 +164,38 @@ describe Doorkeeper::AuthorizationsController, 'implicit grant flow' do
|
|
164
164
|
it 'should not issue a token' do
|
165
165
|
expect(Doorkeeper::AccessToken.count).to be 0
|
166
166
|
end
|
167
|
+
|
168
|
+
context 'with opt_out_native_route_change' do
|
169
|
+
around(:each) do |example|
|
170
|
+
Doorkeeper.configure do
|
171
|
+
orm DOORKEEPER_ORM
|
172
|
+
opt_out_native_route_change
|
173
|
+
end
|
174
|
+
|
175
|
+
Rails.application.reload_routes!
|
176
|
+
|
177
|
+
example.run
|
178
|
+
|
179
|
+
Doorkeeper.configure do
|
180
|
+
orm DOORKEEPER_ORM
|
181
|
+
end
|
182
|
+
|
183
|
+
Rails.application.reload_routes!
|
184
|
+
end
|
185
|
+
|
186
|
+
it 'should redirect immediately' do
|
187
|
+
expect(response).to be_redirect
|
188
|
+
expect(response.location).to match(/oauth\/authorize\/#{Doorkeeper::AccessGrant.first.token}/)
|
189
|
+
end
|
190
|
+
|
191
|
+
it 'should issue a grant' do
|
192
|
+
expect(Doorkeeper::AccessGrant.count).to be 1
|
193
|
+
end
|
194
|
+
|
195
|
+
it 'should not issue a token' do
|
196
|
+
expect(Doorkeeper::AccessToken.count).to be 0
|
197
|
+
end
|
198
|
+
end
|
167
199
|
end
|
168
200
|
|
169
201
|
describe 'GET #new with skip_authorization true' do
|
@@ -184,7 +216,7 @@ describe Doorkeeper::AuthorizationsController, 'implicit grant flow' do
|
|
184
216
|
end
|
185
217
|
|
186
218
|
it 'includes token type in fragment' do
|
187
|
-
expect(response.query_params['token_type']).to eq('
|
219
|
+
expect(response.query_params['token_type']).to eq('Bearer')
|
188
220
|
end
|
189
221
|
|
190
222
|
it 'includes token expiration in fragment' do
|
@@ -59,15 +59,67 @@ describe Doorkeeper::TokensController do
|
|
59
59
|
end
|
60
60
|
end
|
61
61
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
62
|
+
# http://tools.ietf.org/html/rfc7009#section-2.2
|
63
|
+
describe 'revoking tokens' do
|
64
|
+
let(:client) { FactoryBot.create(:application) }
|
65
|
+
let(:access_token) { FactoryBot.create(:access_token, application: client) }
|
66
|
+
|
67
|
+
before(:each) do
|
68
|
+
allow(controller).to receive(:token) { access_token }
|
69
|
+
end
|
70
|
+
|
71
|
+
context 'when associated app is public' do
|
72
|
+
let(:client) { FactoryBot.create(:application, confidential: false) }
|
73
|
+
|
74
|
+
it 'returns 200' do
|
75
|
+
post :revoke
|
76
|
+
|
77
|
+
expect(response.status).to eq 200
|
78
|
+
end
|
79
|
+
|
80
|
+
it 'revokes the access token' do
|
81
|
+
post :revoke
|
82
|
+
|
83
|
+
expect(access_token.reload).to have_attributes(revoked?: true)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
context 'when associated app is confidential' do
|
88
|
+
let(:client) { FactoryBot.create(:application, confidential: true) }
|
89
|
+
let(:oauth_client) { Doorkeeper::OAuth::Client.new(client) }
|
67
90
|
|
68
|
-
|
91
|
+
before(:each) do
|
92
|
+
allow_any_instance_of(Doorkeeper::Server).to receive(:client) { oauth_client }
|
93
|
+
end
|
94
|
+
|
95
|
+
it 'returns 200' do
|
96
|
+
post :revoke
|
97
|
+
|
98
|
+
expect(response.status).to eq 200
|
99
|
+
end
|
100
|
+
|
101
|
+
it 'revokes the access token' do
|
102
|
+
post :revoke
|
103
|
+
|
104
|
+
expect(access_token.reload).to have_attributes(revoked?: true)
|
105
|
+
end
|
106
|
+
|
107
|
+
context 'when authorization fails' do
|
108
|
+
let(:some_other_client) { FactoryBot.create(:application, confidential: true) }
|
109
|
+
let(:oauth_client) { Doorkeeper::OAuth::Client.new(some_other_client) }
|
110
|
+
|
111
|
+
it 'returns 200' do
|
112
|
+
post :revoke
|
69
113
|
|
70
|
-
|
114
|
+
expect(response.status).to eq 200
|
115
|
+
end
|
116
|
+
|
117
|
+
it 'does not revoke the access token' do
|
118
|
+
post :revoke
|
119
|
+
|
120
|
+
expect(access_token.reload).to have_attributes(revoked?: false)
|
121
|
+
end
|
122
|
+
end
|
71
123
|
end
|
72
124
|
end
|
73
125
|
|
@@ -29,6 +29,11 @@ Doorkeeper.configure do
|
|
29
29
|
# Issue access tokens with refresh token (disabled by default)
|
30
30
|
use_refresh_token
|
31
31
|
|
32
|
+
# Opt out of breaking api change to the native authorization code flow. Opting out sets the authorization
|
33
|
+
# code response route for native redirect uris to oauth/authorize/<code>. The default is oauth/authorize/native?code=<code>.
|
34
|
+
# Rationale: https://github.com/doorkeeper-gem/doorkeeper/issues/1143
|
35
|
+
# opt_out_native_route_change
|
36
|
+
|
32
37
|
# Provide support for an owner to be assigned to each registered application (disabled by default)
|
33
38
|
# Optional parameter confirmation: true (default false) if you want to enforce ownership of
|
34
39
|
# a registered application
|
@@ -1,4 +1,6 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class AddOwnerToApplication < ActiveRecord::Migration[4.2]
|
2
4
|
def change
|
3
5
|
add_column :oauth_applications, :owner_id, :integer, null: true
|
4
6
|
add_column :oauth_applications, :owner_type, :string, null: true
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class AddConfidentialToApplication < ActiveRecord::Migration[5.1]
|
4
|
+
def change
|
5
|
+
add_column(
|
6
|
+
:oauth_applications,
|
7
|
+
:confidential,
|
8
|
+
:boolean,
|
9
|
+
null: false,
|
10
|
+
default: true # maintaining backwards compatibility: require secrets
|
11
|
+
)
|
12
|
+
end
|
13
|
+
end
|
data/spec/dummy/db/schema.rb
CHANGED
@@ -11,7 +11,7 @@
|
|
11
11
|
#
|
12
12
|
# It's strongly recommended that you check this file into your version control system.
|
13
13
|
|
14
|
-
ActiveRecord::Schema.define(version:
|
14
|
+
ActiveRecord::Schema.define(version: 20180210183654) do
|
15
15
|
|
16
16
|
create_table "oauth_access_grants", force: :cascade do |t|
|
17
17
|
t.integer "resource_owner_id", null: false
|
@@ -52,6 +52,7 @@ ActiveRecord::Schema.define(version: 20160320211015) do
|
|
52
52
|
t.datetime "updated_at"
|
53
53
|
t.integer "owner_id"
|
54
54
|
t.string "owner_type"
|
55
|
+
t.boolean "confidential", default: true, null: false
|
55
56
|
end
|
56
57
|
|
57
58
|
add_index "oauth_applications", ["owner_id", "owner_type"], name: "index_oauth_applications_on_owner_id_and_owner_type"
|
data/spec/lib/config_spec.rb
CHANGED
@@ -162,6 +162,31 @@ describe Doorkeeper, 'configuration' do
|
|
162
162
|
end
|
163
163
|
end
|
164
164
|
|
165
|
+
describe 'opt_out_native_route_change' do
|
166
|
+
around(:each) do |example|
|
167
|
+
Doorkeeper.configure do
|
168
|
+
orm DOORKEEPER_ORM
|
169
|
+
opt_out_native_route_change
|
170
|
+
end
|
171
|
+
|
172
|
+
Rails.application.reload_routes!
|
173
|
+
|
174
|
+
subject { Doorkeeper.configuration }
|
175
|
+
|
176
|
+
example.run
|
177
|
+
|
178
|
+
Doorkeeper.configure do
|
179
|
+
orm DOORKEEPER_ORM
|
180
|
+
end
|
181
|
+
|
182
|
+
Rails.application.reload_routes!
|
183
|
+
end
|
184
|
+
|
185
|
+
it 'sets the native authorization code route /:code' do
|
186
|
+
expect(subject.native_authorization_code_route).to eq('/:code')
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
165
190
|
describe 'client_credentials' do
|
166
191
|
it 'has defaults order' do
|
167
192
|
expect(subject.client_credentials_methods).to eq([:from_basic, :from_params])
|
@@ -104,5 +104,20 @@ module Doorkeeper::OAuth
|
|
104
104
|
expect(subject.error).to eq(:invalid_grant)
|
105
105
|
end
|
106
106
|
end
|
107
|
+
|
108
|
+
context "when redirect_uri is the native one" do
|
109
|
+
let(:redirect_uri) { 'urn:ietf:wg:oauth:2.0:oob' }
|
110
|
+
|
111
|
+
it "invalidates when redirect_uri of the grant is not native" do
|
112
|
+
subject.validate
|
113
|
+
expect(subject.error).to eq(:invalid_grant)
|
114
|
+
end
|
115
|
+
|
116
|
+
it "validates when redirect_uri of the grant is also native" do
|
117
|
+
allow(grant).to receive(:redirect_uri) { redirect_uri }
|
118
|
+
subject.validate
|
119
|
+
expect(subject.error).to eq(nil)
|
120
|
+
end
|
121
|
+
end
|
107
122
|
end
|
108
123
|
end
|
@@ -7,9 +7,11 @@ class Doorkeeper::OAuth::Client
|
|
7
7
|
let(:client_id) { 'some-uid' }
|
8
8
|
let(:client_secret) { 'some-secret' }
|
9
9
|
|
10
|
-
it 'is blank when
|
10
|
+
it 'is blank when the uid in credentials is blank' do
|
11
|
+
expect(Credentials.new(nil, nil)).to be_blank
|
11
12
|
expect(Credentials.new(nil, 'something')).to be_blank
|
12
|
-
expect(Credentials.new('something', nil)).to
|
13
|
+
expect(Credentials.new('something', nil)).to be_present
|
14
|
+
expect(Credentials.new('something', 'something')).to be_present
|
13
15
|
end
|
14
16
|
|
15
17
|
describe :from_request do
|
@@ -5,6 +5,11 @@ require 'doorkeeper/oauth/helpers/uri_checker'
|
|
5
5
|
module Doorkeeper::OAuth::Helpers
|
6
6
|
describe URIChecker do
|
7
7
|
describe '.valid?' do
|
8
|
+
it 'is valid for native uris' do
|
9
|
+
uri = 'urn:ietf:wg:oauth:2.0:oob'
|
10
|
+
expect(URIChecker.valid?(uri)).to be_truthy
|
11
|
+
end
|
12
|
+
|
8
13
|
it 'is valid for valid uris' do
|
9
14
|
uri = 'http://app.co'
|
10
15
|
expect(URIChecker.valid?(uri)).to be_truthy
|
@@ -123,14 +123,19 @@ module Doorkeeper::OAuth
|
|
123
123
|
expect(subject.scopes).to eq(Scopes.from_string('default'))
|
124
124
|
end
|
125
125
|
|
126
|
-
|
127
|
-
|
128
|
-
expect(subject).to be_authorizable
|
129
|
-
end
|
126
|
+
context 'with native redirect uri' do
|
127
|
+
let(:native_redirect_uri) { 'urn:ietf:wg:oauth:2.0:oob' }
|
130
128
|
|
131
|
-
|
132
|
-
|
133
|
-
|
129
|
+
it 'accepts redirect_uri when it matches with the client' do
|
130
|
+
subject.redirect_uri = native_redirect_uri
|
131
|
+
allow(subject.client).to receive(:redirect_uri) { native_redirect_uri }
|
132
|
+
expect(subject).to be_authorizable
|
133
|
+
end
|
134
|
+
|
135
|
+
it 'invalidates redirect_uri when it does\'n match with the client' do
|
136
|
+
subject.redirect_uri = native_redirect_uri
|
137
|
+
expect(subject).not_to be_authorizable
|
138
|
+
end
|
134
139
|
end
|
135
140
|
|
136
141
|
it 'stores the state' do
|
@@ -49,6 +49,11 @@ module Doorkeeper
|
|
49
49
|
expect(new_application).not_to be_valid
|
50
50
|
end
|
51
51
|
|
52
|
+
it 'is invalid without determining confidentiality' do
|
53
|
+
new_application.confidential = nil
|
54
|
+
expect(new_application).not_to be_valid
|
55
|
+
end
|
56
|
+
|
52
57
|
it 'generates uid on create' do
|
53
58
|
expect(new_application.uid).to be_nil
|
54
59
|
new_application.save
|
@@ -201,11 +206,97 @@ module Doorkeeper
|
|
201
206
|
end
|
202
207
|
end
|
203
208
|
|
204
|
-
describe :
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
+
describe :by_uid_and_secret do
|
210
|
+
context "when application is private/confidential" do
|
211
|
+
it "finds the application via uid/secret" do
|
212
|
+
app = FactoryBot.create :application
|
213
|
+
authenticated = Application.by_uid_and_secret(app.uid, app.secret)
|
214
|
+
expect(authenticated).to eq(app)
|
215
|
+
end
|
216
|
+
context "when secret is wrong" do
|
217
|
+
it "should not find the application" do
|
218
|
+
app = FactoryBot.create :application
|
219
|
+
authenticated = Application.by_uid_and_secret(app.uid, 'bad')
|
220
|
+
expect(authenticated).to eq(nil)
|
221
|
+
end
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
context "when application is public/non-confidential" do
|
226
|
+
context "when secret is blank" do
|
227
|
+
it "should find the application" do
|
228
|
+
app = FactoryBot.create :application, confidential: false
|
229
|
+
authenticated = Application.by_uid_and_secret(app.uid, nil)
|
230
|
+
expect(authenticated).to eq(app)
|
231
|
+
end
|
232
|
+
end
|
233
|
+
context "when secret is wrong" do
|
234
|
+
it "should not find the application" do
|
235
|
+
app = FactoryBot.create :application, confidential: false
|
236
|
+
authenticated = Application.by_uid_and_secret(app.uid, 'bad')
|
237
|
+
expect(authenticated).to eq(nil)
|
238
|
+
end
|
239
|
+
end
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
describe :confidential? do
|
244
|
+
subject { FactoryBot.create(:application, confidential: confidential).confidential? }
|
245
|
+
|
246
|
+
context 'when application is private/confidential' do
|
247
|
+
let(:confidential) { true }
|
248
|
+
it { expect(subject).to eq(true) }
|
249
|
+
end
|
250
|
+
|
251
|
+
context 'when application is public/non-confidential' do
|
252
|
+
let(:confidential) { false }
|
253
|
+
it { expect(subject).to eq(false) }
|
254
|
+
end
|
255
|
+
end
|
256
|
+
|
257
|
+
describe :confidential do
|
258
|
+
subject { FactoryBot.create(:application, confidential: confidential).confidential }
|
259
|
+
|
260
|
+
context 'when application is private/confidential' do
|
261
|
+
let(:confidential) { true }
|
262
|
+
it { expect(subject).to eq(true) }
|
263
|
+
end
|
264
|
+
|
265
|
+
context 'when application is public/non-confidential' do
|
266
|
+
let(:confidential) { false }
|
267
|
+
it { expect(subject).to eq(false) }
|
268
|
+
end
|
269
|
+
|
270
|
+
context 'when the application does not support confidentiality' do
|
271
|
+
let(:confidential) { false }
|
272
|
+
|
273
|
+
before { allow(Application).to receive(:supports_confidentiality?).and_return(false) }
|
274
|
+
|
275
|
+
it 'warns of the CVE' do
|
276
|
+
expect(ActiveSupport::Deprecation).to receive(:warn).with(
|
277
|
+
'You are susceptible to security bug ' \
|
278
|
+
'CVE-2018-1000211. Please follow instructions outlined in ' \
|
279
|
+
'Doorkeeper::CVE_2018_1000211_WARNING'
|
280
|
+
)
|
281
|
+
Application.new.confidential
|
282
|
+
end
|
283
|
+
|
284
|
+
it { expect(subject).to eq(true) }
|
285
|
+
end
|
286
|
+
end
|
287
|
+
|
288
|
+
describe :supports_confidentiality? do
|
289
|
+
context 'when no column' do
|
290
|
+
it 'returns false' do
|
291
|
+
expect(Application).to receive(:column_names).and_return(%w[foo bar])
|
292
|
+
expect(Application.supports_confidentiality?).to eq(false)
|
293
|
+
end
|
294
|
+
end
|
295
|
+
context 'when column' do
|
296
|
+
it 'returns true' do
|
297
|
+
expect(Application).to receive(:column_names).and_return(%w[foo bar confidential])
|
298
|
+
expect(Application.supports_confidentiality?).to eq(true)
|
299
|
+
end
|
209
300
|
end
|
210
301
|
end
|
211
302
|
end
|
@@ -53,7 +53,7 @@ feature 'Authorization Code Flow' do
|
|
53
53
|
should_not_have_json 'error'
|
54
54
|
|
55
55
|
should_have_json 'access_token', Doorkeeper::AccessToken.first.token
|
56
|
-
should_have_json 'token_type', '
|
56
|
+
should_have_json 'token_type', 'Bearer'
|
57
57
|
should_have_json_within 'expires_in', Doorkeeper::AccessToken.first.expires_in, 1
|
58
58
|
end
|
59
59
|
|
@@ -10,46 +10,89 @@ describe 'Resource Owner Password Credentials Flow not set up' do
|
|
10
10
|
it 'doesn\'t issue new token' do
|
11
11
|
expect do
|
12
12
|
post password_token_endpoint_url(client: @client, resource_owner: @resource_owner)
|
13
|
-
end.to_not
|
13
|
+
end.to_not(change { Doorkeeper::AccessToken.count })
|
14
14
|
end
|
15
15
|
end
|
16
16
|
end
|
17
17
|
|
18
18
|
describe 'Resource Owner Password Credentials Flow' do
|
19
|
+
let(:client_attributes) { {} }
|
20
|
+
|
19
21
|
before do
|
20
22
|
config_is_set(:grant_flows, ["password"])
|
21
23
|
config_is_set(:resource_owner_from_credentials) { User.authenticate! params[:username], params[:password] }
|
22
|
-
client_exists
|
24
|
+
client_exists(client_attributes)
|
23
25
|
create_resource_owner
|
24
26
|
end
|
25
27
|
|
26
28
|
context 'with valid user credentials' do
|
27
|
-
|
28
|
-
|
29
|
-
post password_token_endpoint_url(client: @client, resource_owner: @resource_owner)
|
30
|
-
end.to change { Doorkeeper::AccessToken.count }.by(1)
|
29
|
+
context "with non-confidential/public client" do
|
30
|
+
let(:client_attributes) { { confidential: false } }
|
31
31
|
|
32
|
-
|
32
|
+
context "when client_secret absent" do
|
33
|
+
it "should issue new token" do
|
34
|
+
expect do
|
35
|
+
post password_token_endpoint_url(client_id: @client.uid, resource_owner: @resource_owner)
|
36
|
+
end.to change { Doorkeeper::AccessToken.count }.by(1)
|
33
37
|
|
34
|
-
|
35
|
-
|
38
|
+
token = Doorkeeper::AccessToken.first
|
39
|
+
|
40
|
+
expect(token.application_id).to eq @client.id
|
41
|
+
should_have_json 'access_token', token.token
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
context "when client_secret present" do
|
46
|
+
it "should issue new token" do
|
47
|
+
expect do
|
48
|
+
post password_token_endpoint_url(client: @client, resource_owner: @resource_owner)
|
49
|
+
end.to change { Doorkeeper::AccessToken.count }.by(1)
|
50
|
+
|
51
|
+
token = Doorkeeper::AccessToken.first
|
52
|
+
|
53
|
+
expect(token.application_id).to eq @client.id
|
54
|
+
should_have_json 'access_token', token.token
|
55
|
+
end
|
56
|
+
|
57
|
+
context "when client_secret incorrect" do
|
58
|
+
it "should not issue new token" do
|
59
|
+
expect do
|
60
|
+
post password_token_endpoint_url(client_id: @client.uid, client_secret: 'foobar', resource_owner: @resource_owner)
|
61
|
+
end.not_to(change { Doorkeeper::AccessToken.count })
|
62
|
+
|
63
|
+
expect(response).not_to be_ok
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
36
67
|
end
|
37
68
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
69
|
+
context "with confidential/private client" do
|
70
|
+
it "should issue new token" do
|
71
|
+
expect do
|
72
|
+
post password_token_endpoint_url(client: @client, resource_owner: @resource_owner)
|
73
|
+
end.to change { Doorkeeper::AccessToken.count }.by(1)
|
42
74
|
|
43
|
-
|
75
|
+
token = Doorkeeper::AccessToken.first
|
44
76
|
|
45
|
-
|
46
|
-
|
77
|
+
expect(token.application_id).to eq @client.id
|
78
|
+
should_have_json 'access_token', token.token
|
79
|
+
end
|
80
|
+
|
81
|
+
context "when client_secret absent" do
|
82
|
+
it "should not issue new token" do
|
83
|
+
expect do
|
84
|
+
post password_token_endpoint_url(client_id: @client.uid, resource_owner: @resource_owner)
|
85
|
+
end.not_to(change { Doorkeeper::AccessToken.count })
|
86
|
+
|
87
|
+
expect(response).not_to be_ok
|
88
|
+
end
|
89
|
+
end
|
47
90
|
end
|
48
91
|
|
49
92
|
it 'should issue new token without client credentials' do
|
50
93
|
expect do
|
51
94
|
post password_token_endpoint_url(resource_owner: @resource_owner)
|
52
|
-
end.to
|
95
|
+
end.to(change { Doorkeeper::AccessToken.count }.by(1))
|
53
96
|
|
54
97
|
token = Doorkeeper::AccessToken.first
|
55
98
|
|
@@ -124,13 +167,13 @@ describe 'Resource Owner Password Credentials Flow' do
|
|
124
167
|
post password_token_endpoint_url(client: @client,
|
125
168
|
resource_owner_username: @resource_owner.name,
|
126
169
|
resource_owner_password: 'wrongpassword')
|
127
|
-
end.to_not
|
170
|
+
end.to_not(change { Doorkeeper::AccessToken.count })
|
128
171
|
end
|
129
172
|
|
130
173
|
it 'should not issue new token without credentials' do
|
131
174
|
expect do
|
132
175
|
post password_token_endpoint_url(client: @client)
|
133
|
-
end.to_not
|
176
|
+
end.to_not(change { Doorkeeper::AccessToken.count })
|
134
177
|
end
|
135
178
|
end
|
136
179
|
|
@@ -140,7 +183,7 @@ describe 'Resource Owner Password Credentials Flow' do
|
|
140
183
|
post password_token_endpoint_url(client_id: @client.uid,
|
141
184
|
client_secret: 'bad_secret',
|
142
185
|
resource_owner: @resource_owner)
|
143
|
-
end.to_not
|
186
|
+
end.to_not(change { Doorkeeper::AccessToken.count })
|
144
187
|
end
|
145
188
|
end
|
146
189
|
|
@@ -148,7 +191,7 @@ describe 'Resource Owner Password Credentials Flow' do
|
|
148
191
|
it 'should not issue new token with bad client id' do
|
149
192
|
expect do
|
150
193
|
post password_token_endpoint_url(client_id: 'bad_id', resource_owner: @resource_owner)
|
151
|
-
end.to_not
|
194
|
+
end.to_not(change { Doorkeeper::AccessToken.count })
|
152
195
|
end
|
153
196
|
end
|
154
197
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: doorkeeper
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 4.3
|
4
|
+
version: 4.4.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Felipe Elias Philipp
|
@@ -11,7 +11,7 @@ authors:
|
|
11
11
|
autorequire:
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
|
-
date: 2018-
|
14
|
+
date: 2018-09-19 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: railties
|
@@ -259,11 +259,13 @@ files:
|
|
259
259
|
- lib/doorkeeper/server.rb
|
260
260
|
- lib/doorkeeper/validations.rb
|
261
261
|
- lib/doorkeeper/version.rb
|
262
|
+
- lib/generators/doorkeeper/add_client_confidentiality_generator.rb
|
262
263
|
- lib/generators/doorkeeper/application_owner_generator.rb
|
263
264
|
- lib/generators/doorkeeper/install_generator.rb
|
264
265
|
- lib/generators/doorkeeper/migration_generator.rb
|
265
266
|
- lib/generators/doorkeeper/previous_refresh_token_generator.rb
|
266
267
|
- lib/generators/doorkeeper/templates/README
|
268
|
+
- lib/generators/doorkeeper/templates/add_confidential_to_application_migration.rb.erb
|
267
269
|
- lib/generators/doorkeeper/templates/add_owner_to_application_migration.rb.erb
|
268
270
|
- lib/generators/doorkeeper/templates/add_previous_refresh_token_to_access_tokens.rb.erb
|
269
271
|
- lib/generators/doorkeeper/templates/initializer.rb
|
@@ -307,6 +309,7 @@ files:
|
|
307
309
|
- spec/dummy/db/migrate/20151223192035_create_doorkeeper_tables.rb
|
308
310
|
- spec/dummy/db/migrate/20151223200000_add_owner_to_application.rb
|
309
311
|
- spec/dummy/db/migrate/20160320211015_add_previous_refresh_token_to_access_tokens.rb
|
312
|
+
- spec/dummy/db/migrate/20180210183654_add_confidential_to_application.rb
|
310
313
|
- spec/dummy/db/schema.rb
|
311
314
|
- spec/dummy/public/404.html
|
312
315
|
- spec/dummy/public/422.html
|
@@ -397,7 +400,25 @@ homepage: https://github.com/doorkeeper-gem/doorkeeper
|
|
397
400
|
licenses:
|
398
401
|
- MIT
|
399
402
|
metadata: {}
|
400
|
-
post_install_message:
|
403
|
+
post_install_message: |2+
|
404
|
+
|
405
|
+
|
406
|
+
WARNING: This is a security release that addresses token revocation not working for public apps (CVE-2018-1000211)
|
407
|
+
|
408
|
+
There is no breaking change in this release, however to take advantage of the security fix you must:
|
409
|
+
|
410
|
+
1. Run `rails generate doorkeeper:add_client_confidentiality` for the migration
|
411
|
+
2. Review your OAuth apps and determine which ones exclusively use public grant flows (eg implicit)
|
412
|
+
3. Update their `confidential` column to `false` for those public apps
|
413
|
+
|
414
|
+
This is a backported security release.
|
415
|
+
|
416
|
+
For more information:
|
417
|
+
|
418
|
+
* https://github.com/doorkeeper-gem/doorkeeper/pull/1119
|
419
|
+
* https://github.com/doorkeeper-gem/doorkeeper/issues/891
|
420
|
+
|
421
|
+
|
401
422
|
rdoc_options: []
|
402
423
|
require_paths:
|
403
424
|
- lib
|
@@ -456,6 +477,7 @@ test_files:
|
|
456
477
|
- spec/dummy/db/migrate/20151223192035_create_doorkeeper_tables.rb
|
457
478
|
- spec/dummy/db/migrate/20151223200000_add_owner_to_application.rb
|
458
479
|
- spec/dummy/db/migrate/20160320211015_add_previous_refresh_token_to_access_tokens.rb
|
480
|
+
- spec/dummy/db/migrate/20180210183654_add_confidential_to_application.rb
|
459
481
|
- spec/dummy/db/schema.rb
|
460
482
|
- spec/dummy/public/404.html
|
461
483
|
- spec/dummy/public/422.html
|