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
@@ -6,137 +6,151 @@ describe 'Revoke Token Flow' do
|
|
6
6
|
end
|
7
7
|
|
8
8
|
context 'with default parameters' do
|
9
|
-
let(:client_application) {
|
9
|
+
let(:client_application) { FactoryBot.create :application }
|
10
10
|
let(:resource_owner) { User.create!(name: 'John', password: 'sekret') }
|
11
|
-
let(:
|
12
|
-
|
11
|
+
let(:access_token) do
|
12
|
+
FactoryBot.create(:access_token,
|
13
13
|
application: client_application,
|
14
14
|
resource_owner_id: resource_owner.id,
|
15
15
|
use_refresh_token: true)
|
16
16
|
end
|
17
|
-
let(:headers) { { 'HTTP_AUTHORIZATION' => "Bearer #{authorization_access_token.token}" } }
|
18
17
|
|
19
|
-
context '
|
20
|
-
|
21
|
-
|
18
|
+
context 'with authenticated, confidential OAuth 2.0 client/application' do
|
19
|
+
let(:headers) do
|
20
|
+
client_id = client_application.uid
|
21
|
+
client_secret = client_application.secret
|
22
|
+
credentials = Base64.encode64("#{client_id}:#{client_secret}")
|
23
|
+
{ 'HTTP_AUTHORIZATION' => "Basic #{credentials}" }
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'should revoke the access token provided' do
|
27
|
+
post revocation_token_endpoint_url, { token: access_token.token }, headers
|
28
|
+
|
29
|
+
access_token.reload
|
22
30
|
|
23
|
-
|
24
|
-
|
25
|
-
# has been revoked successfully or if the client submitted an invalid token.
|
26
|
-
expect(response).to be_success
|
27
|
-
expect(authorization_access_token).to_not be_revoked
|
31
|
+
expect(response).to be_successful
|
32
|
+
expect(access_token.revoked?).to be_truthy
|
28
33
|
end
|
29
|
-
end
|
30
34
|
|
31
|
-
|
32
|
-
|
35
|
+
it 'should revoke the refresh token provided' do
|
36
|
+
post revocation_token_endpoint_url, { token: access_token.refresh_token }, headers
|
37
|
+
|
38
|
+
access_token.reload
|
33
39
|
|
34
|
-
|
35
|
-
|
40
|
+
expect(response).to be_successful
|
41
|
+
expect(access_token.revoked?).to be_truthy
|
42
|
+
end
|
36
43
|
|
37
|
-
|
38
|
-
|
44
|
+
context 'with invalid token to revoke' do
|
45
|
+
it 'should not revoke any tokens and respond successfully' do
|
46
|
+
num_prev_revoked_tokens = Doorkeeper::AccessToken.where(revoked_at: nil).count
|
47
|
+
post revocation_token_endpoint_url, { token: 'I_AM_AN_INVALID_TOKEN' }, headers
|
39
48
|
|
40
|
-
|
41
|
-
|
42
|
-
|
49
|
+
# The authorization server responds with HTTP status code 200 even if
|
50
|
+
# token is invalid
|
51
|
+
expect(response).to be_successful
|
52
|
+
expect(Doorkeeper::AccessToken.where(revoked_at: nil).count).to eq(num_prev_revoked_tokens)
|
53
|
+
end
|
43
54
|
end
|
44
55
|
|
45
|
-
|
46
|
-
|
47
|
-
|
56
|
+
context 'with bad credentials and a valid token' do
|
57
|
+
let(:headers) do
|
58
|
+
client_id = client_application.uid
|
59
|
+
credentials = Base64.encode64("#{client_id}:poop")
|
60
|
+
{ 'HTTP_AUTHORIZATION' => "Basic #{credentials}" }
|
61
|
+
end
|
62
|
+
it 'should not revoke any tokens and respond successfully' do
|
63
|
+
post revocation_token_endpoint_url, { token: access_token.token }, headers
|
48
64
|
|
49
|
-
|
50
|
-
authorization_access_token.reload
|
65
|
+
access_token.reload
|
51
66
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
expect(authorization_access_token.revoked?).to be_falsey
|
67
|
+
expect(response).to be_successful
|
68
|
+
expect(access_token.revoked?).to be_falsey
|
69
|
+
end
|
56
70
|
end
|
57
|
-
end
|
58
71
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
72
|
+
context 'with no credentials and a valid token' do
|
73
|
+
it 'should not revoke any tokens and respond successfully' do
|
74
|
+
post revocation_token_endpoint_url, { token: access_token.token }
|
75
|
+
|
76
|
+
access_token.reload
|
77
|
+
|
78
|
+
expect(response).to be_successful
|
79
|
+
expect(access_token.revoked?).to be_falsey
|
80
|
+
end
|
65
81
|
end
|
66
82
|
|
67
|
-
|
68
|
-
|
83
|
+
context 'with valid token for another client application' do
|
84
|
+
let(:other_client_application) { FactoryBot.create :application }
|
85
|
+
let(:headers) do
|
86
|
+
client_id = other_client_application.uid
|
87
|
+
client_secret = other_client_application.secret
|
88
|
+
credentials = Base64.encode64("#{client_id}:#{client_secret}")
|
89
|
+
{ 'HTTP_AUTHORIZATION' => "Basic #{credentials}" }
|
90
|
+
end
|
69
91
|
|
70
|
-
|
71
|
-
|
92
|
+
it 'should not revoke the token as its unauthorized' do
|
93
|
+
post revocation_token_endpoint_url, { token: access_token.token }, headers
|
72
94
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
95
|
+
access_token.reload
|
96
|
+
|
97
|
+
expect(response).to be_successful
|
98
|
+
expect(access_token.revoked?).to be_falsey
|
99
|
+
end
|
77
100
|
end
|
78
101
|
end
|
79
102
|
|
80
|
-
context '
|
81
|
-
let(:
|
82
|
-
|
83
|
-
|
84
|
-
application: other_client_application,
|
103
|
+
context 'with public OAuth 2.0 client/application' do
|
104
|
+
let(:access_token) do
|
105
|
+
FactoryBot.create(:access_token,
|
106
|
+
application: nil,
|
85
107
|
resource_owner_id: resource_owner.id,
|
86
108
|
use_refresh_token: true)
|
87
109
|
end
|
88
110
|
|
89
|
-
it '
|
90
|
-
post revocation_token_endpoint_url, { token:
|
111
|
+
it 'should revoke the access token provided' do
|
112
|
+
post revocation_token_endpoint_url, { token: access_token.token }
|
91
113
|
|
92
|
-
|
93
|
-
authorization_access_token.reload
|
114
|
+
access_token.reload
|
94
115
|
|
95
|
-
expect(response).to
|
96
|
-
expect(
|
97
|
-
expect(Doorkeeper::AccessToken.by_refresh_token(token_to_revoke.refresh_token).revoked?).to be_falsey
|
98
|
-
expect(authorization_access_token.revoked?).to be_falsey
|
116
|
+
expect(response).to be_successful
|
117
|
+
expect(access_token.revoked?).to be_truthy
|
99
118
|
end
|
100
|
-
end
|
101
119
|
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
120
|
+
it 'should revoke the refresh token provided' do
|
121
|
+
post revocation_token_endpoint_url, { token: access_token.refresh_token }
|
122
|
+
|
123
|
+
access_token.reload
|
124
|
+
|
125
|
+
expect(response).to be_successful
|
126
|
+
expect(access_token.revoked?).to be_truthy
|
109
127
|
end
|
110
128
|
|
111
|
-
|
112
|
-
|
129
|
+
context 'with a valid token issued for a confidential client' do
|
130
|
+
let(:access_token) do
|
131
|
+
FactoryBot.create(:access_token,
|
132
|
+
application: client_application,
|
133
|
+
resource_owner_id: resource_owner.id,
|
134
|
+
use_refresh_token: true)
|
135
|
+
end
|
113
136
|
|
114
|
-
|
115
|
-
|
137
|
+
it 'should not revoke the access token provided' do
|
138
|
+
post revocation_token_endpoint_url, { token: access_token.token }
|
116
139
|
|
117
|
-
|
118
|
-
expect(token_to_revoke.revoked?).to be_falsey
|
119
|
-
expect(Doorkeeper::AccessToken.by_refresh_token(token_to_revoke.refresh_token).revoked?).to be_falsey
|
120
|
-
expect(authorization_access_token.revoked?).to be_falsey
|
121
|
-
end
|
122
|
-
end
|
140
|
+
access_token.reload
|
123
141
|
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
end
|
142
|
+
expect(response).to be_successful
|
143
|
+
expect(access_token.revoked?).to be_falsey
|
144
|
+
end
|
145
|
+
|
146
|
+
it 'should not revoke the refresh token provided' do
|
147
|
+
post revocation_token_endpoint_url, { token: access_token.token }
|
131
148
|
|
132
|
-
|
133
|
-
post revocation_token_endpoint_url, { token: token_to_revoke.refresh_token, token_type_hint: 'refresh_token' }, headers
|
134
|
-
authorization_access_token.reload
|
135
|
-
token_to_revoke.reload
|
149
|
+
access_token.reload
|
136
150
|
|
137
|
-
|
138
|
-
|
139
|
-
|
151
|
+
expect(response).to be_successful
|
152
|
+
expect(access_token.revoked?).to be_falsey
|
153
|
+
end
|
140
154
|
end
|
141
155
|
end
|
142
156
|
end
|
@@ -2,7 +2,7 @@ require 'spec_helper_integration'
|
|
2
2
|
|
3
3
|
describe 'ActionController::Metal API' do
|
4
4
|
before do
|
5
|
-
@client =
|
5
|
+
@client = FactoryBot.create(:application)
|
6
6
|
@resource = User.create!(name: 'Joe', password: 'sekret')
|
7
7
|
@token = client_is_authorized(@client, @resource)
|
8
8
|
end
|
@@ -2,7 +2,7 @@ require 'spec_helper_integration'
|
|
2
2
|
|
3
3
|
feature 'Private API' do
|
4
4
|
background do
|
5
|
-
@client =
|
5
|
+
@client = FactoryBot.create(:application)
|
6
6
|
@resource = User.create!(name: 'Joe', password: 'sekret')
|
7
7
|
@token = client_is_authorized(@client, @resource)
|
8
8
|
end
|
@@ -45,6 +45,10 @@ describe 'Custom controller for routes' do
|
|
45
45
|
expect(post('/space/oauth/revoke')).to route_to('custom_authorizations#revoke')
|
46
46
|
end
|
47
47
|
|
48
|
+
it 'POST /space/oauth/introspect routes to tokens controller' do
|
49
|
+
expect(post('/space/oauth/introspect')).to route_to('custom_authorizations#introspect')
|
50
|
+
end
|
51
|
+
|
48
52
|
it 'GET /space/oauth/applications routes to applications controller' do
|
49
53
|
expect(get('/space/oauth/applications')).to route_to('custom_authorizations#index')
|
50
54
|
end
|
@@ -21,6 +21,10 @@ describe 'Default routes' do
|
|
21
21
|
expect(post('/oauth/revoke')).to route_to('doorkeeper/tokens#revoke')
|
22
22
|
end
|
23
23
|
|
24
|
+
it 'POST /oauth/introspect routes to tokens controller' do
|
25
|
+
expect(post('/oauth/introspect')).to route_to('doorkeeper/tokens#introspect')
|
26
|
+
end
|
27
|
+
|
24
28
|
it 'GET /oauth/applications routes to applications controller' do
|
25
29
|
expect(get('/oauth/applications')).to route_to('doorkeeper/applications#index')
|
26
30
|
end
|
@@ -29,7 +33,7 @@ describe 'Default routes' do
|
|
29
33
|
expect(get('/oauth/authorized_applications')).to route_to('doorkeeper/authorized_applications#index')
|
30
34
|
end
|
31
35
|
|
32
|
-
it 'GET /oauth/token/info route to
|
36
|
+
it 'GET /oauth/token/info route to authorized tokeninfo controller' do
|
33
37
|
expect(get('/oauth/token/info')).to route_to('doorkeeper/token_info#show')
|
34
38
|
end
|
35
39
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,3 +1,19 @@
|
|
1
|
+
if ENV['TRAVIS']
|
2
|
+
require 'coveralls'
|
3
|
+
|
4
|
+
Coveralls.wear!('rails') do
|
5
|
+
add_filter('/spec/')
|
6
|
+
add_filter('/lib/generators/doorkeeper/templates/')
|
7
|
+
end
|
8
|
+
else
|
9
|
+
require 'simplecov'
|
10
|
+
|
11
|
+
SimpleCov.start do
|
12
|
+
add_filter('/spec/')
|
13
|
+
add_filter('/lib/generators/doorkeeper/templates/')
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
1
17
|
ENV['RAILS_ENV'] ||= 'test'
|
2
18
|
TABLE_NAME_PREFIX = ENV['table_name_prefix'] || nil
|
3
19
|
TABLE_NAME_SUFFIX = ENV['table_name_suffix'] || nil
|
@@ -11,7 +27,6 @@ require 'capybara/rspec'
|
|
11
27
|
require 'dummy/config/environment'
|
12
28
|
require 'rspec/rails'
|
13
29
|
require 'generator_spec/test_case'
|
14
|
-
require 'timecop'
|
15
30
|
require 'database_cleaner'
|
16
31
|
|
17
32
|
# Load JRuby SQLite3 if in that platform
|
@@ -21,10 +36,10 @@ begin
|
|
21
36
|
rescue LoadError
|
22
37
|
end
|
23
38
|
|
24
|
-
Rails.logger.info "====> Doorkeeper.orm = #{Doorkeeper.configuration.orm
|
39
|
+
Rails.logger.info "====> Doorkeeper.orm = #{Doorkeeper.configuration.orm}"
|
25
40
|
if Doorkeeper.configuration.orm == :active_record
|
26
|
-
Rails.logger.info "======> active_record.table_name_prefix = #{Rails.configuration.active_record.table_name_prefix
|
27
|
-
Rails.logger.info "======> active_record.table_name_suffix = #{Rails.configuration.active_record.table_name_suffix
|
41
|
+
Rails.logger.info "======> active_record.table_name_prefix = #{Rails.configuration.active_record.table_name_prefix}"
|
42
|
+
Rails.logger.info "======> active_record.table_name_suffix = #{Rails.configuration.active_record.table_name_suffix}"
|
28
43
|
end
|
29
44
|
Rails.logger.info "====> Rails version: #{Rails.version}"
|
30
45
|
Rails.logger.info "====> Ruby version: #{RUBY_VERSION}"
|
@@ -35,6 +50,9 @@ ENGINE_RAILS_ROOT = File.join(File.dirname(__FILE__), '../')
|
|
35
50
|
|
36
51
|
Dir["#{File.dirname(__FILE__)}/support/{dependencies,helpers,shared}/*.rb"].each { |f| require f }
|
37
52
|
|
53
|
+
# Remove after dropping support of Rails 4.2
|
54
|
+
require "#{File.dirname(__FILE__)}/support/http_method_shim.rb"
|
55
|
+
|
38
56
|
RSpec.configure do |config|
|
39
57
|
config.infer_spec_type_from_file_location!
|
40
58
|
config.mock_with :rspec
|
@@ -1,2 +1,2 @@
|
|
1
|
-
require '
|
2
|
-
|
1
|
+
require 'factory_bot'
|
2
|
+
FactoryBot.find_definitions
|
@@ -1,6 +1,6 @@
|
|
1
1
|
module ModelHelper
|
2
2
|
def client_exists(client_attributes = {})
|
3
|
-
@client =
|
3
|
+
@client = FactoryBot.create(:application, client_attributes)
|
4
4
|
end
|
5
5
|
|
6
6
|
def create_resource_owner
|
@@ -8,19 +8,25 @@ module ModelHelper
|
|
8
8
|
end
|
9
9
|
|
10
10
|
def authorization_code_exists(options = {})
|
11
|
-
@authorization =
|
11
|
+
@authorization = FactoryBot.create(:access_grant, options)
|
12
12
|
end
|
13
13
|
|
14
14
|
def access_grant_should_exist_for(client, resource_owner)
|
15
15
|
grant = Doorkeeper::AccessGrant.first
|
16
|
-
|
17
|
-
grant.
|
16
|
+
|
17
|
+
expect(grant.application).to have_attributes(id: client.id).
|
18
|
+
and(be_instance_of(Doorkeeper::Application))
|
19
|
+
|
20
|
+
expect(grant.resource_owner_id).to eq(resource_owner.id)
|
18
21
|
end
|
19
22
|
|
20
23
|
def access_token_should_exist_for(client, resource_owner)
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
+
token = Doorkeeper::AccessToken.first
|
25
|
+
|
26
|
+
expect(token.application).to have_attributes(id: client.id).
|
27
|
+
and(be_instance_of(Doorkeeper::Application))
|
28
|
+
|
29
|
+
expect(token.resource_owner_id).to eq(resource_owner.id)
|
24
30
|
end
|
25
31
|
|
26
32
|
def access_grant_should_not_exist
|
@@ -40,6 +46,27 @@ module ModelHelper
|
|
40
46
|
grant = Doorkeeper::AccessToken.last
|
41
47
|
expect(grant.scopes).to eq(Doorkeeper::OAuth::Scopes.from_array(args))
|
42
48
|
end
|
49
|
+
|
50
|
+
def uniqueness_error
|
51
|
+
case DOORKEEPER_ORM
|
52
|
+
when :active_record
|
53
|
+
ActiveRecord::RecordNotUnique
|
54
|
+
when :sequel
|
55
|
+
error_classes = [Sequel::UniqueConstraintViolation, Sequel::ValidationFailed]
|
56
|
+
proc { |error| expect(error.class).to be_in(error_classes) }
|
57
|
+
when :mongo_mapper
|
58
|
+
error_classes = [MongoMapper::DocumentNotValid, Mongo::OperationFailure]
|
59
|
+
proc { |error| expect(error.class).to be_in(error_classes) }
|
60
|
+
when /mongoid/
|
61
|
+
error_classes = [Mongoid::Errors::Validations]
|
62
|
+
error_classes << Moped::Errors::OperationFailure if defined?(::Moped) # Mongoid 4
|
63
|
+
error_classes << Mongo::Error::OperationFailure if defined?(::Mongo) # Mongoid 5
|
64
|
+
|
65
|
+
proc { |error| expect(error.class).to be_in(error_classes) }
|
66
|
+
else
|
67
|
+
raise "'#{DOORKEEPER_ORM}' ORM is not supported!"
|
68
|
+
end
|
69
|
+
end
|
43
70
|
end
|
44
71
|
|
45
72
|
RSpec.configuration.send :include, ModelHelper
|
@@ -27,6 +27,14 @@ module RequestSpecHelper
|
|
27
27
|
URI.parse(page.current_url)
|
28
28
|
end
|
29
29
|
|
30
|
+
def request_response
|
31
|
+
respond_to?(:response) ? response : page.driver.response
|
32
|
+
end
|
33
|
+
|
34
|
+
def json_response
|
35
|
+
JSON.parse(request_response.body)
|
36
|
+
end
|
37
|
+
|
30
38
|
def should_have_header(header, value)
|
31
39
|
expect(headers[header]).to eq(value)
|
32
40
|
end
|
@@ -44,15 +52,15 @@ module RequestSpecHelper
|
|
44
52
|
end
|
45
53
|
|
46
54
|
def should_have_json(key, value)
|
47
|
-
expect(
|
55
|
+
expect(json_response.fetch(key)).to eq(value)
|
48
56
|
end
|
49
57
|
|
50
58
|
def should_have_json_within(key, value, range)
|
51
|
-
expect(
|
59
|
+
expect(json_response.fetch(key)).to be_within(range).of(value)
|
52
60
|
end
|
53
61
|
|
54
62
|
def should_not_have_json(key)
|
55
|
-
expect(
|
63
|
+
expect(json_response).not_to have_key(key)
|
56
64
|
end
|
57
65
|
|
58
66
|
def sign_in
|
@@ -60,16 +68,20 @@ module RequestSpecHelper
|
|
60
68
|
click_on 'Sign in'
|
61
69
|
end
|
62
70
|
|
71
|
+
def create_access_token(authorization_code, client)
|
72
|
+
page.driver.post token_endpoint_url(code: authorization_code, client: client)
|
73
|
+
end
|
74
|
+
|
63
75
|
def i_should_see_translated_error_message(key)
|
64
76
|
i_should_see translated_error_message(key)
|
65
77
|
end
|
66
78
|
|
67
79
|
def translated_error_message(key)
|
68
|
-
I18n.translate key, scope: [
|
80
|
+
I18n.translate key, scope: %i[doorkeeper errors messages]
|
69
81
|
end
|
70
82
|
|
71
83
|
def response_status_should_be(status)
|
72
|
-
expect(
|
84
|
+
expect(request_response.status.to_i).to eq(status)
|
73
85
|
end
|
74
86
|
end
|
75
87
|
|
@@ -2,10 +2,10 @@ module UrlHelper
|
|
2
2
|
def token_endpoint_url(options = {})
|
3
3
|
parameters = {
|
4
4
|
code: options[:code],
|
5
|
-
client_id: options[:client_id]
|
5
|
+
client_id: options[:client_id] || (options[:client] ? options[:client].uid : nil),
|
6
6
|
client_secret: options[:client_secret] || (options[:client] ? options[:client].secret : nil),
|
7
7
|
redirect_uri: options[:redirect_uri] || (options[:client] ? options[:client].redirect_uri : nil),
|
8
|
-
grant_type: options[:grant_type]
|
8
|
+
grant_type: options[:grant_type] || 'authorization_code'
|
9
9
|
}
|
10
10
|
"/oauth/token?#{build_query(parameters)}"
|
11
11
|
end
|
@@ -13,10 +13,11 @@ module UrlHelper
|
|
13
13
|
def password_token_endpoint_url(options = {})
|
14
14
|
parameters = {
|
15
15
|
code: options[:code],
|
16
|
-
client_id: options[:client_id]
|
16
|
+
client_id: options[:client_id] || (options[:client] ? options[:client].uid : nil),
|
17
17
|
client_secret: options[:client_secret] || (options[:client] ? options[:client].secret : nil),
|
18
18
|
username: options[:resource_owner_username] || (options[:resource_owner] ? options[:resource_owner].name : nil),
|
19
19
|
password: options[:resource_owner_password] || (options[:resource_owner] ? options[:resource_owner].password : nil),
|
20
|
+
scope: options[:scope],
|
20
21
|
grant_type: 'password'
|
21
22
|
}
|
22
23
|
"/oauth/token?#{build_query(parameters)}"
|
@@ -24,21 +25,21 @@ module UrlHelper
|
|
24
25
|
|
25
26
|
def authorization_endpoint_url(options = {})
|
26
27
|
parameters = {
|
27
|
-
client_id: options[:client_id]
|
28
|
-
redirect_uri: options[:redirect_uri]
|
28
|
+
client_id: options[:client_id] || options[:client].uid,
|
29
|
+
redirect_uri: options[:redirect_uri] || options[:client].redirect_uri,
|
29
30
|
response_type: options[:response_type] || 'code',
|
30
31
|
scope: options[:scope],
|
31
32
|
state: options[:state]
|
32
|
-
}.reject { |
|
33
|
+
}.reject { |_, v| v.blank? }
|
33
34
|
"/oauth/authorize?#{build_query(parameters)}"
|
34
35
|
end
|
35
36
|
|
36
37
|
def refresh_token_endpoint_url(options = {})
|
37
38
|
parameters = {
|
38
39
|
refresh_token: options[:refresh_token],
|
39
|
-
client_id: options[:client_id]
|
40
|
+
client_id: options[:client_id] || options[:client].uid,
|
40
41
|
client_secret: options[:client_secret] || options[:client].secret,
|
41
|
-
grant_type: options[:grant_type]
|
42
|
+
grant_type: options[:grant_type] || 'refresh_token'
|
42
43
|
}
|
43
44
|
"/oauth/token?#{build_query(parameters)}"
|
44
45
|
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# Rails 5 deprecates calling HTTP action methods with positional arguments
|
2
|
+
# in favor of keyword arguments. However, the keyword argument form is only
|
3
|
+
# supported in Rails 5+. Since we support back to 4, we need some sort of shim
|
4
|
+
# to avoid super noisy deprecations when running tests.
|
5
|
+
module RoutingHTTPMethodShim
|
6
|
+
def get(path, params = {}, headers = nil)
|
7
|
+
super(path, params: params, headers: headers)
|
8
|
+
end
|
9
|
+
|
10
|
+
def post(path, params = {}, headers = nil)
|
11
|
+
super(path, params: params, headers: headers)
|
12
|
+
end
|
13
|
+
|
14
|
+
def put(path, params = {}, headers = nil)
|
15
|
+
super(path, params: params, headers: headers)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
module ControllerHTTPMethodShim
|
20
|
+
def get(path, params = {})
|
21
|
+
super(path, params: params)
|
22
|
+
end
|
23
|
+
|
24
|
+
def post(path, params = {})
|
25
|
+
super(path, params: params)
|
26
|
+
end
|
27
|
+
|
28
|
+
def put(path, params = {})
|
29
|
+
super(path, params: params)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
if ::Rails::VERSION::MAJOR >= 5
|
34
|
+
RSpec.configure do |config|
|
35
|
+
config.include ControllerHTTPMethodShim, type: :controller
|
36
|
+
config.include RoutingHTTPMethodShim, type: :request
|
37
|
+
end
|
38
|
+
end
|
@@ -1,28 +1,33 @@
|
|
1
1
|
shared_context 'valid token', token: :valid do
|
2
|
-
let
|
3
|
-
'1A2B3C4D'
|
4
|
-
end
|
2
|
+
let(:token_string) { '1A2B3C4D' }
|
5
3
|
|
6
4
|
let :token do
|
7
|
-
double(Doorkeeper::AccessToken,
|
5
|
+
double(Doorkeeper::AccessToken,
|
6
|
+
accessible?: true, includes_scope?: true, acceptable?: true,
|
7
|
+
previous_refresh_token: "", revoke_previous_refresh_token!: true)
|
8
8
|
end
|
9
9
|
|
10
10
|
before :each do
|
11
|
-
allow(
|
11
|
+
allow(
|
12
|
+
Doorkeeper::AccessToken
|
13
|
+
).to receive(:by_token).with(token_string).and_return(token)
|
12
14
|
end
|
13
15
|
end
|
14
16
|
|
15
17
|
shared_context 'invalid token', token: :invalid do
|
16
|
-
let
|
17
|
-
'1A2B3C4D'
|
18
|
-
end
|
18
|
+
let(:token_string) { '1A2B3C4D' }
|
19
19
|
|
20
20
|
let :token do
|
21
|
-
double(Doorkeeper::AccessToken,
|
21
|
+
double(Doorkeeper::AccessToken,
|
22
|
+
accessible?: false, revoked?: false, expired?: false,
|
23
|
+
includes_scope?: false, acceptable?: false,
|
24
|
+
previous_refresh_token: "", revoke_previous_refresh_token!: true)
|
22
25
|
end
|
23
26
|
|
24
27
|
before :each do
|
25
|
-
allow(
|
28
|
+
allow(
|
29
|
+
Doorkeeper::AccessToken
|
30
|
+
).to receive(:by_token).with(token_string).and_return(token)
|
26
31
|
end
|
27
32
|
end
|
28
33
|
|
@@ -34,19 +34,19 @@ shared_examples 'a unique token' do
|
|
34
34
|
end
|
35
35
|
|
36
36
|
it 'is not valid if token exists' do
|
37
|
-
token1 =
|
38
|
-
token2 =
|
37
|
+
token1 = FactoryBot.create factory_name
|
38
|
+
token2 = FactoryBot.create factory_name
|
39
39
|
token2.token = token1.token
|
40
40
|
expect(token2).not_to be_valid
|
41
41
|
end
|
42
42
|
|
43
43
|
it 'expects database to throw an error when tokens are the same' do
|
44
|
-
token1 =
|
45
|
-
token2 =
|
44
|
+
token1 = FactoryBot.create factory_name
|
45
|
+
token2 = FactoryBot.create factory_name
|
46
46
|
token2.token = token1.token
|
47
47
|
expect do
|
48
48
|
token2.save!(validate: false)
|
49
|
-
end.to raise_error(
|
49
|
+
end.to raise_error(uniqueness_error)
|
50
50
|
end
|
51
51
|
end
|
52
52
|
end
|