doorkeeper 5.0.3 → 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 +4 -4
- data/.hound.yml +2 -1
- data/.rubocop.yml +37 -4
- data/.travis.yml +11 -21
- data/Appraisals +29 -7
- data/Dangerfile +5 -2
- data/Gemfile +19 -5
- data/NEWS.md +81 -21
- data/README.md +75 -485
- data/Rakefile +10 -8
- data/app/controllers/doorkeeper/application_controller.rb +1 -2
- data/app/controllers/doorkeeper/application_metal_controller.rb +2 -13
- data/app/controllers/doorkeeper/applications_controller.rb +20 -8
- data/app/controllers/doorkeeper/authorized_applications_controller.rb +1 -1
- data/app/controllers/doorkeeper/token_info_controller.rb +2 -2
- data/app/controllers/doorkeeper/tokens_controller.rb +11 -11
- data/app/helpers/doorkeeper/dashboard_helper.rb +1 -1
- data/app/validators/redirect_uri_validator.rb +5 -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 +24 -21
- 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 +191 -75
- data/lib/doorkeeper/engine.rb +1 -1
- data/lib/doorkeeper/grape/authorization_decorator.rb +4 -4
- data/lib/doorkeeper/grape/helpers.rb +3 -3
- data/lib/doorkeeper/helpers/controller.rb +3 -2
- data/lib/doorkeeper/models/access_grant_mixin.rb +20 -3
- data/lib/doorkeeper/models/access_token_mixin.rb +63 -19
- data/lib/doorkeeper/models/application_mixin.rb +43 -1
- data/lib/doorkeeper/models/concerns/expirable.rb +4 -2
- data/lib/doorkeeper/models/concerns/ownership.rb +1 -6
- data/lib/doorkeeper/models/concerns/reusable.rb +19 -0
- data/lib/doorkeeper/models/concerns/revocable.rb +2 -1
- data/lib/doorkeeper/models/concerns/scopes.rb +5 -1
- data/lib/doorkeeper/models/concerns/secret_storable.rb +108 -0
- data/lib/doorkeeper/oauth/authorization/code.rb +2 -2
- data/lib/doorkeeper/oauth/authorization/token.rb +12 -7
- data/lib/doorkeeper/oauth/authorization/uri_builder.rb +1 -1
- data/lib/doorkeeper/oauth/authorization_code_request.rb +6 -4
- data/lib/doorkeeper/oauth/client.rb +1 -1
- data/lib/doorkeeper/oauth/client_credentials/validation.rb +5 -4
- data/lib/doorkeeper/oauth/client_credentials_request.rb +1 -1
- data/lib/doorkeeper/oauth/code_response.rb +2 -2
- data/lib/doorkeeper/oauth/error_response.rb +10 -6
- data/lib/doorkeeper/oauth/forbidden_token_response.rb +1 -1
- data/lib/doorkeeper/oauth/helpers/scope_checker.rb +23 -8
- data/lib/doorkeeper/oauth/helpers/unique_token.rb +13 -1
- data/lib/doorkeeper/oauth/helpers/uri_checker.rb +37 -1
- data/lib/doorkeeper/oauth/invalid_token_response.rb +5 -1
- data/lib/doorkeeper/oauth/password_access_token_request.rb +7 -2
- data/lib/doorkeeper/oauth/pre_authorization.rb +11 -5
- data/lib/doorkeeper/oauth/refresh_token_request.rb +5 -2
- data/lib/doorkeeper/oauth/scopes.rb +5 -3
- data/lib/doorkeeper/oauth/token.rb +2 -2
- data/lib/doorkeeper/oauth/token_introspection.rb +74 -8
- data/lib/doorkeeper/oauth/token_response.rb +9 -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 +21 -57
- data/lib/doorkeeper/orm/active_record/stale_records_cleaner.rb +10 -3
- data/lib/doorkeeper/orm/active_record.rb +6 -6
- data/lib/doorkeeper/rails/helpers.rb +1 -1
- data/lib/doorkeeper/rails/routes/mapping.rb +7 -7
- data/lib/doorkeeper/rails/routes.rb +11 -11
- data/lib/doorkeeper/rake/db.rake +13 -13
- data/lib/doorkeeper/rake.rb +1 -1
- data/lib/doorkeeper/request.rb +1 -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/stale_records_cleaner.rb +1 -1
- data/lib/doorkeeper/version.rb +3 -3
- data/lib/doorkeeper.rb +69 -60
- 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 +120 -13
- data/lib/generators/doorkeeper/templates/migration.rb.erb +15 -7
- 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 +54 -52
- data/spec/controllers/authorizations_controller_spec.rb +139 -145
- data/spec/controllers/protected_resources_controller_spec.rb +78 -76
- data/spec/controllers/token_info_controller_spec.rb +14 -12
- data/spec/controllers/tokens_controller_spec.rb +167 -108
- 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 +2 -0
- data/spec/dummy/app/controllers/full_protected_resources_controller.rb +4 -2
- data/spec/dummy/app/controllers/home_controller.rb +5 -3
- 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 +25 -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 +3 -1
- data/spec/dummy/config/initializers/backtrace_silencers.rb +2 -0
- data/spec/dummy/config/initializers/doorkeeper.rb +5 -2
- 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 +17 -10
- data/spec/dummy/db/migrate/20170822064514_enable_pkce.rb +2 -0
- data/spec/dummy/db/schema.rb +1 -1
- data/spec/dummy/script/rails +5 -3
- data/spec/factories.rb +8 -6
- 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 +17 -15
- 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 -0
- data/spec/generators/views_generator_spec.rb +14 -12
- data/spec/grape/grape_integration_spec.rb +34 -32
- data/spec/helpers/doorkeeper/dashboard_helper_spec.rb +9 -7
- data/spec/lib/config_spec.rb +268 -99
- data/spec/lib/doorkeeper_spec.rb +3 -1
- 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 +34 -11
- data/spec/lib/oauth/base_request_spec.rb +20 -8
- data/spec/lib/oauth/base_response_spec.rb +3 -1
- data/spec/lib/oauth/client/credentials_spec.rb +24 -22
- data/spec/lib/oauth/client_credentials/creator_spec.rb +56 -10
- data/spec/lib/oauth/client_credentials/issuer_spec.rb +27 -18
- data/spec/lib/oauth/client_credentials/validation_spec.rb +20 -15
- data/spec/lib/oauth/client_credentials_integration_spec.rb +7 -5
- 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 +8 -6
- 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 +115 -95
- data/spec/lib/oauth/invalid_token_response_spec.rb +3 -1
- data/spec/lib/oauth/password_access_token_request_spec.rb +79 -30
- data/spec/lib/oauth/pre_authorization_spec.rb +80 -54
- data/spec/lib/oauth/refresh_token_request_spec.rb +36 -33
- data/spec/lib/oauth/scopes_spec.rb +63 -61
- data/spec/lib/oauth/token_request_spec.rb +79 -24
- data/spec/lib/oauth/token_response_spec.rb +40 -38
- data/spec/lib/oauth/token_spec.rb +60 -44
- 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 +16 -14
- data/spec/lib/stale_records_cleaner_spec.rb +17 -17
- data/spec/models/doorkeeper/access_grant_spec.rb +80 -15
- data/spec/models/doorkeeper/access_token_spec.rb +198 -73
- data/spec/models/doorkeeper/application_spec.rb +280 -288
- data/spec/requests/applications/applications_request_spec.rb +98 -66
- data/spec/requests/applications/authorized_applications_spec.rb +20 -18
- data/spec/requests/endpoints/authorization_spec.rb +25 -23
- data/spec/requests/endpoints/token_spec.rb +38 -36
- data/spec/requests/flows/authorization_code_errors_spec.rb +26 -24
- data/spec/requests/flows/authorization_code_spec.rb +193 -151
- data/spec/requests/flows/client_credentials_spec.rb +54 -52
- data/spec/requests/flows/implicit_grant_errors_spec.rb +10 -8
- data/spec/requests/flows/implicit_grant_spec.rb +27 -25
- data/spec/requests/flows/password_spec.rb +59 -55
- data/spec/requests/flows/refresh_token_spec.rb +45 -43
- data/spec/requests/flows/revoke_token_spec.rb +40 -54
- 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 +35 -33
- 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 +3 -1
- 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 +3 -1
- data/spec/support/helpers/request_spec_helper.rb +5 -3
- data/spec/support/helpers/url_helper.rb +9 -7
- 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 +18 -16
- 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 +74 -45
- data/spec/version/version_spec.rb +7 -5
- metadata +60 -26
- data/gemfiles/rails_4_2.gemfile +0 -13
- data/spec/dummy/config/initializers/new_framework_defaults.rb +0 -8
|
@@ -1,11 +1,13 @@
|
|
|
1
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "spec_helper"
|
|
2
4
|
|
|
3
5
|
describe Doorkeeper::TokensController do
|
|
4
|
-
describe
|
|
6
|
+
describe "when authorization has succeeded" do
|
|
5
7
|
let(:token) { double(:token, authorize: true) }
|
|
6
8
|
|
|
7
|
-
it
|
|
8
|
-
skip
|
|
9
|
+
it "returns the authorization" do
|
|
10
|
+
skip "verify need of these specs"
|
|
9
11
|
|
|
10
12
|
expect(token).to receive(:authorization)
|
|
11
13
|
|
|
@@ -13,20 +15,20 @@ describe Doorkeeper::TokensController do
|
|
|
13
15
|
end
|
|
14
16
|
end
|
|
15
17
|
|
|
16
|
-
describe
|
|
17
|
-
it
|
|
18
|
+
describe "when authorization has failed" do
|
|
19
|
+
it "returns the error response" do
|
|
18
20
|
token = double(:token, authorize: false)
|
|
19
21
|
allow(controller).to receive(:token) { token }
|
|
20
22
|
|
|
21
23
|
post :create
|
|
22
24
|
|
|
23
|
-
expect(response.status).to eq
|
|
24
|
-
expect(response.headers[
|
|
25
|
+
expect(response.status).to eq 400
|
|
26
|
+
expect(response.headers["WWW-Authenticate"]).to match(/Bearer/)
|
|
25
27
|
end
|
|
26
28
|
end
|
|
27
29
|
|
|
28
|
-
describe
|
|
29
|
-
it
|
|
30
|
+
describe "when there is a failure due to a custom error" do
|
|
31
|
+
it "returns the error response with a custom message" do
|
|
30
32
|
# I18n looks for `doorkeeper.errors.messages.custom_message` in locale files
|
|
31
33
|
custom_message = "my_message"
|
|
32
34
|
allow(I18n).to receive(:translate)
|
|
@@ -34,7 +36,7 @@ describe Doorkeeper::TokensController do
|
|
|
34
36
|
custom_message,
|
|
35
37
|
hash_including(scope: %i[doorkeeper errors messages])
|
|
36
38
|
)
|
|
37
|
-
.and_return(
|
|
39
|
+
.and_return("Authorization custom message")
|
|
38
40
|
|
|
39
41
|
doorkeeper_error = Doorkeeper::Errors::DoorkeeperError.new(custom_message)
|
|
40
42
|
|
|
@@ -46,41 +48,37 @@ describe Doorkeeper::TokensController do
|
|
|
46
48
|
post :create
|
|
47
49
|
|
|
48
50
|
expected_response_body = {
|
|
49
|
-
"error"
|
|
50
|
-
"error_description" => "Authorization custom message"
|
|
51
|
+
"error" => custom_message,
|
|
52
|
+
"error_description" => "Authorization custom message",
|
|
51
53
|
}
|
|
52
|
-
expect(response.status).to eq
|
|
53
|
-
expect(response.headers[
|
|
54
|
+
expect(response.status).to eq 400
|
|
55
|
+
expect(response.headers["WWW-Authenticate"]).to match(/Bearer/)
|
|
54
56
|
expect(JSON.parse(response.body)).to eq expected_response_body
|
|
55
57
|
end
|
|
56
58
|
end
|
|
57
59
|
|
|
58
60
|
# http://tools.ietf.org/html/rfc7009#section-2.2
|
|
59
|
-
describe
|
|
61
|
+
describe "revoking tokens" do
|
|
60
62
|
let(:client) { FactoryBot.create(:application) }
|
|
61
63
|
let(:access_token) { FactoryBot.create(:access_token, application: client) }
|
|
62
64
|
|
|
63
|
-
|
|
64
|
-
allow(controller).to receive(:token) { access_token }
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
context 'when associated app is public' do
|
|
65
|
+
context "when associated app is public" do
|
|
68
66
|
let(:client) { FactoryBot.create(:application, confidential: false) }
|
|
69
67
|
|
|
70
|
-
it
|
|
71
|
-
post :revoke
|
|
68
|
+
it "returns 200" do
|
|
69
|
+
post :revoke, params: { token: access_token.token }
|
|
72
70
|
|
|
73
71
|
expect(response.status).to eq 200
|
|
74
72
|
end
|
|
75
73
|
|
|
76
|
-
it
|
|
77
|
-
post :revoke
|
|
74
|
+
it "revokes the access token" do
|
|
75
|
+
post :revoke, params: { token: access_token.token }
|
|
78
76
|
|
|
79
77
|
expect(access_token.reload).to have_attributes(revoked?: true)
|
|
80
78
|
end
|
|
81
79
|
end
|
|
82
80
|
|
|
83
|
-
context
|
|
81
|
+
context "when associated app is confidential" do
|
|
84
82
|
let(:client) { FactoryBot.create(:application, confidential: true) }
|
|
85
83
|
let(:oauth_client) { Doorkeeper::OAuth::Client.new(client) }
|
|
86
84
|
|
|
@@ -88,30 +86,30 @@ describe Doorkeeper::TokensController do
|
|
|
88
86
|
allow_any_instance_of(Doorkeeper::Server).to receive(:client) { oauth_client }
|
|
89
87
|
end
|
|
90
88
|
|
|
91
|
-
it
|
|
92
|
-
post :revoke
|
|
89
|
+
it "returns 200" do
|
|
90
|
+
post :revoke, params: { token: access_token.token }
|
|
93
91
|
|
|
94
92
|
expect(response.status).to eq 200
|
|
95
93
|
end
|
|
96
94
|
|
|
97
|
-
it
|
|
98
|
-
post :revoke
|
|
95
|
+
it "revokes the access token" do
|
|
96
|
+
post :revoke, params: { token: access_token.token }
|
|
99
97
|
|
|
100
98
|
expect(access_token.reload).to have_attributes(revoked?: true)
|
|
101
99
|
end
|
|
102
100
|
|
|
103
|
-
context
|
|
101
|
+
context "when authorization fails" do
|
|
104
102
|
let(:some_other_client) { FactoryBot.create(:application, confidential: true) }
|
|
105
103
|
let(:oauth_client) { Doorkeeper::OAuth::Client.new(some_other_client) }
|
|
106
104
|
|
|
107
|
-
it
|
|
108
|
-
post :revoke
|
|
105
|
+
it "returns 200" do
|
|
106
|
+
post :revoke, params: { token: access_token.token }
|
|
109
107
|
|
|
110
108
|
expect(response.status).to eq 200
|
|
111
109
|
end
|
|
112
110
|
|
|
113
|
-
it
|
|
114
|
-
post :revoke
|
|
111
|
+
it "does not revoke the access token" do
|
|
112
|
+
post :revoke, params: { token: access_token.token }
|
|
115
113
|
|
|
116
114
|
expect(access_token.reload).to have_attributes(revoked?: false)
|
|
117
115
|
end
|
|
@@ -119,7 +117,7 @@ describe Doorkeeper::TokensController do
|
|
|
119
117
|
end
|
|
120
118
|
end
|
|
121
119
|
|
|
122
|
-
describe
|
|
120
|
+
describe "authorize response memoization" do
|
|
123
121
|
it "memoizes the result of the authorization" do
|
|
124
122
|
strategy = double(:strategy, authorize: true)
|
|
125
123
|
expect(strategy).to receive(:authorize).once
|
|
@@ -133,138 +131,199 @@ describe Doorkeeper::TokensController do
|
|
|
133
131
|
end
|
|
134
132
|
end
|
|
135
133
|
|
|
136
|
-
describe
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
134
|
+
describe "when requested token introspection" do
|
|
135
|
+
let(:client) { FactoryBot.create(:application) }
|
|
136
|
+
let(:access_token) { FactoryBot.create(:access_token, application: client) }
|
|
137
|
+
let(:token_for_introspection) { FactoryBot.create(:access_token, application: client) }
|
|
140
138
|
|
|
141
|
-
|
|
142
|
-
|
|
139
|
+
context "authorized using valid Bearer token" do
|
|
140
|
+
it "responds with full token introspection" do
|
|
141
|
+
request.headers["Authorization"] = "Bearer #{access_token.token}"
|
|
143
142
|
|
|
144
|
-
post :introspect, params: { token:
|
|
143
|
+
post :introspect, params: { token: token_for_introspection.token }
|
|
145
144
|
|
|
146
|
-
should_have_json
|
|
147
|
-
expect(json_response).to include(
|
|
145
|
+
should_have_json "active", true
|
|
146
|
+
expect(json_response).to include("client_id", "token_type", "exp", "iat")
|
|
148
147
|
end
|
|
149
148
|
end
|
|
150
149
|
|
|
151
|
-
context
|
|
152
|
-
|
|
153
|
-
|
|
150
|
+
context "authorized using valid Client Authentication" do
|
|
151
|
+
it "responds with full token introspection" do
|
|
152
|
+
request.headers["Authorization"] = basic_auth_header_for_client(client)
|
|
154
153
|
|
|
155
|
-
|
|
156
|
-
request.headers['Authorization'] = basic_auth_header_for_client(client)
|
|
154
|
+
post :introspect, params: { token: token_for_introspection.token }
|
|
157
155
|
|
|
158
|
-
|
|
156
|
+
should_have_json "active", true
|
|
157
|
+
expect(json_response).to include("client_id", "token_type", "exp", "iat")
|
|
158
|
+
should_have_json "client_id", client.uid
|
|
159
|
+
end
|
|
160
|
+
end
|
|
159
161
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
162
|
+
context "using custom introspection response" do
|
|
163
|
+
before do
|
|
164
|
+
Doorkeeper.configure do
|
|
165
|
+
orm DOORKEEPER_ORM
|
|
166
|
+
custom_introspection_response do |_token, _context|
|
|
167
|
+
{
|
|
168
|
+
sub: "Z5O3upPC88QrAjx00dis",
|
|
169
|
+
aud: "https://protected.example.net/resource",
|
|
170
|
+
}
|
|
171
|
+
end
|
|
172
|
+
end
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
it "responds with full token introspection" do
|
|
176
|
+
request.headers["Authorization"] = "Bearer #{access_token.token}"
|
|
177
|
+
|
|
178
|
+
post :introspect, params: { token: token_for_introspection.token }
|
|
179
|
+
|
|
180
|
+
expect(json_response).to include("client_id", "token_type", "exp", "iat", "sub", "aud")
|
|
181
|
+
should_have_json "sub", "Z5O3upPC88QrAjx00dis"
|
|
182
|
+
should_have_json "aud", "https://protected.example.net/resource"
|
|
163
183
|
end
|
|
164
184
|
end
|
|
165
185
|
|
|
166
|
-
context
|
|
167
|
-
let(:
|
|
168
|
-
let(:access_token) { FactoryBot.create(:access_token, application: nil) }
|
|
186
|
+
context "public access token" do
|
|
187
|
+
let(:token_for_introspection) { FactoryBot.create(:access_token, application: nil) }
|
|
169
188
|
|
|
170
|
-
it
|
|
171
|
-
request.headers[
|
|
189
|
+
it "responds with full token introspection" do
|
|
190
|
+
request.headers["Authorization"] = basic_auth_header_for_client(client)
|
|
172
191
|
|
|
173
|
-
post :introspect, params: { token:
|
|
192
|
+
post :introspect, params: { token: token_for_introspection.token }
|
|
174
193
|
|
|
175
|
-
should_have_json
|
|
176
|
-
expect(json_response).to include(
|
|
177
|
-
should_have_json
|
|
194
|
+
should_have_json "active", true
|
|
195
|
+
expect(json_response).to include("client_id", "token_type", "exp", "iat")
|
|
196
|
+
should_have_json "client_id", nil
|
|
178
197
|
end
|
|
179
198
|
end
|
|
180
199
|
|
|
181
|
-
context
|
|
182
|
-
let(:client) { FactoryBot.create(:application) }
|
|
200
|
+
context "token was issued to a different client than is making this request" do
|
|
183
201
|
let(:different_client) { FactoryBot.create(:application) }
|
|
184
|
-
let(:access_token) { FactoryBot.create(:access_token, application: client) }
|
|
185
202
|
|
|
186
|
-
it
|
|
187
|
-
request.headers[
|
|
203
|
+
it "responds with only active state" do
|
|
204
|
+
request.headers["Authorization"] = basic_auth_header_for_client(different_client)
|
|
188
205
|
|
|
189
|
-
post :introspect, params: { token:
|
|
206
|
+
post :introspect, params: { token: token_for_introspection.token }
|
|
190
207
|
|
|
191
208
|
expect(response).to be_successful
|
|
192
209
|
|
|
193
|
-
should_have_json
|
|
194
|
-
expect(json_response).not_to include(
|
|
210
|
+
should_have_json "active", false
|
|
211
|
+
expect(json_response).not_to include("client_id", "token_type", "exp", "iat")
|
|
195
212
|
end
|
|
196
213
|
end
|
|
197
214
|
|
|
198
|
-
context
|
|
199
|
-
let(:
|
|
215
|
+
context "authorized using invalid Bearer token" do
|
|
216
|
+
let(:access_token) do
|
|
217
|
+
FactoryBot.create(:access_token, application: client, revoked_at: 1.day.ago)
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
it "responds with invalid token error" do
|
|
221
|
+
request.headers["Authorization"] = "Bearer #{access_token.token}"
|
|
222
|
+
|
|
223
|
+
post :introspect, params: { token: token_for_introspection.token }
|
|
224
|
+
|
|
225
|
+
response_status_should_be 401
|
|
226
|
+
|
|
227
|
+
should_not_have_json "active"
|
|
228
|
+
should_have_json "error", "invalid_token"
|
|
229
|
+
end
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
context "authorized using the Bearer token that need to be introspected" do
|
|
233
|
+
it "responds with invalid token error" do
|
|
234
|
+
request.headers["Authorization"] = "Bearer #{access_token.token}"
|
|
235
|
+
|
|
236
|
+
post :introspect, params: { token: access_token.token }
|
|
237
|
+
|
|
238
|
+
response_status_should_be 401
|
|
239
|
+
|
|
240
|
+
should_not_have_json "active"
|
|
241
|
+
should_have_json "error", "invalid_token"
|
|
242
|
+
end
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
context "using invalid credentials to authorize" do
|
|
246
|
+
let(:client) { double(uid: "123123", secret: "666999") }
|
|
200
247
|
let(:access_token) { FactoryBot.create(:access_token) }
|
|
201
248
|
|
|
202
|
-
it
|
|
203
|
-
request.headers[
|
|
249
|
+
it "responds with invalid_client error" do
|
|
250
|
+
request.headers["Authorization"] = basic_auth_header_for_client(client)
|
|
204
251
|
|
|
205
252
|
post :introspect, params: { token: access_token.token }
|
|
206
253
|
|
|
207
254
|
expect(response).not_to be_successful
|
|
208
255
|
response_status_should_be 401
|
|
209
256
|
|
|
210
|
-
should_not_have_json
|
|
211
|
-
should_have_json
|
|
257
|
+
should_not_have_json "active"
|
|
258
|
+
should_have_json "error", "invalid_client"
|
|
212
259
|
end
|
|
213
260
|
end
|
|
214
261
|
|
|
215
|
-
context
|
|
216
|
-
|
|
217
|
-
|
|
262
|
+
context "using wrong token value" do
|
|
263
|
+
context "authorized using client credentials" do
|
|
264
|
+
it "responds with only active state" do
|
|
265
|
+
request.headers["Authorization"] = basic_auth_header_for_client(client)
|
|
266
|
+
|
|
267
|
+
post :introspect, params: { token: SecureRandom.hex(16) }
|
|
218
268
|
|
|
219
|
-
|
|
220
|
-
|
|
269
|
+
should_have_json "active", false
|
|
270
|
+
expect(json_response).not_to include("client_id", "token_type", "exp", "iat")
|
|
271
|
+
end
|
|
272
|
+
end
|
|
273
|
+
|
|
274
|
+
context "authorized using valid Bearer token" do
|
|
275
|
+
it "responds with only active state" do
|
|
276
|
+
request.headers["Authorization"] = "Bearer #{access_token.token}"
|
|
221
277
|
|
|
222
|
-
|
|
278
|
+
post :introspect, params: { token: SecureRandom.hex(16) }
|
|
223
279
|
|
|
224
|
-
|
|
225
|
-
|
|
280
|
+
should_have_json "active", false
|
|
281
|
+
expect(json_response).not_to include("client_id", "token_type", "exp", "iat")
|
|
282
|
+
end
|
|
226
283
|
end
|
|
227
284
|
end
|
|
228
285
|
|
|
229
|
-
context
|
|
230
|
-
let(:
|
|
231
|
-
|
|
286
|
+
context "when requested access token expired" do
|
|
287
|
+
let(:token_for_introspection) do
|
|
288
|
+
FactoryBot.create(:access_token, application: client, created_at: 1.year.ago)
|
|
289
|
+
end
|
|
232
290
|
|
|
233
|
-
it
|
|
234
|
-
request.headers[
|
|
291
|
+
it "responds with only active state" do
|
|
292
|
+
request.headers["Authorization"] = basic_auth_header_for_client(client)
|
|
235
293
|
|
|
236
|
-
post :introspect, params: { token:
|
|
294
|
+
post :introspect, params: { token: token_for_introspection.token }
|
|
237
295
|
|
|
238
|
-
should_have_json
|
|
239
|
-
expect(json_response).not_to include(
|
|
296
|
+
should_have_json "active", false
|
|
297
|
+
expect(json_response).not_to include("client_id", "token_type", "exp", "iat")
|
|
240
298
|
end
|
|
241
299
|
end
|
|
242
300
|
|
|
243
|
-
context
|
|
244
|
-
let(:
|
|
245
|
-
|
|
301
|
+
context "when requested Access Token revoked" do
|
|
302
|
+
let(:token_for_introspection) do
|
|
303
|
+
FactoryBot.create(:access_token, application: client, revoked_at: 1.year.ago)
|
|
304
|
+
end
|
|
246
305
|
|
|
247
|
-
it
|
|
248
|
-
request.headers[
|
|
306
|
+
it "responds with only active state" do
|
|
307
|
+
request.headers["Authorization"] = basic_auth_header_for_client(client)
|
|
249
308
|
|
|
250
|
-
post :introspect, params: { token:
|
|
309
|
+
post :introspect, params: { token: token_for_introspection.token }
|
|
251
310
|
|
|
252
|
-
should_have_json
|
|
253
|
-
expect(json_response).not_to include(
|
|
311
|
+
should_have_json "active", false
|
|
312
|
+
expect(json_response).not_to include("client_id", "token_type", "exp", "iat")
|
|
254
313
|
end
|
|
255
314
|
end
|
|
256
315
|
|
|
257
|
-
context
|
|
258
|
-
let(:
|
|
316
|
+
context "unauthorized (no bearer token or client credentials)" do
|
|
317
|
+
let(:token_for_introspection) { FactoryBot.create(:access_token) }
|
|
259
318
|
|
|
260
|
-
it
|
|
261
|
-
post :introspect, params: { token:
|
|
319
|
+
it "responds with invalid_request error" do
|
|
320
|
+
post :introspect, params: { token: token_for_introspection.token }
|
|
262
321
|
|
|
263
322
|
expect(response).not_to be_successful
|
|
264
|
-
response_status_should_be
|
|
323
|
+
response_status_should_be 400
|
|
265
324
|
|
|
266
|
-
should_not_have_json
|
|
267
|
-
should_have_json
|
|
325
|
+
should_not_have_json "active"
|
|
326
|
+
should_have_json "error", "invalid_request"
|
|
268
327
|
end
|
|
269
328
|
end
|
|
270
329
|
end
|
data/spec/dummy/Rakefile
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env rake
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
2
4
|
# Add your own tasks in files placed in lib/tasks ending in .rake,
|
|
3
5
|
# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
|
|
4
6
|
|
|
5
|
-
require File.expand_path(
|
|
7
|
+
require File.expand_path("config/application", __dir__)
|
|
6
8
|
|
|
7
9
|
Dummy::Application.load_tasks
|
|
@@ -1,12 +1,14 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
class FullProtectedResourcesController < ApplicationController
|
|
2
4
|
before_action -> { doorkeeper_authorize! :write, :admin }, only: :show
|
|
3
5
|
before_action :doorkeeper_authorize!, only: :index
|
|
4
6
|
|
|
5
7
|
def index
|
|
6
|
-
render plain:
|
|
8
|
+
render plain: "index"
|
|
7
9
|
end
|
|
8
10
|
|
|
9
11
|
def show
|
|
10
|
-
render plain:
|
|
12
|
+
render plain: "show"
|
|
11
13
|
end
|
|
12
14
|
end
|
|
@@ -1,16 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
class HomeController < ApplicationController
|
|
2
4
|
def index; end
|
|
3
5
|
|
|
4
6
|
def sign_in
|
|
5
7
|
session[:user_id] = if Rails.env.development?
|
|
6
|
-
User.first || User.create!(name:
|
|
8
|
+
User.first || User.create!(name: "Joe", password: "sekret")
|
|
7
9
|
else
|
|
8
10
|
User.first
|
|
9
11
|
end
|
|
10
|
-
redirect_to
|
|
12
|
+
redirect_to "/"
|
|
11
13
|
end
|
|
12
14
|
|
|
13
15
|
def callback
|
|
14
|
-
render plain:
|
|
16
|
+
render plain: "ok"
|
|
15
17
|
end
|
|
16
18
|
end
|
|
@@ -1,11 +1,13 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
class SemiProtectedResourcesController < ApplicationController
|
|
2
4
|
before_action :doorkeeper_authorize!, only: :index
|
|
3
5
|
|
|
4
6
|
def index
|
|
5
|
-
render plain:
|
|
7
|
+
render plain: "protected index"
|
|
6
8
|
end
|
|
7
9
|
|
|
8
10
|
def show
|
|
9
|
-
render plain:
|
|
11
|
+
render plain: "non protected show"
|
|
10
12
|
end
|
|
11
13
|
end
|
|
@@ -1,6 +1,17 @@
|
|
|
1
1
|
require File.expand_path('boot', __dir__)
|
|
2
2
|
|
|
3
|
-
require
|
|
3
|
+
require "rails"
|
|
4
|
+
|
|
5
|
+
%w[
|
|
6
|
+
action_controller/railtie
|
|
7
|
+
action_view/railtie
|
|
8
|
+
sprockets/railtie
|
|
9
|
+
].each do |railtie|
|
|
10
|
+
begin
|
|
11
|
+
require railtie
|
|
12
|
+
rescue LoadError
|
|
13
|
+
end
|
|
14
|
+
end
|
|
4
15
|
|
|
5
16
|
Bundler.require(*Rails.groups)
|
|
6
17
|
|
|
@@ -16,6 +27,19 @@ require "#{orm}/railtie"
|
|
|
16
27
|
|
|
17
28
|
module Dummy
|
|
18
29
|
class Application < Rails::Application
|
|
30
|
+
if Rails.gem_version < Gem::Version.new('5.1')
|
|
31
|
+
config.action_controller.per_form_csrf_tokens = true
|
|
32
|
+
config.action_controller.forgery_protection_origin_check = true
|
|
33
|
+
|
|
34
|
+
ActiveSupport.to_time_preserves_timezone = true
|
|
35
|
+
|
|
36
|
+
config.active_record.belongs_to_required_by_default = true
|
|
37
|
+
|
|
38
|
+
config.ssl_options = { hsts: { subdomains: true } }
|
|
39
|
+
else
|
|
40
|
+
config.load_defaults "#{Rails::VERSION::MAJOR}.#{Rails::VERSION::MINOR}"
|
|
41
|
+
end
|
|
42
|
+
|
|
19
43
|
# Settings in config/environments/* take precedence over those specified here.
|
|
20
44
|
# Application configuration should go into files in config/initializers
|
|
21
45
|
# -- all .rb files in that directory are automatically loaded.
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
Dummy::Application.configure do
|
|
2
4
|
# Settings specified here will take precedence over those in config/application.rb
|
|
3
5
|
|
|
@@ -8,7 +10,7 @@ Dummy::Application.configure do
|
|
|
8
10
|
config.cache_classes = true
|
|
9
11
|
|
|
10
12
|
config.assets.enabled = true
|
|
11
|
-
config.assets.version =
|
|
13
|
+
config.assets.version = "1.0"
|
|
12
14
|
config.assets.digest = false
|
|
13
15
|
|
|
14
16
|
# Do not eager load code on boot. This avoids loading your whole application
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
Doorkeeper.configure do
|
|
2
4
|
# Change the ORM that doorkeeper will use.
|
|
3
5
|
orm DOORKEEPER_ORM
|
|
@@ -5,7 +7,7 @@ Doorkeeper.configure do
|
|
|
5
7
|
# This block will be called to check whether the resource owner is authenticated or not.
|
|
6
8
|
resource_owner_authenticator do
|
|
7
9
|
# Put your resource owner authentication logic here.
|
|
8
|
-
User.where(id: session[:user_id]).first || redirect_to(root_url, alert:
|
|
10
|
+
User.where(id: session[:user_id]).first || redirect_to(root_url, alert: "Needs sign in.")
|
|
9
11
|
end
|
|
10
12
|
|
|
11
13
|
# If you didn't skip applications controller from Doorkeeper routes in your application routes.rb
|
|
@@ -66,7 +68,8 @@ Doorkeeper.configure do
|
|
|
66
68
|
# Change the native redirect uri for client apps
|
|
67
69
|
# When clients register with the following redirect uri, they won't be redirected to any server and
|
|
68
70
|
# the authorization code will be displayed within the provider
|
|
69
|
-
# The value can be any string. Use nil to disable this feature.
|
|
71
|
+
# The value can be any string. Use nil to disable this feature.
|
|
72
|
+
# When disabled, clients must provide a valid URL
|
|
70
73
|
# (Similar behaviour: https://developers.google.com/accounts/docs/OAuth2InstalledApp#choosingredirecturi)
|
|
71
74
|
#
|
|
72
75
|
# native_redirect_uri 'urn:ietf:wg:oauth:2.0:oob'
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
# Be sure to restart your server when you modify this file.
|
|
2
4
|
|
|
3
5
|
# Your secret key for verifying the integrity of signed cookies.
|
|
@@ -5,4 +7,4 @@
|
|
|
5
7
|
# Make sure the secret is at least 30 characters and all random,
|
|
6
8
|
# no regular words or you'll be exposed to dictionary attacks.
|
|
7
9
|
Dummy::Application.config.secret_key_base =
|
|
8
|
-
|
|
10
|
+
"c00157b5a1bb6181792f0f4a8a080485de7bab9987e6cf159"
|