simple_oauth2 0.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.codeclimate.yml +25 -0
- data/.coveralls.yml +1 -0
- data/.gitignore +26 -0
- data/.hound.yml +4 -0
- data/.rubocop.yml +5 -0
- data/.rubocop_todo.yml +12 -0
- data/.travis.yml +31 -0
- data/Gemfile +18 -0
- data/LICENSE +21 -0
- data/README.md +11 -0
- data/Rakefile +11 -0
- data/gemfiles/nobrainer.rb +15 -0
- data/lib/simple_oauth2/configuration/class_accessors.rb +36 -0
- data/lib/simple_oauth2/configuration/constants.rb +36 -0
- data/lib/simple_oauth2/configuration.rb +169 -0
- data/lib/simple_oauth2/generators/authorization.rb +64 -0
- data/lib/simple_oauth2/generators/base.rb +31 -0
- data/lib/simple_oauth2/generators/token.rb +71 -0
- data/lib/simple_oauth2/helpers.rb +40 -0
- data/lib/simple_oauth2/mixins/nobrainer/access_grant.rb +62 -0
- data/lib/simple_oauth2/mixins/nobrainer/access_token.rb +98 -0
- data/lib/simple_oauth2/mixins/nobrainer/client.rb +43 -0
- data/lib/simple_oauth2/resource/bearer.rb +20 -0
- data/lib/simple_oauth2/responses.rb +62 -0
- data/lib/simple_oauth2/scopes.rb +59 -0
- data/lib/simple_oauth2/strategies/authorization_code.rb +22 -0
- data/lib/simple_oauth2/strategies/base.rb +61 -0
- data/lib/simple_oauth2/strategies/client_credentials.rb +21 -0
- data/lib/simple_oauth2/strategies/code.rb +25 -0
- data/lib/simple_oauth2/strategies/password.rb +21 -0
- data/lib/simple_oauth2/strategies/refresh_token.rb +53 -0
- data/lib/simple_oauth2/strategies/token.rb +24 -0
- data/lib/simple_oauth2/uniq_token.rb +20 -0
- data/lib/simple_oauth2/version.rb +26 -0
- data/lib/simple_oauth2.rb +62 -0
- data/logo.png +0 -0
- data/simple_oauth2.gemspec +22 -0
- data/spec/configuration/config_spec.rb +181 -0
- data/spec/configuration/version_spec.rb +11 -0
- data/spec/dummy/endpoints/authorization.rb +15 -0
- data/spec/dummy/endpoints/custom_authorization.rb +21 -0
- data/spec/dummy/endpoints/custom_token.rb +21 -0
- data/spec/dummy/endpoints/status.rb +51 -0
- data/spec/dummy/endpoints/token.rb +22 -0
- data/spec/dummy/orm/nobrainer/app/config/db.rb +8 -0
- data/spec/dummy/orm/nobrainer/app/models/access_grant.rb +3 -0
- data/spec/dummy/orm/nobrainer/app/models/access_token.rb +3 -0
- data/spec/dummy/orm/nobrainer/app/models/client.rb +3 -0
- data/spec/dummy/orm/nobrainer/app/models/user.rb +11 -0
- data/spec/dummy/orm/nobrainer/app/twitter.rb +51 -0
- data/spec/dummy/orm/nobrainer/config.ru +37 -0
- data/spec/dummy/simple_oauth2_config.rb +7 -0
- data/spec/requests/flows/authorization_code_spec.rb +177 -0
- data/spec/requests/flows/client_credentials_spec.rb +163 -0
- data/spec/requests/flows/code_spec.rb +98 -0
- data/spec/requests/flows/password_spec.rb +183 -0
- data/spec/requests/flows/refresh_token_spec.rb +282 -0
- data/spec/requests/flows/token_spec.rb +113 -0
- data/spec/requests/protected_resources_spec.rb +65 -0
- data/spec/requests/revoke_token_spec.rb +90 -0
- data/spec/spec_helper.rb +51 -0
- data/spec/support/helper.rb +11 -0
- metadata +125 -0
@@ -0,0 +1,177 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'Token Endpoint' do
|
4
|
+
subject { -> { post url, params } }
|
5
|
+
|
6
|
+
let(:url) { '/oauth/token' }
|
7
|
+
let(:client) { Client.create(name: FFaker::Internet.domain_word, redirect_uri: 'http://localhost:3000/home') }
|
8
|
+
let(:user) { User.create(username: FFaker::Internet.user_name, encrypted_password: FFaker::Internet.password) }
|
9
|
+
let(:grant_type) { 'authorization_code' }
|
10
|
+
let(:client_id) { client.key }
|
11
|
+
let(:client_secret) { client.secret }
|
12
|
+
let(:scopes) { nil }
|
13
|
+
let(:redirect_uri) { 'localhost:3000/home' }
|
14
|
+
let(:another_redirect_uri) { redirect_uri }
|
15
|
+
let(:access_grant) { AccessGrant.create_for(client, user, redirect_uri, scopes) }
|
16
|
+
let(:code) { access_grant.token }
|
17
|
+
let(:params) do
|
18
|
+
{
|
19
|
+
code: code,
|
20
|
+
redirect_uri: another_redirect_uri,
|
21
|
+
client_id: client_id,
|
22
|
+
client_secret: client_secret,
|
23
|
+
grant_type: grant_type
|
24
|
+
}
|
25
|
+
end
|
26
|
+
|
27
|
+
describe 'POST /oauth/custom_token' do
|
28
|
+
let(:url) { '/oauth/custom_token' }
|
29
|
+
before { subject.call }
|
30
|
+
|
31
|
+
context 'invokes custom block' do
|
32
|
+
it { expect(last_response.status).to eq(400) }
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
describe 'POST /oauth/token' do
|
37
|
+
describe 'AuthorizationCode flow' do
|
38
|
+
before { subject.call }
|
39
|
+
|
40
|
+
context 'when valid params' do
|
41
|
+
it { expect(AccessToken.count).to eq 1 }
|
42
|
+
it { expect(last_response.status).to eq 200 }
|
43
|
+
it { expect(json_body[:access_token]).not_to be_nil }
|
44
|
+
it { expect(json_body[:token_type]).to eq 'bearer' }
|
45
|
+
it { expect(json_body[:expires_in]).to eq 7200 }
|
46
|
+
end
|
47
|
+
|
48
|
+
context 'when invalid params' do
|
49
|
+
context 'without code' do
|
50
|
+
let(:code) {}
|
51
|
+
|
52
|
+
it { expect(AccessToken.count).to be_zero }
|
53
|
+
it { expect(json_body[:error]).to eq('invalid_request') }
|
54
|
+
it { expect(json_body[:error_description]).to eq("'code' required.") }
|
55
|
+
it { expect(last_response.status).to eq 400 }
|
56
|
+
end
|
57
|
+
|
58
|
+
context 'with invalid code' do
|
59
|
+
let(:code) { 'invalid' }
|
60
|
+
let(:error_description) do
|
61
|
+
'The provided access grant is invalid, expired, or revoked '\
|
62
|
+
'(e.g. invalid assertion, expired authorization token, '\
|
63
|
+
'bad end-user password credentials, or mismatching authorization code and redirection URI).'
|
64
|
+
end
|
65
|
+
|
66
|
+
it { expect(AccessToken.count).to be_zero }
|
67
|
+
it { expect(json_body[:error]).to eq('invalid_grant') }
|
68
|
+
it { expect(json_body[:error_description]).to eq(error_description) }
|
69
|
+
it { expect(last_response.status).to eq 400 }
|
70
|
+
end
|
71
|
+
|
72
|
+
context 'without redirect_uri' do
|
73
|
+
let(:redirect_uri) {}
|
74
|
+
let(:error_description) do
|
75
|
+
'The provided access grant is invalid, expired, or revoked '\
|
76
|
+
'(e.g. invalid assertion, expired authorization token, '\
|
77
|
+
'bad end-user password credentials, or mismatching authorization code and redirection URI).'
|
78
|
+
end
|
79
|
+
|
80
|
+
it { expect(AccessToken.count).to be_zero }
|
81
|
+
it { expect(json_body[:error]).to eq('invalid_grant') }
|
82
|
+
it { expect(json_body[:error_description]).to eq(error_description) }
|
83
|
+
it { expect(last_response.status).to eq 400 }
|
84
|
+
end
|
85
|
+
|
86
|
+
context 'with invalid redirect_uri' do
|
87
|
+
let(:another_redirect_uri) { 'invalid' }
|
88
|
+
|
89
|
+
let(:error_description) do
|
90
|
+
'The provided access grant is invalid, expired, or revoked '\
|
91
|
+
'(e.g. invalid assertion, expired authorization token, '\
|
92
|
+
'bad end-user password credentials, or mismatching authorization code and redirection URI).'
|
93
|
+
end
|
94
|
+
|
95
|
+
it { expect(AccessToken.count).to be_zero }
|
96
|
+
it { expect(json_body[:error]).to eq('invalid_grant') }
|
97
|
+
it { expect(json_body[:error_description]).to eq(error_description) }
|
98
|
+
it { expect(last_response.status).to eq 400 }
|
99
|
+
end
|
100
|
+
|
101
|
+
context 'without client_id' do
|
102
|
+
let(:client_id) {}
|
103
|
+
|
104
|
+
it { expect(AccessToken.count).to be_zero }
|
105
|
+
it { expect(json_body[:error]).to eq('invalid_request') }
|
106
|
+
it { expect(json_body[:error_description]).to eq("'client_id' required.") }
|
107
|
+
it { expect(last_response.status).to eq 400 }
|
108
|
+
end
|
109
|
+
|
110
|
+
context 'with invalid client_id' do
|
111
|
+
let(:client_id) { 'invalid' }
|
112
|
+
let(:error_description) do
|
113
|
+
'The client identifier provided is invalid, the client failed to authenticate, '\
|
114
|
+
'the client did not include its credentials, provided multiple client credentials, '\
|
115
|
+
'or used unsupported credentials type.'
|
116
|
+
end
|
117
|
+
|
118
|
+
it { expect(AccessToken.count).to be_zero }
|
119
|
+
it { expect(json_body[:error]).to eq('invalid_client') }
|
120
|
+
it { expect(json_body[:error_description]).to eq(error_description) }
|
121
|
+
it { expect(last_response.status).to eq 401 }
|
122
|
+
end
|
123
|
+
|
124
|
+
context 'without client_secret' do
|
125
|
+
let(:client_secret) {}
|
126
|
+
let(:error_description) do
|
127
|
+
'The client identifier provided is invalid, the client failed to authenticate, '\
|
128
|
+
'the client did not include its credentials, provided multiple client credentials, '\
|
129
|
+
'or used unsupported credentials type.'
|
130
|
+
end
|
131
|
+
|
132
|
+
it { expect(AccessToken.count).to be_zero }
|
133
|
+
it { expect(json_body[:error]).to eq('invalid_client') }
|
134
|
+
it { expect(json_body[:error_description]).to eq(error_description) }
|
135
|
+
it { expect(last_response.status).to eq 401 }
|
136
|
+
end
|
137
|
+
|
138
|
+
context 'with invalid client_secret' do
|
139
|
+
let(:client_secret) { 'invalid' }
|
140
|
+
let(:error_description) do
|
141
|
+
'The client identifier provided is invalid, the client failed to authenticate, '\
|
142
|
+
'the client did not include its credentials, provided multiple client credentials, '\
|
143
|
+
'or used unsupported credentials type.'
|
144
|
+
end
|
145
|
+
|
146
|
+
it { expect(AccessToken.count).to be_zero }
|
147
|
+
it { expect(json_body[:error]).to eq('invalid_client') }
|
148
|
+
it { expect(json_body[:error_description]).to eq(error_description) }
|
149
|
+
it { expect(last_response.status).to eq 401 }
|
150
|
+
end
|
151
|
+
|
152
|
+
context 'without grant_type' do
|
153
|
+
let(:grant_type) {}
|
154
|
+
|
155
|
+
it { expect(AccessToken.count).to be_zero }
|
156
|
+
it { expect(json_body[:error]).to eq('invalid_request') }
|
157
|
+
it { expect(json_body[:error_description]).to eq("'grant_type' required.") }
|
158
|
+
it { expect(last_response.status).to eq 400 }
|
159
|
+
end
|
160
|
+
|
161
|
+
context 'with invalid grant_type' do
|
162
|
+
let(:grant_type) { 'invalid' }
|
163
|
+
let(:error_description) do
|
164
|
+
'The access grant included - '\
|
165
|
+
'its type or another attribute - '\
|
166
|
+
'is not supported by the authorization server.'
|
167
|
+
end
|
168
|
+
|
169
|
+
it { expect(AccessToken.count).to be_zero }
|
170
|
+
it { expect(json_body[:error]).to eq('unsupported_grant_type') }
|
171
|
+
it { expect(json_body[:error_description]).to eq(error_description) }
|
172
|
+
it { expect(last_response.status).to eq 400 }
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
@@ -0,0 +1,163 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'Token Endpoint' do
|
4
|
+
subject { -> { post url, params } }
|
5
|
+
|
6
|
+
let(:url) { '/oauth/token' }
|
7
|
+
let(:client) { Client.create(name: FFaker::Internet.domain_word, redirect_uri: 'http://localhost:3000/home') }
|
8
|
+
let(:user) { User.create(username: FFaker::Internet.user_name, encrypted_password: FFaker::Internet.password) }
|
9
|
+
let(:grant_type) { 'client_credentials' }
|
10
|
+
let(:scopes) { 'read,write' }
|
11
|
+
let(:username) { user.username }
|
12
|
+
let(:password) { user.encrypted_password }
|
13
|
+
let(:client_id) { client.key }
|
14
|
+
let(:params) do
|
15
|
+
{
|
16
|
+
username: username,
|
17
|
+
password: password,
|
18
|
+
client_id: client_id,
|
19
|
+
grant_type: grant_type,
|
20
|
+
scope: scopes
|
21
|
+
}
|
22
|
+
end
|
23
|
+
|
24
|
+
describe 'POST /oauth/token' do
|
25
|
+
describe 'ClientCredentials flow' do
|
26
|
+
before { subject.call }
|
27
|
+
|
28
|
+
context 'when valid params' do
|
29
|
+
context 'return AccessToken' do
|
30
|
+
it { expect(AccessToken.count).to eq 1 }
|
31
|
+
it { expect(AccessToken.first.client_id).to eq(client.id) }
|
32
|
+
it { expect(AccessToken.first.resource_owner_id).to eq(user.id) }
|
33
|
+
|
34
|
+
it { expect(last_response.status).to eq 200 }
|
35
|
+
it { expect(json_body[:access_token]).to be_present }
|
36
|
+
it { expect(json_body[:token_type]).to eq 'bearer' }
|
37
|
+
it { expect(json_body[:expires_in]).to eq 7200 }
|
38
|
+
it { expect(json_body[:refresh_token]).to be_nil }
|
39
|
+
it { expect(json_body[:scope]).to eq('read,write') }
|
40
|
+
end
|
41
|
+
|
42
|
+
context 'return AccessToken without scopes' do
|
43
|
+
let(:scopes) {}
|
44
|
+
|
45
|
+
it { expect(AccessToken.count).to eq 1 }
|
46
|
+
it { expect(AccessToken.first.client_id).to eq(client.id) }
|
47
|
+
it { expect(AccessToken.first.resource_owner_id).to eq(user.id) }
|
48
|
+
|
49
|
+
it { expect(last_response.status).to eq 200 }
|
50
|
+
it { expect(json_body[:access_token]).to be_present }
|
51
|
+
it { expect(json_body[:token_type]).to eq 'bearer' }
|
52
|
+
it { expect(json_body[:expires_in]).to eq 7200 }
|
53
|
+
it { expect(json_body[:refresh_token]).to be_nil }
|
54
|
+
it { expect(json_body[:scope]).to be_nil }
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
context 'when invalid params' do
|
59
|
+
context 'without username' do
|
60
|
+
let(:username) {}
|
61
|
+
let(:error_description) do
|
62
|
+
'The provided access grant is invalid, expired, or revoked (e.g. invalid assertion, '\
|
63
|
+
'expired authorization token, bad end-user password credentials, '\
|
64
|
+
'or mismatching authorization code and redirection URI).'
|
65
|
+
end
|
66
|
+
|
67
|
+
it { expect(AccessToken.count).to be_zero }
|
68
|
+
it { expect(json_body[:error]).to eq('invalid_grant') }
|
69
|
+
it { expect(json_body[:error_description]).to eq error_description }
|
70
|
+
it { expect(last_response.status).to eq 400 }
|
71
|
+
end
|
72
|
+
|
73
|
+
context 'with invalid username' do
|
74
|
+
let(:username) { 'invalid@example.com' }
|
75
|
+
let(:error_description) do
|
76
|
+
'The provided access grant is invalid, expired, or revoked (e.g. invalid assertion, '\
|
77
|
+
'expired authorization token, bad end-user password credentials, '\
|
78
|
+
'or mismatching authorization code and redirection URI).'
|
79
|
+
end
|
80
|
+
|
81
|
+
it { expect(AccessToken.count).to be_zero }
|
82
|
+
it { expect(json_body[:error]).to eq('invalid_grant') }
|
83
|
+
it { expect(json_body[:error_description]).to eq(error_description) }
|
84
|
+
it { expect(last_response.status).to eq 400 }
|
85
|
+
end
|
86
|
+
|
87
|
+
context 'without password' do
|
88
|
+
let(:password) {}
|
89
|
+
let(:error_description) do
|
90
|
+
'The provided access grant is invalid, expired, or revoked (e.g. invalid assertion, '\
|
91
|
+
'expired authorization token, bad end-user password credentials, '\
|
92
|
+
'or mismatching authorization code and redirection URI).'
|
93
|
+
end
|
94
|
+
|
95
|
+
it { expect(AccessToken.count).to be_zero }
|
96
|
+
it { expect(json_body[:error]).to eq('invalid_grant') }
|
97
|
+
it { expect(json_body[:error_description]).to eq error_description }
|
98
|
+
it { expect(last_response.status).to eq 400 }
|
99
|
+
end
|
100
|
+
|
101
|
+
context 'with invalid params' do
|
102
|
+
let(:password) { 'invalid@password.com' }
|
103
|
+
let(:error_description) do
|
104
|
+
'The provided access grant is invalid, expired, or revoked (e.g. invalid assertion, '\
|
105
|
+
'expired authorization token, bad end-user password credentials, '\
|
106
|
+
'or mismatching authorization code and redirection URI).'
|
107
|
+
end
|
108
|
+
|
109
|
+
it { expect(AccessToken.count).to be_zero }
|
110
|
+
it { expect(json_body[:error]).to eq('invalid_grant') }
|
111
|
+
it { expect(json_body[:error_description]).to eq(error_description) }
|
112
|
+
it { expect(last_response.status).to eq 400 }
|
113
|
+
end
|
114
|
+
|
115
|
+
context 'without client_id' do
|
116
|
+
let(:client_id) {}
|
117
|
+
|
118
|
+
it { expect(AccessToken.count).to be_zero }
|
119
|
+
it { expect(json_body[:error]).to eq('invalid_request') }
|
120
|
+
it { expect(json_body[:error_description]).to eq("'client_id' required.") }
|
121
|
+
it { expect(last_response.status).to eq 400 }
|
122
|
+
end
|
123
|
+
|
124
|
+
context 'with invalid client_id' do
|
125
|
+
let(:client_id) { 'invalid' }
|
126
|
+
let(:error_description) do
|
127
|
+
'The client identifier provided is invalid, the client failed to authenticate, '\
|
128
|
+
'the client did not include its credentials, provided multiple client credentials, '\
|
129
|
+
'or used unsupported credentials type.'
|
130
|
+
end
|
131
|
+
|
132
|
+
it { expect(AccessToken.count).to be_zero }
|
133
|
+
it { expect(json_body[:error]).to eq('invalid_client') }
|
134
|
+
it { expect(json_body[:error_description]).to eq(error_description) }
|
135
|
+
it { expect(last_response.status).to eq 401 }
|
136
|
+
end
|
137
|
+
|
138
|
+
context 'without grant_type' do
|
139
|
+
let(:grant_type) {}
|
140
|
+
|
141
|
+
it { expect(AccessToken.count).to be_zero }
|
142
|
+
it { expect(json_body[:error]).to eq('invalid_request') }
|
143
|
+
it { expect(json_body[:error_description]).to eq("'grant_type' required.") }
|
144
|
+
it { expect(last_response.status).to eq 400 }
|
145
|
+
end
|
146
|
+
|
147
|
+
context 'with invalid grant_type' do
|
148
|
+
let(:grant_type) { 'invalid' }
|
149
|
+
let(:error_description) do
|
150
|
+
'The access grant included - '\
|
151
|
+
'its type or another attribute - '\
|
152
|
+
'is not supported by the authorization server.'
|
153
|
+
end
|
154
|
+
|
155
|
+
it { expect(AccessToken.count).to be_zero }
|
156
|
+
it { expect(json_body[:error]).to eq('unsupported_grant_type') }
|
157
|
+
it { expect(json_body[:error_description]).to eq(error_description) }
|
158
|
+
it { expect(last_response.status).to eq 400 }
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'Authorization Endpoint' do
|
4
|
+
subject { -> { post url, params } }
|
5
|
+
|
6
|
+
let(:url) { '/oauth/authorization' }
|
7
|
+
let!(:user) { User.create(username: FFaker::Internet.user_name, encrypted_password: FFaker::Internet.password) }
|
8
|
+
let(:client) { Client.create(name: FFaker::Internet.domain_word, redirect_uri: 'http://localhost:3000/home') }
|
9
|
+
let(:client_id) { client.key }
|
10
|
+
let(:redirect_uri) { client.redirect_uri }
|
11
|
+
let(:response_type) { 'code' }
|
12
|
+
let(:state) { nil }
|
13
|
+
let(:scope) { nil }
|
14
|
+
let(:params) do
|
15
|
+
{
|
16
|
+
client_id: client_id,
|
17
|
+
redirect_uri: redirect_uri,
|
18
|
+
response_type: response_type,
|
19
|
+
state: state,
|
20
|
+
scope: scope
|
21
|
+
}
|
22
|
+
end
|
23
|
+
|
24
|
+
describe 'POST /oauth/authorization' do
|
25
|
+
describe 'Code flow' do
|
26
|
+
before { subject.call }
|
27
|
+
|
28
|
+
context 'when valid params' do
|
29
|
+
let(:response_header) { "#{client.redirect_uri}?code=#{AccessGrant.last.token}" }
|
30
|
+
|
31
|
+
it { expect(AccessGrant.count).to eq 1 }
|
32
|
+
it { expect(AccessGrant.last.scopes).to be_empty }
|
33
|
+
it { expect(AccessGrant.last.resource_owner.username).to eq user.username }
|
34
|
+
it { expect(last_response.status).to eq 302 }
|
35
|
+
it { expect(last_response.headers['Location']).to eq response_header }
|
36
|
+
|
37
|
+
context 'without redirect_uri' do
|
38
|
+
let(:redirect_uri) {}
|
39
|
+
|
40
|
+
it { expect(last_response.headers['Location']).to eq response_header }
|
41
|
+
end
|
42
|
+
|
43
|
+
context 'with state' do
|
44
|
+
let(:state) { 'zxc' }
|
45
|
+
let(:response_header_with_state) { "#{client.redirect_uri}?code=#{AccessGrant.last.token}&state=#{state}" }
|
46
|
+
|
47
|
+
it { expect(last_response.headers['Location']).to eq response_header_with_state }
|
48
|
+
end
|
49
|
+
|
50
|
+
context 'with scopes' do
|
51
|
+
let(:scope) { 'read,write' }
|
52
|
+
|
53
|
+
it { expect(AccessGrant.last.scopes).to eq 'read,write' }
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
context 'when invalid params' do
|
58
|
+
context 'without client_id' do
|
59
|
+
let(:client_id) {}
|
60
|
+
|
61
|
+
it { expect(last_response.status).to eq 400 }
|
62
|
+
it { expect(json_body[:error]).to eq('bad_request') }
|
63
|
+
end
|
64
|
+
|
65
|
+
context 'with invalid client_id' do
|
66
|
+
let(:client_id) { 'invalid' }
|
67
|
+
|
68
|
+
it { expect(last_response.status).to eq 400 }
|
69
|
+
it { expect(json_body[:error]).to eq('bad_request') }
|
70
|
+
end
|
71
|
+
|
72
|
+
context 'with invalid redirect_uri' do
|
73
|
+
let(:redirect_uri) { 'invalid' }
|
74
|
+
|
75
|
+
it { expect(last_response.status).to eq 400 }
|
76
|
+
it { expect(json_body[:error]).to eq('bad_request') }
|
77
|
+
end
|
78
|
+
|
79
|
+
context 'without response_type' do
|
80
|
+
let(:response_type) {}
|
81
|
+
|
82
|
+
it { expect(last_response.status).to eq 400 }
|
83
|
+
it { expect(json_body[:error]).to eq('invalid_request') }
|
84
|
+
it { expect(json_body[:error_description]).to eq "'response_type' required." }
|
85
|
+
end
|
86
|
+
|
87
|
+
context 'with invalid response_type' do
|
88
|
+
let(:response_type) { 'invalid' }
|
89
|
+
let(:error_description) { 'The requested response type is not supported by the authorization server.' }
|
90
|
+
|
91
|
+
it { expect(last_response.status).to eq 400 }
|
92
|
+
it { expect(json_body[:error]).to eq 'unsupported_response_type' }
|
93
|
+
it { expect(json_body[:error_description]).to eq error_description }
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
@@ -0,0 +1,183 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'Token Endpoint' do
|
4
|
+
subject { -> { post url, params } }
|
5
|
+
|
6
|
+
let(:url) { '/oauth/token' }
|
7
|
+
let(:client) { Client.create(name: FFaker::Internet.domain_word, redirect_uri: 'http://localhost:3000/home') }
|
8
|
+
let(:user) { User.create(username: FFaker::Internet.user_name, encrypted_password: FFaker::Internet.password) }
|
9
|
+
let(:grant_type) { 'password' }
|
10
|
+
let(:scopes) { 'read,write' }
|
11
|
+
let(:username) { user.username }
|
12
|
+
let(:password) { user.encrypted_password }
|
13
|
+
let(:client_id) { client.key }
|
14
|
+
let(:client_secret) { client.secret }
|
15
|
+
let(:params) do
|
16
|
+
{
|
17
|
+
username: username,
|
18
|
+
password: password,
|
19
|
+
client_id: client_id,
|
20
|
+
client_secret: client_secret,
|
21
|
+
grant_type: grant_type,
|
22
|
+
scope: scopes
|
23
|
+
}
|
24
|
+
end
|
25
|
+
|
26
|
+
describe 'POST /oauth/token' do
|
27
|
+
describe 'Password flow' do
|
28
|
+
before { subject.call }
|
29
|
+
|
30
|
+
context 'when invalid params' do
|
31
|
+
context 'without username' do
|
32
|
+
let(:username) {}
|
33
|
+
|
34
|
+
it { expect(AccessToken.count).to be_zero }
|
35
|
+
it { expect(json_body[:error]).to eq('invalid_request') }
|
36
|
+
it { expect(json_body[:error_description]).to eq("'username' required.") }
|
37
|
+
it { expect(last_response.status).to eq 400 }
|
38
|
+
end
|
39
|
+
|
40
|
+
context 'with invalid username' do
|
41
|
+
let(:username) { 'invalid@example.com' }
|
42
|
+
let(:error_description) do
|
43
|
+
'The provided access grant is invalid, expired, or revoked (e.g. invalid assertion, '\
|
44
|
+
'expired authorization token, bad end-user password credentials, '\
|
45
|
+
'or mismatching authorization code and redirection URI).'
|
46
|
+
end
|
47
|
+
|
48
|
+
it { expect(AccessToken.count).to be_zero }
|
49
|
+
it { expect(json_body[:error]).to eq('invalid_grant') }
|
50
|
+
it { expect(json_body[:error_description]).to eq(error_description) }
|
51
|
+
it { expect(last_response.status).to eq 400 }
|
52
|
+
end
|
53
|
+
|
54
|
+
context 'without password' do
|
55
|
+
let(:password) {}
|
56
|
+
|
57
|
+
it { expect(AccessToken.count).to be_zero }
|
58
|
+
it { expect(json_body[:error]).to eq('invalid_request') }
|
59
|
+
it { expect(json_body[:error_description]).to eq("'password' required.") }
|
60
|
+
it { expect(last_response.status).to eq 400 }
|
61
|
+
end
|
62
|
+
|
63
|
+
context 'with invalid password' do
|
64
|
+
let(:password) { 'invalid@password.com' }
|
65
|
+
let(:error_description) do
|
66
|
+
'The provided access grant is invalid, expired, or revoked (e.g. invalid assertion, '\
|
67
|
+
'expired authorization token, bad end-user password credentials, '\
|
68
|
+
'or mismatching authorization code and redirection URI).'
|
69
|
+
end
|
70
|
+
|
71
|
+
it { expect(AccessToken.count).to be_zero }
|
72
|
+
it { expect(json_body[:error]).to eq('invalid_grant') }
|
73
|
+
it { expect(json_body[:error_description]).to eq(error_description) }
|
74
|
+
it { expect(last_response.status).to eq 400 }
|
75
|
+
end
|
76
|
+
|
77
|
+
context 'without client_id' do
|
78
|
+
let(:client_id) {}
|
79
|
+
|
80
|
+
it { expect(AccessToken.count).to be_zero }
|
81
|
+
it { expect(json_body[:error]).to eq('invalid_request') }
|
82
|
+
it { expect(json_body[:error_description]).to eq("'client_id' required.") }
|
83
|
+
it { expect(last_response.status).to eq 400 }
|
84
|
+
end
|
85
|
+
|
86
|
+
context 'with invalid client_id' do
|
87
|
+
let(:client_id) { 'invalid' }
|
88
|
+
let(:error_description) do
|
89
|
+
'The client identifier provided is invalid, the client failed to authenticate, '\
|
90
|
+
'the client did not include its credentials, provided multiple client credentials, '\
|
91
|
+
'or used unsupported credentials type.'
|
92
|
+
end
|
93
|
+
|
94
|
+
it { expect(AccessToken.count).to be_zero }
|
95
|
+
it { expect(json_body[:error]).to eq('invalid_client') }
|
96
|
+
it { expect(json_body[:error_description]).to eq(error_description) }
|
97
|
+
it { expect(last_response.status).to eq 401 }
|
98
|
+
end
|
99
|
+
|
100
|
+
context 'without client_secret' do
|
101
|
+
let(:client_secret) {}
|
102
|
+
let(:error_description) do
|
103
|
+
'The client identifier provided is invalid, the client failed to authenticate, '\
|
104
|
+
'the client did not include its credentials, provided multiple client credentials, '\
|
105
|
+
'or used unsupported credentials type.'
|
106
|
+
end
|
107
|
+
|
108
|
+
it { expect(AccessToken.count).to be_zero }
|
109
|
+
it { expect(json_body[:error]).to eq('invalid_client') }
|
110
|
+
it { expect(json_body[:error_description]).to eq(error_description) }
|
111
|
+
it { expect(last_response.status).to eq 401 }
|
112
|
+
end
|
113
|
+
|
114
|
+
context 'with invalid client_secret' do
|
115
|
+
let(:client_secret) { 'invalid' }
|
116
|
+
let(:error_description) do
|
117
|
+
'The client identifier provided is invalid, the client failed to authenticate, '\
|
118
|
+
'the client did not include its credentials, provided multiple client credentials, '\
|
119
|
+
'or used unsupported credentials type.'
|
120
|
+
end
|
121
|
+
|
122
|
+
it { expect(AccessToken.count).to be_zero }
|
123
|
+
it { expect(json_body[:error]).to eq('invalid_client') }
|
124
|
+
it { expect(json_body[:error_description]).to eq(error_description) }
|
125
|
+
it { expect(last_response.status).to eq 401 }
|
126
|
+
end
|
127
|
+
|
128
|
+
context 'without grant_type' do
|
129
|
+
let(:grant_type) {}
|
130
|
+
|
131
|
+
it { expect(AccessToken.count).to be_zero }
|
132
|
+
it { expect(json_body[:error]).to eq('invalid_request') }
|
133
|
+
it { expect(json_body[:error_description]).to eq("'grant_type' required.") }
|
134
|
+
it { expect(last_response.status).to eq 400 }
|
135
|
+
end
|
136
|
+
|
137
|
+
context 'with invalid grant_type' do
|
138
|
+
let(:grant_type) { 'invalid' }
|
139
|
+
let(:error_description) do
|
140
|
+
'The access grant included - '\
|
141
|
+
'its type or another attribute - '\
|
142
|
+
'is not supported by the authorization server.'
|
143
|
+
end
|
144
|
+
|
145
|
+
it { expect(AccessToken.count).to be_zero }
|
146
|
+
it { expect(json_body[:error]).to eq('unsupported_grant_type') }
|
147
|
+
it { expect(json_body[:error_description]).to eq(error_description) }
|
148
|
+
it { expect(last_response.status).to eq 400 }
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
context 'when valid params' do
|
153
|
+
context 'return AccessToken' do
|
154
|
+
it { expect(AccessToken.count).to eq 1 }
|
155
|
+
it { expect(AccessToken.first.client_id).to eq(client.id) }
|
156
|
+
it { expect(AccessToken.first.resource_owner_id).to eq(user.id) }
|
157
|
+
|
158
|
+
it { expect(last_response.status).to eq 200 }
|
159
|
+
it { expect(json_body[:access_token]).to be_present }
|
160
|
+
it { expect(json_body[:token_type]).to eq 'bearer' }
|
161
|
+
it { expect(json_body[:expires_in]).to eq 7200 }
|
162
|
+
it { expect(json_body[:refresh_token]).to be_nil }
|
163
|
+
it { expect(json_body[:scope]).to eq('read,write') }
|
164
|
+
end
|
165
|
+
|
166
|
+
context 'return AccessToken without scopes' do
|
167
|
+
let(:scopes) {}
|
168
|
+
|
169
|
+
it { expect(AccessToken.count).to eq 1 }
|
170
|
+
it { expect(AccessToken.first.client_id).to eq(client.id) }
|
171
|
+
it { expect(AccessToken.first.resource_owner_id).to eq(user.id) }
|
172
|
+
|
173
|
+
it { expect(last_response.status).to eq 200 }
|
174
|
+
it { expect(json_body[:access_token]).to be_present }
|
175
|
+
it { expect(json_body[:token_type]).to eq 'bearer' }
|
176
|
+
it { expect(json_body[:expires_in]).to eq 7200 }
|
177
|
+
it { expect(json_body[:refresh_token]).to be_nil }
|
178
|
+
it { expect(json_body[:scope]).to be_nil }
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|