doorkeeper 4.3.2 → 5.0.0.rc1
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 +1 -0
- data/.rubocop.yml +4 -0
- data/.travis.yml +2 -0
- data/Appraisals +2 -2
- data/Gemfile +1 -1
- data/NEWS.md +36 -0
- data/README.md +85 -3
- data/Rakefile +6 -0
- data/app/assets/stylesheets/doorkeeper/admin/application.css +2 -2
- data/app/controllers/doorkeeper/application_controller.rb +4 -3
- data/app/controllers/doorkeeper/application_metal_controller.rb +4 -0
- data/app/controllers/doorkeeper/applications_controller.rb +43 -22
- data/app/controllers/doorkeeper/authorizations_controller.rb +55 -12
- data/app/controllers/doorkeeper/authorized_applications_controller.rb +15 -1
- data/app/controllers/doorkeeper/tokens_controller.rb +2 -6
- data/app/helpers/doorkeeper/dashboard_helper.rb +7 -7
- data/app/validators/redirect_uri_validator.rb +3 -2
- data/app/views/doorkeeper/applications/_delete_form.html.erb +3 -1
- data/app/views/doorkeeper/applications/_form.html.erb +31 -19
- data/app/views/doorkeeper/applications/edit.html.erb +1 -1
- data/app/views/doorkeeper/applications/index.html.erb +18 -6
- data/app/views/doorkeeper/applications/new.html.erb +1 -1
- data/app/views/doorkeeper/applications/show.html.erb +8 -5
- data/app/views/doorkeeper/authorizations/error.html.erb +1 -1
- data/app/views/doorkeeper/authorizations/new.html.erb +4 -0
- data/app/views/layouts/doorkeeper/admin.html.erb +15 -15
- data/config/locales/en.yml +15 -1
- data/gemfiles/rails_5_2.gemfile +1 -1
- data/lib/doorkeeper/config.rb +60 -23
- data/lib/doorkeeper/engine.rb +4 -0
- data/lib/doorkeeper/errors.rb +2 -5
- data/lib/doorkeeper/grape/helpers.rb +1 -1
- data/lib/doorkeeper/helpers/controller.rb +7 -2
- data/lib/doorkeeper/models/access_grant_mixin.rb +56 -0
- data/lib/doorkeeper/models/access_token_mixin.rb +37 -20
- data/lib/doorkeeper/models/application_mixin.rb +8 -1
- data/lib/doorkeeper/models/concerns/scopes.rb +1 -1
- data/lib/doorkeeper/oauth/authorization/code.rb +31 -8
- data/lib/doorkeeper/oauth/authorization/context.rb +15 -0
- data/lib/doorkeeper/oauth/authorization/token.rb +23 -6
- data/lib/doorkeeper/oauth/authorization_code_request.rb +27 -2
- data/lib/doorkeeper/oauth/base_request.rb +18 -8
- data/lib/doorkeeper/oauth/client/credentials.rb +4 -2
- data/lib/doorkeeper/oauth/client_credentials/issuer.rb +6 -1
- data/lib/doorkeeper/oauth/client_credentials/validation.rb +4 -2
- data/lib/doorkeeper/oauth/error_response.rb +11 -3
- data/lib/doorkeeper/oauth/helpers/scope_checker.rb +0 -8
- data/lib/doorkeeper/oauth/helpers/uri_checker.rb +1 -0
- data/lib/doorkeeper/oauth/password_access_token_request.rb +7 -4
- data/lib/doorkeeper/oauth/pre_authorization.rb +45 -13
- data/lib/doorkeeper/oauth/refresh_token_request.rb +6 -1
- data/lib/doorkeeper/oauth/scopes.rb +1 -1
- data/lib/doorkeeper/oauth/token.rb +5 -2
- data/lib/doorkeeper/oauth/token_introspection.rb +2 -2
- data/lib/doorkeeper/oauth/token_response.rb +4 -2
- data/lib/doorkeeper/oauth.rb +13 -0
- data/lib/doorkeeper/orm/active_record/application.rb +14 -0
- data/lib/doorkeeper/orm/active_record/stale_records_cleaner.rb +26 -0
- data/lib/doorkeeper/orm/active_record.rb +2 -0
- data/lib/doorkeeper/rails/helpers.rb +2 -4
- data/lib/doorkeeper/rails/routes.rb +13 -1
- data/lib/doorkeeper/rake/db.rake +40 -0
- data/lib/doorkeeper/rake/setup.rake +6 -0
- data/lib/doorkeeper/rake.rb +14 -0
- data/lib/doorkeeper/request/password.rb +1 -11
- data/lib/doorkeeper/request.rb +28 -28
- data/lib/doorkeeper/version.rb +5 -4
- data/lib/doorkeeper.rb +4 -17
- data/lib/generators/doorkeeper/application_owner_generator.rb +23 -18
- data/lib/generators/doorkeeper/confidential_applications_generator.rb +32 -0
- data/lib/generators/doorkeeper/install_generator.rb +17 -9
- data/lib/generators/doorkeeper/migration_generator.rb +23 -18
- data/lib/generators/doorkeeper/pkce_generator.rb +32 -0
- data/lib/generators/doorkeeper/previous_refresh_token_generator.rb +29 -24
- data/lib/generators/doorkeeper/templates/add_confidential_to_applications.rb.erb +13 -0
- data/lib/generators/doorkeeper/templates/enable_pkce_migration.rb.erb +6 -0
- data/lib/generators/doorkeeper/templates/initializer.rb +60 -9
- data/lib/generators/doorkeeper/templates/migration.rb.erb +1 -0
- data/lib/generators/doorkeeper/views_generator.rb +3 -1
- data/spec/controllers/application_metal_controller_spec.rb +50 -0
- data/spec/controllers/applications_controller_spec.rb +126 -13
- data/spec/controllers/authorizations_controller_spec.rb +250 -15
- data/spec/controllers/protected_resources_controller_spec.rb +16 -16
- data/spec/controllers/token_info_controller_spec.rb +4 -12
- data/spec/controllers/tokens_controller_spec.rb +12 -14
- data/spec/dummy/app/assets/config/manifest.js +2 -0
- data/spec/dummy/config/environments/test.rb +4 -5
- data/spec/dummy/config/initializers/doorkeeper.rb +6 -0
- data/spec/dummy/config/initializers/new_framework_defaults.rb +4 -0
- data/spec/dummy/config/routes.rb +3 -42
- 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/20170822064514_enable_pkce.rb +6 -0
- data/spec/dummy/db/migrate/20180210183654_add_confidential_to_applications.rb +13 -0
- data/spec/dummy/db/schema.rb +38 -37
- data/spec/generators/application_owner_generator_spec.rb +1 -1
- data/spec/generators/confidential_applications_generator_spec.rb +45 -0
- data/spec/generators/install_generator_spec.rb +1 -1
- data/spec/generators/migration_generator_spec.rb +1 -1
- data/spec/generators/pkce_generator_spec.rb +43 -0
- data/spec/generators/previous_refresh_token_generator_spec.rb +1 -1
- data/spec/generators/views_generator_spec.rb +1 -1
- data/spec/grape/grape_integration_spec.rb +1 -1
- data/spec/helpers/doorkeeper/dashboard_helper_spec.rb +1 -1
- data/spec/lib/config_spec.rb +59 -14
- data/spec/lib/doorkeeper_spec.rb +1 -126
- data/spec/lib/models/expirable_spec.rb +0 -3
- data/spec/lib/models/revocable_spec.rb +0 -2
- data/spec/lib/models/scopes_spec.rb +0 -4
- data/spec/lib/oauth/authorization/uri_builder_spec.rb +0 -4
- data/spec/lib/oauth/authorization_code_request_spec.rb +24 -2
- data/spec/lib/oauth/base_request_spec.rb +16 -2
- data/spec/lib/oauth/base_response_spec.rb +1 -1
- data/spec/lib/oauth/client/credentials_spec.rb +5 -5
- data/spec/lib/oauth/client_credentials/creator_spec.rb +5 -1
- data/spec/lib/oauth/client_credentials/issuer_spec.rb +26 -7
- data/spec/lib/oauth/client_credentials/validation_spec.rb +2 -3
- data/spec/lib/oauth/client_credentials_integration_spec.rb +1 -1
- data/spec/lib/oauth/client_credentials_request_spec.rb +3 -5
- data/spec/lib/oauth/client_spec.rb +0 -3
- data/spec/lib/oauth/code_request_spec.rb +4 -2
- data/spec/lib/oauth/error_response_spec.rb +0 -3
- data/spec/lib/oauth/error_spec.rb +0 -2
- data/spec/lib/oauth/forbidden_token_response_spec.rb +1 -4
- data/spec/lib/oauth/helpers/scope_checker_spec.rb +0 -3
- data/spec/lib/oauth/helpers/unique_token_spec.rb +0 -1
- data/spec/lib/oauth/helpers/uri_checker_spec.rb +5 -2
- data/spec/lib/oauth/invalid_token_response_spec.rb +1 -4
- data/spec/lib/oauth/password_access_token_request_spec.rb +37 -2
- data/spec/lib/oauth/pre_authorization_spec.rb +40 -6
- data/spec/lib/oauth/refresh_token_request_spec.rb +11 -7
- data/spec/lib/oauth/scopes_spec.rb +0 -3
- data/spec/lib/oauth/token_request_spec.rb +4 -5
- data/spec/lib/oauth/token_response_spec.rb +0 -1
- data/spec/lib/oauth/token_spec.rb +37 -14
- data/spec/lib/orm/active_record/stale_records_cleaner_spec.rb +79 -0
- data/spec/lib/request/strategy_spec.rb +0 -1
- data/spec/lib/server_spec.rb +1 -1
- data/spec/models/doorkeeper/access_grant_spec.rb +1 -1
- data/spec/models/doorkeeper/access_token_spec.rb +50 -16
- data/spec/models/doorkeeper/application_spec.rb +51 -6
- data/spec/requests/applications/applications_request_spec.rb +89 -1
- data/spec/requests/applications/authorized_applications_spec.rb +1 -1
- data/spec/requests/endpoints/authorization_spec.rb +1 -1
- data/spec/requests/endpoints/token_spec.rb +7 -5
- data/spec/requests/flows/authorization_code_errors_spec.rb +1 -1
- data/spec/requests/flows/authorization_code_spec.rb +197 -1
- data/spec/requests/flows/client_credentials_spec.rb +46 -6
- data/spec/requests/flows/implicit_grant_errors_spec.rb +1 -1
- data/spec/requests/flows/implicit_grant_spec.rb +38 -11
- data/spec/requests/flows/password_spec.rb +120 -23
- data/spec/requests/flows/refresh_token_spec.rb +2 -2
- data/spec/requests/flows/revoke_token_spec.rb +11 -11
- data/spec/requests/flows/skip_authorization_spec.rb +16 -11
- data/spec/requests/protected_resources/metal_spec.rb +1 -1
- data/spec/requests/protected_resources/private_api_spec.rb +1 -1
- data/spec/routing/custom_controller_routes_spec.rb +59 -7
- data/spec/routing/default_routes_spec.rb +2 -2
- data/spec/routing/scoped_routes_spec.rb +16 -2
- data/spec/spec_helper.rb +54 -3
- data/spec/spec_helper_integration.rb +2 -74
- data/spec/support/doorkeeper_rspec.rb +19 -0
- data/spec/support/helpers/authorization_request_helper.rb +4 -4
- data/spec/support/helpers/request_spec_helper.rb +2 -2
- data/spec/support/helpers/url_helper.rb +7 -3
- data/spec/support/http_method_shim.rb +12 -16
- data/spec/validators/redirect_uri_validator_spec.rb +7 -1
- data/spec/version/version_spec.rb +3 -3
- data/vendor/assets/stylesheets/doorkeeper/bootstrap.min.css +4 -5
- metadata +32 -8
- data/spec/controllers/application_metal_controller.rb +0 -10
- /data/spec/support/dependencies/{factory_girl.rb → factory_bot.rb} +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
require '
|
|
1
|
+
require 'spec_helper'
|
|
2
2
|
|
|
3
3
|
feature 'Authorization Code Flow' do
|
|
4
4
|
background do
|
|
@@ -39,6 +39,7 @@ feature 'Authorization Code Flow' do
|
|
|
39
39
|
click_on 'Authorize'
|
|
40
40
|
url_should_have_param('code', Doorkeeper::AccessGrant.first.token)
|
|
41
41
|
url_should_have_param('state', 'return-me')
|
|
42
|
+
url_should_not_have_param('code_challenge_method')
|
|
42
43
|
end
|
|
43
44
|
|
|
44
45
|
scenario 'resource owner requests an access token with authorization code' do
|
|
@@ -57,6 +58,201 @@ feature 'Authorization Code Flow' do
|
|
|
57
58
|
should_have_json_within 'expires_in', Doorkeeper::AccessToken.first.expires_in, 1
|
|
58
59
|
end
|
|
59
60
|
|
|
61
|
+
scenario 'resource owner requests an access token with authorization code but without secret' do
|
|
62
|
+
visit authorization_endpoint_url(client: @client)
|
|
63
|
+
click_on 'Authorize'
|
|
64
|
+
|
|
65
|
+
authorization_code = Doorkeeper::AccessGrant.first.token
|
|
66
|
+
page.driver.post token_endpoint_url(code: authorization_code, client_id: @client.uid,
|
|
67
|
+
redirect_uri: @client.redirect_uri)
|
|
68
|
+
|
|
69
|
+
expect(Doorkeeper::AccessToken).not_to exist
|
|
70
|
+
|
|
71
|
+
should_have_json 'error', 'invalid_client'
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
context 'with PKCE' do
|
|
75
|
+
context 'plain' do
|
|
76
|
+
let(:code_challenge) { 'a45a9fea-0676-477e-95b1-a40f72ac3cfb' }
|
|
77
|
+
let(:code_verifier) { 'a45a9fea-0676-477e-95b1-a40f72ac3cfb' }
|
|
78
|
+
|
|
79
|
+
scenario 'resource owner authorizes the client with code_challenge parameter set' do
|
|
80
|
+
visit authorization_endpoint_url(client: @client, code_challenge: code_challenge, code_challenge_method: 'plain')
|
|
81
|
+
click_on 'Authorize'
|
|
82
|
+
|
|
83
|
+
url_should_have_param('code', Doorkeeper::AccessGrant.first.token)
|
|
84
|
+
url_should_not_have_param('code_challenge_method')
|
|
85
|
+
url_should_not_have_param('code_challenge')
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
scenario 'mobile app requests an access token with authorization code but not pkce token' do
|
|
89
|
+
visit authorization_endpoint_url(client: @client)
|
|
90
|
+
click_on 'Authorize'
|
|
91
|
+
|
|
92
|
+
authorization_code = current_params['code']
|
|
93
|
+
create_access_token authorization_code, @client, code_verifier
|
|
94
|
+
|
|
95
|
+
should_have_json 'error', 'invalid_grant'
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
scenario 'mobile app requests an access token with authorization code and plain code challenge method' do
|
|
99
|
+
visit authorization_endpoint_url(client: @client, code_challenge: code_challenge, code_challenge_method: 'plain')
|
|
100
|
+
click_on 'Authorize'
|
|
101
|
+
|
|
102
|
+
authorization_code = current_params['code']
|
|
103
|
+
create_access_token authorization_code, @client, code_verifier
|
|
104
|
+
|
|
105
|
+
access_token_should_exist_for(@client, @resource_owner)
|
|
106
|
+
|
|
107
|
+
should_not_have_json 'error'
|
|
108
|
+
|
|
109
|
+
should_have_json 'access_token', Doorkeeper::AccessToken.first.token
|
|
110
|
+
should_have_json 'token_type', 'bearer'
|
|
111
|
+
should_have_json_within 'expires_in', Doorkeeper::AccessToken.first.expires_in, 1
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
scenario 'mobile app requests an access token with authorization code and code_challenge' do
|
|
115
|
+
visit authorization_endpoint_url(client: @client,
|
|
116
|
+
code_challenge: code_verifier,
|
|
117
|
+
code_challenge_method: 'plain')
|
|
118
|
+
click_on 'Authorize'
|
|
119
|
+
|
|
120
|
+
authorization_code = current_params['code']
|
|
121
|
+
create_access_token authorization_code, @client, code_verifier: nil
|
|
122
|
+
|
|
123
|
+
should_not_have_json 'access_token'
|
|
124
|
+
should_have_json 'error', 'invalid_grant'
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
context 's256' do
|
|
129
|
+
let(:code_challenge) { 'Oz733NtQ0rJP8b04fgZMJMwprn6Iw8sMCT_9bR1q4tA' }
|
|
130
|
+
let(:code_verifier) { 'a45a9fea-0676-477e-95b1-a40f72ac3cfb' }
|
|
131
|
+
|
|
132
|
+
scenario 'resource owner authorizes the client with code_challenge parameter set' do
|
|
133
|
+
visit authorization_endpoint_url(client: @client, code_challenge: code_challenge, code_challenge_method: 'S256')
|
|
134
|
+
click_on 'Authorize'
|
|
135
|
+
|
|
136
|
+
url_should_have_param('code', Doorkeeper::AccessGrant.first.token)
|
|
137
|
+
url_should_not_have_param('code_challenge_method')
|
|
138
|
+
url_should_not_have_param('code_challenge')
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
scenario 'mobile app requests an access token with authorization code and S256 code challenge method' do
|
|
142
|
+
visit authorization_endpoint_url(client: @client, code_challenge: code_challenge, code_challenge_method: 'S256')
|
|
143
|
+
click_on 'Authorize'
|
|
144
|
+
|
|
145
|
+
authorization_code = current_params['code']
|
|
146
|
+
create_access_token authorization_code, @client, code_verifier
|
|
147
|
+
|
|
148
|
+
access_token_should_exist_for(@client, @resource_owner)
|
|
149
|
+
|
|
150
|
+
should_not_have_json 'error'
|
|
151
|
+
|
|
152
|
+
should_have_json 'access_token', Doorkeeper::AccessToken.first.token
|
|
153
|
+
should_have_json 'token_type', 'bearer'
|
|
154
|
+
should_have_json_within 'expires_in', Doorkeeper::AccessToken.first.expires_in, 1
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
scenario 'mobile app requests an access token with authorization code and without code_verifier' do
|
|
158
|
+
visit authorization_endpoint_url(client: @client, code_challenge: code_challenge, code_challenge_method: 'S256')
|
|
159
|
+
click_on 'Authorize'
|
|
160
|
+
authorization_code = current_params['code']
|
|
161
|
+
create_access_token authorization_code, @client
|
|
162
|
+
should_have_json 'error', 'invalid_request'
|
|
163
|
+
should_not_have_json 'access_token'
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
scenario 'mobile app requests an access token with authorization code and without secret' do
|
|
167
|
+
visit authorization_endpoint_url(client: @client, code_challenge: code_challenge, code_challenge_method: 'S256')
|
|
168
|
+
click_on 'Authorize'
|
|
169
|
+
|
|
170
|
+
authorization_code = current_params['code']
|
|
171
|
+
page.driver.post token_endpoint_url(code: authorization_code, client_id: @client.uid,
|
|
172
|
+
redirect_uri: @client.redirect_uri, code_verifier: code_verifier)
|
|
173
|
+
should_have_json 'error', 'invalid_client'
|
|
174
|
+
should_not_have_json 'access_token'
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
scenario 'mobile app requests an access token with authorization code and without secret but is marked as not confidential' do
|
|
178
|
+
@client.update_attribute :confidential, false
|
|
179
|
+
visit authorization_endpoint_url(client: @client, code_challenge: code_challenge, code_challenge_method: 'S256')
|
|
180
|
+
click_on 'Authorize'
|
|
181
|
+
|
|
182
|
+
authorization_code = current_params['code']
|
|
183
|
+
page.driver.post token_endpoint_url(code: authorization_code, client_id: @client.uid,
|
|
184
|
+
redirect_uri: @client.redirect_uri, code_verifier: code_verifier)
|
|
185
|
+
should_not_have_json 'error'
|
|
186
|
+
|
|
187
|
+
should_have_json 'access_token', Doorkeeper::AccessToken.first.token
|
|
188
|
+
should_have_json 'token_type', 'bearer'
|
|
189
|
+
should_have_json_within 'expires_in', Doorkeeper::AccessToken.first.expires_in, 1
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
scenario 'mobile app requests an access token with authorization code but no code verifier' do
|
|
193
|
+
visit authorization_endpoint_url(client: @client, code_challenge: code_challenge, code_challenge_method: 'S256')
|
|
194
|
+
click_on 'Authorize'
|
|
195
|
+
|
|
196
|
+
authorization_code = current_params['code']
|
|
197
|
+
create_access_token authorization_code, @client
|
|
198
|
+
|
|
199
|
+
should_not_have_json 'access_token'
|
|
200
|
+
should_have_json 'error', 'invalid_request'
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
scenario 'mobile app requests an access token with authorization code with wrong verifier' do
|
|
204
|
+
visit authorization_endpoint_url(client: @client, code_challenge: code_challenge, code_challenge_method: 'S256')
|
|
205
|
+
click_on 'Authorize'
|
|
206
|
+
|
|
207
|
+
authorization_code = current_params['code']
|
|
208
|
+
create_access_token authorization_code, @client, 'incorrect-code-verifier'
|
|
209
|
+
|
|
210
|
+
should_not_have_json 'access_token'
|
|
211
|
+
should_have_json 'error', 'invalid_grant'
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
scenario 'code_challenge_mehthod in token request is totally ignored' do
|
|
215
|
+
visit authorization_endpoint_url(client: @client, code_challenge: code_challenge, code_challenge_method: 'S256')
|
|
216
|
+
click_on 'Authorize'
|
|
217
|
+
|
|
218
|
+
authorization_code = current_params['code']
|
|
219
|
+
page.driver.post token_endpoint_url(code: authorization_code, client: @client, code_verifier: code_challenge,
|
|
220
|
+
code_challenge_method: 'plain')
|
|
221
|
+
|
|
222
|
+
should_not_have_json 'access_token'
|
|
223
|
+
should_have_json 'error', 'invalid_grant'
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
scenario 'expects to set code_challenge_method explicitely without fallback' do
|
|
227
|
+
visit authorization_endpoint_url(client: @client, code_challenge: code_challenge)
|
|
228
|
+
expect(page).to have_content('The code challenge method must be plain or S256.')
|
|
229
|
+
end
|
|
230
|
+
end
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
context 'when application scopes are present and no scope is passed' do
|
|
234
|
+
background do
|
|
235
|
+
@client.update_attributes(scopes: 'public write read')
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
scenario 'access grant has no scope' do
|
|
239
|
+
default_scopes_exist :admin
|
|
240
|
+
visit authorization_endpoint_url(client: @client)
|
|
241
|
+
click_on 'Authorize'
|
|
242
|
+
access_grant_should_exist_for(@client, @resource_owner)
|
|
243
|
+
grant = Doorkeeper::AccessGrant.first
|
|
244
|
+
expect(grant.scopes).to be_empty
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
scenario 'access grant have scopes which are common in application scopees and default scopes' do
|
|
248
|
+
default_scopes_exist :public, :write
|
|
249
|
+
visit authorization_endpoint_url(client: @client)
|
|
250
|
+
click_on 'Authorize'
|
|
251
|
+
access_grant_should_exist_for(@client, @resource_owner)
|
|
252
|
+
access_grant_should_have_scopes :public, :write
|
|
253
|
+
end
|
|
254
|
+
end
|
|
255
|
+
|
|
60
256
|
context 'with scopes' do
|
|
61
257
|
background do
|
|
62
258
|
default_scopes_exist :public
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
require '
|
|
1
|
+
require 'spec_helper'
|
|
2
2
|
|
|
3
3
|
describe 'Client Credentials Request' do
|
|
4
4
|
let(:client) { FactoryBot.create :application }
|
|
@@ -8,7 +8,7 @@ describe 'Client Credentials Request' do
|
|
|
8
8
|
headers = authorization client.uid, client.secret
|
|
9
9
|
params = { grant_type: 'client_credentials' }
|
|
10
10
|
|
|
11
|
-
post '/oauth/token', params, headers
|
|
11
|
+
post '/oauth/token', params: params, headers: headers
|
|
12
12
|
|
|
13
13
|
should_have_json 'access_token', Doorkeeper::AccessToken.first.token
|
|
14
14
|
should_have_json_within 'expires_in', Doorkeeper.configuration.access_token_expires_in, 1
|
|
@@ -29,7 +29,7 @@ describe 'Client Credentials Request' do
|
|
|
29
29
|
headers = authorization client.uid, client.secret
|
|
30
30
|
params = { grant_type: 'client_credentials', scope: 'write' }
|
|
31
31
|
|
|
32
|
-
post '/oauth/token', params, headers
|
|
32
|
+
post '/oauth/token', params: params, headers: headers
|
|
33
33
|
|
|
34
34
|
should_have_json 'access_token', Doorkeeper::AccessToken.first.token
|
|
35
35
|
should_have_json 'scope', 'write'
|
|
@@ -40,7 +40,7 @@ describe 'Client Credentials Request' do
|
|
|
40
40
|
headers = authorization client.uid, client.secret
|
|
41
41
|
params = { grant_type: 'client_credentials', scope: 'public' }
|
|
42
42
|
|
|
43
|
-
post '/oauth/token', params, headers
|
|
43
|
+
post '/oauth/token', params: params, headers: headers
|
|
44
44
|
|
|
45
45
|
should_have_json 'access_token', Doorkeeper::AccessToken.first.token
|
|
46
46
|
should_have_json 'scope', 'public'
|
|
@@ -52,7 +52,7 @@ describe 'Client Credentials Request' do
|
|
|
52
52
|
headers = authorization client.uid, client.secret
|
|
53
53
|
params = { grant_type: 'client_credentials', scope: 'random' }
|
|
54
54
|
|
|
55
|
-
post '/oauth/token', params, headers
|
|
55
|
+
post '/oauth/token', params: params, headers: headers
|
|
56
56
|
|
|
57
57
|
should_have_json 'error', 'invalid_scope'
|
|
58
58
|
should_have_json 'error_description', translated_error_message(:invalid_scope)
|
|
@@ -64,12 +64,52 @@ describe 'Client Credentials Request' do
|
|
|
64
64
|
end
|
|
65
65
|
end
|
|
66
66
|
|
|
67
|
+
context 'when application scopes contain some of the default scopes and no scope is passed' do
|
|
68
|
+
before do
|
|
69
|
+
client.update_attributes(scopes: 'read write public')
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
it 'issues new token with one default scope that are present in application scopes' do
|
|
73
|
+
default_scopes_exist :public
|
|
74
|
+
|
|
75
|
+
headers = authorization client.uid, client.secret
|
|
76
|
+
params = { grant_type: 'client_credentials' }
|
|
77
|
+
|
|
78
|
+
expect do
|
|
79
|
+
post '/oauth/token', params: params, headers: headers
|
|
80
|
+
end.to change { Doorkeeper::AccessToken.count }.by(1)
|
|
81
|
+
|
|
82
|
+
token = Doorkeeper::AccessToken.first
|
|
83
|
+
|
|
84
|
+
expect(token.application_id).to eq client.id
|
|
85
|
+
should_have_json 'access_token', token.token
|
|
86
|
+
should_have_json 'scope', 'public'
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
it 'issues new token with multiple default scopes that are present in application scopes' do
|
|
90
|
+
default_scopes_exist :public, :read, :update
|
|
91
|
+
|
|
92
|
+
headers = authorization client.uid, client.secret
|
|
93
|
+
params = { grant_type: 'client_credentials' }
|
|
94
|
+
|
|
95
|
+
expect do
|
|
96
|
+
post '/oauth/token', params: params, headers: headers
|
|
97
|
+
end.to change { Doorkeeper::AccessToken.count }.by(1)
|
|
98
|
+
|
|
99
|
+
token = Doorkeeper::AccessToken.first
|
|
100
|
+
|
|
101
|
+
expect(token.application_id).to eq client.id
|
|
102
|
+
should_have_json 'access_token', token.token
|
|
103
|
+
should_have_json 'scope', 'public read'
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
|
|
67
107
|
context 'an invalid request' do
|
|
68
108
|
it 'does not authorize the client and returns the error' do
|
|
69
109
|
headers = {}
|
|
70
110
|
params = { grant_type: 'client_credentials' }
|
|
71
111
|
|
|
72
|
-
post '/oauth/token', params, headers
|
|
112
|
+
post '/oauth/token', params: params, headers: headers
|
|
73
113
|
|
|
74
114
|
should_have_json 'error', 'invalid_client'
|
|
75
115
|
should_have_json 'error_description', translated_error_message(:invalid_client)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
require '
|
|
1
|
+
require 'spec_helper'
|
|
2
2
|
|
|
3
3
|
feature 'Implicit Grant Flow (feature spec)' do
|
|
4
4
|
background do
|
|
@@ -17,6 +17,29 @@ feature 'Implicit Grant Flow (feature spec)' do
|
|
|
17
17
|
|
|
18
18
|
i_should_be_on_client_callback @client
|
|
19
19
|
end
|
|
20
|
+
|
|
21
|
+
context 'when application scopes are present and no scope is passed' do
|
|
22
|
+
background do
|
|
23
|
+
@client.update_attributes(scopes: 'public write read')
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
scenario 'access token has no scopes' do
|
|
27
|
+
default_scopes_exist :admin
|
|
28
|
+
visit authorization_endpoint_url(client: @client, response_type: 'token')
|
|
29
|
+
click_on 'Authorize'
|
|
30
|
+
access_token_should_exist_for @client, @resource_owner
|
|
31
|
+
token = Doorkeeper::AccessToken.first
|
|
32
|
+
expect(token.scopes).to be_empty
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
scenario 'access token has scopes which are common in application scopees and default scopes' do
|
|
36
|
+
default_scopes_exist :public, :write
|
|
37
|
+
visit authorization_endpoint_url(client: @client, response_type: 'token')
|
|
38
|
+
click_on 'Authorize'
|
|
39
|
+
access_token_should_exist_for @client, @resource_owner
|
|
40
|
+
access_token_should_have_scopes :public, :write
|
|
41
|
+
end
|
|
42
|
+
end
|
|
20
43
|
end
|
|
21
44
|
|
|
22
45
|
describe 'Implicit Grant Flow (request spec)' do
|
|
@@ -34,11 +57,13 @@ describe 'Implicit Grant Flow (request spec)' do
|
|
|
34
57
|
token = client_is_authorized(@client, @resource_owner)
|
|
35
58
|
|
|
36
59
|
post "/oauth/authorize",
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
60
|
+
params: {
|
|
61
|
+
client_id: @client.uid,
|
|
62
|
+
state: '',
|
|
63
|
+
redirect_uri: @client.redirect_uri,
|
|
64
|
+
response_type: 'token',
|
|
65
|
+
commit: 'Authorize'
|
|
66
|
+
}
|
|
42
67
|
|
|
43
68
|
expect(response.location).not_to include(token.token)
|
|
44
69
|
end
|
|
@@ -49,11 +74,13 @@ describe 'Implicit Grant Flow (request spec)' do
|
|
|
49
74
|
token = client_is_authorized(@client, @resource_owner)
|
|
50
75
|
|
|
51
76
|
post "/oauth/authorize",
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
77
|
+
params: {
|
|
78
|
+
client_id: @client.uid,
|
|
79
|
+
state: '',
|
|
80
|
+
redirect_uri: @client.redirect_uri,
|
|
81
|
+
response_type: 'token',
|
|
82
|
+
commit: 'Authorize'
|
|
83
|
+
}
|
|
57
84
|
|
|
58
85
|
expect(response.location).to include(token.token)
|
|
59
86
|
end
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
require '
|
|
1
|
+
require 'spec_helper'
|
|
2
2
|
|
|
3
3
|
describe 'Resource Owner Password Credentials Flow not set up' do
|
|
4
4
|
before do
|
|
@@ -7,49 +7,92 @@ describe 'Resource Owner Password Credentials Flow not set up' do
|
|
|
7
7
|
end
|
|
8
8
|
|
|
9
9
|
context 'with valid user credentials' do
|
|
10
|
-
it '
|
|
10
|
+
it 'does not 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
|
|
|
@@ -97,6 +140,60 @@ describe 'Resource Owner Password Credentials Flow' do
|
|
|
97
140
|
end
|
|
98
141
|
end
|
|
99
142
|
|
|
143
|
+
context 'when application scopes are present and differs from configured default scopes and no scope is passed' do
|
|
144
|
+
before do
|
|
145
|
+
default_scopes_exist :public
|
|
146
|
+
@client.update_attributes(scopes: 'abc')
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
it 'issues new token without any scope' do
|
|
150
|
+
expect do
|
|
151
|
+
post password_token_endpoint_url(client: @client, resource_owner: @resource_owner)
|
|
152
|
+
end.to change { Doorkeeper::AccessToken.count }.by(1)
|
|
153
|
+
|
|
154
|
+
token = Doorkeeper::AccessToken.first
|
|
155
|
+
|
|
156
|
+
expect(token.application_id).to eq @client.id
|
|
157
|
+
expect(token.scopes).to be_empty
|
|
158
|
+
should_have_json 'access_token', token.token
|
|
159
|
+
should_not_have_json 'scope'
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
context 'when application scopes contain some of the default scopes and no scope is passed' do
|
|
164
|
+
before do
|
|
165
|
+
@client.update_attributes(scopes: 'read write public')
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
it 'issues new token with one default scope that are present in application scopes' do
|
|
169
|
+
default_scopes_exist :public, :admin
|
|
170
|
+
|
|
171
|
+
expect do
|
|
172
|
+
post password_token_endpoint_url(client: @client, resource_owner: @resource_owner)
|
|
173
|
+
end.to change { Doorkeeper::AccessToken.count }.by(1)
|
|
174
|
+
|
|
175
|
+
token = Doorkeeper::AccessToken.first
|
|
176
|
+
|
|
177
|
+
expect(token.application_id).to eq @client.id
|
|
178
|
+
should_have_json 'access_token', token.token
|
|
179
|
+
should_have_json 'scope', 'public'
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
it 'issues new token with multiple default scopes that are present in application scopes' do
|
|
183
|
+
default_scopes_exist :public, :read, :update
|
|
184
|
+
|
|
185
|
+
expect do
|
|
186
|
+
post password_token_endpoint_url(client: @client, resource_owner: @resource_owner)
|
|
187
|
+
end.to change { Doorkeeper::AccessToken.count }.by(1)
|
|
188
|
+
|
|
189
|
+
token = Doorkeeper::AccessToken.first
|
|
190
|
+
|
|
191
|
+
expect(token.application_id).to eq @client.id
|
|
192
|
+
should_have_json 'access_token', token.token
|
|
193
|
+
should_have_json 'scope', 'public read'
|
|
194
|
+
end
|
|
195
|
+
end
|
|
196
|
+
|
|
100
197
|
context 'with invalid scopes' do
|
|
101
198
|
subject do
|
|
102
199
|
post password_token_endpoint_url(client: @client,
|
|
@@ -124,13 +221,13 @@ describe 'Resource Owner Password Credentials Flow' do
|
|
|
124
221
|
post password_token_endpoint_url(client: @client,
|
|
125
222
|
resource_owner_username: @resource_owner.name,
|
|
126
223
|
resource_owner_password: 'wrongpassword')
|
|
127
|
-
end.to_not
|
|
224
|
+
end.to_not(change { Doorkeeper::AccessToken.count })
|
|
128
225
|
end
|
|
129
226
|
|
|
130
227
|
it 'should not issue new token without credentials' do
|
|
131
228
|
expect do
|
|
132
229
|
post password_token_endpoint_url(client: @client)
|
|
133
|
-
end.to_not
|
|
230
|
+
end.to_not(change { Doorkeeper::AccessToken.count })
|
|
134
231
|
end
|
|
135
232
|
end
|
|
136
233
|
|
|
@@ -140,7 +237,7 @@ describe 'Resource Owner Password Credentials Flow' do
|
|
|
140
237
|
post password_token_endpoint_url(client_id: @client.uid,
|
|
141
238
|
client_secret: 'bad_secret',
|
|
142
239
|
resource_owner: @resource_owner)
|
|
143
|
-
end.to_not
|
|
240
|
+
end.to_not(change { Doorkeeper::AccessToken.count })
|
|
144
241
|
end
|
|
145
242
|
end
|
|
146
243
|
|
|
@@ -148,7 +245,7 @@ describe 'Resource Owner Password Credentials Flow' do
|
|
|
148
245
|
it 'should not issue new token with bad client id' do
|
|
149
246
|
expect do
|
|
150
247
|
post password_token_endpoint_url(client_id: 'bad_id', resource_owner: @resource_owner)
|
|
151
|
-
end.to_not
|
|
248
|
+
end.to_not(change { Doorkeeper::AccessToken.count })
|
|
152
249
|
end
|
|
153
250
|
end
|
|
154
251
|
end
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
require '
|
|
1
|
+
require 'spec_helper'
|
|
2
2
|
|
|
3
3
|
describe 'Refresh Token Flow' do
|
|
4
4
|
before do
|
|
@@ -14,7 +14,7 @@ describe 'Refresh Token Flow' do
|
|
|
14
14
|
authorization_code_exists application: @client
|
|
15
15
|
end
|
|
16
16
|
|
|
17
|
-
it 'client gets the refresh token and
|
|
17
|
+
it 'client gets the refresh token and refreshes it' do
|
|
18
18
|
post token_endpoint_url(code: @authorization.token, client: @client)
|
|
19
19
|
|
|
20
20
|
token = Doorkeeper::AccessToken.first
|