doorkeeper 3.1.0 → 4.4.3
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of doorkeeper might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/.coveralls.yml +1 -0
- data/.github/ISSUE_TEMPLATE.md +25 -0
- data/.github/PULL_REQUEST_TEMPLATE.md +17 -0
- data/.gitignore +6 -1
- data/.hound.yml +2 -13
- data/.rubocop.yml +17 -0
- data/.travis.yml +26 -10
- data/Appraisals +18 -0
- data/CODE_OF_CONDUCT.md +46 -0
- data/CONTRIBUTING.md +2 -0
- data/Gemfile +5 -5
- data/NEWS.md +141 -2
- data/README.md +149 -66
- data/RELEASING.md +5 -12
- data/Rakefile +1 -1
- data/SECURITY.md +15 -0
- data/app/controllers/doorkeeper/application_controller.rb +4 -6
- data/app/controllers/doorkeeper/application_metal_controller.rb +3 -2
- data/app/controllers/doorkeeper/applications_controller.rb +18 -8
- data/app/controllers/doorkeeper/authorizations_controller.rb +1 -1
- data/app/controllers/doorkeeper/authorized_applications_controller.rb +1 -1
- data/app/controllers/doorkeeper/tokens_controller.rb +62 -15
- data/app/helpers/doorkeeper/dashboard_helper.rb +14 -10
- data/app/validators/redirect_uri_validator.rb +12 -2
- data/app/views/doorkeeper/applications/_delete_form.html.erb +1 -2
- data/app/views/doorkeeper/applications/_form.html.erb +13 -2
- data/app/views/doorkeeper/applications/index.html.erb +2 -0
- data/app/views/doorkeeper/applications/show.html.erb +4 -1
- data/app/views/doorkeeper/authorizations/new.html.erb +1 -1
- data/app/views/doorkeeper/authorized_applications/_delete_form.html.erb +1 -2
- data/app/views/doorkeeper/authorized_applications/index.html.erb +0 -1
- data/app/views/layouts/doorkeeper/admin.html.erb +1 -1
- data/config/locales/en.yml +12 -7
- data/doorkeeper.gemspec +16 -11
- data/gemfiles/rails_4_2.gemfile +13 -0
- data/gemfiles/rails_5_0.gemfile +12 -0
- data/gemfiles/rails_5_1.gemfile +12 -0
- data/gemfiles/rails_5_2.gemfile +12 -0
- data/gemfiles/rails_master.gemfile +14 -0
- data/lib/doorkeeper/config.rb +119 -46
- data/lib/doorkeeper/engine.rb +11 -7
- data/lib/doorkeeper/errors.rb +18 -0
- data/lib/doorkeeper/grape/helpers.rb +14 -8
- data/lib/doorkeeper/helpers/controller.rb +8 -19
- data/lib/doorkeeper/models/access_grant_mixin.rb +10 -21
- data/lib/doorkeeper/models/access_token_mixin.rb +147 -43
- data/lib/doorkeeper/models/application_mixin.rb +33 -35
- data/lib/doorkeeper/models/concerns/accessible.rb +4 -0
- data/lib/doorkeeper/models/concerns/expirable.rb +15 -5
- data/lib/doorkeeper/models/concerns/orderable.rb +13 -0
- data/lib/doorkeeper/models/concerns/ownership.rb +6 -1
- data/lib/doorkeeper/models/concerns/revocable.rb +37 -2
- data/lib/doorkeeper/oauth/authorization/token.rb +22 -18
- data/lib/doorkeeper/oauth/authorization/uri_builder.rb +20 -18
- data/lib/doorkeeper/oauth/authorization_code_request.rb +7 -5
- data/lib/doorkeeper/oauth/{request_concern.rb → base_request.rb} +9 -2
- data/lib/doorkeeper/oauth/base_response.rb +29 -0
- data/lib/doorkeeper/oauth/client/credentials.rb +21 -8
- data/lib/doorkeeper/oauth/client.rb +2 -3
- data/lib/doorkeeper/oauth/client_credentials/creator.rb +1 -1
- data/lib/doorkeeper/oauth/client_credentials/issuer.rb +3 -2
- data/lib/doorkeeper/oauth/client_credentials/validation.rb +1 -1
- data/lib/doorkeeper/oauth/client_credentials_request.rb +8 -8
- data/lib/doorkeeper/oauth/code_response.rb +16 -16
- data/lib/doorkeeper/oauth/error.rb +2 -2
- data/lib/doorkeeper/oauth/error_response.rb +10 -10
- data/lib/doorkeeper/oauth/forbidden_token_response.rb +1 -1
- data/lib/doorkeeper/oauth/helpers/scope_checker.rb +1 -1
- data/lib/doorkeeper/oauth/helpers/uri_checker.rb +17 -1
- data/lib/doorkeeper/oauth/invalid_token_response.rb +5 -4
- data/lib/doorkeeper/oauth/password_access_token_request.rb +8 -13
- data/lib/doorkeeper/oauth/pre_authorization.rb +5 -3
- data/lib/doorkeeper/oauth/refresh_token_request.rb +23 -14
- data/lib/doorkeeper/oauth/scopes.rb +18 -8
- data/lib/doorkeeper/oauth/token.rb +20 -21
- data/lib/doorkeeper/oauth/token_introspection.rb +128 -0
- data/lib/doorkeeper/oauth/token_request.rb +1 -2
- data/lib/doorkeeper/oauth/token_response.rb +1 -1
- data/lib/doorkeeper/orm/active_record/access_grant.rb +27 -0
- data/lib/doorkeeper/orm/active_record/access_token.rb +34 -8
- data/lib/doorkeeper/orm/active_record/application.rb +48 -11
- data/lib/doorkeeper/orm/active_record.rb +17 -22
- data/lib/doorkeeper/rails/helpers.rb +6 -9
- data/lib/doorkeeper/rails/routes/mapper.rb +4 -4
- data/lib/doorkeeper/rails/routes/mapping.rb +1 -1
- data/lib/doorkeeper/rails/routes.rb +17 -11
- data/lib/doorkeeper/request/authorization_code.rb +7 -1
- data/lib/doorkeeper/request/password.rb +2 -2
- data/lib/doorkeeper/request/refresh_token.rb +1 -1
- data/lib/doorkeeper/request.rb +7 -1
- data/lib/doorkeeper/server.rb +0 -8
- data/lib/doorkeeper/validations.rb +3 -2
- data/lib/doorkeeper/version.rb +34 -1
- data/lib/doorkeeper.rb +10 -2
- data/lib/generators/doorkeeper/add_client_confidentiality_generator.rb +31 -0
- data/lib/generators/doorkeeper/application_owner_generator.rb +11 -2
- data/lib/generators/doorkeeper/migration_generator.rb +13 -1
- data/lib/generators/doorkeeper/previous_refresh_token_generator.rb +35 -0
- data/lib/generators/doorkeeper/templates/add_confidential_to_application_migration.rb.erb +11 -0
- data/{spec/dummy/db/migrate/20130902175349_add_owner_to_application.rb → lib/generators/doorkeeper/templates/add_owner_to_application_migration.rb.erb} +1 -1
- data/lib/generators/doorkeeper/templates/add_previous_refresh_token_to_access_tokens.rb.erb +11 -0
- data/lib/generators/doorkeeper/templates/initializer.rb +38 -6
- data/lib/generators/doorkeeper/templates/migration.rb.erb +69 -0
- data/spec/controllers/application_metal_controller.rb +10 -0
- data/spec/controllers/applications_controller_spec.rb +15 -4
- data/spec/controllers/authorizations_controller_spec.rb +74 -27
- data/spec/controllers/protected_resources_controller_spec.rb +70 -32
- data/spec/controllers/token_info_controller_spec.rb +17 -13
- data/spec/controllers/tokens_controller_spec.rb +198 -12
- data/spec/dummy/app/controllers/full_protected_resources_controller.rb +4 -4
- data/spec/dummy/app/controllers/home_controller.rb +1 -1
- data/spec/dummy/app/controllers/metal_controller.rb +1 -1
- data/spec/dummy/app/controllers/semi_protected_resources_controller.rb +3 -3
- data/spec/dummy/app/models/user.rb +0 -4
- data/spec/dummy/config/application.rb +2 -36
- data/spec/dummy/config/environment.rb +1 -1
- data/spec/dummy/config/environments/test.rb +4 -15
- data/spec/dummy/config/initializers/doorkeeper.rb +19 -3
- data/spec/dummy/config/initializers/new_framework_defaults.rb +6 -0
- data/spec/dummy/config/initializers/secret_token.rb +0 -1
- 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/{lib/generators/doorkeeper/templates/migration.rb → spec/dummy/db/migrate/20151223192035_create_doorkeeper_tables.rb} +16 -4
- data/{lib/generators/doorkeeper/templates/add_owner_to_application_migration.rb → spec/dummy/db/migrate/20151223200000_add_owner_to_application.rb} +4 -2
- data/spec/dummy/db/migrate/20160320211015_add_previous_refresh_token_to_access_tokens.rb +13 -0
- data/spec/dummy/db/migrate/20180210183654_add_confidential_to_application.rb +13 -0
- data/spec/dummy/db/schema.rb +24 -22
- data/spec/factories.rb +4 -2
- data/spec/generators/application_owner_generator_spec.rb +24 -5
- data/spec/generators/migration_generator_spec.rb +24 -3
- data/spec/generators/previous_refresh_token_generator_spec.rb +57 -0
- data/spec/grape/grape_integration_spec.rb +135 -0
- data/spec/helpers/doorkeeper/dashboard_helper_spec.rb +1 -1
- data/spec/lib/config_spec.rb +159 -14
- data/spec/lib/doorkeeper_spec.rb +135 -13
- data/spec/lib/models/expirable_spec.rb +0 -1
- data/spec/lib/models/revocable_spec.rb +27 -4
- data/spec/lib/oauth/authorization/uri_builder_spec.rb +1 -2
- data/spec/lib/oauth/authorization_code_request_spec.rb +55 -12
- data/spec/lib/oauth/base_request_spec.rb +155 -0
- data/spec/lib/oauth/base_response_spec.rb +45 -0
- data/spec/lib/oauth/client/credentials_spec.rb +45 -2
- data/spec/lib/oauth/client_credentials/creator_spec.rb +1 -1
- data/spec/lib/oauth/client_credentials_integration_spec.rb +1 -1
- data/spec/lib/oauth/client_credentials_request_spec.rb +1 -0
- data/spec/lib/oauth/code_request_spec.rb +1 -3
- data/spec/lib/oauth/code_response_spec.rb +34 -0
- data/spec/lib/oauth/error_response_spec.rb +9 -9
- data/spec/lib/oauth/error_spec.rb +1 -1
- data/spec/lib/oauth/helpers/uri_checker_spec.rb +115 -1
- data/spec/lib/oauth/invalid_token_response_spec.rb +36 -8
- data/spec/lib/oauth/password_access_token_request_spec.rb +14 -8
- data/spec/lib/oauth/pre_authorization_spec.rb +12 -7
- data/spec/lib/oauth/refresh_token_request_spec.rb +52 -9
- data/spec/lib/oauth/scopes_spec.rb +28 -2
- data/spec/lib/oauth/token_request_spec.rb +6 -8
- data/spec/lib/oauth/token_spec.rb +12 -5
- data/spec/lib/server_spec.rb +10 -3
- data/spec/models/doorkeeper/access_grant_spec.rb +1 -1
- data/spec/models/doorkeeper/access_token_spec.rb +116 -48
- data/spec/models/doorkeeper/application_spec.rb +145 -29
- data/spec/requests/applications/applications_request_spec.rb +5 -5
- data/spec/requests/endpoints/authorization_spec.rb +5 -6
- data/spec/requests/endpoints/token_spec.rb +8 -1
- data/spec/requests/flows/authorization_code_errors_spec.rb +11 -1
- data/spec/requests/flows/authorization_code_spec.rb +6 -13
- data/spec/requests/flows/client_credentials_spec.rb +29 -1
- data/spec/requests/flows/implicit_grant_errors_spec.rb +2 -2
- data/spec/requests/flows/password_spec.rb +118 -15
- data/spec/requests/flows/refresh_token_spec.rb +89 -19
- data/spec/requests/flows/revoke_token_spec.rb +105 -91
- 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 +4 -0
- data/spec/routing/default_routes_spec.rb +5 -1
- data/spec/spec_helper.rb +2 -0
- data/spec/spec_helper_integration.rb +22 -4
- data/spec/support/dependencies/factory_girl.rb +2 -2
- data/spec/support/helpers/access_token_request_helper.rb +1 -1
- data/spec/support/helpers/model_helper.rb +34 -7
- data/spec/support/helpers/request_spec_helper.rb +17 -5
- data/spec/support/helpers/url_helper.rb +9 -8
- data/spec/support/http_method_shim.rb +38 -0
- data/spec/support/shared/controllers_shared_context.rb +15 -10
- data/spec/support/shared/models_shared_examples.rb +5 -5
- data/spec/validators/redirect_uri_validator_spec.rb +51 -6
- data/spec/version/version_spec.rb +15 -0
- metadata +128 -46
- data/lib/doorkeeper/oauth/client/methods.rb +0 -18
- data/lib/generators/doorkeeper/application_scopes_generator.rb +0 -34
- data/lib/generators/doorkeeper/templates/add_scopes_to_oauth_applications.rb +0 -5
- data/spec/dummy/db/migrate/20130902165751_create_doorkeeper_tables.rb +0 -41
- data/spec/dummy/db/migrate/20141209001746_add_scopes_to_oauth_applications.rb +0 -5
- data/spec/lib/oauth/client/methods_spec.rb +0 -54
@@ -25,8 +25,8 @@ end
|
|
25
25
|
|
26
26
|
feature 'Listing applications' do
|
27
27
|
background do
|
28
|
-
|
29
|
-
|
28
|
+
FactoryBot.create :application, name: 'Oauth Dude'
|
29
|
+
FactoryBot.create :application, name: 'Awesome App'
|
30
30
|
end
|
31
31
|
|
32
32
|
scenario 'application list' do
|
@@ -38,7 +38,7 @@ end
|
|
38
38
|
|
39
39
|
feature 'Show application' do
|
40
40
|
given :app do
|
41
|
-
|
41
|
+
FactoryBot.create :application, name: 'Just another oauth app'
|
42
42
|
end
|
43
43
|
|
44
44
|
scenario 'visiting application page' do
|
@@ -49,7 +49,7 @@ end
|
|
49
49
|
|
50
50
|
feature 'Edit application' do
|
51
51
|
let :app do
|
52
|
-
|
52
|
+
FactoryBot.create :application, name: 'OMG my app'
|
53
53
|
end
|
54
54
|
|
55
55
|
background do
|
@@ -73,7 +73,7 @@ end
|
|
73
73
|
|
74
74
|
feature 'Remove application' do
|
75
75
|
background do
|
76
|
-
@app =
|
76
|
+
@app = FactoryBot.create :application
|
77
77
|
end
|
78
78
|
|
79
79
|
scenario 'deleting an application from list' do
|
@@ -59,13 +59,12 @@ feature 'Authorization endpoint' do
|
|
59
59
|
end
|
60
60
|
|
61
61
|
scenario 'raises exception on forged requests' do
|
62
|
-
skip 'TODO: need to add request helpers to this feature spec'
|
63
|
-
allow_any_instance_of(ActionController::Base).to receive(:handle_unverified_request)
|
64
62
|
allowing_forgery_protection do
|
65
|
-
|
66
|
-
client_id:
|
67
|
-
|
68
|
-
|
63
|
+
expect {
|
64
|
+
page.driver.post authorization_endpoint_url(client_id: @client.uid,
|
65
|
+
redirect_uri: @client.redirect_uri,
|
66
|
+
response_type: 'code')
|
67
|
+
}.to raise_error(ActionController::InvalidAuthenticityToken)
|
69
68
|
end
|
70
69
|
end
|
71
70
|
end
|
@@ -9,7 +9,14 @@ describe 'Token endpoint' do
|
|
9
9
|
it 'respond with correct headers' do
|
10
10
|
post token_endpoint_url(code: @authorization.token, client: @client)
|
11
11
|
should_have_header 'Pragma', 'no-cache'
|
12
|
-
|
12
|
+
|
13
|
+
# Rails 5.2 changed headers
|
14
|
+
if ::Rails::VERSION::MAJOR >= 5 && ::Rails::VERSION::MINOR >= 2 || ::Rails::VERSION::MAJOR >= 6
|
15
|
+
should_have_header 'Cache-Control', 'private, no-store'
|
16
|
+
else
|
17
|
+
should_have_header 'Cache-Control', 'no-store'
|
18
|
+
end
|
19
|
+
|
13
20
|
should_have_header 'Content-Type', 'application/json; charset=utf-8'
|
14
21
|
end
|
15
22
|
|
@@ -1,9 +1,10 @@
|
|
1
1
|
require 'spec_helper_integration'
|
2
2
|
|
3
3
|
feature 'Authorization Code Flow Errors' do
|
4
|
+
let(:client_params) { {} }
|
4
5
|
background do
|
5
6
|
config_is_set(:authenticate_resource_owner) { User.first || redirect_to('/sign_in') }
|
6
|
-
client_exists
|
7
|
+
client_exists client_params
|
7
8
|
create_resource_owner
|
8
9
|
sign_in
|
9
10
|
end
|
@@ -12,6 +13,15 @@ feature 'Authorization Code Flow Errors' do
|
|
12
13
|
access_grant_should_not_exist
|
13
14
|
end
|
14
15
|
|
16
|
+
context "with a client trying to xss resource owner" do
|
17
|
+
let(:client_name) { "<div id='xss'>XSS</div>" }
|
18
|
+
let(:client_params) { { name: client_name } }
|
19
|
+
scenario "resource owner visit authorization endpoint" do
|
20
|
+
visit authorization_endpoint_url(client: @client)
|
21
|
+
expect(page).not_to have_css("#xss")
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
15
25
|
context 'when access was denied' do
|
16
26
|
scenario 'redirects with error' do
|
17
27
|
visit authorization_endpoint_url(client: @client)
|
@@ -29,6 +29,7 @@ feature 'Authorization Code Flow' do
|
|
29
29
|
|
30
30
|
access_grant_should_exist_for(@client, @resource_owner)
|
31
31
|
|
32
|
+
url_should_have_param('code', Doorkeeper::AccessGrant.first.token)
|
32
33
|
i_should_see 'Authorization code:'
|
33
34
|
i_should_see Doorkeeper::AccessGrant.first.token
|
34
35
|
end
|
@@ -41,20 +42,18 @@ feature 'Authorization Code Flow' do
|
|
41
42
|
end
|
42
43
|
|
43
44
|
scenario 'resource owner requests an access token with authorization code' do
|
44
|
-
skip 'TODO: need to add request helpers to this feature spec'
|
45
|
-
|
46
45
|
visit authorization_endpoint_url(client: @client)
|
47
46
|
click_on 'Authorize'
|
48
47
|
|
49
48
|
authorization_code = Doorkeeper::AccessGrant.first.token
|
50
|
-
|
49
|
+
create_access_token authorization_code, @client
|
51
50
|
|
52
51
|
access_token_should_exist_for(@client, @resource_owner)
|
53
52
|
|
54
53
|
should_not_have_json 'error'
|
55
54
|
|
56
55
|
should_have_json 'access_token', Doorkeeper::AccessToken.first.token
|
57
|
-
should_have_json 'token_type', '
|
56
|
+
should_have_json 'token_type', 'Bearer'
|
58
57
|
should_have_json_within 'expires_in', Doorkeeper::AccessToken.first.expires_in, 1
|
59
58
|
end
|
60
59
|
|
@@ -84,27 +83,23 @@ feature 'Authorization Code Flow' do
|
|
84
83
|
end
|
85
84
|
|
86
85
|
scenario 'new access token matches required scopes' do
|
87
|
-
skip 'TODO: need to add request helpers to this feature spec'
|
88
|
-
|
89
86
|
visit authorization_endpoint_url(client: @client, scope: 'public write')
|
90
87
|
click_on 'Authorize'
|
91
88
|
|
92
89
|
authorization_code = Doorkeeper::AccessGrant.first.token
|
93
|
-
|
90
|
+
create_access_token authorization_code, @client
|
94
91
|
|
95
92
|
access_token_should_exist_for(@client, @resource_owner)
|
96
93
|
access_token_should_have_scopes :public, :write
|
97
94
|
end
|
98
95
|
|
99
96
|
scenario 'returns new token if scopes have changed' do
|
100
|
-
skip 'TODO: need to add request helpers to this feature spec'
|
101
|
-
|
102
97
|
client_is_authorized(@client, @resource_owner, scopes: 'public write')
|
103
98
|
visit authorization_endpoint_url(client: @client, scope: 'public')
|
104
99
|
click_on 'Authorize'
|
105
100
|
|
106
101
|
authorization_code = Doorkeeper::AccessGrant.first.token
|
107
|
-
|
102
|
+
create_access_token authorization_code, @client
|
108
103
|
|
109
104
|
expect(Doorkeeper::AccessToken.count).to be(2)
|
110
105
|
|
@@ -112,14 +107,12 @@ feature 'Authorization Code Flow' do
|
|
112
107
|
end
|
113
108
|
|
114
109
|
scenario 'resource owner authorizes the client with extra scopes' do
|
115
|
-
skip 'TODO: need to add request helpers to this feature spec'
|
116
|
-
|
117
110
|
client_is_authorized(@client, @resource_owner, scopes: 'public')
|
118
111
|
visit authorization_endpoint_url(client: @client, scope: 'public write')
|
119
112
|
click_on 'Authorize'
|
120
113
|
|
121
114
|
authorization_code = Doorkeeper::AccessGrant.first.token
|
122
|
-
|
115
|
+
create_access_token authorization_code, @client
|
123
116
|
|
124
117
|
expect(Doorkeeper::AccessToken.count).to be(2)
|
125
118
|
|
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'spec_helper_integration'
|
2
2
|
|
3
3
|
describe 'Client Credentials Request' do
|
4
|
-
let(:client) {
|
4
|
+
let(:client) { FactoryBot.create :application }
|
5
5
|
|
6
6
|
context 'a valid request' do
|
7
7
|
it 'authorizes the client and returns the token response' do
|
@@ -22,6 +22,7 @@ describe 'Client Credentials Request' do
|
|
22
22
|
context 'with scopes' do
|
23
23
|
before do
|
24
24
|
optional_scopes_exist :write
|
25
|
+
default_scopes_exist :public
|
25
26
|
end
|
26
27
|
|
27
28
|
it 'adds the scope to the token an returns in the response' do
|
@@ -33,6 +34,33 @@ describe 'Client Credentials Request' do
|
|
33
34
|
should_have_json 'access_token', Doorkeeper::AccessToken.first.token
|
34
35
|
should_have_json 'scope', 'write'
|
35
36
|
end
|
37
|
+
|
38
|
+
context 'that are default' do
|
39
|
+
it 'adds the scope to the token an returns in the response' do
|
40
|
+
headers = authorization client.uid, client.secret
|
41
|
+
params = { grant_type: 'client_credentials', scope: 'public' }
|
42
|
+
|
43
|
+
post '/oauth/token', params, headers
|
44
|
+
|
45
|
+
should_have_json 'access_token', Doorkeeper::AccessToken.first.token
|
46
|
+
should_have_json 'scope', 'public'
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
context 'that are invalid' do
|
51
|
+
it 'does not authorize the client and returns the error' do
|
52
|
+
headers = authorization client.uid, client.secret
|
53
|
+
params = { grant_type: 'client_credentials', scope: 'random' }
|
54
|
+
|
55
|
+
post '/oauth/token', params, headers
|
56
|
+
|
57
|
+
should_have_json 'error', 'invalid_scope'
|
58
|
+
should_have_json 'error_description', translated_error_message(:invalid_scope)
|
59
|
+
should_not_have_json 'access_token'
|
60
|
+
|
61
|
+
expect(response.status).to eq(401)
|
62
|
+
end
|
63
|
+
end
|
36
64
|
end
|
37
65
|
end
|
38
66
|
|
@@ -17,13 +17,13 @@ feature 'Implicit Grant Flow Errors' do
|
|
17
17
|
[:client_id, :invalid_client],
|
18
18
|
[:redirect_uri, :invalid_redirect_uri]
|
19
19
|
].each do |error|
|
20
|
-
scenario "displays #{error.last
|
20
|
+
scenario "displays #{error.last} error for invalid #{error.first}" do
|
21
21
|
visit authorization_endpoint_url(client: @client, error.first => 'invalid', response_type: 'token')
|
22
22
|
i_should_not_see 'Authorize'
|
23
23
|
i_should_see_translated_error_message error.last
|
24
24
|
end
|
25
25
|
|
26
|
-
scenario "displays #{error.last
|
26
|
+
scenario "displays #{error.last} error when #{error.first} is missing" do
|
27
27
|
visit authorization_endpoint_url(client: @client, error.first => '', response_type: 'token')
|
28
28
|
i_should_not_see 'Authorize'
|
29
29
|
i_should_see_translated_error_message error.last
|
@@ -10,38 +10,94 @@ describe 'Resource Owner Password Credentials Flow not set up' do
|
|
10
10
|
it 'doesn\'t issue new token' do
|
11
11
|
expect do
|
12
12
|
post password_token_endpoint_url(client: @client, resource_owner: @resource_owner)
|
13
|
-
end.to_not
|
13
|
+
end.to_not(change { Doorkeeper::AccessToken.count })
|
14
14
|
end
|
15
15
|
end
|
16
16
|
end
|
17
17
|
|
18
18
|
describe 'Resource Owner Password Credentials Flow' do
|
19
|
+
let(:client_attributes) { {} }
|
20
|
+
|
19
21
|
before do
|
20
22
|
config_is_set(:grant_flows, ["password"])
|
21
23
|
config_is_set(:resource_owner_from_credentials) { User.authenticate! params[:username], params[:password] }
|
22
|
-
client_exists
|
24
|
+
client_exists(client_attributes)
|
23
25
|
create_resource_owner
|
24
26
|
end
|
25
27
|
|
26
28
|
context 'with valid user credentials' do
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
29
|
+
context "with non-confidential/public client" do
|
30
|
+
let(:client_attributes) { { confidential: false } }
|
31
|
+
|
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)
|
37
|
+
|
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
|
67
|
+
end
|
31
68
|
|
32
|
-
|
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)
|
74
|
+
|
75
|
+
token = Doorkeeper::AccessToken.first
|
33
76
|
|
34
|
-
|
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
|
35
90
|
end
|
36
91
|
|
37
92
|
it 'should issue new token without client credentials' do
|
38
93
|
expect do
|
39
94
|
post password_token_endpoint_url(resource_owner: @resource_owner)
|
40
|
-
end.to
|
95
|
+
end.to(change { Doorkeeper::AccessToken.count }.by(1))
|
41
96
|
|
42
97
|
token = Doorkeeper::AccessToken.first
|
43
98
|
|
44
|
-
|
99
|
+
expect(token.application_id).to be_nil
|
100
|
+
should_have_json 'access_token', token.token
|
45
101
|
end
|
46
102
|
|
47
103
|
it 'should issue a refresh token if enabled' do
|
@@ -51,7 +107,7 @@ describe 'Resource Owner Password Credentials Flow' do
|
|
51
107
|
|
52
108
|
token = Doorkeeper::AccessToken.first
|
53
109
|
|
54
|
-
should_have_json 'refresh_token',
|
110
|
+
should_have_json 'refresh_token', token.refresh_token
|
55
111
|
end
|
56
112
|
|
57
113
|
it 'should return the same token if it is still accessible' do
|
@@ -64,6 +120,45 @@ describe 'Resource Owner Password Credentials Flow' do
|
|
64
120
|
expect(Doorkeeper::AccessToken.count).to be(1)
|
65
121
|
should_have_json 'access_token', Doorkeeper::AccessToken.first.token
|
66
122
|
end
|
123
|
+
|
124
|
+
context 'with valid, default scope' do
|
125
|
+
before do
|
126
|
+
default_scopes_exist :public
|
127
|
+
end
|
128
|
+
|
129
|
+
it 'should issue new token' do
|
130
|
+
expect do
|
131
|
+
post password_token_endpoint_url(client: @client, resource_owner: @resource_owner, scope: 'public')
|
132
|
+
end.to change { Doorkeeper::AccessToken.count }.by(1)
|
133
|
+
|
134
|
+
token = Doorkeeper::AccessToken.first
|
135
|
+
|
136
|
+
expect(token.application_id).to eq @client.id
|
137
|
+
should_have_json 'access_token', token.token
|
138
|
+
should_have_json 'scope', 'public'
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
context 'with invalid scopes' do
|
144
|
+
subject do
|
145
|
+
post password_token_endpoint_url(client: @client,
|
146
|
+
resource_owner: @resource_owner,
|
147
|
+
scope: 'random')
|
148
|
+
end
|
149
|
+
|
150
|
+
it 'should not issue new token' do
|
151
|
+
expect { subject }.to_not(change { Doorkeeper::AccessToken.count })
|
152
|
+
end
|
153
|
+
|
154
|
+
it 'should return invalid_scope error' do
|
155
|
+
subject
|
156
|
+
should_have_json 'error', 'invalid_scope'
|
157
|
+
should_have_json 'error_description', translated_error_message(:invalid_scope)
|
158
|
+
should_not_have_json 'access_token'
|
159
|
+
|
160
|
+
expect(response.status).to eq(401)
|
161
|
+
end
|
67
162
|
end
|
68
163
|
|
69
164
|
context 'with invalid user credentials' do
|
@@ -72,23 +167,31 @@ describe 'Resource Owner Password Credentials Flow' do
|
|
72
167
|
post password_token_endpoint_url(client: @client,
|
73
168
|
resource_owner_username: @resource_owner.name,
|
74
169
|
resource_owner_password: 'wrongpassword')
|
75
|
-
end.to_not
|
170
|
+
end.to_not(change { Doorkeeper::AccessToken.count })
|
76
171
|
end
|
77
172
|
|
78
173
|
it 'should not issue new token without credentials' do
|
79
174
|
expect do
|
80
175
|
post password_token_endpoint_url(client: @client)
|
81
|
-
end.to_not
|
176
|
+
end.to_not(change { Doorkeeper::AccessToken.count })
|
82
177
|
end
|
83
178
|
end
|
84
179
|
|
85
|
-
context 'with invalid client credentials' do
|
180
|
+
context 'with invalid confidential client credentials' do
|
86
181
|
it 'should not issue new token with bad client credentials' do
|
87
182
|
expect do
|
88
183
|
post password_token_endpoint_url(client_id: @client.uid,
|
89
184
|
client_secret: 'bad_secret',
|
90
185
|
resource_owner: @resource_owner)
|
91
|
-
end.to_not
|
186
|
+
end.to_not(change { Doorkeeper::AccessToken.count })
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
context 'with invalid public client id' do
|
191
|
+
it 'should not issue new token with bad client id' do
|
192
|
+
expect do
|
193
|
+
post password_token_endpoint_url(client_id: 'bad_id', resource_owner: @resource_owner)
|
194
|
+
end.to_not(change { Doorkeeper::AccessToken.count })
|
92
195
|
end
|
93
196
|
end
|
94
197
|
end
|
@@ -37,20 +37,62 @@ describe 'Refresh Token Flow' do
|
|
37
37
|
|
38
38
|
context 'refreshing the token' do
|
39
39
|
before do
|
40
|
-
@token =
|
40
|
+
@token = FactoryBot.create(
|
41
|
+
:access_token,
|
42
|
+
application: @client,
|
43
|
+
resource_owner_id: 1,
|
44
|
+
use_refresh_token: true
|
45
|
+
)
|
41
46
|
end
|
42
47
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
48
|
+
context "refresh_token revoked on use" do
|
49
|
+
it 'client request a token with refresh token' do
|
50
|
+
post refresh_token_endpoint_url(
|
51
|
+
client: @client, refresh_token: @token.refresh_token
|
52
|
+
)
|
53
|
+
should_have_json(
|
54
|
+
'refresh_token', Doorkeeper::AccessToken.last.refresh_token
|
55
|
+
)
|
56
|
+
expect(@token.reload).not_to be_revoked
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'client request a token with expired access token' do
|
60
|
+
@token.update_attribute :expires_in, -100
|
61
|
+
post refresh_token_endpoint_url(
|
62
|
+
client: @client, refresh_token: @token.refresh_token
|
63
|
+
)
|
64
|
+
should_have_json(
|
65
|
+
'refresh_token', Doorkeeper::AccessToken.last.refresh_token
|
66
|
+
)
|
67
|
+
expect(@token.reload).not_to be_revoked
|
68
|
+
end
|
47
69
|
end
|
48
70
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
71
|
+
context "refresh_token revoked on refresh_token request" do
|
72
|
+
before do
|
73
|
+
allow(Doorkeeper::AccessToken).to receive(:refresh_token_revoked_on_use?).and_return(false)
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'client request a token with refresh token' do
|
77
|
+
post refresh_token_endpoint_url(
|
78
|
+
client: @client, refresh_token: @token.refresh_token
|
79
|
+
)
|
80
|
+
should_have_json(
|
81
|
+
'refresh_token', Doorkeeper::AccessToken.last.refresh_token
|
82
|
+
)
|
83
|
+
expect(@token.reload).to be_revoked
|
84
|
+
end
|
85
|
+
|
86
|
+
it 'client request a token with expired access token' do
|
87
|
+
@token.update_attribute :expires_in, -100
|
88
|
+
post refresh_token_endpoint_url(
|
89
|
+
client: @client, refresh_token: @token.refresh_token
|
90
|
+
)
|
91
|
+
should_have_json(
|
92
|
+
'refresh_token', Doorkeeper::AccessToken.last.refresh_token
|
93
|
+
)
|
94
|
+
expect(@token.reload).to be_revoked
|
95
|
+
end
|
54
96
|
end
|
55
97
|
|
56
98
|
it 'client gets an error for invalid refresh token' do
|
@@ -59,14 +101,14 @@ describe 'Refresh Token Flow' do
|
|
59
101
|
should_have_json 'error', 'invalid_grant'
|
60
102
|
end
|
61
103
|
|
62
|
-
it 'client gets an error for revoked
|
104
|
+
it 'client gets an error for revoked access token' do
|
63
105
|
@token.revoke
|
64
106
|
post refresh_token_endpoint_url(client: @client, refresh_token: @token.refresh_token)
|
65
107
|
should_not_have_json 'refresh_token'
|
66
108
|
should_have_json 'error', 'invalid_grant'
|
67
109
|
end
|
68
110
|
|
69
|
-
it 'second of simultaneous client requests get an error for revoked
|
111
|
+
it 'second of simultaneous client requests get an error for revoked access token' do
|
70
112
|
allow_any_instance_of(Doorkeeper::AccessToken).to receive(:revoked?).and_return(false, true)
|
71
113
|
post refresh_token_endpoint_url(client: @client, refresh_token: @token.refresh_token)
|
72
114
|
|
@@ -79,20 +121,48 @@ describe 'Refresh Token Flow' do
|
|
79
121
|
before do
|
80
122
|
# enable password auth to simulate other devices
|
81
123
|
config_is_set(:grant_flows, ["password"])
|
82
|
-
config_is_set(:resource_owner_from_credentials)
|
124
|
+
config_is_set(:resource_owner_from_credentials) do
|
125
|
+
User.authenticate! params[:username], params[:password]
|
126
|
+
end
|
83
127
|
create_resource_owner
|
84
|
-
_another_token = post password_token_endpoint_url(
|
128
|
+
_another_token = post password_token_endpoint_url(
|
129
|
+
client: @client, resource_owner: @resource_owner
|
130
|
+
)
|
85
131
|
last_token.update_attribute :created_at, 5.seconds.ago
|
86
132
|
|
87
|
-
@token =
|
133
|
+
@token = FactoryBot.create(
|
134
|
+
:access_token,
|
135
|
+
application: @client,
|
136
|
+
resource_owner_id: @resource_owner.id,
|
137
|
+
use_refresh_token: true
|
138
|
+
)
|
88
139
|
@token.update_attribute :expires_in, -100
|
89
140
|
end
|
90
141
|
|
91
|
-
|
92
|
-
|
142
|
+
context "refresh_token revoked on use" do
|
143
|
+
it 'client request a token after creating another token with the same user' do
|
144
|
+
post refresh_token_endpoint_url(
|
145
|
+
client: @client, refresh_token: @token.refresh_token
|
146
|
+
)
|
147
|
+
|
148
|
+
should_have_json 'refresh_token', last_token.refresh_token
|
149
|
+
expect(@token.reload).not_to be_revoked
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
context "refresh_token revoked on refresh_token request" do
|
154
|
+
before do
|
155
|
+
allow(Doorkeeper::AccessToken).to receive(:refresh_token_revoked_on_use?).and_return(false)
|
156
|
+
end
|
157
|
+
|
158
|
+
it 'client request a token after creating another token with the same user' do
|
159
|
+
post refresh_token_endpoint_url(
|
160
|
+
client: @client, refresh_token: @token.refresh_token
|
161
|
+
)
|
93
162
|
|
94
|
-
|
95
|
-
|
163
|
+
should_have_json 'refresh_token', last_token.refresh_token
|
164
|
+
expect(@token.reload).to be_revoked
|
165
|
+
end
|
96
166
|
end
|
97
167
|
|
98
168
|
def last_token
|