grape_oauth2 0.1.1 → 0.2.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 +4 -4
- data/.gitignore +11 -11
- data/Gemfile +23 -23
- data/Rakefile +11 -11
- data/grape_oauth2.gemspec +26 -27
- data/lib/grape_oauth2.rb +129 -129
- data/lib/grape_oauth2/configuration.rb +143 -143
- data/lib/grape_oauth2/configuration/class_accessors.rb +36 -36
- data/lib/grape_oauth2/configuration/validation.rb +71 -71
- data/lib/grape_oauth2/endpoints/authorize.rb +34 -34
- data/lib/grape_oauth2/endpoints/token.rb +72 -72
- data/lib/grape_oauth2/gem_version.rb +24 -24
- data/lib/grape_oauth2/generators/authorization.rb +44 -44
- data/lib/grape_oauth2/generators/base.rb +26 -26
- data/lib/grape_oauth2/generators/token.rb +62 -62
- data/lib/grape_oauth2/helpers/access_token_helpers.rb +52 -54
- data/lib/grape_oauth2/helpers/oauth_params.rb +41 -41
- data/lib/grape_oauth2/mixins/active_record/access_grant.rb +47 -47
- data/lib/grape_oauth2/mixins/active_record/access_token.rb +75 -75
- data/lib/grape_oauth2/mixins/active_record/client.rb +36 -35
- data/lib/grape_oauth2/mixins/mongoid/access_grant.rb +58 -58
- data/lib/grape_oauth2/mixins/mongoid/access_token.rb +88 -88
- data/lib/grape_oauth2/mixins/mongoid/client.rb +44 -41
- data/lib/grape_oauth2/mixins/sequel/access_grant.rb +68 -68
- data/lib/grape_oauth2/mixins/sequel/access_token.rb +86 -86
- data/lib/grape_oauth2/mixins/sequel/client.rb +54 -46
- data/lib/grape_oauth2/responses/authorization.rb +11 -10
- data/lib/grape_oauth2/responses/base.rb +56 -56
- data/lib/grape_oauth2/responses/token.rb +10 -10
- data/lib/grape_oauth2/scopes.rb +74 -74
- data/lib/grape_oauth2/strategies/authorization_code.rb +38 -38
- data/lib/grape_oauth2/strategies/base.rb +47 -47
- data/lib/grape_oauth2/strategies/client_credentials.rb +20 -20
- data/lib/grape_oauth2/strategies/password.rb +22 -22
- data/lib/grape_oauth2/strategies/refresh_token.rb +47 -47
- data/lib/grape_oauth2/unique_token.rb +20 -20
- data/lib/grape_oauth2/version.rb +14 -14
- data/spec/configuration/config_spec.rb +231 -231
- data/spec/configuration/version_spec.rb +12 -12
- data/spec/dummy/endpoints/custom_authorization.rb +25 -25
- data/spec/dummy/endpoints/custom_token.rb +35 -35
- data/spec/dummy/endpoints/status.rb +25 -25
- data/spec/dummy/grape_oauth2_config.rb +11 -11
- data/spec/dummy/orm/active_record/app/config/db.rb +7 -7
- data/spec/dummy/orm/active_record/app/models/access_code.rb +3 -3
- data/spec/dummy/orm/active_record/app/models/access_token.rb +3 -3
- data/spec/dummy/orm/active_record/app/models/application.rb +3 -3
- data/spec/dummy/orm/active_record/app/models/application_record.rb +3 -3
- data/spec/dummy/orm/active_record/app/models/user.rb +10 -10
- data/spec/dummy/orm/active_record/app/twitter.rb +36 -36
- data/spec/dummy/orm/active_record/config.ru +7 -7
- data/spec/dummy/orm/active_record/db/schema.rb +53 -53
- data/spec/dummy/orm/mongoid/app/config/db.rb +6 -6
- data/spec/dummy/orm/mongoid/app/config/mongoid.yml +21 -21
- data/spec/dummy/orm/mongoid/app/models/access_code.rb +3 -3
- data/spec/dummy/orm/mongoid/app/models/access_token.rb +3 -3
- data/spec/dummy/orm/mongoid/app/models/application.rb +3 -3
- data/spec/dummy/orm/mongoid/app/models/user.rb +11 -11
- data/spec/dummy/orm/mongoid/app/twitter.rb +34 -34
- data/spec/dummy/orm/mongoid/config.ru +5 -5
- data/spec/dummy/orm/sequel/app/config/db.rb +1 -1
- data/spec/dummy/orm/sequel/app/models/access_code.rb +4 -4
- data/spec/dummy/orm/sequel/app/models/access_token.rb +4 -4
- data/spec/dummy/orm/sequel/app/models/application.rb +4 -4
- data/spec/dummy/orm/sequel/app/models/application_record.rb +2 -2
- data/spec/dummy/orm/sequel/app/models/user.rb +11 -11
- data/spec/dummy/orm/sequel/app/twitter.rb +47 -47
- data/spec/dummy/orm/sequel/config.ru +5 -5
- data/spec/dummy/orm/sequel/db/schema.rb +50 -50
- data/spec/lib/scopes_spec.rb +50 -50
- data/spec/mixins/active_record/access_token_spec.rb +185 -185
- data/spec/mixins/active_record/client_spec.rb +104 -95
- data/spec/mixins/mongoid/access_token_spec.rb +185 -185
- data/spec/mixins/mongoid/client_spec.rb +104 -95
- data/spec/mixins/sequel/access_token_spec.rb +185 -185
- data/spec/mixins/sequel/client_spec.rb +105 -96
- data/spec/requests/flows/authorization_code_spec.rb +67 -67
- data/spec/requests/flows/client_credentials_spec.rb +101 -101
- data/spec/requests/flows/password_spec.rb +210 -210
- data/spec/requests/flows/refresh_token_spec.rb +222 -222
- data/spec/requests/flows/revoke_token_spec.rb +103 -103
- data/spec/requests/protected_resources_spec.rb +64 -64
- data/spec/spec_helper.rb +60 -60
- data/spec/support/api_helper.rb +11 -11
- metadata +50 -52
- data/.rspec +0 -2
- data/.rubocop.yml +0 -18
- data/.travis.yml +0 -42
- data/README.md +0 -820
- data/gemfiles/active_record.rb +0 -25
- data/gemfiles/mongoid.rb +0 -14
- data/gemfiles/sequel.rb +0 -24
- data/grape_oauth2.png +0 -0
@@ -1,210 +1,210 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe 'Token Endpoint' do
|
4
|
-
let(:application) { Application.create(name: 'App1') }
|
5
|
-
let(:user) { User.create(username: 'test', password: '12345678') }
|
6
|
-
|
7
|
-
describe 'Resource Owner Password Credentials flow' do
|
8
|
-
describe 'POST /oauth/token' do
|
9
|
-
let(:authentication_url) { '/api/v1/oauth/token' }
|
10
|
-
|
11
|
-
context 'with valid params' do
|
12
|
-
context 'when request is invalid' do
|
13
|
-
it 'fails without Grant Type' do
|
14
|
-
post authentication_url,
|
15
|
-
username: user.username,
|
16
|
-
password: '12345678',
|
17
|
-
client_id: application.key,
|
18
|
-
client_secret: application.secret
|
19
|
-
|
20
|
-
expect(AccessToken.all).to be_empty
|
21
|
-
|
22
|
-
expect(json_body[:error]).to eq('invalid_request')
|
23
|
-
expect(last_response.status).to eq 400
|
24
|
-
end
|
25
|
-
|
26
|
-
it 'fails with invalid Grant Type' do
|
27
|
-
post authentication_url,
|
28
|
-
grant_type: 'invalid',
|
29
|
-
username: user.username,
|
30
|
-
password: '12345678'
|
31
|
-
|
32
|
-
expect(AccessToken.all).to be_empty
|
33
|
-
|
34
|
-
expect(json_body[:error]).to eq('unsupported_grant_type')
|
35
|
-
expect(last_response.status).to eq 400
|
36
|
-
end
|
37
|
-
|
38
|
-
it 'fails without Client Credentials' do
|
39
|
-
post authentication_url,
|
40
|
-
grant_type: 'password',
|
41
|
-
username: user.username,
|
42
|
-
password: '12345678'
|
43
|
-
|
44
|
-
expect(AccessToken.all).to be_empty
|
45
|
-
|
46
|
-
expect(json_body[:error]).to eq('invalid_request')
|
47
|
-
expect(last_response.status).to eq 400
|
48
|
-
end
|
49
|
-
|
50
|
-
it 'fails with invalid Client Credentials' do
|
51
|
-
post authentication_url,
|
52
|
-
grant_type: 'password',
|
53
|
-
username: user.username,
|
54
|
-
password: '12345678',
|
55
|
-
client_id: 'blah-blah',
|
56
|
-
client_secret: application.secret
|
57
|
-
|
58
|
-
expect(AccessToken.all).to be_empty
|
59
|
-
|
60
|
-
expect(json_body[:error]).to eq('invalid_client')
|
61
|
-
expect(last_response.status).to eq 401
|
62
|
-
end
|
63
|
-
|
64
|
-
it 'fails without Resource Owner credentials' do
|
65
|
-
post authentication_url,
|
66
|
-
grant_type: 'password',
|
67
|
-
client_id: application.key,
|
68
|
-
client_secret: application.secret
|
69
|
-
|
70
|
-
expect(json_body[:error]).to eq('invalid_request')
|
71
|
-
expect(json_body[:error_description]).not_to be_blank
|
72
|
-
expect(last_response.status).to eq 400
|
73
|
-
end
|
74
|
-
|
75
|
-
it 'fails with invalid Resource Owner credentials' do
|
76
|
-
post authentication_url,
|
77
|
-
grant_type: 'password',
|
78
|
-
username: 'invalid@example.com',
|
79
|
-
password: 'invalid',
|
80
|
-
client_id: application.key,
|
81
|
-
client_secret: application.secret
|
82
|
-
|
83
|
-
expect(json_body[:error]).to eq('invalid_grant')
|
84
|
-
expect(json_body[:error_description]).not_to be_blank
|
85
|
-
expect(last_response.status).to eq 400
|
86
|
-
end
|
87
|
-
end
|
88
|
-
|
89
|
-
context 'with valid data' do
|
90
|
-
context 'when scopes requested' do
|
91
|
-
it 'returns an Access Token with scopes' do
|
92
|
-
post authentication_url,
|
93
|
-
grant_type: 'password',
|
94
|
-
username: user.username,
|
95
|
-
password: '12345678',
|
96
|
-
scope: 'read write',
|
97
|
-
client_id: application.key,
|
98
|
-
client_secret: application.secret
|
99
|
-
|
100
|
-
expect(AccessToken.count).to eq 1
|
101
|
-
expect(AccessToken.first.client_id).to eq application.id
|
102
|
-
|
103
|
-
expect(json_body[:access_token]).to be_present
|
104
|
-
expect(json_body[:token_type]).to eq 'bearer'
|
105
|
-
expect(json_body[:expires_in]).to eq 7200
|
106
|
-
expect(json_body[:refresh_token]).to be_nil
|
107
|
-
expect(json_body[:scope]).to eq('read write')
|
108
|
-
|
109
|
-
expect(last_response.status).to eq 200
|
110
|
-
end
|
111
|
-
end
|
112
|
-
|
113
|
-
context 'without scopes' do
|
114
|
-
it 'returns an Access Token without scopes' do
|
115
|
-
post authentication_url,
|
116
|
-
grant_type: 'password',
|
117
|
-
username: user.username,
|
118
|
-
password: '12345678',
|
119
|
-
client_id: application.key,
|
120
|
-
client_secret: application.secret
|
121
|
-
|
122
|
-
expect(AccessToken.count).to eq 1
|
123
|
-
expect(AccessToken.first.client_id).to eq application.id
|
124
|
-
|
125
|
-
expect(json_body[:access_token]).to be_present
|
126
|
-
expect(json_body[:token_type]).to eq 'bearer'
|
127
|
-
expect(json_body[:expires_in]).to eq 7200
|
128
|
-
expect(json_body[:refresh_token]).to be_nil
|
129
|
-
expect(json_body[:scope]).to be_nil
|
130
|
-
|
131
|
-
expect(last_response.status).to eq 200
|
132
|
-
end
|
133
|
-
end
|
134
|
-
end
|
135
|
-
|
136
|
-
context 'when Token endpoint not mounted' do
|
137
|
-
before do
|
138
|
-
Twitter::API.reset!
|
139
|
-
Twitter::API.change!
|
140
|
-
|
141
|
-
# Mount only Authorization Endpoint
|
142
|
-
Twitter::API.send(:include, Grape::OAuth2.api(:authorize))
|
143
|
-
end
|
144
|
-
|
145
|
-
after do
|
146
|
-
Twitter::API.reset!
|
147
|
-
Twitter::API.change!
|
148
|
-
|
149
|
-
Twitter::API.send(:include, Grape::OAuth2.api)
|
150
|
-
Twitter::API.mount(Twitter::Endpoints::Status)
|
151
|
-
Twitter::API.mount(Twitter::Endpoints::CustomToken)
|
152
|
-
Twitter::API.mount(Twitter::Endpoints::CustomAuthorization)
|
153
|
-
end
|
154
|
-
|
155
|
-
it 'returns 404' do
|
156
|
-
post authentication_url,
|
157
|
-
grant_type: 'password',
|
158
|
-
username: user.username,
|
159
|
-
password: '12345678',
|
160
|
-
client_id: application.key,
|
161
|
-
client_secret: application.secret
|
162
|
-
|
163
|
-
expect(last_response.status).to eq 404
|
164
|
-
end
|
165
|
-
end
|
166
|
-
end
|
167
|
-
end
|
168
|
-
end
|
169
|
-
|
170
|
-
describe 'POST /oauth/custom_token' do
|
171
|
-
context 'when block processed successfully' do
|
172
|
-
it 'returns an access token' do
|
173
|
-
application.update(name: 'Admin')
|
174
|
-
|
175
|
-
post '/api/v1/oauth/custom_token',
|
176
|
-
grant_type: 'password',
|
177
|
-
username: user.username,
|
178
|
-
password: '12345678',
|
179
|
-
client_id: application.key,
|
180
|
-
client_secret: application.secret
|
181
|
-
|
182
|
-
expect(last_response.status).to eq 200
|
183
|
-
|
184
|
-
expect(AccessToken.count).to eq 1
|
185
|
-
expect(AccessToken.first.client_id).to eq application.id
|
186
|
-
|
187
|
-
expect(json_body[:access_token]).to be_present
|
188
|
-
expect(json_body[:token_type]).to eq 'bearer'
|
189
|
-
expect(json_body[:expires_in]).to eq 7200
|
190
|
-
end
|
191
|
-
end
|
192
|
-
|
193
|
-
context 'when authentication failed' do
|
194
|
-
it 'returns an error' do
|
195
|
-
application.update(name: 'Admin')
|
196
|
-
|
197
|
-
post '/api/v1/oauth/custom_token',
|
198
|
-
grant_type: 'password',
|
199
|
-
username: 'invalid@example.com',
|
200
|
-
password: 'invalid',
|
201
|
-
client_id: application.key,
|
202
|
-
client_secret: application.secret
|
203
|
-
|
204
|
-
expect(json_body[:error]).to eq('invalid_grant')
|
205
|
-
expect(json_body[:error_description]).not_to be_blank
|
206
|
-
expect(last_response.status).to eq 400
|
207
|
-
end
|
208
|
-
end
|
209
|
-
end
|
210
|
-
end
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'Token Endpoint' do
|
4
|
+
let(:application) { Application.create(name: 'App1') }
|
5
|
+
let(:user) { User.create(username: 'test', password: '12345678') }
|
6
|
+
|
7
|
+
describe 'Resource Owner Password Credentials flow' do
|
8
|
+
describe 'POST /oauth/token' do
|
9
|
+
let(:authentication_url) { '/api/v1/oauth/token' }
|
10
|
+
|
11
|
+
context 'with valid params' do
|
12
|
+
context 'when request is invalid' do
|
13
|
+
it 'fails without Grant Type' do
|
14
|
+
post authentication_url,
|
15
|
+
username: user.username,
|
16
|
+
password: '12345678',
|
17
|
+
client_id: application.key,
|
18
|
+
client_secret: application.secret
|
19
|
+
|
20
|
+
expect(AccessToken.all).to be_empty
|
21
|
+
|
22
|
+
expect(json_body[:error]).to eq('invalid_request')
|
23
|
+
expect(last_response.status).to eq 400
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'fails with invalid Grant Type' do
|
27
|
+
post authentication_url,
|
28
|
+
grant_type: 'invalid',
|
29
|
+
username: user.username,
|
30
|
+
password: '12345678'
|
31
|
+
|
32
|
+
expect(AccessToken.all).to be_empty
|
33
|
+
|
34
|
+
expect(json_body[:error]).to eq('unsupported_grant_type')
|
35
|
+
expect(last_response.status).to eq 400
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'fails without Client Credentials' do
|
39
|
+
post authentication_url,
|
40
|
+
grant_type: 'password',
|
41
|
+
username: user.username,
|
42
|
+
password: '12345678'
|
43
|
+
|
44
|
+
expect(AccessToken.all).to be_empty
|
45
|
+
|
46
|
+
expect(json_body[:error]).to eq('invalid_request')
|
47
|
+
expect(last_response.status).to eq 400
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'fails with invalid Client Credentials' do
|
51
|
+
post authentication_url,
|
52
|
+
grant_type: 'password',
|
53
|
+
username: user.username,
|
54
|
+
password: '12345678',
|
55
|
+
client_id: 'blah-blah',
|
56
|
+
client_secret: application.secret
|
57
|
+
|
58
|
+
expect(AccessToken.all).to be_empty
|
59
|
+
|
60
|
+
expect(json_body[:error]).to eq('invalid_client')
|
61
|
+
expect(last_response.status).to eq 401
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'fails without Resource Owner credentials' do
|
65
|
+
post authentication_url,
|
66
|
+
grant_type: 'password',
|
67
|
+
client_id: application.key,
|
68
|
+
client_secret: application.secret
|
69
|
+
|
70
|
+
expect(json_body[:error]).to eq('invalid_request')
|
71
|
+
expect(json_body[:error_description]).not_to be_blank
|
72
|
+
expect(last_response.status).to eq 400
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'fails with invalid Resource Owner credentials' do
|
76
|
+
post authentication_url,
|
77
|
+
grant_type: 'password',
|
78
|
+
username: 'invalid@example.com',
|
79
|
+
password: 'invalid',
|
80
|
+
client_id: application.key,
|
81
|
+
client_secret: application.secret
|
82
|
+
|
83
|
+
expect(json_body[:error]).to eq('invalid_grant')
|
84
|
+
expect(json_body[:error_description]).not_to be_blank
|
85
|
+
expect(last_response.status).to eq 400
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
context 'with valid data' do
|
90
|
+
context 'when scopes requested' do
|
91
|
+
it 'returns an Access Token with scopes' do
|
92
|
+
post authentication_url,
|
93
|
+
grant_type: 'password',
|
94
|
+
username: user.username,
|
95
|
+
password: '12345678',
|
96
|
+
scope: 'read write',
|
97
|
+
client_id: application.key,
|
98
|
+
client_secret: application.secret
|
99
|
+
|
100
|
+
expect(AccessToken.count).to eq 1
|
101
|
+
expect(AccessToken.first.client_id).to eq application.id
|
102
|
+
|
103
|
+
expect(json_body[:access_token]).to be_present
|
104
|
+
expect(json_body[:token_type]).to eq 'bearer'
|
105
|
+
expect(json_body[:expires_in]).to eq 7200
|
106
|
+
expect(json_body[:refresh_token]).to be_nil
|
107
|
+
expect(json_body[:scope]).to eq('read write')
|
108
|
+
|
109
|
+
expect(last_response.status).to eq 200
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
context 'without scopes' do
|
114
|
+
it 'returns an Access Token without scopes' do
|
115
|
+
post authentication_url,
|
116
|
+
grant_type: 'password',
|
117
|
+
username: user.username,
|
118
|
+
password: '12345678',
|
119
|
+
client_id: application.key,
|
120
|
+
client_secret: application.secret
|
121
|
+
|
122
|
+
expect(AccessToken.count).to eq 1
|
123
|
+
expect(AccessToken.first.client_id).to eq application.id
|
124
|
+
|
125
|
+
expect(json_body[:access_token]).to be_present
|
126
|
+
expect(json_body[:token_type]).to eq 'bearer'
|
127
|
+
expect(json_body[:expires_in]).to eq 7200
|
128
|
+
expect(json_body[:refresh_token]).to be_nil
|
129
|
+
expect(json_body[:scope]).to be_nil
|
130
|
+
|
131
|
+
expect(last_response.status).to eq 200
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
context 'when Token endpoint not mounted' do
|
137
|
+
before do
|
138
|
+
Twitter::API.reset!
|
139
|
+
Twitter::API.change!
|
140
|
+
|
141
|
+
# Mount only Authorization Endpoint
|
142
|
+
Twitter::API.send(:include, Grape::OAuth2.api(:authorize))
|
143
|
+
end
|
144
|
+
|
145
|
+
after do
|
146
|
+
Twitter::API.reset!
|
147
|
+
Twitter::API.change!
|
148
|
+
|
149
|
+
Twitter::API.send(:include, Grape::OAuth2.api)
|
150
|
+
Twitter::API.mount(Twitter::Endpoints::Status)
|
151
|
+
Twitter::API.mount(Twitter::Endpoints::CustomToken)
|
152
|
+
Twitter::API.mount(Twitter::Endpoints::CustomAuthorization)
|
153
|
+
end
|
154
|
+
|
155
|
+
it 'returns 404' do
|
156
|
+
post authentication_url,
|
157
|
+
grant_type: 'password',
|
158
|
+
username: user.username,
|
159
|
+
password: '12345678',
|
160
|
+
client_id: application.key,
|
161
|
+
client_secret: application.secret
|
162
|
+
|
163
|
+
expect(last_response.status).to eq 404
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
describe 'POST /oauth/custom_token' do
|
171
|
+
context 'when block processed successfully' do
|
172
|
+
it 'returns an access token' do
|
173
|
+
application.update(name: 'Admin')
|
174
|
+
|
175
|
+
post '/api/v1/oauth/custom_token',
|
176
|
+
grant_type: 'password',
|
177
|
+
username: user.username,
|
178
|
+
password: '12345678',
|
179
|
+
client_id: application.key,
|
180
|
+
client_secret: application.secret
|
181
|
+
|
182
|
+
expect(last_response.status).to eq 200
|
183
|
+
|
184
|
+
expect(AccessToken.count).to eq 1
|
185
|
+
expect(AccessToken.first.client_id).to eq application.id
|
186
|
+
|
187
|
+
expect(json_body[:access_token]).to be_present
|
188
|
+
expect(json_body[:token_type]).to eq 'bearer'
|
189
|
+
expect(json_body[:expires_in]).to eq 7200
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
context 'when authentication failed' do
|
194
|
+
it 'returns an error' do
|
195
|
+
application.update(name: 'Admin')
|
196
|
+
|
197
|
+
post '/api/v1/oauth/custom_token',
|
198
|
+
grant_type: 'password',
|
199
|
+
username: 'invalid@example.com',
|
200
|
+
password: 'invalid',
|
201
|
+
client_id: application.key,
|
202
|
+
client_secret: application.secret
|
203
|
+
|
204
|
+
expect(json_body[:error]).to eq('invalid_grant')
|
205
|
+
expect(json_body[:error_description]).not_to be_blank
|
206
|
+
expect(last_response.status).to eq 400
|
207
|
+
end
|
208
|
+
end
|
209
|
+
end
|
210
|
+
end
|
@@ -1,222 +1,222 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe 'Token Endpoint' do
|
4
|
-
describe 'POST /oauth/token' do
|
5
|
-
describe 'Refresh Token flow' do
|
6
|
-
context 'with valid params' do
|
7
|
-
let(:api_url) { '/api/v1/oauth/token' }
|
8
|
-
let(:application) { Application.create(name: 'App1') }
|
9
|
-
let(:user) { User.create(username: 'test', password: '12345678') }
|
10
|
-
|
11
|
-
context 'when request is invalid' do
|
12
|
-
it 'fails without Grant Type' do
|
13
|
-
post api_url,
|
14
|
-
client_id: application.key,
|
15
|
-
client_secret: application.secret
|
16
|
-
|
17
|
-
expect(AccessToken.all).to be_empty
|
18
|
-
|
19
|
-
expect(json_body[:error]).to eq('invalid_request')
|
20
|
-
expect(last_response.status).to eq 400
|
21
|
-
end
|
22
|
-
|
23
|
-
it 'fails with invalid Grant Type' do
|
24
|
-
post api_url,
|
25
|
-
grant_type: 'invalid'
|
26
|
-
|
27
|
-
expect(AccessToken.all).to be_empty
|
28
|
-
|
29
|
-
expect(json_body[:error]).to eq('unsupported_grant_type')
|
30
|
-
expect(last_response.status).to eq 400
|
31
|
-
end
|
32
|
-
|
33
|
-
it 'fails without Client Credentials' do
|
34
|
-
post api_url,
|
35
|
-
grant_type: 'refresh_token'
|
36
|
-
|
37
|
-
expect(AccessToken.all).to be_empty
|
38
|
-
|
39
|
-
expect(json_body[:error]).to eq('invalid_request')
|
40
|
-
expect(last_response.status).to eq 400
|
41
|
-
end
|
42
|
-
|
43
|
-
it 'fails with invalid Client Credentials' do
|
44
|
-
post api_url,
|
45
|
-
grant_type: 'refresh_token',
|
46
|
-
refresh_token: SecureRandom.hex(6),
|
47
|
-
client_id: 'blah-blah',
|
48
|
-
client_secret: application.secret
|
49
|
-
|
50
|
-
expect(AccessToken.all).to be_empty
|
51
|
-
|
52
|
-
expect(json_body[:error]).to eq('invalid_client')
|
53
|
-
expect(last_response.status).to eq 401
|
54
|
-
end
|
55
|
-
|
56
|
-
it 'fails when Access Token was issued to another client' do
|
57
|
-
allow(Grape::OAuth2.config).to receive(:issue_refresh_token).and_return(true)
|
58
|
-
|
59
|
-
another_client = Application.create(name: 'Some')
|
60
|
-
token = AccessToken.create_for(another_client, user)
|
61
|
-
expect(token.refresh_token).not_to be_nil
|
62
|
-
|
63
|
-
post api_url,
|
64
|
-
grant_type: 'refresh_token',
|
65
|
-
refresh_token: token.refresh_token,
|
66
|
-
client_id: application.key,
|
67
|
-
client_secret: application.secret
|
68
|
-
|
69
|
-
expect(json_body[:error]).to eq('unauthorized_client')
|
70
|
-
expect(last_response.status).to eq 400
|
71
|
-
|
72
|
-
expect(AccessToken.count).to eq(1)
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
context 'with valid data' do
|
77
|
-
before { allow(Grape::OAuth2.config).to receive(:issue_refresh_token).and_return(true) }
|
78
|
-
|
79
|
-
it 'returns a new Access Token' do
|
80
|
-
token = AccessToken.create_for(application, user)
|
81
|
-
expect(token.refresh_token).not_to be_nil
|
82
|
-
|
83
|
-
post api_url,
|
84
|
-
grant_type: 'refresh_token',
|
85
|
-
refresh_token: token.refresh_token,
|
86
|
-
client_id: application.key,
|
87
|
-
client_secret: application.secret
|
88
|
-
|
89
|
-
expect(last_response.status).to eq 200
|
90
|
-
|
91
|
-
expect(AccessToken.count).to eq 2
|
92
|
-
expect(AccessToken.last.client_id).to eq application.id
|
93
|
-
expect(AccessToken.last.resource_owner_id).to eq user.id
|
94
|
-
|
95
|
-
expect(json_body[:access_token]).to eq AccessToken.last.token
|
96
|
-
expect(json_body[:token_type]).to eq 'bearer'
|
97
|
-
expect(json_body[:expires_in]).to eq 7200
|
98
|
-
expect(json_body[:refresh_token]).to eq AccessToken.last.refresh_token
|
99
|
-
end
|
100
|
-
|
101
|
-
it 'revokes old Access Token if it is configured' do
|
102
|
-
allow(Grape::OAuth2.config).to receive(:on_refresh).and_return(:revoke!)
|
103
|
-
|
104
|
-
token = AccessToken.create_for(application, user)
|
105
|
-
expect(token.refresh_token).not_to be_nil
|
106
|
-
|
107
|
-
post api_url,
|
108
|
-
grant_type: 'refresh_token',
|
109
|
-
refresh_token: token.refresh_token,
|
110
|
-
client_id: application.key,
|
111
|
-
client_secret: application.secret
|
112
|
-
|
113
|
-
expect(last_response.status).to eq 200
|
114
|
-
|
115
|
-
expect(AccessToken.count).to eq 2
|
116
|
-
expect(AccessToken.last.client).to eq application
|
117
|
-
expect(AccessToken.last.resource_owner).to eq user
|
118
|
-
|
119
|
-
expect(token.reload.revoked?).to be_truthy
|
120
|
-
|
121
|
-
expect(json_body[:access_token]).to eq AccessToken.last.token
|
122
|
-
expect(json_body[:refresh_token]).to eq AccessToken.last.refresh_token
|
123
|
-
end
|
124
|
-
|
125
|
-
it 'destroy old Access Token if it is configured' do
|
126
|
-
allow(Grape::OAuth2.config).to receive(:on_refresh).and_return(:destroy)
|
127
|
-
|
128
|
-
token = AccessToken.create_for(application, user)
|
129
|
-
expect(token.refresh_token).not_to be_nil
|
130
|
-
|
131
|
-
post api_url,
|
132
|
-
grant_type: 'refresh_token',
|
133
|
-
refresh_token: token.refresh_token,
|
134
|
-
client_id: application.key,
|
135
|
-
client_secret: application.secret
|
136
|
-
|
137
|
-
expect(last_response.status).to eq 200
|
138
|
-
|
139
|
-
expect(AccessToken.count).to eq 1
|
140
|
-
expect(AccessToken.where(token: token.token).first).to be_nil
|
141
|
-
end
|
142
|
-
|
143
|
-
it 'calls custom block on token refresh if it is configured' do
|
144
|
-
scopes = 'just for test'
|
145
|
-
allow(Grape::OAuth2.config).to receive(:on_refresh).and_return(->(token) { token.update(scopes: scopes) })
|
146
|
-
|
147
|
-
token = AccessToken.create_for(application, user)
|
148
|
-
expect(token.refresh_token).not_to be_nil
|
149
|
-
|
150
|
-
post api_url,
|
151
|
-
grant_type: 'refresh_token',
|
152
|
-
refresh_token: token.refresh_token,
|
153
|
-
client_id: application.key,
|
154
|
-
client_secret: application.secret
|
155
|
-
|
156
|
-
expect(last_response.status).to eq 200
|
157
|
-
|
158
|
-
expect(AccessToken.count).to eq 2
|
159
|
-
expect(token.reload.scopes).to eq(scopes)
|
160
|
-
end
|
161
|
-
|
162
|
-
it 'does nothing on token refresh if :on_refresh is equal to :nothing or nil' do
|
163
|
-
allow(Grape::OAuth2.config).to receive(:on_refresh).and_return(:nothing)
|
164
|
-
|
165
|
-
token = AccessToken.create_for(application, user)
|
166
|
-
expect(token.refresh_token).not_to be_nil
|
167
|
-
|
168
|
-
# Check for :nothing
|
169
|
-
expect(Grape::OAuth2::Strategies::RefreshToken).not_to receive(:run_on_refresh_callback)
|
170
|
-
|
171
|
-
post api_url,
|
172
|
-
grant_type: 'refresh_token',
|
173
|
-
refresh_token: token.refresh_token,
|
174
|
-
client_id: application.key,
|
175
|
-
client_secret: application.secret
|
176
|
-
|
177
|
-
expect(last_response.status).to eq 200
|
178
|
-
|
179
|
-
allow(Grape::OAuth2.config).to receive(:on_refresh).and_return(nil)
|
180
|
-
|
181
|
-
token = AccessToken.create_for(application, user)
|
182
|
-
expect(token.refresh_token).not_to be_nil
|
183
|
-
|
184
|
-
# Check for nil
|
185
|
-
expect(Grape::OAuth2::Strategies::RefreshToken).not_to receive(:run_on_refresh_callback)
|
186
|
-
|
187
|
-
post api_url,
|
188
|
-
grant_type: 'refresh_token',
|
189
|
-
refresh_token: token.refresh_token,
|
190
|
-
client_id: application.key,
|
191
|
-
client_secret: application.secret
|
192
|
-
|
193
|
-
expect(last_response.status).to eq 200
|
194
|
-
end
|
195
|
-
|
196
|
-
it 'returns a new Access Token even if used token is expired' do
|
197
|
-
token = AccessToken.create_for(application, user)
|
198
|
-
token.update(expires_at: Time.now - 604800) # - 7 days
|
199
|
-
expect(token.refresh_token).not_to be_nil
|
200
|
-
|
201
|
-
post api_url,
|
202
|
-
grant_type: 'refresh_token',
|
203
|
-
refresh_token: token.refresh_token,
|
204
|
-
client_id: application.key,
|
205
|
-
client_secret: application.secret
|
206
|
-
|
207
|
-
expect(last_response.status).to eq 200
|
208
|
-
|
209
|
-
expect(AccessToken.count).to eq 2
|
210
|
-
expect(AccessToken.last.client_id).to eq application.id
|
211
|
-
expect(AccessToken.last.resource_owner_id).to eq user.id
|
212
|
-
|
213
|
-
expect(json_body[:access_token]).to eq AccessToken.last.token
|
214
|
-
expect(json_body[:token_type]).to eq 'bearer'
|
215
|
-
expect(json_body[:expires_in]).to eq 7200
|
216
|
-
expect(json_body[:refresh_token]).to eq AccessToken.last.refresh_token
|
217
|
-
end
|
218
|
-
end
|
219
|
-
end
|
220
|
-
end
|
221
|
-
end
|
222
|
-
end
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'Token Endpoint' do
|
4
|
+
describe 'POST /oauth/token' do
|
5
|
+
describe 'Refresh Token flow' do
|
6
|
+
context 'with valid params' do
|
7
|
+
let(:api_url) { '/api/v1/oauth/token' }
|
8
|
+
let(:application) { Application.create(name: 'App1') }
|
9
|
+
let(:user) { User.create(username: 'test', password: '12345678') }
|
10
|
+
|
11
|
+
context 'when request is invalid' do
|
12
|
+
it 'fails without Grant Type' do
|
13
|
+
post api_url,
|
14
|
+
client_id: application.key,
|
15
|
+
client_secret: application.secret
|
16
|
+
|
17
|
+
expect(AccessToken.all).to be_empty
|
18
|
+
|
19
|
+
expect(json_body[:error]).to eq('invalid_request')
|
20
|
+
expect(last_response.status).to eq 400
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'fails with invalid Grant Type' do
|
24
|
+
post api_url,
|
25
|
+
grant_type: 'invalid'
|
26
|
+
|
27
|
+
expect(AccessToken.all).to be_empty
|
28
|
+
|
29
|
+
expect(json_body[:error]).to eq('unsupported_grant_type')
|
30
|
+
expect(last_response.status).to eq 400
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'fails without Client Credentials' do
|
34
|
+
post api_url,
|
35
|
+
grant_type: 'refresh_token'
|
36
|
+
|
37
|
+
expect(AccessToken.all).to be_empty
|
38
|
+
|
39
|
+
expect(json_body[:error]).to eq('invalid_request')
|
40
|
+
expect(last_response.status).to eq 400
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'fails with invalid Client Credentials' do
|
44
|
+
post api_url,
|
45
|
+
grant_type: 'refresh_token',
|
46
|
+
refresh_token: SecureRandom.hex(6),
|
47
|
+
client_id: 'blah-blah',
|
48
|
+
client_secret: application.secret
|
49
|
+
|
50
|
+
expect(AccessToken.all).to be_empty
|
51
|
+
|
52
|
+
expect(json_body[:error]).to eq('invalid_client')
|
53
|
+
expect(last_response.status).to eq 401
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'fails when Access Token was issued to another client' do
|
57
|
+
allow(Grape::OAuth2.config).to receive(:issue_refresh_token).and_return(true)
|
58
|
+
|
59
|
+
another_client = Application.create(name: 'Some')
|
60
|
+
token = AccessToken.create_for(another_client, user)
|
61
|
+
expect(token.refresh_token).not_to be_nil
|
62
|
+
|
63
|
+
post api_url,
|
64
|
+
grant_type: 'refresh_token',
|
65
|
+
refresh_token: token.refresh_token,
|
66
|
+
client_id: application.key,
|
67
|
+
client_secret: application.secret
|
68
|
+
|
69
|
+
expect(json_body[:error]).to eq('unauthorized_client')
|
70
|
+
expect(last_response.status).to eq 400
|
71
|
+
|
72
|
+
expect(AccessToken.count).to eq(1)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
context 'with valid data' do
|
77
|
+
before { allow(Grape::OAuth2.config).to receive(:issue_refresh_token).and_return(true) }
|
78
|
+
|
79
|
+
it 'returns a new Access Token' do
|
80
|
+
token = AccessToken.create_for(application, user)
|
81
|
+
expect(token.refresh_token).not_to be_nil
|
82
|
+
|
83
|
+
post api_url,
|
84
|
+
grant_type: 'refresh_token',
|
85
|
+
refresh_token: token.refresh_token,
|
86
|
+
client_id: application.key,
|
87
|
+
client_secret: application.secret
|
88
|
+
|
89
|
+
expect(last_response.status).to eq 200
|
90
|
+
|
91
|
+
expect(AccessToken.count).to eq 2
|
92
|
+
expect(AccessToken.last.client_id).to eq application.id
|
93
|
+
expect(AccessToken.last.resource_owner_id).to eq user.id
|
94
|
+
|
95
|
+
expect(json_body[:access_token]).to eq AccessToken.last.token
|
96
|
+
expect(json_body[:token_type]).to eq 'bearer'
|
97
|
+
expect(json_body[:expires_in]).to eq 7200
|
98
|
+
expect(json_body[:refresh_token]).to eq AccessToken.last.refresh_token
|
99
|
+
end
|
100
|
+
|
101
|
+
it 'revokes old Access Token if it is configured' do
|
102
|
+
allow(Grape::OAuth2.config).to receive(:on_refresh).and_return(:revoke!)
|
103
|
+
|
104
|
+
token = AccessToken.create_for(application, user)
|
105
|
+
expect(token.refresh_token).not_to be_nil
|
106
|
+
|
107
|
+
post api_url,
|
108
|
+
grant_type: 'refresh_token',
|
109
|
+
refresh_token: token.refresh_token,
|
110
|
+
client_id: application.key,
|
111
|
+
client_secret: application.secret
|
112
|
+
|
113
|
+
expect(last_response.status).to eq 200
|
114
|
+
|
115
|
+
expect(AccessToken.count).to eq 2
|
116
|
+
expect(AccessToken.last.client).to eq application
|
117
|
+
expect(AccessToken.last.resource_owner).to eq user
|
118
|
+
|
119
|
+
expect(token.reload.revoked?).to be_truthy
|
120
|
+
|
121
|
+
expect(json_body[:access_token]).to eq AccessToken.last.token
|
122
|
+
expect(json_body[:refresh_token]).to eq AccessToken.last.refresh_token
|
123
|
+
end
|
124
|
+
|
125
|
+
it 'destroy old Access Token if it is configured' do
|
126
|
+
allow(Grape::OAuth2.config).to receive(:on_refresh).and_return(:destroy)
|
127
|
+
|
128
|
+
token = AccessToken.create_for(application, user)
|
129
|
+
expect(token.refresh_token).not_to be_nil
|
130
|
+
|
131
|
+
post api_url,
|
132
|
+
grant_type: 'refresh_token',
|
133
|
+
refresh_token: token.refresh_token,
|
134
|
+
client_id: application.key,
|
135
|
+
client_secret: application.secret
|
136
|
+
|
137
|
+
expect(last_response.status).to eq 200
|
138
|
+
|
139
|
+
expect(AccessToken.count).to eq 1
|
140
|
+
expect(AccessToken.where(token: token.token).first).to be_nil
|
141
|
+
end
|
142
|
+
|
143
|
+
it 'calls custom block on token refresh if it is configured' do
|
144
|
+
scopes = 'just for test'
|
145
|
+
allow(Grape::OAuth2.config).to receive(:on_refresh).and_return(->(token) { token.update(scopes: scopes) })
|
146
|
+
|
147
|
+
token = AccessToken.create_for(application, user)
|
148
|
+
expect(token.refresh_token).not_to be_nil
|
149
|
+
|
150
|
+
post api_url,
|
151
|
+
grant_type: 'refresh_token',
|
152
|
+
refresh_token: token.refresh_token,
|
153
|
+
client_id: application.key,
|
154
|
+
client_secret: application.secret
|
155
|
+
|
156
|
+
expect(last_response.status).to eq 200
|
157
|
+
|
158
|
+
expect(AccessToken.count).to eq 2
|
159
|
+
expect(token.reload.scopes).to eq(scopes)
|
160
|
+
end
|
161
|
+
|
162
|
+
it 'does nothing on token refresh if :on_refresh is equal to :nothing or nil' do
|
163
|
+
allow(Grape::OAuth2.config).to receive(:on_refresh).and_return(:nothing)
|
164
|
+
|
165
|
+
token = AccessToken.create_for(application, user)
|
166
|
+
expect(token.refresh_token).not_to be_nil
|
167
|
+
|
168
|
+
# Check for :nothing
|
169
|
+
expect(Grape::OAuth2::Strategies::RefreshToken).not_to receive(:run_on_refresh_callback)
|
170
|
+
|
171
|
+
post api_url,
|
172
|
+
grant_type: 'refresh_token',
|
173
|
+
refresh_token: token.refresh_token,
|
174
|
+
client_id: application.key,
|
175
|
+
client_secret: application.secret
|
176
|
+
|
177
|
+
expect(last_response.status).to eq 200
|
178
|
+
|
179
|
+
allow(Grape::OAuth2.config).to receive(:on_refresh).and_return(nil)
|
180
|
+
|
181
|
+
token = AccessToken.create_for(application, user)
|
182
|
+
expect(token.refresh_token).not_to be_nil
|
183
|
+
|
184
|
+
# Check for nil
|
185
|
+
expect(Grape::OAuth2::Strategies::RefreshToken).not_to receive(:run_on_refresh_callback)
|
186
|
+
|
187
|
+
post api_url,
|
188
|
+
grant_type: 'refresh_token',
|
189
|
+
refresh_token: token.refresh_token,
|
190
|
+
client_id: application.key,
|
191
|
+
client_secret: application.secret
|
192
|
+
|
193
|
+
expect(last_response.status).to eq 200
|
194
|
+
end
|
195
|
+
|
196
|
+
it 'returns a new Access Token even if used token is expired' do
|
197
|
+
token = AccessToken.create_for(application, user)
|
198
|
+
token.update(expires_at: Time.now - 604800) # - 7 days
|
199
|
+
expect(token.refresh_token).not_to be_nil
|
200
|
+
|
201
|
+
post api_url,
|
202
|
+
grant_type: 'refresh_token',
|
203
|
+
refresh_token: token.refresh_token,
|
204
|
+
client_id: application.key,
|
205
|
+
client_secret: application.secret
|
206
|
+
|
207
|
+
expect(last_response.status).to eq 200
|
208
|
+
|
209
|
+
expect(AccessToken.count).to eq 2
|
210
|
+
expect(AccessToken.last.client_id).to eq application.id
|
211
|
+
expect(AccessToken.last.resource_owner_id).to eq user.id
|
212
|
+
|
213
|
+
expect(json_body[:access_token]).to eq AccessToken.last.token
|
214
|
+
expect(json_body[:token_type]).to eq 'bearer'
|
215
|
+
expect(json_body[:expires_in]).to eq 7200
|
216
|
+
expect(json_body[:refresh_token]).to eq AccessToken.last.refresh_token
|
217
|
+
end
|
218
|
+
end
|
219
|
+
end
|
220
|
+
end
|
221
|
+
end
|
222
|
+
end
|