doorkeeper 5.0.0 → 5.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/.hound.yml +2 -1
- data/.rubocop.yml +37 -4
- data/.travis.yml +16 -21
- data/Appraisals +29 -7
- data/Dangerfile +67 -0
- data/Gemfile +19 -5
- data/NEWS.md +107 -10
- data/README.md +75 -470
- data/Rakefile +10 -8
- data/app/controllers/doorkeeper/application_controller.rb +3 -2
- data/app/controllers/doorkeeper/application_metal_controller.rb +4 -13
- data/app/controllers/doorkeeper/applications_controller.rb +21 -7
- data/app/controllers/doorkeeper/authorizations_controller.rb +3 -3
- data/app/controllers/doorkeeper/authorized_applications_controller.rb +2 -0
- data/app/controllers/doorkeeper/token_info_controller.rb +4 -2
- data/app/controllers/doorkeeper/tokens_controller.rb +13 -11
- data/app/helpers/doorkeeper/dashboard_helper.rb +3 -1
- data/app/validators/redirect_uri_validator.rb +7 -2
- data/app/views/doorkeeper/applications/_form.html.erb +6 -0
- data/app/views/doorkeeper/applications/show.html.erb +1 -1
- data/app/views/layouts/doorkeeper/admin.html.erb +5 -3
- data/bin/console +16 -0
- data/config/locales/en.yml +1 -0
- data/doorkeeper.gemspec +28 -24
- data/gemfiles/rails_5_0.gemfile +9 -4
- data/gemfiles/rails_5_1.gemfile +9 -4
- data/gemfiles/rails_5_2.gemfile +10 -5
- data/gemfiles/rails_6_0.gemfile +17 -0
- data/gemfiles/rails_master.gemfile +9 -9
- data/lib/doorkeeper/config/option.rb +64 -0
- data/lib/doorkeeper/config.rb +197 -76
- data/lib/doorkeeper/engine.rb +3 -1
- data/lib/doorkeeper/errors.rb +17 -0
- data/lib/doorkeeper/grape/authorization_decorator.rb +6 -4
- data/lib/doorkeeper/grape/helpers.rb +5 -3
- data/lib/doorkeeper/helpers/controller.rb +5 -2
- data/lib/doorkeeper/models/access_grant_mixin.rb +25 -6
- data/lib/doorkeeper/models/access_token_mixin.rb +68 -22
- data/lib/doorkeeper/models/application_mixin.rb +45 -1
- data/lib/doorkeeper/models/concerns/accessible.rb +2 -0
- data/lib/doorkeeper/models/concerns/expirable.rb +6 -2
- data/lib/doorkeeper/models/concerns/orderable.rb +2 -0
- data/lib/doorkeeper/models/concerns/ownership.rb +3 -6
- data/lib/doorkeeper/models/concerns/reusable.rb +19 -0
- data/lib/doorkeeper/models/concerns/revocable.rb +4 -1
- data/lib/doorkeeper/models/concerns/scopes.rb +7 -1
- data/lib/doorkeeper/models/concerns/secret_storable.rb +108 -0
- data/lib/doorkeeper/oauth/authorization/code.rb +4 -2
- data/lib/doorkeeper/oauth/authorization/context.rb +2 -0
- data/lib/doorkeeper/oauth/authorization/token.rb +14 -7
- data/lib/doorkeeper/oauth/authorization/uri_builder.rb +3 -1
- data/lib/doorkeeper/oauth/authorization_code_request.rb +8 -4
- data/lib/doorkeeper/oauth/base_request.rb +2 -0
- data/lib/doorkeeper/oauth/base_response.rb +2 -0
- data/lib/doorkeeper/oauth/client/credentials.rb +2 -0
- data/lib/doorkeeper/oauth/client.rb +3 -1
- data/lib/doorkeeper/oauth/client_credentials/creator.rb +2 -0
- data/lib/doorkeeper/oauth/client_credentials/issuer.rb +2 -0
- data/lib/doorkeeper/oauth/client_credentials/validation.rb +7 -4
- data/lib/doorkeeper/oauth/client_credentials_request.rb +3 -1
- data/lib/doorkeeper/oauth/code_request.rb +2 -0
- data/lib/doorkeeper/oauth/code_response.rb +4 -2
- data/lib/doorkeeper/oauth/error.rb +2 -0
- data/lib/doorkeeper/oauth/error_response.rb +20 -6
- data/lib/doorkeeper/oauth/forbidden_token_response.rb +10 -3
- data/lib/doorkeeper/oauth/helpers/scope_checker.rb +25 -8
- data/lib/doorkeeper/oauth/helpers/unique_token.rb +15 -1
- data/lib/doorkeeper/oauth/helpers/uri_checker.rb +42 -3
- data/lib/doorkeeper/oauth/invalid_token_response.rb +22 -0
- data/lib/doorkeeper/oauth/password_access_token_request.rb +9 -2
- data/lib/doorkeeper/oauth/pre_authorization.rb +13 -5
- data/lib/doorkeeper/oauth/refresh_token_request.rb +15 -4
- data/lib/doorkeeper/oauth/scopes.rb +7 -3
- data/lib/doorkeeper/oauth/token.rb +4 -2
- data/lib/doorkeeper/oauth/token_introspection.rb +76 -8
- data/lib/doorkeeper/oauth/token_request.rb +2 -0
- data/lib/doorkeeper/oauth/token_response.rb +11 -9
- data/lib/doorkeeper/oauth.rb +5 -5
- data/lib/doorkeeper/orm/active_record/access_grant.rb +27 -13
- data/lib/doorkeeper/orm/active_record/access_token.rb +6 -13
- data/lib/doorkeeper/orm/active_record/application.rb +26 -7
- data/lib/doorkeeper/orm/active_record/stale_records_cleaner.rb +10 -3
- data/lib/doorkeeper/orm/active_record.rb +8 -6
- data/lib/doorkeeper/rails/helpers.rb +5 -1
- data/lib/doorkeeper/rails/routes/mapper.rb +2 -0
- data/lib/doorkeeper/rails/routes/mapping.rb +9 -7
- data/lib/doorkeeper/rails/routes.rb +19 -12
- data/lib/doorkeeper/rake/db.rake +17 -17
- data/lib/doorkeeper/rake.rb +1 -1
- data/lib/doorkeeper/request/authorization_code.rb +2 -0
- data/lib/doorkeeper/request/client_credentials.rb +2 -0
- data/lib/doorkeeper/request/code.rb +2 -0
- data/lib/doorkeeper/request/password.rb +2 -0
- data/lib/doorkeeper/request/refresh_token.rb +2 -0
- data/lib/doorkeeper/request/strategy.rb +2 -0
- data/lib/doorkeeper/request/token.rb +2 -0
- data/lib/doorkeeper/request.rb +3 -1
- data/lib/doorkeeper/secret_storing/base.rb +64 -0
- data/lib/doorkeeper/secret_storing/bcrypt.rb +60 -0
- data/lib/doorkeeper/secret_storing/plain.rb +33 -0
- data/lib/doorkeeper/secret_storing/sha256_hash.rb +26 -0
- data/lib/doorkeeper/server.rb +2 -0
- data/lib/doorkeeper/stale_records_cleaner.rb +20 -0
- data/lib/doorkeeper/validations.rb +2 -0
- data/lib/doorkeeper/version.rb +4 -2
- data/lib/doorkeeper.rb +69 -59
- data/lib/generators/doorkeeper/application_owner_generator.rb +10 -9
- data/lib/generators/doorkeeper/confidential_applications_generator.rb +10 -9
- data/lib/generators/doorkeeper/install_generator.rb +11 -9
- data/lib/generators/doorkeeper/migration_generator.rb +9 -9
- data/lib/generators/doorkeeper/pkce_generator.rb +10 -9
- data/lib/generators/doorkeeper/previous_refresh_token_generator.rb +10 -9
- data/lib/generators/doorkeeper/templates/initializer.rb +138 -13
- data/lib/generators/doorkeeper/templates/migration.rb.erb +17 -10
- data/lib/generators/doorkeeper/views_generator.rb +6 -4
- data/spec/controllers/application_metal_controller_spec.rb +24 -10
- data/spec/controllers/applications_controller_spec.rb +76 -78
- data/spec/controllers/authorizations_controller_spec.rb +189 -142
- data/spec/controllers/protected_resources_controller_spec.rb +111 -67
- data/spec/controllers/token_info_controller_spec.rb +14 -12
- data/spec/controllers/tokens_controller_spec.rb +170 -112
- data/spec/dummy/Rakefile +3 -1
- data/spec/dummy/app/controllers/application_controller.rb +3 -1
- data/spec/dummy/app/controllers/custom_authorizations_controller.rb +3 -1
- data/spec/dummy/app/controllers/full_protected_resources_controller.rb +4 -2
- data/spec/dummy/app/controllers/home_controller.rb +6 -5
- data/spec/dummy/app/controllers/metal_controller.rb +2 -0
- data/spec/dummy/app/controllers/semi_protected_resources_controller.rb +4 -2
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/models/user.rb +2 -0
- data/spec/dummy/config/application.rb +26 -2
- data/spec/dummy/config/boot.rb +2 -4
- data/spec/dummy/config/environment.rb +1 -1
- data/spec/dummy/config/environments/development.rb +2 -0
- data/spec/dummy/config/environments/production.rb +2 -0
- data/spec/dummy/config/environments/test.rb +4 -2
- data/spec/dummy/config/initializers/backtrace_silencers.rb +2 -0
- data/spec/dummy/config/initializers/doorkeeper.rb +7 -3
- data/spec/dummy/config/initializers/secret_token.rb +3 -1
- data/spec/dummy/config/initializers/session_store.rb +3 -1
- data/spec/dummy/config/initializers/wrap_parameters.rb +2 -0
- data/spec/dummy/config.ru +3 -1
- data/spec/dummy/db/migrate/20151223192035_create_doorkeeper_tables.rb +20 -13
- data/spec/dummy/db/migrate/20151223200000_add_owner_to_application.rb +1 -1
- data/spec/dummy/db/migrate/20170822064514_enable_pkce.rb +2 -0
- data/spec/dummy/db/schema.rb +1 -1
- data/spec/dummy/script/rails +7 -4
- data/spec/factories.rb +11 -9
- data/spec/generators/application_owner_generator_spec.rb +13 -26
- data/spec/generators/confidential_applications_generator_spec.rb +12 -28
- data/spec/generators/install_generator_spec.rb +19 -14
- data/spec/generators/migration_generator_spec.rb +13 -26
- data/spec/generators/pkce_generator_spec.rb +11 -26
- data/spec/generators/previous_refresh_token_generator_spec.rb +16 -29
- data/spec/generators/templates/routes.rb +2 -1
- data/spec/generators/views_generator_spec.rb +14 -12
- data/spec/grape/grape_integration_spec.rb +35 -33
- data/spec/helpers/doorkeeper/dashboard_helper_spec.rb +9 -7
- data/spec/lib/config_spec.rb +290 -104
- data/spec/lib/doorkeeper_spec.rb +8 -6
- data/spec/lib/models/expirable_spec.rb +22 -8
- data/spec/lib/models/reusable_spec.rb +40 -0
- data/spec/lib/models/revocable_spec.rb +8 -6
- data/spec/lib/models/scopes_spec.rb +27 -13
- data/spec/lib/models/secret_storable_spec.rb +135 -0
- data/spec/lib/oauth/authorization/uri_builder_spec.rb +17 -15
- data/spec/lib/oauth/authorization_code_request_spec.rb +43 -17
- data/spec/lib/oauth/base_request_spec.rb +24 -12
- data/spec/lib/oauth/base_response_spec.rb +3 -1
- data/spec/lib/oauth/client/credentials_spec.rb +26 -24
- data/spec/lib/oauth/client_credentials/creator_spec.rb +56 -10
- data/spec/lib/oauth/client_credentials/issuer_spec.rb +27 -20
- data/spec/lib/oauth/client_credentials/validation_spec.rb +21 -15
- data/spec/lib/oauth/client_credentials_integration_spec.rb +8 -6
- data/spec/lib/oauth/client_credentials_request_spec.rb +27 -21
- data/spec/lib/oauth/client_spec.rb +15 -13
- data/spec/lib/oauth/code_request_spec.rb +10 -8
- data/spec/lib/oauth/code_response_spec.rb +9 -7
- data/spec/lib/oauth/error_response_spec.rb +19 -11
- data/spec/lib/oauth/error_spec.rb +4 -2
- data/spec/lib/oauth/forbidden_token_response_spec.rb +7 -5
- data/spec/lib/oauth/helpers/scope_checker_spec.rb +68 -31
- data/spec/lib/oauth/helpers/unique_token_spec.rb +8 -6
- data/spec/lib/oauth/helpers/uri_checker_spec.rb +124 -93
- data/spec/lib/oauth/invalid_token_response_spec.rb +3 -1
- data/spec/lib/oauth/password_access_token_request_spec.rb +95 -34
- data/spec/lib/oauth/pre_authorization_spec.rb +80 -54
- data/spec/lib/oauth/refresh_token_request_spec.rb +46 -39
- data/spec/lib/oauth/scopes_spec.rb +63 -61
- data/spec/lib/oauth/token_request_spec.rb +80 -25
- data/spec/lib/oauth/token_response_spec.rb +40 -38
- data/spec/lib/oauth/token_spec.rb +64 -45
- data/spec/lib/request/strategy_spec.rb +3 -1
- data/spec/lib/secret_storing/base_spec.rb +60 -0
- data/spec/lib/secret_storing/bcrypt_spec.rb +49 -0
- data/spec/lib/secret_storing/plain_spec.rb +44 -0
- data/spec/lib/secret_storing/sha256_hash_spec.rb +48 -0
- data/spec/lib/server_spec.rb +20 -18
- data/spec/lib/{orm/active_record/stale_records_cleaner_spec.rb → stale_records_cleaner_spec.rb} +28 -18
- data/spec/models/doorkeeper/access_grant_spec.rb +80 -15
- data/spec/models/doorkeeper/access_token_spec.rb +212 -83
- data/spec/models/doorkeeper/application_spec.rb +146 -49
- data/spec/requests/applications/applications_request_spec.rb +100 -68
- data/spec/requests/applications/authorized_applications_spec.rb +20 -18
- data/spec/requests/endpoints/authorization_spec.rb +27 -25
- data/spec/requests/endpoints/token_spec.rb +38 -36
- data/spec/requests/flows/authorization_code_errors_spec.rb +27 -25
- data/spec/requests/flows/authorization_code_spec.rb +260 -158
- data/spec/requests/flows/client_credentials_spec.rb +54 -52
- data/spec/requests/flows/implicit_grant_errors_spec.rb +11 -9
- data/spec/requests/flows/implicit_grant_spec.rb +27 -25
- data/spec/requests/flows/password_spec.rb +64 -56
- data/spec/requests/flows/refresh_token_spec.rb +91 -32
- data/spec/requests/flows/revoke_token_spec.rb +49 -63
- data/spec/requests/flows/skip_authorization_spec.rb +23 -21
- data/spec/requests/protected_resources/metal_spec.rb +7 -5
- data/spec/requests/protected_resources/private_api_spec.rb +37 -35
- data/spec/routing/custom_controller_routes_spec.rb +71 -65
- data/spec/routing/default_routes_spec.rb +22 -20
- data/spec/routing/scoped_routes_spec.rb +20 -18
- data/spec/spec_helper.rb +15 -13
- data/spec/spec_helper_integration.rb +3 -1
- data/spec/support/dependencies/factory_bot.rb +3 -1
- data/spec/support/doorkeeper_rspec.rb +5 -2
- data/spec/support/helpers/access_token_request_helper.rb +3 -1
- data/spec/support/helpers/authorization_request_helper.rb +4 -2
- data/spec/support/helpers/config_helper.rb +2 -0
- data/spec/support/helpers/model_helper.rb +11 -5
- data/spec/support/helpers/request_spec_helper.rb +5 -3
- data/spec/support/helpers/url_helper.rb +20 -18
- data/spec/support/http_method_shim.rb +4 -9
- data/spec/support/orm/active_record.rb +3 -1
- data/spec/support/shared/controllers_shared_context.rb +68 -10
- data/spec/support/shared/hashing_shared_context.rb +36 -0
- data/spec/support/shared/models_shared_examples.rb +12 -10
- data/spec/validators/redirect_uri_validator_spec.rb +76 -47
- data/spec/version/version_spec.rb +7 -5
- metadata +70 -21
- data/gemfiles/rails_4_2.gemfile +0 -13
- data/spec/dummy/config/initializers/new_framework_defaults.rb +0 -10
|
@@ -1,41 +1,44 @@
|
|
|
1
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
require "spec_helper"
|
|
4
|
+
|
|
5
|
+
describe "Refresh Token Flow" do
|
|
4
6
|
before do
|
|
5
7
|
Doorkeeper.configure do
|
|
6
8
|
orm DOORKEEPER_ORM
|
|
7
9
|
use_refresh_token
|
|
8
10
|
end
|
|
11
|
+
|
|
9
12
|
client_exists
|
|
10
13
|
end
|
|
11
14
|
|
|
12
|
-
context
|
|
15
|
+
context "issuing a refresh token" do
|
|
13
16
|
before do
|
|
14
17
|
authorization_code_exists application: @client
|
|
15
18
|
end
|
|
16
19
|
|
|
17
|
-
it
|
|
20
|
+
it "client gets the refresh token and refreshes it" do
|
|
18
21
|
post token_endpoint_url(code: @authorization.token, client: @client)
|
|
19
22
|
|
|
20
23
|
token = Doorkeeper::AccessToken.first
|
|
21
24
|
|
|
22
|
-
should_have_json
|
|
23
|
-
should_have_json
|
|
25
|
+
should_have_json "access_token", token.token
|
|
26
|
+
should_have_json "refresh_token", token.refresh_token
|
|
24
27
|
|
|
25
28
|
expect(@authorization.reload).to be_revoked
|
|
26
29
|
|
|
27
30
|
post refresh_token_endpoint_url(client: @client, refresh_token: token.refresh_token)
|
|
28
31
|
|
|
29
32
|
new_token = Doorkeeper::AccessToken.last
|
|
30
|
-
should_have_json
|
|
31
|
-
should_have_json
|
|
33
|
+
should_have_json "access_token", new_token.token
|
|
34
|
+
should_have_json "refresh_token", new_token.refresh_token
|
|
32
35
|
|
|
33
36
|
expect(token.token).not_to eq(new_token.token)
|
|
34
37
|
expect(token.refresh_token).not_to eq(new_token.refresh_token)
|
|
35
38
|
end
|
|
36
39
|
end
|
|
37
40
|
|
|
38
|
-
context
|
|
41
|
+
context "refreshing the token" do
|
|
39
42
|
before do
|
|
40
43
|
@token = FactoryBot.create(
|
|
41
44
|
:access_token,
|
|
@@ -46,23 +49,23 @@ describe 'Refresh Token Flow' do
|
|
|
46
49
|
end
|
|
47
50
|
|
|
48
51
|
context "refresh_token revoked on use" do
|
|
49
|
-
it
|
|
52
|
+
it "client request a token with refresh token" do
|
|
50
53
|
post refresh_token_endpoint_url(
|
|
51
54
|
client: @client, refresh_token: @token.refresh_token
|
|
52
55
|
)
|
|
53
56
|
should_have_json(
|
|
54
|
-
|
|
57
|
+
"refresh_token", Doorkeeper::AccessToken.last.refresh_token
|
|
55
58
|
)
|
|
56
59
|
expect(@token.reload).not_to be_revoked
|
|
57
60
|
end
|
|
58
61
|
|
|
59
|
-
it
|
|
62
|
+
it "client request a token with expired access token" do
|
|
60
63
|
@token.update_attribute :expires_in, -100
|
|
61
64
|
post refresh_token_endpoint_url(
|
|
62
65
|
client: @client, refresh_token: @token.refresh_token
|
|
63
66
|
)
|
|
64
67
|
should_have_json(
|
|
65
|
-
|
|
68
|
+
"refresh_token", Doorkeeper::AccessToken.last.refresh_token
|
|
66
69
|
)
|
|
67
70
|
expect(@token.reload).not_to be_revoked
|
|
68
71
|
end
|
|
@@ -73,51 +76,107 @@ describe 'Refresh Token Flow' do
|
|
|
73
76
|
allow(Doorkeeper::AccessToken).to receive(:refresh_token_revoked_on_use?).and_return(false)
|
|
74
77
|
end
|
|
75
78
|
|
|
76
|
-
it
|
|
79
|
+
it "client request a token with refresh token" do
|
|
77
80
|
post refresh_token_endpoint_url(
|
|
78
81
|
client: @client, refresh_token: @token.refresh_token
|
|
79
82
|
)
|
|
80
83
|
should_have_json(
|
|
81
|
-
|
|
84
|
+
"refresh_token", Doorkeeper::AccessToken.last.refresh_token
|
|
82
85
|
)
|
|
83
86
|
expect(@token.reload).to be_revoked
|
|
84
87
|
end
|
|
85
88
|
|
|
86
|
-
it
|
|
89
|
+
it "client request a token with expired access token" do
|
|
87
90
|
@token.update_attribute :expires_in, -100
|
|
88
91
|
post refresh_token_endpoint_url(
|
|
89
92
|
client: @client, refresh_token: @token.refresh_token
|
|
90
93
|
)
|
|
91
94
|
should_have_json(
|
|
92
|
-
|
|
95
|
+
"refresh_token", Doorkeeper::AccessToken.last.refresh_token
|
|
93
96
|
)
|
|
94
97
|
expect(@token.reload).to be_revoked
|
|
95
98
|
end
|
|
96
99
|
end
|
|
97
100
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
101
|
+
context "public & private clients" do
|
|
102
|
+
let(:public_client) do
|
|
103
|
+
FactoryBot.create(
|
|
104
|
+
:application,
|
|
105
|
+
confidential: false
|
|
106
|
+
)
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
let(:token_for_private_client) do
|
|
110
|
+
FactoryBot.create(
|
|
111
|
+
:access_token,
|
|
112
|
+
application: @client,
|
|
113
|
+
resource_owner_id: 1,
|
|
114
|
+
use_refresh_token: true
|
|
115
|
+
)
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
let(:token_for_public_client) do
|
|
119
|
+
FactoryBot.create(
|
|
120
|
+
:access_token,
|
|
121
|
+
application: public_client,
|
|
122
|
+
resource_owner_id: 1,
|
|
123
|
+
use_refresh_token: true
|
|
124
|
+
)
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
it "issues a new token without client_secret when refresh token was issued to a public client" do
|
|
128
|
+
post refresh_token_endpoint_url(
|
|
129
|
+
client_id: public_client.uid,
|
|
130
|
+
refresh_token: token_for_public_client.refresh_token
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
new_token = Doorkeeper::AccessToken.last
|
|
134
|
+
should_have_json "access_token", new_token.token
|
|
135
|
+
should_have_json "refresh_token", new_token.refresh_token
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
it "returns an error without credentials" do
|
|
139
|
+
post refresh_token_endpoint_url(refresh_token: token_for_private_client.refresh_token)
|
|
140
|
+
|
|
141
|
+
should_not_have_json "refresh_token"
|
|
142
|
+
should_have_json "error", "invalid_grant"
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
it "returns an error with wrong credentials" do
|
|
146
|
+
post refresh_token_endpoint_url(
|
|
147
|
+
client_id: "1",
|
|
148
|
+
client_secret: "1",
|
|
149
|
+
refresh_token: token_for_private_client.refresh_token
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
should_not_have_json "refresh_token"
|
|
153
|
+
should_have_json "error", "invalid_client"
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
it "client gets an error for invalid refresh token" do
|
|
158
|
+
post refresh_token_endpoint_url(client: @client, refresh_token: "invalid")
|
|
159
|
+
should_not_have_json "refresh_token"
|
|
160
|
+
should_have_json "error", "invalid_grant"
|
|
102
161
|
end
|
|
103
162
|
|
|
104
|
-
it
|
|
163
|
+
it "client gets an error for revoked access token" do
|
|
105
164
|
@token.revoke
|
|
106
165
|
post refresh_token_endpoint_url(client: @client, refresh_token: @token.refresh_token)
|
|
107
|
-
should_not_have_json
|
|
108
|
-
should_have_json
|
|
166
|
+
should_not_have_json "refresh_token"
|
|
167
|
+
should_have_json "error", "invalid_grant"
|
|
109
168
|
end
|
|
110
169
|
|
|
111
|
-
it
|
|
170
|
+
it "second of simultaneous client requests get an error for revoked access token" do
|
|
112
171
|
allow_any_instance_of(Doorkeeper::AccessToken).to receive(:revoked?).and_return(false, true)
|
|
113
172
|
post refresh_token_endpoint_url(client: @client, refresh_token: @token.refresh_token)
|
|
114
173
|
|
|
115
|
-
should_not_have_json
|
|
116
|
-
should_have_json
|
|
174
|
+
should_not_have_json "refresh_token"
|
|
175
|
+
should_have_json "error", "invalid_request"
|
|
117
176
|
end
|
|
118
177
|
end
|
|
119
178
|
|
|
120
|
-
context
|
|
179
|
+
context "refreshing the token with multiple sessions (devices)" do
|
|
121
180
|
before do
|
|
122
181
|
# enable password auth to simulate other devices
|
|
123
182
|
config_is_set(:grant_flows, ["password"])
|
|
@@ -140,12 +199,12 @@ describe 'Refresh Token Flow' do
|
|
|
140
199
|
end
|
|
141
200
|
|
|
142
201
|
context "refresh_token revoked on use" do
|
|
143
|
-
it
|
|
202
|
+
it "client request a token after creating another token with the same user" do
|
|
144
203
|
post refresh_token_endpoint_url(
|
|
145
204
|
client: @client, refresh_token: @token.refresh_token
|
|
146
205
|
)
|
|
147
206
|
|
|
148
|
-
should_have_json
|
|
207
|
+
should_have_json "refresh_token", last_token.refresh_token
|
|
149
208
|
expect(@token.reload).not_to be_revoked
|
|
150
209
|
end
|
|
151
210
|
end
|
|
@@ -155,12 +214,12 @@ describe 'Refresh Token Flow' do
|
|
|
155
214
|
allow(Doorkeeper::AccessToken).to receive(:refresh_token_revoked_on_use?).and_return(false)
|
|
156
215
|
end
|
|
157
216
|
|
|
158
|
-
it
|
|
217
|
+
it "client request a token after creating another token with the same user" do
|
|
159
218
|
post refresh_token_endpoint_url(
|
|
160
219
|
client: @client, refresh_token: @token.refresh_token
|
|
161
220
|
)
|
|
162
221
|
|
|
163
|
-
should_have_json
|
|
222
|
+
should_have_json "refresh_token", last_token.refresh_token
|
|
164
223
|
expect(@token.reload).to be_revoked
|
|
165
224
|
end
|
|
166
225
|
end
|
|
@@ -1,155 +1,141 @@
|
|
|
1
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
require "spec_helper"
|
|
4
|
+
|
|
5
|
+
describe "Revoke Token Flow" do
|
|
4
6
|
before do
|
|
5
7
|
Doorkeeper.configure { orm DOORKEEPER_ORM }
|
|
6
8
|
end
|
|
7
9
|
|
|
8
|
-
context
|
|
10
|
+
context "with default parameters" do
|
|
9
11
|
let(:client_application) { FactoryBot.create :application }
|
|
10
|
-
let(:resource_owner) { User.create!(name:
|
|
12
|
+
let(:resource_owner) { User.create!(name: "John", password: "sekret") }
|
|
11
13
|
let(:access_token) do
|
|
12
14
|
FactoryBot.create(:access_token,
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
15
|
+
application: client_application,
|
|
16
|
+
resource_owner_id: resource_owner.id,
|
|
17
|
+
use_refresh_token: true)
|
|
16
18
|
end
|
|
17
19
|
|
|
18
|
-
context
|
|
20
|
+
context "with authenticated, confidential OAuth 2.0 client/application" do
|
|
19
21
|
let(:headers) do
|
|
20
22
|
client_id = client_application.uid
|
|
21
23
|
client_secret = client_application.secret
|
|
22
24
|
credentials = Base64.encode64("#{client_id}:#{client_secret}")
|
|
23
|
-
{
|
|
25
|
+
{ "HTTP_AUTHORIZATION" => "Basic #{credentials}" }
|
|
24
26
|
end
|
|
25
27
|
|
|
26
|
-
it
|
|
28
|
+
it "should revoke the access token provided" do
|
|
27
29
|
post revocation_token_endpoint_url, params: { token: access_token.token }, headers: headers
|
|
28
30
|
|
|
29
|
-
access_token.reload
|
|
30
|
-
|
|
31
31
|
expect(response).to be_successful
|
|
32
|
-
expect(access_token.revoked?).to be_truthy
|
|
32
|
+
expect(access_token.reload.revoked?).to be_truthy
|
|
33
33
|
end
|
|
34
34
|
|
|
35
|
-
it
|
|
35
|
+
it "should revoke the refresh token provided" do
|
|
36
36
|
post revocation_token_endpoint_url, params: { token: access_token.refresh_token }, headers: headers
|
|
37
37
|
|
|
38
|
-
access_token.reload
|
|
39
|
-
|
|
40
38
|
expect(response).to be_successful
|
|
41
|
-
expect(access_token.revoked?).to be_truthy
|
|
39
|
+
expect(access_token.reload.revoked?).to be_truthy
|
|
42
40
|
end
|
|
43
41
|
|
|
44
|
-
context
|
|
45
|
-
it
|
|
46
|
-
|
|
47
|
-
|
|
42
|
+
context "with invalid token to revoke" do
|
|
43
|
+
it "should not revoke any tokens and respond successfully" do
|
|
44
|
+
expect do
|
|
45
|
+
post revocation_token_endpoint_url,
|
|
46
|
+
params: { token: "I_AM_AN_INVALID_TOKEN" },
|
|
47
|
+
headers: headers
|
|
48
|
+
end.not_to(change { Doorkeeper::AccessToken.where(revoked_at: nil).count })
|
|
48
49
|
|
|
49
50
|
# The authorization server responds with HTTP status code 200 even if
|
|
50
51
|
# token is invalid
|
|
51
52
|
expect(response).to be_successful
|
|
52
|
-
expect(Doorkeeper::AccessToken.where(revoked_at: nil).count).to eq(num_prev_revoked_tokens)
|
|
53
53
|
end
|
|
54
54
|
end
|
|
55
55
|
|
|
56
|
-
context
|
|
56
|
+
context "with bad credentials and a valid token" do
|
|
57
57
|
let(:headers) do
|
|
58
58
|
client_id = client_application.uid
|
|
59
59
|
credentials = Base64.encode64("#{client_id}:poop")
|
|
60
|
-
{
|
|
60
|
+
{ "HTTP_AUTHORIZATION" => "Basic #{credentials}" }
|
|
61
61
|
end
|
|
62
|
-
it
|
|
62
|
+
it "should not revoke any tokens and respond successfully" do
|
|
63
63
|
post revocation_token_endpoint_url, params: { token: access_token.token }, headers: headers
|
|
64
64
|
|
|
65
|
-
access_token.reload
|
|
66
|
-
|
|
67
65
|
expect(response).to be_successful
|
|
68
|
-
expect(access_token.revoked?).to be_falsey
|
|
66
|
+
expect(access_token.reload.revoked?).to be_falsey
|
|
69
67
|
end
|
|
70
68
|
end
|
|
71
69
|
|
|
72
|
-
context
|
|
73
|
-
it
|
|
70
|
+
context "with no credentials and a valid token" do
|
|
71
|
+
it "should not revoke any tokens and respond successfully" do
|
|
74
72
|
post revocation_token_endpoint_url, params: { token: access_token.token }
|
|
75
73
|
|
|
76
|
-
access_token.reload
|
|
77
|
-
|
|
78
74
|
expect(response).to be_successful
|
|
79
|
-
expect(access_token.revoked?).to be_falsey
|
|
75
|
+
expect(access_token.reload.revoked?).to be_falsey
|
|
80
76
|
end
|
|
81
77
|
end
|
|
82
78
|
|
|
83
|
-
context
|
|
79
|
+
context "with valid token for another client application" do
|
|
84
80
|
let(:other_client_application) { FactoryBot.create :application }
|
|
85
81
|
let(:headers) do
|
|
86
82
|
client_id = other_client_application.uid
|
|
87
83
|
client_secret = other_client_application.secret
|
|
88
84
|
credentials = Base64.encode64("#{client_id}:#{client_secret}")
|
|
89
|
-
{
|
|
85
|
+
{ "HTTP_AUTHORIZATION" => "Basic #{credentials}" }
|
|
90
86
|
end
|
|
91
87
|
|
|
92
|
-
it
|
|
88
|
+
it "should not revoke the token as its unauthorized" do
|
|
93
89
|
post revocation_token_endpoint_url, params: { token: access_token.token }, headers: headers
|
|
94
90
|
|
|
95
|
-
access_token.reload
|
|
96
|
-
|
|
97
91
|
expect(response).to be_successful
|
|
98
|
-
expect(access_token.revoked?).to be_falsey
|
|
92
|
+
expect(access_token.reload.revoked?).to be_falsey
|
|
99
93
|
end
|
|
100
94
|
end
|
|
101
95
|
end
|
|
102
96
|
|
|
103
|
-
context
|
|
97
|
+
context "with public OAuth 2.0 client/application" do
|
|
104
98
|
let(:access_token) do
|
|
105
99
|
FactoryBot.create(:access_token,
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
100
|
+
application: nil,
|
|
101
|
+
resource_owner_id: resource_owner.id,
|
|
102
|
+
use_refresh_token: true)
|
|
109
103
|
end
|
|
110
104
|
|
|
111
|
-
it
|
|
105
|
+
it "should revoke the access token provided" do
|
|
112
106
|
post revocation_token_endpoint_url, params: { token: access_token.token }
|
|
113
107
|
|
|
114
|
-
access_token.reload
|
|
115
|
-
|
|
116
108
|
expect(response).to be_successful
|
|
117
|
-
expect(access_token.revoked?).to be_truthy
|
|
109
|
+
expect(access_token.reload.revoked?).to be_truthy
|
|
118
110
|
end
|
|
119
111
|
|
|
120
|
-
it
|
|
112
|
+
it "should revoke the refresh token provided" do
|
|
121
113
|
post revocation_token_endpoint_url, params: { token: access_token.refresh_token }
|
|
122
114
|
|
|
123
|
-
access_token.reload
|
|
124
|
-
|
|
125
115
|
expect(response).to be_successful
|
|
126
|
-
expect(access_token.revoked?).to be_truthy
|
|
116
|
+
expect(access_token.reload.revoked?).to be_truthy
|
|
127
117
|
end
|
|
128
118
|
|
|
129
|
-
context
|
|
119
|
+
context "with a valid token issued for a confidential client" do
|
|
130
120
|
let(:access_token) do
|
|
131
121
|
FactoryBot.create(:access_token,
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
122
|
+
application: client_application,
|
|
123
|
+
resource_owner_id: resource_owner.id,
|
|
124
|
+
use_refresh_token: true)
|
|
135
125
|
end
|
|
136
126
|
|
|
137
|
-
it
|
|
127
|
+
it "should not revoke the access token provided" do
|
|
138
128
|
post revocation_token_endpoint_url, params: { token: access_token.token }
|
|
139
129
|
|
|
140
|
-
access_token.reload
|
|
141
|
-
|
|
142
130
|
expect(response).to be_successful
|
|
143
|
-
expect(access_token.revoked?).to be_falsey
|
|
131
|
+
expect(access_token.reload.revoked?).to be_falsey
|
|
144
132
|
end
|
|
145
133
|
|
|
146
|
-
it
|
|
134
|
+
it "should not revoke the refresh token provided" do
|
|
147
135
|
post revocation_token_endpoint_url, params: { token: access_token.token }
|
|
148
136
|
|
|
149
|
-
access_token.reload
|
|
150
|
-
|
|
151
137
|
expect(response).to be_successful
|
|
152
|
-
expect(access_token.revoked?).to be_falsey
|
|
138
|
+
expect(access_token.reload.revoked?).to be_falsey
|
|
153
139
|
end
|
|
154
140
|
end
|
|
155
141
|
end
|
|
@@ -1,20 +1,22 @@
|
|
|
1
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
require "spec_helper"
|
|
4
|
+
|
|
5
|
+
feature "Skip authorization form" do
|
|
4
6
|
background do
|
|
5
|
-
config_is_set(:authenticate_resource_owner) { User.first || redirect_to(
|
|
7
|
+
config_is_set(:authenticate_resource_owner) { User.first || redirect_to("/sign_in") }
|
|
6
8
|
client_exists
|
|
7
9
|
default_scopes_exist :public
|
|
8
10
|
optional_scopes_exist :write
|
|
9
11
|
end
|
|
10
12
|
|
|
11
|
-
context
|
|
13
|
+
context "for previously authorized clients" do
|
|
12
14
|
background do
|
|
13
15
|
create_resource_owner
|
|
14
16
|
sign_in
|
|
15
17
|
end
|
|
16
18
|
|
|
17
|
-
scenario
|
|
19
|
+
scenario "skips the authorization and return a new grant code" do
|
|
18
20
|
client_is_authorized(@client, @resource_owner, scopes: "public")
|
|
19
21
|
visit authorization_endpoint_url(client: @client, scope: "public")
|
|
20
22
|
|
|
@@ -35,29 +37,29 @@ feature 'Skip authorization form' do
|
|
|
35
37
|
url_should_have_param "code", Doorkeeper::AccessGrant.first.token
|
|
36
38
|
end
|
|
37
39
|
|
|
38
|
-
scenario
|
|
39
|
-
client_is_authorized(@client, @resource_owner, scopes:
|
|
40
|
-
visit authorization_endpoint_url(client: @client, scope:
|
|
41
|
-
i_should_see
|
|
40
|
+
scenario "does not skip authorization when scopes differ (new request has fewer scopes)" do
|
|
41
|
+
client_is_authorized(@client, @resource_owner, scopes: "public write")
|
|
42
|
+
visit authorization_endpoint_url(client: @client, scope: "public")
|
|
43
|
+
i_should_see "Authorize"
|
|
42
44
|
end
|
|
43
45
|
|
|
44
|
-
scenario
|
|
45
|
-
client_is_authorized(@client, @resource_owner, scopes:
|
|
46
|
-
visit authorization_endpoint_url(client: @client, scopes:
|
|
47
|
-
i_should_see
|
|
46
|
+
scenario "does not skip authorization when scopes differ (new request has more scopes)" do
|
|
47
|
+
client_is_authorized(@client, @resource_owner, scopes: "public write")
|
|
48
|
+
visit authorization_endpoint_url(client: @client, scopes: "public write email")
|
|
49
|
+
i_should_see "Authorize"
|
|
48
50
|
end
|
|
49
51
|
|
|
50
|
-
scenario
|
|
51
|
-
client_is_authorized(@client, @resource_owner, scopes:
|
|
52
|
-
visit authorization_endpoint_url(client: @client, scope:
|
|
53
|
-
click_on
|
|
52
|
+
scenario "creates grant with new scope when scopes differ" do
|
|
53
|
+
client_is_authorized(@client, @resource_owner, scopes: "public write")
|
|
54
|
+
visit authorization_endpoint_url(client: @client, scope: "public")
|
|
55
|
+
click_on "Authorize"
|
|
54
56
|
access_grant_should_have_scopes :public
|
|
55
57
|
end
|
|
56
58
|
|
|
57
|
-
scenario
|
|
58
|
-
client_is_authorized(@client, @resource_owner, scopes:
|
|
59
|
-
visit authorization_endpoint_url(client: @client, scope:
|
|
60
|
-
click_on
|
|
59
|
+
scenario "creates grant with new scope when scopes are greater" do
|
|
60
|
+
client_is_authorized(@client, @resource_owner, scopes: "public")
|
|
61
|
+
visit authorization_endpoint_url(client: @client, scope: "public write")
|
|
62
|
+
click_on "Authorize"
|
|
61
63
|
access_grant_should_have_scopes :public, :write
|
|
62
64
|
end
|
|
63
65
|
end
|
|
@@ -1,14 +1,16 @@
|
|
|
1
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
require "spec_helper"
|
|
4
|
+
|
|
5
|
+
describe "ActionController::Metal API" do
|
|
4
6
|
before do
|
|
5
7
|
@client = FactoryBot.create(:application)
|
|
6
|
-
@resource = User.create!(name:
|
|
8
|
+
@resource = User.create!(name: "Joe", password: "sekret")
|
|
7
9
|
@token = client_is_authorized(@client, @resource)
|
|
8
10
|
end
|
|
9
11
|
|
|
10
|
-
it
|
|
12
|
+
it "client requests protected resource with valid token" do
|
|
11
13
|
get "/metal.json?access_token=#{@token.token}"
|
|
12
|
-
should_have_json
|
|
14
|
+
should_have_json "ok", true
|
|
13
15
|
end
|
|
14
16
|
end
|
|
@@ -1,81 +1,83 @@
|
|
|
1
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
require "spec_helper"
|
|
4
|
+
|
|
5
|
+
feature "Private API" do
|
|
4
6
|
background do
|
|
5
7
|
@client = FactoryBot.create(:application)
|
|
6
|
-
@resource = User.create!(name:
|
|
8
|
+
@resource = User.create!(name: "Joe", password: "sekret")
|
|
7
9
|
@token = client_is_authorized(@client, @resource)
|
|
8
10
|
end
|
|
9
11
|
|
|
10
|
-
scenario
|
|
12
|
+
scenario "client requests protected resource with valid token" do
|
|
11
13
|
with_access_token_header @token.token
|
|
12
|
-
visit
|
|
13
|
-
expect(page.body).to have_content(
|
|
14
|
+
visit "/full_protected_resources"
|
|
15
|
+
expect(page.body).to have_content("index")
|
|
14
16
|
end
|
|
15
17
|
|
|
16
|
-
scenario
|
|
18
|
+
scenario "client requests protected resource with disabled header authentication" do
|
|
17
19
|
config_is_set :access_token_methods, [:from_access_token_param]
|
|
18
20
|
with_access_token_header @token.token
|
|
19
|
-
visit
|
|
21
|
+
visit "/full_protected_resources"
|
|
20
22
|
response_status_should_be 401
|
|
21
23
|
end
|
|
22
24
|
|
|
23
|
-
scenario
|
|
24
|
-
with_access_token_header
|
|
25
|
-
visit
|
|
25
|
+
scenario "client attempts to request protected resource with invalid token" do
|
|
26
|
+
with_access_token_header "invalid"
|
|
27
|
+
visit "/full_protected_resources"
|
|
26
28
|
response_status_should_be 401
|
|
27
29
|
end
|
|
28
30
|
|
|
29
|
-
scenario
|
|
31
|
+
scenario "client attempts to request protected resource with expired token" do
|
|
30
32
|
@token.update_attribute :expires_in, -100 # expires token
|
|
31
33
|
with_access_token_header @token.token
|
|
32
|
-
visit
|
|
34
|
+
visit "/full_protected_resources"
|
|
33
35
|
response_status_should_be 401
|
|
34
36
|
end
|
|
35
37
|
|
|
36
|
-
scenario
|
|
38
|
+
scenario "client requests protected resource with permanent token" do
|
|
37
39
|
@token.update_attribute :expires_in, nil # never expires
|
|
38
40
|
with_access_token_header @token.token
|
|
39
|
-
visit
|
|
40
|
-
expect(page.body).to have_content(
|
|
41
|
+
visit "/full_protected_resources"
|
|
42
|
+
expect(page.body).to have_content("index")
|
|
41
43
|
end
|
|
42
44
|
|
|
43
|
-
scenario
|
|
44
|
-
Doorkeeper.configuration.instance_eval
|
|
45
|
+
scenario "access token with no default scopes" do
|
|
46
|
+
Doorkeeper.configuration.instance_eval do
|
|
45
47
|
@default_scopes = Doorkeeper::OAuth::Scopes.from_array([:public])
|
|
46
48
|
@scopes = default_scopes + optional_scopes
|
|
47
|
-
|
|
48
|
-
@token.update_attribute :scopes,
|
|
49
|
+
end
|
|
50
|
+
@token.update_attribute :scopes, "dummy"
|
|
49
51
|
with_access_token_header @token.token
|
|
50
|
-
visit
|
|
52
|
+
visit "/full_protected_resources"
|
|
51
53
|
response_status_should_be 403
|
|
52
54
|
end
|
|
53
55
|
|
|
54
|
-
scenario
|
|
56
|
+
scenario "access token with no allowed scopes" do
|
|
55
57
|
@token.update_attribute :scopes, nil
|
|
56
58
|
with_access_token_header @token.token
|
|
57
|
-
visit
|
|
59
|
+
visit "/full_protected_resources/1.json"
|
|
58
60
|
response_status_should_be 403
|
|
59
61
|
end
|
|
60
62
|
|
|
61
|
-
scenario
|
|
62
|
-
@token.update_attribute :scopes,
|
|
63
|
+
scenario "access token with one of allowed scopes" do
|
|
64
|
+
@token.update_attribute :scopes, "admin"
|
|
63
65
|
with_access_token_header @token.token
|
|
64
|
-
visit
|
|
65
|
-
expect(page.body).to have_content(
|
|
66
|
+
visit "/full_protected_resources/1.json"
|
|
67
|
+
expect(page.body).to have_content("show")
|
|
66
68
|
end
|
|
67
69
|
|
|
68
|
-
scenario
|
|
69
|
-
@token.update_attribute :scopes,
|
|
70
|
+
scenario "access token with another of allowed scopes" do
|
|
71
|
+
@token.update_attribute :scopes, "write"
|
|
70
72
|
with_access_token_header @token.token
|
|
71
|
-
visit
|
|
72
|
-
expect(page.body).to have_content(
|
|
73
|
+
visit "/full_protected_resources/1.json"
|
|
74
|
+
expect(page.body).to have_content("show")
|
|
73
75
|
end
|
|
74
76
|
|
|
75
|
-
scenario
|
|
76
|
-
@token.update_attribute :scopes,
|
|
77
|
+
scenario "access token with both allowed scopes" do
|
|
78
|
+
@token.update_attribute :scopes, "write admin"
|
|
77
79
|
with_access_token_header @token.token
|
|
78
|
-
visit
|
|
79
|
-
expect(page.body).to have_content(
|
|
80
|
+
visit "/full_protected_resources/1.json"
|
|
81
|
+
expect(page.body).to have_content("show")
|
|
80
82
|
end
|
|
81
83
|
end
|