doorkeeper 4.3.2 → 4.4.0
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 +4 -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/models/application_mixin.rb +8 -1
- data/lib/doorkeeper/oauth/client/credentials.rb +3 -1
- data/lib/doorkeeper/orm/active_record/application.rb +17 -0
- 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/tokens_controller_spec.rb +59 -7
- 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/oauth/client/credentials_spec.rb +4 -2
- data/spec/models/doorkeeper/application_spec.rb +79 -5
- 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: f0d71c132c7d1ccefc8c14eb694b17390f294153
|
4
|
+
data.tar.gz: db67a65aac1502b753acb20ea125fa4b5a87b613
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fd03d7d674e053e08d4eaaa5b71d60290983d1d0376bddf4eacd01c903bffbf495dac6d3c56ff4e42cd91a47084eebb8332332553e239eb964cf79a0949087d0
|
7
|
+
data.tar.gz: 12873f75f22927c542c3d3bd739b5b1ec1ed0b89135bd1e492106e5d94d4485f8ca0fc89b6dcedf1d5a8707d9ff3cfc9f6c4d539a51a86c7dd23633477adfc57
|
data/.rubocop.yml
CHANGED
data/NEWS.md
CHANGED
@@ -4,6 +4,10 @@ User-visible changes worth mentioning.
|
|
4
4
|
|
5
5
|
## master
|
6
6
|
|
7
|
+
## 4.4.0
|
8
|
+
|
9
|
+
- [#1120] Backport security fix from 5.x for token revocation when using public clients
|
10
|
+
|
7
11
|
## 4.3.2
|
8
12
|
|
9
13
|
- [#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
@@ -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.
|
@@ -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
|
@@ -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 = 0
|
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
|
|
@@ -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
|
|
@@ -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"
|
@@ -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
|
@@ -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,80 @@ 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
|
+
end
|
270
|
+
|
271
|
+
describe :supports_confidentiality? do
|
272
|
+
context 'when no column' do
|
273
|
+
it 'returns false' do
|
274
|
+
expect(Application).to receive(:column_names).and_return(%w[foo bar])
|
275
|
+
expect(Application.supports_confidentiality?).to eq(false)
|
276
|
+
end
|
277
|
+
end
|
278
|
+
context 'when column' do
|
279
|
+
it 'returns true' do
|
280
|
+
expect(Application).to receive(:column_names).and_return(%w[foo bar confidential])
|
281
|
+
expect(Application.supports_confidentiality?).to eq(true)
|
282
|
+
end
|
209
283
|
end
|
210
284
|
end
|
211
285
|
end
|
@@ -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.
|
4
|
+
version: 4.4.0
|
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-07-17 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
|