doorkeeper 4.2.0 → 4.2.5
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/.coveralls.yml +1 -0
- data/.gitignore +5 -0
- data/.travis.yml +11 -6
- data/Appraisals +14 -0
- data/Gemfile +4 -8
- data/NEWS.md +10 -1
- data/README.md +6 -1
- data/app/controllers/doorkeeper/applications_controller.rb +1 -5
- data/app/views/doorkeeper/applications/_delete_form.html.erb +1 -2
- data/app/views/doorkeeper/authorized_applications/_delete_form.html.erb +1 -2
- data/config/locales/en.yml +2 -2
- data/doorkeeper.gemspec +9 -7
- data/gemfiles/rails_4_2.gemfile +11 -0
- data/gemfiles/rails_5_0.gemfile +12 -0
- data/gemfiles/rails_5_1.gemfile +13 -0
- data/lib/doorkeeper.rb +7 -1
- data/lib/doorkeeper/config.rb +55 -0
- data/lib/doorkeeper/grape/helpers.rb +2 -1
- data/lib/doorkeeper/helpers/controller.rb +6 -6
- data/lib/doorkeeper/models/access_grant_mixin.rb +12 -0
- data/lib/doorkeeper/models/access_token_mixin.rb +117 -1
- data/lib/doorkeeper/models/application_mixin.rb +18 -2
- data/lib/doorkeeper/models/concerns/accessible.rb +4 -0
- data/lib/doorkeeper/models/concerns/expirable.rb +8 -0
- data/lib/doorkeeper/models/concerns/revocable.rb +18 -0
- data/lib/doorkeeper/oauth/authorization/uri_builder.rb +20 -18
- data/lib/doorkeeper/oauth/authorization_code_request.rb +1 -4
- data/lib/doorkeeper/oauth/{request_concern.rb → base_request.rb} +3 -1
- data/lib/doorkeeper/oauth/base_response.rb +29 -0
- data/lib/doorkeeper/oauth/client.rb +0 -1
- data/lib/doorkeeper/oauth/client/credentials.rb +17 -6
- data/lib/doorkeeper/oauth/client_credentials/creator.rb +1 -1
- data/lib/doorkeeper/oauth/client_credentials/issuer.rb +1 -1
- data/lib/doorkeeper/oauth/client_credentials/validation.rb +1 -1
- data/lib/doorkeeper/oauth/client_credentials_request.rb +1 -4
- data/lib/doorkeeper/oauth/code_response.rb +7 -6
- data/lib/doorkeeper/oauth/error_response.rb +9 -8
- data/lib/doorkeeper/oauth/invalid_token_response.rb +2 -0
- data/lib/doorkeeper/oauth/password_access_token_request.rb +1 -3
- data/lib/doorkeeper/oauth/refresh_token_request.rb +3 -7
- data/lib/doorkeeper/oauth/token.rb +17 -19
- data/lib/doorkeeper/oauth/token_request.rb +1 -2
- data/lib/doorkeeper/orm/active_record/access_token.rb +17 -0
- data/lib/doorkeeper/orm/active_record/application.rb +10 -5
- data/lib/doorkeeper/rails/helpers.rb +0 -2
- data/lib/doorkeeper/rails/routes.rb +3 -4
- data/lib/doorkeeper/rails/routes/mapper.rb +3 -3
- data/lib/doorkeeper/rails/routes/mapping.rb +1 -1
- data/lib/doorkeeper/request/authorization_code.rb +7 -1
- data/lib/doorkeeper/request/refresh_token.rb +1 -1
- data/lib/doorkeeper/server.rb +0 -8
- data/lib/doorkeeper/version.rb +1 -1
- data/spec/controllers/authorizations_controller_spec.rb +17 -3
- data/spec/lib/doorkeeper_spec.rb +135 -13
- data/spec/lib/oauth/authorization/uri_builder_spec.rb +1 -2
- data/spec/lib/oauth/base_request_spec.rb +160 -0
- data/spec/lib/oauth/base_response_spec.rb +45 -0
- data/spec/lib/oauth/client/credentials_spec.rb +41 -0
- data/spec/lib/oauth/error_response_spec.rb +9 -9
- data/spec/lib/oauth/invalid_token_response_spec.rb +36 -8
- data/spec/lib/server_spec.rb +0 -3
- data/spec/requests/endpoints/authorization_spec.rb +5 -6
- data/spec/requests/flows/authorization_code_spec.rb +4 -12
- data/spec/spec_helper.rb +2 -0
- data/spec/spec_helper_integration.rb +5 -0
- data/spec/support/helpers/request_spec_helper.rb +12 -4
- data/spec/support/http_method_shim.rb +20 -6
- metadata +43 -21
- data/lib/doorkeeper/oauth/client/methods.rb +0 -18
- data/spec/lib/oauth/client/methods_spec.rb +0 -54
@@ -6,8 +6,7 @@ require 'doorkeeper/oauth/authorization/uri_builder'
|
|
6
6
|
|
7
7
|
module Doorkeeper::OAuth::Authorization
|
8
8
|
describe URIBuilder do
|
9
|
-
|
10
|
-
subject { Object.new.class.send :include, URIBuilder }
|
9
|
+
subject { URIBuilder }
|
11
10
|
|
12
11
|
describe :uri_with_query do
|
13
12
|
it 'returns the uri with query' do
|
@@ -0,0 +1,160 @@
|
|
1
|
+
require 'spec_helper_integration'
|
2
|
+
|
3
|
+
module Doorkeeper::OAuth
|
4
|
+
describe BaseRequest do
|
5
|
+
let(:access_token) do
|
6
|
+
double :access_token,
|
7
|
+
token: "some-token",
|
8
|
+
expires_in: "3600",
|
9
|
+
expires_in_seconds: "300",
|
10
|
+
scopes_string: "two scopes",
|
11
|
+
refresh_token: "some-refresh-token",
|
12
|
+
token_type: "bearer",
|
13
|
+
created_at: 0
|
14
|
+
end
|
15
|
+
|
16
|
+
let(:client) do
|
17
|
+
double :client,
|
18
|
+
id: '1'
|
19
|
+
end
|
20
|
+
|
21
|
+
let(:scopes_array) do
|
22
|
+
%w(public write)
|
23
|
+
end
|
24
|
+
|
25
|
+
let(:server) do
|
26
|
+
double :server,
|
27
|
+
access_token_expires_in: 100,
|
28
|
+
custom_access_token_expires_in: ->(_) { nil },
|
29
|
+
refresh_token_enabled?: false
|
30
|
+
end
|
31
|
+
|
32
|
+
subject do
|
33
|
+
BaseRequest.new
|
34
|
+
end
|
35
|
+
|
36
|
+
describe "#authorize" do
|
37
|
+
before do
|
38
|
+
allow(subject).to receive(:access_token).and_return(access_token)
|
39
|
+
end
|
40
|
+
|
41
|
+
it "validates itself" do
|
42
|
+
expect(subject).to receive(:validate).once
|
43
|
+
subject.authorize
|
44
|
+
end
|
45
|
+
|
46
|
+
context "valid" do
|
47
|
+
before do
|
48
|
+
allow(subject).to receive(:valid?).and_return(true)
|
49
|
+
end
|
50
|
+
|
51
|
+
it "calls callback methods" do
|
52
|
+
expect(subject).to receive(:before_successful_response).once
|
53
|
+
expect(subject).to receive(:after_successful_response).once
|
54
|
+
subject.authorize
|
55
|
+
end
|
56
|
+
|
57
|
+
it "returns a TokenResponse object" do
|
58
|
+
result = subject.authorize
|
59
|
+
|
60
|
+
expect(result).to be_an_instance_of(TokenResponse)
|
61
|
+
expect(result.body).to eq(
|
62
|
+
TokenResponse.new(access_token).body
|
63
|
+
)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
context "invalid" do
|
68
|
+
before do
|
69
|
+
allow(subject).to receive(:valid?).and_return(false)
|
70
|
+
allow(subject).to receive(:error).and_return("server_error")
|
71
|
+
allow(subject).to receive(:state).and_return("hello")
|
72
|
+
end
|
73
|
+
|
74
|
+
it "returns an ErrorResponse object" do
|
75
|
+
error_description = I18n.translate(
|
76
|
+
"server_error",
|
77
|
+
scope: [:doorkeeper, :errors, :messages]
|
78
|
+
)
|
79
|
+
|
80
|
+
result = subject.authorize
|
81
|
+
|
82
|
+
expect(result).to be_an_instance_of(ErrorResponse)
|
83
|
+
|
84
|
+
expect(result.body).to eq(
|
85
|
+
error: "server_error",
|
86
|
+
error_description: error_description,
|
87
|
+
state: "hello"
|
88
|
+
)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
describe "#default_scopes" do
|
94
|
+
it "delegates to the server" do
|
95
|
+
expect(subject).to receive(:server).and_return(server).once
|
96
|
+
expect(server).to receive(:default_scopes).once
|
97
|
+
|
98
|
+
subject.default_scopes
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
describe "#find_or_create_access_token" do
|
103
|
+
it "returns an instance of AccessToken" do
|
104
|
+
result = subject.find_or_create_access_token(
|
105
|
+
client,
|
106
|
+
"1",
|
107
|
+
"public",
|
108
|
+
server
|
109
|
+
)
|
110
|
+
|
111
|
+
expect(result).to be_an_instance_of(Doorkeeper::AccessToken)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
describe "#scopes" do
|
116
|
+
context "@original_scopes is present" do
|
117
|
+
before do
|
118
|
+
subject.instance_variable_set(:@original_scopes, "public write")
|
119
|
+
end
|
120
|
+
|
121
|
+
it "returns array of @original_scopes" do
|
122
|
+
result = subject.scopes
|
123
|
+
|
124
|
+
expect(result).to eq(scopes_array)
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
context "@original_scopes is not present" do
|
129
|
+
before do
|
130
|
+
subject.instance_variable_set(:@original_scopes, "")
|
131
|
+
end
|
132
|
+
|
133
|
+
it "calls #default_scopes" do
|
134
|
+
allow(subject).to receive(:server).and_return(server).once
|
135
|
+
allow(server).to receive(:default_scopes).and_return(scopes_array).once
|
136
|
+
|
137
|
+
result = subject.scopes
|
138
|
+
|
139
|
+
expect(result).to eq(scopes_array)
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
describe "#valid?" do
|
145
|
+
context "error is nil" do
|
146
|
+
it "returns true" do
|
147
|
+
allow(subject).to receive(:error).and_return(nil).once
|
148
|
+
expect(subject.valid?).to eq(true)
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
context "error is not nil" do
|
153
|
+
it "returns false" do
|
154
|
+
allow(subject).to receive(:error).and_return(Object.new).once
|
155
|
+
expect(subject.valid?).to eq(false)
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'spec_helper_integration'
|
2
|
+
|
3
|
+
module Doorkeeper::OAuth
|
4
|
+
describe BaseResponse do
|
5
|
+
subject do
|
6
|
+
BaseResponse.new
|
7
|
+
end
|
8
|
+
|
9
|
+
describe "#body" do
|
10
|
+
it "returns an empty Hash" do
|
11
|
+
expect(subject.body).to eq({})
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
describe "#description" do
|
16
|
+
it "returns an empty String" do
|
17
|
+
expect(subject.description).to eq("")
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe "#headers" do
|
22
|
+
it "returns an empty Hash" do
|
23
|
+
expect(subject.headers).to eq({})
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe "#redirectable?" do
|
28
|
+
it "returns false" do
|
29
|
+
expect(subject.redirectable?).to eq(false)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
describe "#redirect_uri" do
|
34
|
+
it "returns an empty String" do
|
35
|
+
expect(subject.redirect_uri).to eq("")
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe "#status" do
|
40
|
+
it "returns :ok" do
|
41
|
+
expect(subject.status).to eq(:ok)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -4,6 +4,9 @@ require 'doorkeeper/oauth/client'
|
|
4
4
|
|
5
5
|
class Doorkeeper::OAuth::Client
|
6
6
|
describe Credentials do
|
7
|
+
let(:client_id) { 'some-uid' }
|
8
|
+
let(:client_secret) { 'some-secret' }
|
9
|
+
|
7
10
|
it 'is blank when any of the credentials is blank' do
|
8
11
|
expect(Credentials.new(nil, 'something')).to be_blank
|
9
12
|
expect(Credentials.new('something', nil)).to be_blank
|
@@ -43,5 +46,43 @@ class Doorkeeper::OAuth::Client
|
|
43
46
|
expect(credentials.secret).to eq('secret')
|
44
47
|
end
|
45
48
|
end
|
49
|
+
|
50
|
+
describe :from_params do
|
51
|
+
it 'returns credentials from parameters when Authorization header is not available' do
|
52
|
+
request = double parameters: { client_id: client_id, client_secret: client_secret }
|
53
|
+
uid, secret = Credentials.from_params(request)
|
54
|
+
|
55
|
+
expect(uid).to eq('some-uid')
|
56
|
+
expect(secret).to eq('some-secret')
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'is blank when there are no credentials' do
|
60
|
+
request = double parameters: {}
|
61
|
+
uid, secret = Credentials.from_params(request)
|
62
|
+
|
63
|
+
expect(uid).to be_blank
|
64
|
+
expect(secret).to be_blank
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
describe :from_basic do
|
69
|
+
let(:credentials) { Base64.encode64("#{client_id}:#{client_secret}") }
|
70
|
+
|
71
|
+
it 'decodes the credentials' do
|
72
|
+
request = double authorization: "Basic #{credentials}"
|
73
|
+
uid, secret = Credentials.from_basic(request)
|
74
|
+
|
75
|
+
expect(uid).to eq('some-uid')
|
76
|
+
expect(secret).to eq('some-secret')
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'is blank if Authorization is not Basic' do
|
80
|
+
request = double authorization: "#{credentials}"
|
81
|
+
uid, secret = Credentials.from_basic(request)
|
82
|
+
|
83
|
+
expect(uid).to be_blank
|
84
|
+
expect(secret).to be_blank
|
85
|
+
end
|
86
|
+
end
|
46
87
|
end
|
47
88
|
end
|
@@ -43,19 +43,19 @@ module Doorkeeper::OAuth
|
|
43
43
|
end
|
44
44
|
end
|
45
45
|
|
46
|
-
describe '.
|
46
|
+
describe '.headers' do
|
47
47
|
let(:error_response) { ErrorResponse.new(name: :some_error, state: :some_state) }
|
48
|
-
subject { error_response.
|
48
|
+
subject { error_response.headers }
|
49
49
|
|
50
|
-
it { expect(subject).to include
|
51
|
-
it { expect(subject).to include("error=\"#{error_response.name}\"") }
|
52
|
-
it { expect(subject).to include("error_description=\"#{error_response.description}\"") }
|
53
|
-
end
|
50
|
+
it { expect(subject).to include 'WWW-Authenticate' }
|
54
51
|
|
55
|
-
|
56
|
-
|
52
|
+
describe "WWW-Authenticate header" do
|
53
|
+
subject { error_response.headers["WWW-Authenticate"] }
|
57
54
|
|
58
|
-
|
55
|
+
it { expect(subject).to include("realm=\"#{error_response.realm}\"") }
|
56
|
+
it { expect(subject).to include("error=\"#{error_response.name}\"") }
|
57
|
+
it { expect(subject).to include("error_description=\"#{error_response.description}\"") }
|
58
|
+
end
|
59
59
|
end
|
60
60
|
end
|
61
61
|
end
|
@@ -5,23 +5,51 @@ require 'doorkeeper/oauth/invalid_token_response'
|
|
5
5
|
|
6
6
|
module Doorkeeper::OAuth
|
7
7
|
describe InvalidTokenResponse do
|
8
|
-
describe
|
8
|
+
describe "#name" do
|
9
9
|
it { expect(subject.name).to eq(:invalid_token) }
|
10
10
|
end
|
11
11
|
|
12
|
-
describe
|
12
|
+
describe "#status" do
|
13
13
|
it { expect(subject.status).to eq(:unauthorized) }
|
14
14
|
end
|
15
15
|
|
16
16
|
describe :from_access_token do
|
17
|
-
|
18
|
-
|
19
|
-
|
17
|
+
let(:response) { InvalidTokenResponse.from_access_token(access_token) }
|
18
|
+
|
19
|
+
context "revoked" do
|
20
|
+
let(:access_token) { double(revoked?: true, expired?: true) }
|
21
|
+
|
22
|
+
it "sets a description" do
|
23
|
+
expect(response.description).to include("revoked")
|
24
|
+
end
|
25
|
+
|
26
|
+
it "sets the reason" do
|
27
|
+
expect(response.reason).to eq(:revoked)
|
28
|
+
end
|
20
29
|
end
|
21
30
|
|
22
|
-
|
23
|
-
|
24
|
-
|
31
|
+
context "expired" do
|
32
|
+
let(:access_token) { double(revoked?: false, expired?: true) }
|
33
|
+
|
34
|
+
it "sets a description" do
|
35
|
+
expect(response.description).to include("expired")
|
36
|
+
end
|
37
|
+
|
38
|
+
it "sets the reason" do
|
39
|
+
expect(response.reason).to eq(:expired)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
context "unkown" do
|
44
|
+
let(:access_token) { double(revoked?: false, expired?: false) }
|
45
|
+
|
46
|
+
it "sets a description" do
|
47
|
+
expect(response.description).to include("invalid")
|
48
|
+
end
|
49
|
+
|
50
|
+
it "sets the reason" do
|
51
|
+
expect(response.reason).to eq(:unknown)
|
52
|
+
end
|
25
53
|
end
|
26
54
|
end
|
27
55
|
end
|
data/spec/lib/server_spec.rb
CHANGED
@@ -59,13 +59,12 @@ feature 'Authorization endpoint' do
|
|
59
59
|
end
|
60
60
|
|
61
61
|
scenario 'raises exception on forged requests' do
|
62
|
-
skip 'TODO: need to add request helpers to this feature spec'
|
63
|
-
allow_any_instance_of(ActionController::Base).to receive(:handle_unverified_request)
|
64
62
|
allowing_forgery_protection do
|
65
|
-
|
66
|
-
client_id:
|
67
|
-
|
68
|
-
|
63
|
+
expect {
|
64
|
+
page.driver.post authorization_endpoint_url(client_id: @client.uid,
|
65
|
+
redirect_uri: @client.redirect_uri,
|
66
|
+
response_type: 'code')
|
67
|
+
}.to raise_error(ActionController::InvalidAuthenticityToken)
|
69
68
|
end
|
70
69
|
end
|
71
70
|
end
|
@@ -41,13 +41,11 @@ feature 'Authorization Code Flow' do
|
|
41
41
|
end
|
42
42
|
|
43
43
|
scenario 'resource owner requests an access token with authorization code' do
|
44
|
-
skip 'TODO: need to add request helpers to this feature spec'
|
45
|
-
|
46
44
|
visit authorization_endpoint_url(client: @client)
|
47
45
|
click_on 'Authorize'
|
48
46
|
|
49
47
|
authorization_code = Doorkeeper::AccessGrant.first.token
|
50
|
-
|
48
|
+
create_access_token authorization_code, @client
|
51
49
|
|
52
50
|
access_token_should_exist_for(@client, @resource_owner)
|
53
51
|
|
@@ -84,27 +82,23 @@ feature 'Authorization Code Flow' do
|
|
84
82
|
end
|
85
83
|
|
86
84
|
scenario 'new access token matches required scopes' do
|
87
|
-
skip 'TODO: need to add request helpers to this feature spec'
|
88
|
-
|
89
85
|
visit authorization_endpoint_url(client: @client, scope: 'public write')
|
90
86
|
click_on 'Authorize'
|
91
87
|
|
92
88
|
authorization_code = Doorkeeper::AccessGrant.first.token
|
93
|
-
|
89
|
+
create_access_token authorization_code, @client
|
94
90
|
|
95
91
|
access_token_should_exist_for(@client, @resource_owner)
|
96
92
|
access_token_should_have_scopes :public, :write
|
97
93
|
end
|
98
94
|
|
99
95
|
scenario 'returns new token if scopes have changed' do
|
100
|
-
skip 'TODO: need to add request helpers to this feature spec'
|
101
|
-
|
102
96
|
client_is_authorized(@client, @resource_owner, scopes: 'public write')
|
103
97
|
visit authorization_endpoint_url(client: @client, scope: 'public')
|
104
98
|
click_on 'Authorize'
|
105
99
|
|
106
100
|
authorization_code = Doorkeeper::AccessGrant.first.token
|
107
|
-
|
101
|
+
create_access_token authorization_code, @client
|
108
102
|
|
109
103
|
expect(Doorkeeper::AccessToken.count).to be(2)
|
110
104
|
|
@@ -112,14 +106,12 @@ feature 'Authorization Code Flow' do
|
|
112
106
|
end
|
113
107
|
|
114
108
|
scenario 'resource owner authorizes the client with extra scopes' do
|
115
|
-
skip 'TODO: need to add request helpers to this feature spec'
|
116
|
-
|
117
109
|
client_is_authorized(@client, @resource_owner, scopes: 'public')
|
118
110
|
visit authorization_endpoint_url(client: @client, scope: 'public write')
|
119
111
|
click_on 'Authorize'
|
120
112
|
|
121
113
|
authorization_code = Doorkeeper::AccessGrant.first.token
|
122
|
-
|
114
|
+
create_access_token authorization_code, @client
|
123
115
|
|
124
116
|
expect(Doorkeeper::AccessToken.count).to be(2)
|
125
117
|
|