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,4 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "spec_helper"
|
|
2
4
|
|
|
3
5
|
module Doorkeeper
|
|
4
6
|
unless defined?(AccessToken)
|
|
@@ -12,108 +14,122 @@ module Doorkeeper
|
|
|
12
14
|
let(:request) { double.as_null_object }
|
|
13
15
|
|
|
14
16
|
let(:method) do
|
|
15
|
-
->(*) {
|
|
17
|
+
->(*) { "token-value" }
|
|
16
18
|
end
|
|
17
19
|
|
|
18
|
-
it
|
|
20
|
+
it "accepts anything that responds to #call" do
|
|
19
21
|
expect(method).to receive(:call).with(request)
|
|
20
22
|
Token.from_request request, method
|
|
21
23
|
end
|
|
22
24
|
|
|
23
|
-
it
|
|
25
|
+
it "delegates methods received as symbols to Token class" do
|
|
24
26
|
expect(Token).to receive(:from_params).with(request)
|
|
25
27
|
Token.from_request request, :from_params
|
|
26
28
|
end
|
|
27
29
|
|
|
28
|
-
it
|
|
30
|
+
it "stops at the first credentials found" do
|
|
29
31
|
not_called_method = double
|
|
30
32
|
expect(not_called_method).not_to receive(:call)
|
|
31
33
|
Token.from_request request, ->(_r) {}, method, not_called_method
|
|
32
34
|
end
|
|
33
35
|
|
|
34
|
-
it
|
|
36
|
+
it "returns the credential from extractor method" do
|
|
35
37
|
credentials = Token.from_request request, method
|
|
36
|
-
expect(credentials).to eq(
|
|
38
|
+
expect(credentials).to eq("token-value")
|
|
37
39
|
end
|
|
38
40
|
end
|
|
39
41
|
|
|
40
42
|
describe :from_access_token_param do
|
|
41
|
-
it
|
|
42
|
-
request = double parameters: { access_token:
|
|
43
|
+
it "returns token from access_token parameter" do
|
|
44
|
+
request = double parameters: { access_token: "some-token" }
|
|
43
45
|
token = Token.from_access_token_param(request)
|
|
44
|
-
expect(token).to eq(
|
|
46
|
+
expect(token).to eq("some-token")
|
|
45
47
|
end
|
|
46
48
|
end
|
|
47
49
|
|
|
48
50
|
describe :from_bearer_param do
|
|
49
|
-
it
|
|
50
|
-
request = double parameters: { bearer_token:
|
|
51
|
+
it "returns token from bearer_token parameter" do
|
|
52
|
+
request = double parameters: { bearer_token: "some-token" }
|
|
51
53
|
token = Token.from_bearer_param(request)
|
|
52
|
-
expect(token).to eq(
|
|
54
|
+
expect(token).to eq("some-token")
|
|
53
55
|
end
|
|
54
56
|
end
|
|
55
57
|
|
|
56
58
|
describe :from_bearer_authorization do
|
|
57
|
-
it
|
|
58
|
-
request = double authorization:
|
|
59
|
+
it "returns token from capitalized authorization bearer" do
|
|
60
|
+
request = double authorization: "Bearer SomeToken"
|
|
59
61
|
token = Token.from_bearer_authorization(request)
|
|
60
|
-
expect(token).to eq(
|
|
62
|
+
expect(token).to eq("SomeToken")
|
|
61
63
|
end
|
|
62
64
|
|
|
63
|
-
it
|
|
64
|
-
request = double authorization:
|
|
65
|
+
it "returns token from lowercased authorization bearer" do
|
|
66
|
+
request = double authorization: "bearer SomeToken"
|
|
65
67
|
token = Token.from_bearer_authorization(request)
|
|
66
|
-
expect(token).to eq(
|
|
68
|
+
expect(token).to eq("SomeToken")
|
|
67
69
|
end
|
|
68
70
|
|
|
69
|
-
it
|
|
70
|
-
request = double authorization:
|
|
71
|
+
it "does not return token if authorization is not bearer" do
|
|
72
|
+
request = double authorization: "MAC SomeToken"
|
|
71
73
|
token = Token.from_bearer_authorization(request)
|
|
72
74
|
expect(token).to be_blank
|
|
73
75
|
end
|
|
74
76
|
end
|
|
75
77
|
|
|
76
78
|
describe :from_basic_authorization do
|
|
77
|
-
it
|
|
78
|
-
request = double authorization: "Basic #{Base64.encode64
|
|
79
|
+
it "returns token from capitalized authorization basic" do
|
|
80
|
+
request = double authorization: "Basic #{Base64.encode64 "SomeToken:"}"
|
|
79
81
|
token = Token.from_basic_authorization(request)
|
|
80
|
-
expect(token).to eq(
|
|
82
|
+
expect(token).to eq("SomeToken")
|
|
81
83
|
end
|
|
82
84
|
|
|
83
|
-
it
|
|
84
|
-
request = double authorization: "basic #{Base64.encode64
|
|
85
|
+
it "returns token from lowercased authorization basic" do
|
|
86
|
+
request = double authorization: "basic #{Base64.encode64 "SomeToken:"}"
|
|
85
87
|
token = Token.from_basic_authorization(request)
|
|
86
|
-
expect(token).to eq(
|
|
88
|
+
expect(token).to eq("SomeToken")
|
|
87
89
|
end
|
|
88
90
|
|
|
89
|
-
it
|
|
90
|
-
request = double authorization: "MAC #{Base64.encode64
|
|
91
|
+
it "does not return token if authorization is not basic" do
|
|
92
|
+
request = double authorization: "MAC #{Base64.encode64 "SomeToken:"}"
|
|
91
93
|
token = Token.from_basic_authorization(request)
|
|
92
94
|
expect(token).to be_blank
|
|
93
95
|
end
|
|
94
96
|
end
|
|
95
97
|
|
|
96
98
|
describe :authenticate do
|
|
97
|
-
context
|
|
98
|
-
context
|
|
99
|
-
it
|
|
100
|
-
token = ->(_r) {
|
|
99
|
+
context "refresh tokens are disabled (default)" do
|
|
100
|
+
context "refresh tokens are enabled" do
|
|
101
|
+
it "does not revoke previous refresh_token if token was found" do
|
|
102
|
+
token = ->(_r) { "token" }
|
|
101
103
|
expect(
|
|
102
104
|
AccessToken
|
|
103
|
-
).to receive(:by_token).with(
|
|
105
|
+
).to receive(:by_token).with("token").and_return(token)
|
|
104
106
|
expect(token).not_to receive(:revoke_previous_refresh_token!)
|
|
105
107
|
Token.authenticate double, token
|
|
106
108
|
end
|
|
107
109
|
end
|
|
108
110
|
|
|
109
|
-
it
|
|
110
|
-
token = ->(_r) {
|
|
111
|
-
expect(AccessToken).to receive(:by_token).with(
|
|
111
|
+
it "calls the finder if token was returned" do
|
|
112
|
+
token = ->(_r) { "token" }
|
|
113
|
+
expect(AccessToken).to receive(:by_token).with("token")
|
|
114
|
+
Token.authenticate double, token
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
context "token hashing is enabled" do
|
|
119
|
+
include_context "with token hashing enabled"
|
|
120
|
+
|
|
121
|
+
let(:hashed_token) { hashed_or_plain_token_func.call("token") }
|
|
122
|
+
let(:token) { ->(_r) { "token" } }
|
|
123
|
+
|
|
124
|
+
it "searches with the hashed token" do
|
|
125
|
+
expect(
|
|
126
|
+
AccessToken
|
|
127
|
+
).to receive(:find_by).with(token: hashed_token).and_return(token)
|
|
112
128
|
Token.authenticate double, token
|
|
113
129
|
end
|
|
114
130
|
end
|
|
115
131
|
|
|
116
|
-
context
|
|
132
|
+
context "refresh tokens are enabled" do
|
|
117
133
|
before do
|
|
118
134
|
Doorkeeper.configure do
|
|
119
135
|
orm DOORKEEPER_ORM
|
|
@@ -121,18 +137,18 @@ module Doorkeeper
|
|
|
121
137
|
end
|
|
122
138
|
end
|
|
123
139
|
|
|
124
|
-
it
|
|
125
|
-
token = ->(_r) {
|
|
140
|
+
it "revokes previous refresh_token if token was found" do
|
|
141
|
+
token = ->(_r) { "token" }
|
|
126
142
|
expect(
|
|
127
143
|
AccessToken
|
|
128
|
-
).to receive(:by_token).with(
|
|
144
|
+
).to receive(:by_token).with("token").and_return(token)
|
|
129
145
|
expect(token).to receive(:revoke_previous_refresh_token!)
|
|
130
146
|
Token.authenticate double, token
|
|
131
147
|
end
|
|
132
148
|
|
|
133
|
-
it
|
|
134
|
-
token = ->(_r) {
|
|
135
|
-
expect(AccessToken).to receive(:by_token).with(
|
|
149
|
+
it "calls the finder if token was returned" do
|
|
150
|
+
token = ->(_r) { "token" }
|
|
151
|
+
expect(AccessToken).to receive(:by_token).with("token")
|
|
136
152
|
Token.authenticate double, token
|
|
137
153
|
end
|
|
138
154
|
end
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "spec_helper"
|
|
4
|
+
|
|
5
|
+
describe ::Doorkeeper::SecretStoring::Base do
|
|
6
|
+
let(:instance) { double("instance", token: "foo") }
|
|
7
|
+
subject { described_class }
|
|
8
|
+
|
|
9
|
+
describe "#transform_secret" do
|
|
10
|
+
it "raises" do
|
|
11
|
+
expect { subject.transform_secret("foo") }.to raise_error(NotImplementedError)
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
describe "#store_secret" do
|
|
16
|
+
it "sends to response of #transform_secret to the instance" do
|
|
17
|
+
expect(described_class)
|
|
18
|
+
.to receive(:transform_secret).with("bar")
|
|
19
|
+
.and_return "bar+transform"
|
|
20
|
+
|
|
21
|
+
expect(instance).to receive(:token=).with "bar+transform"
|
|
22
|
+
result = subject.store_secret instance, :token, "bar"
|
|
23
|
+
expect(result).to eq "bar+transform"
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
describe "#restore_secret" do
|
|
28
|
+
it "raises" do
|
|
29
|
+
expect { subject.restore_secret(subject, :token) }.to raise_error(NotImplementedError)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
describe "#allows_restoring_secrets?" do
|
|
34
|
+
it "does not allow it" do
|
|
35
|
+
expect(subject.allows_restoring_secrets?).to eq false
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
describe "validate_for" do
|
|
40
|
+
it "allows for valid model" do
|
|
41
|
+
expect(subject.validate_for(:application)).to eq true
|
|
42
|
+
expect(subject.validate_for(:token)).to eq true
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
it "raises for invalid model" do
|
|
46
|
+
expect { subject.validate_for(:wat) }.to raise_error(ArgumentError, /can not be used for wat/)
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
describe "secret_matches?" do
|
|
51
|
+
before do
|
|
52
|
+
allow(subject).to receive(:transform_secret) { |input| "transformed: #{input}" }
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
it "compares input with #transform_secret" do
|
|
56
|
+
expect(subject.secret_matches?("input", "input")).to eq false
|
|
57
|
+
expect(subject.secret_matches?("a", "transformed: a")).to eq true
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "spec_helper"
|
|
4
|
+
require "bcrypt"
|
|
5
|
+
|
|
6
|
+
describe ::Doorkeeper::SecretStoring::BCrypt do
|
|
7
|
+
subject { described_class }
|
|
8
|
+
let(:instance) { double("instance", token: "foo") }
|
|
9
|
+
|
|
10
|
+
describe "#transform_secret" do
|
|
11
|
+
it "creates a bcrypt password" do
|
|
12
|
+
expect(subject.transform_secret("foo")).to be_a BCrypt::Password
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
describe "#restore_secret" do
|
|
17
|
+
it "raises" do
|
|
18
|
+
expect { subject.restore_secret(instance, :token) }.to raise_error(NotImplementedError)
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
describe "#allows_restoring_secrets?" do
|
|
23
|
+
it "does not allow it" do
|
|
24
|
+
expect(subject.allows_restoring_secrets?).to eq false
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
describe "validate_for" do
|
|
29
|
+
it "allows for valid model" do
|
|
30
|
+
expect(subject.validate_for(:application)).to eq true
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
it "raises for invalid model" do
|
|
34
|
+
expect { subject.validate_for(:wat) }
|
|
35
|
+
.to raise_error(ArgumentError, /can only be used for storing application secrets/)
|
|
36
|
+
expect { subject.validate_for(:token) }
|
|
37
|
+
.to raise_error(ArgumentError, /can only be used for storing application secrets/)
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
describe "secret_matches?" do
|
|
42
|
+
it "compares input with #transform_secret" do
|
|
43
|
+
expect(subject.secret_matches?("input", "input")).to eq false
|
|
44
|
+
|
|
45
|
+
password = BCrypt::Password.create "foobar"
|
|
46
|
+
expect(subject.secret_matches?("foobar", password.to_s)).to eq true
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "spec_helper"
|
|
4
|
+
|
|
5
|
+
describe ::Doorkeeper::SecretStoring::Plain do
|
|
6
|
+
subject { described_class }
|
|
7
|
+
let(:instance) { double("instance", token: "foo") }
|
|
8
|
+
|
|
9
|
+
describe "#transform_secret" do
|
|
10
|
+
it "raises" do
|
|
11
|
+
expect(subject.transform_secret("foo")).to eq "foo"
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
describe "#restore_secret" do
|
|
16
|
+
it "raises" do
|
|
17
|
+
expect(subject.restore_secret(instance, :token)).to eq "foo"
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
describe "#allows_restoring_secrets?" do
|
|
22
|
+
it "does allow it" do
|
|
23
|
+
expect(subject.allows_restoring_secrets?).to eq true
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
describe "validate_for" do
|
|
28
|
+
it "allows for valid model" do
|
|
29
|
+
expect(subject.validate_for(:application)).to eq true
|
|
30
|
+
expect(subject.validate_for(:token)).to eq true
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
it "raises for invalid model" do
|
|
34
|
+
expect { subject.validate_for(:wat) }.to raise_error(ArgumentError, /can not be used for wat/)
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
describe "secret_matches?" do
|
|
39
|
+
it "compares input with #transform_secret" do
|
|
40
|
+
expect(subject.secret_matches?("input", "input")).to eq true
|
|
41
|
+
expect(subject.secret_matches?("a", "b")).to eq false
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "spec_helper"
|
|
4
|
+
|
|
5
|
+
describe ::Doorkeeper::SecretStoring::Sha256Hash do
|
|
6
|
+
subject { described_class }
|
|
7
|
+
let(:instance) { double("instance") }
|
|
8
|
+
|
|
9
|
+
let(:hash_function) do
|
|
10
|
+
->(input) { ::Digest::SHA256.hexdigest(input) }
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
describe "#transform_secret" do
|
|
14
|
+
it "raises" do
|
|
15
|
+
expect(subject.transform_secret("foo")).to eq hash_function.call("foo")
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
describe "#restore_secret" do
|
|
20
|
+
it "raises" do
|
|
21
|
+
expect { subject.restore_secret(instance, :token) }.to raise_error(NotImplementedError)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
describe "#allows_restoring_secrets?" do
|
|
26
|
+
it "does not allow it" do
|
|
27
|
+
expect(subject.allows_restoring_secrets?).to eq false
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
describe "validate_for" do
|
|
32
|
+
it "allows for valid model" do
|
|
33
|
+
expect(subject.validate_for(:application)).to eq true
|
|
34
|
+
expect(subject.validate_for(:token)).to eq true
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
it "raises for invalid model" do
|
|
38
|
+
expect { subject.validate_for(:wat) }.to raise_error(ArgumentError, /can not be used for wat/)
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
describe "secret_matches?" do
|
|
43
|
+
it "compares input with #transform_secret" do
|
|
44
|
+
expect(subject.secret_matches?("input", "input")).to eq false
|
|
45
|
+
expect(subject.secret_matches?("a", hash_function.call("a"))).to eq true
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
data/spec/lib/server_spec.rb
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "spec_helper"
|
|
2
4
|
|
|
3
5
|
describe Doorkeeper::Server do
|
|
4
6
|
let(:fake_class) { double :fake_class }
|
|
@@ -7,53 +9,53 @@ describe Doorkeeper::Server do
|
|
|
7
9
|
described_class.new
|
|
8
10
|
end
|
|
9
11
|
|
|
10
|
-
describe
|
|
11
|
-
it
|
|
12
|
+
describe ".authorization_request" do
|
|
13
|
+
it "raises error when strategy does not exist" do
|
|
12
14
|
expect do
|
|
13
15
|
subject.authorization_request(:duh)
|
|
14
16
|
end.to raise_error(Doorkeeper::Errors::InvalidAuthorizationStrategy)
|
|
15
17
|
end
|
|
16
18
|
|
|
17
|
-
it
|
|
19
|
+
it "raises error when strategy does not match phase" do
|
|
18
20
|
expect do
|
|
19
21
|
subject.token_request(:code)
|
|
20
22
|
end.to raise_error(Doorkeeper::Errors::InvalidTokenStrategy)
|
|
21
23
|
end
|
|
22
24
|
|
|
23
|
-
context
|
|
25
|
+
context "when only Authorization Code strategy is enabled" do
|
|
24
26
|
before do
|
|
25
27
|
allow(Doorkeeper.configuration)
|
|
26
28
|
.to receive(:grant_flows)
|
|
27
|
-
.and_return([
|
|
29
|
+
.and_return(["authorization_code"])
|
|
28
30
|
end
|
|
29
31
|
|
|
30
|
-
it
|
|
32
|
+
it "raises error when using the disabled Implicit strategy" do
|
|
31
33
|
expect do
|
|
32
34
|
subject.authorization_request(:token)
|
|
33
35
|
end.to raise_error(Doorkeeper::Errors::InvalidAuthorizationStrategy)
|
|
34
36
|
end
|
|
35
37
|
|
|
36
|
-
it
|
|
38
|
+
it "raises error when using the disabled Client Credentials strategy" do
|
|
37
39
|
expect do
|
|
38
40
|
subject.token_request(:client_credentials)
|
|
39
41
|
end.to raise_error(Doorkeeper::Errors::InvalidTokenStrategy)
|
|
40
42
|
end
|
|
41
43
|
end
|
|
42
44
|
|
|
43
|
-
it
|
|
44
|
-
stub_const
|
|
45
|
+
it "builds the request with selected strategy" do
|
|
46
|
+
stub_const "Doorkeeper::Request::Code", fake_class
|
|
45
47
|
expect(fake_class).to receive(:new).with(subject)
|
|
46
48
|
subject.authorization_request :code
|
|
47
49
|
end
|
|
48
50
|
|
|
49
|
-
it
|
|
51
|
+
it "builds the request with composite strategy name" do
|
|
50
52
|
allow(Doorkeeper.configuration)
|
|
51
53
|
.to receive(:authorization_response_types)
|
|
52
|
-
.and_return([
|
|
54
|
+
.and_return(["id_token token"])
|
|
53
55
|
|
|
54
|
-
stub_const
|
|
56
|
+
stub_const "Doorkeeper::Request::IdTokenToken", fake_class
|
|
55
57
|
expect(fake_class).to receive(:new).with(subject)
|
|
56
|
-
subject.authorization_request
|
|
58
|
+
subject.authorization_request "id_token token"
|
|
57
59
|
end
|
|
58
60
|
end
|
|
59
61
|
end
|
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require
|
|
3
|
+
require "spec_helper"
|
|
4
4
|
|
|
5
5
|
describe Doorkeeper::StaleRecordsCleaner do
|
|
6
6
|
let(:cleaner) { described_class.new(model) }
|
|
7
7
|
let(:models_by_name) do
|
|
8
8
|
{
|
|
9
9
|
access_token: Doorkeeper::AccessToken,
|
|
10
|
-
access_grant: Doorkeeper::AccessGrant
|
|
10
|
+
access_grant: Doorkeeper::AccessGrant,
|
|
11
11
|
}
|
|
12
12
|
end
|
|
13
13
|
|
|
14
|
-
context
|
|
15
|
-
it
|
|
16
|
-
allow_any_instance_of(Doorkeeper::Config).to receive(:orm).and_return(
|
|
14
|
+
context "when ORM has no cleaner class" do
|
|
15
|
+
it "raises an error" do
|
|
16
|
+
allow_any_instance_of(Doorkeeper::Config).to receive(:orm).and_return("hibernate")
|
|
17
17
|
|
|
18
18
|
expect do
|
|
19
19
|
described_class.for(Doorkeeper::AccessToken)
|
|
@@ -25,61 +25,61 @@ describe Doorkeeper::StaleRecordsCleaner do
|
|
|
25
25
|
context "(#{model_name})" do
|
|
26
26
|
let(:model) { models_by_name.fetch(model_name) }
|
|
27
27
|
|
|
28
|
-
describe
|
|
28
|
+
describe "#clean_revoked" do
|
|
29
29
|
subject { cleaner.clean_revoked }
|
|
30
30
|
|
|
31
|
-
context
|
|
31
|
+
context "with revoked record" do
|
|
32
32
|
before do
|
|
33
33
|
FactoryBot.create model_name, revoked_at: Time.current - 1.minute
|
|
34
34
|
end
|
|
35
35
|
|
|
36
|
-
it
|
|
36
|
+
it "removes the record" do
|
|
37
37
|
expect { subject }.to change { model.count }.to(0)
|
|
38
38
|
end
|
|
39
39
|
end
|
|
40
40
|
|
|
41
|
-
context
|
|
41
|
+
context "with record revoked in the future" do
|
|
42
42
|
before do
|
|
43
43
|
FactoryBot.create model_name, revoked_at: Time.current + 1.minute
|
|
44
44
|
end
|
|
45
45
|
|
|
46
|
-
it
|
|
46
|
+
it "keeps the record" do
|
|
47
47
|
expect { subject }.not_to(change { model.count })
|
|
48
48
|
end
|
|
49
49
|
end
|
|
50
50
|
|
|
51
|
-
context
|
|
51
|
+
context "with unrevoked record" do
|
|
52
52
|
before do
|
|
53
53
|
FactoryBot.create model_name, revoked_at: nil
|
|
54
54
|
end
|
|
55
55
|
|
|
56
|
-
it
|
|
56
|
+
it "keeps the record" do
|
|
57
57
|
expect { subject }.not_to(change { model.count })
|
|
58
58
|
end
|
|
59
59
|
end
|
|
60
60
|
end
|
|
61
61
|
|
|
62
|
-
describe
|
|
62
|
+
describe "#clean_expired" do
|
|
63
63
|
subject { cleaner.clean_expired(ttl) }
|
|
64
64
|
let(:ttl) { 500 }
|
|
65
65
|
let(:expiry_border) { ttl.seconds.ago }
|
|
66
66
|
|
|
67
|
-
context
|
|
67
|
+
context "with record that is expired" do
|
|
68
68
|
before do
|
|
69
69
|
FactoryBot.create model_name, created_at: expiry_border - 1.minute
|
|
70
70
|
end
|
|
71
71
|
|
|
72
|
-
it
|
|
72
|
+
it "removes the record" do
|
|
73
73
|
expect { subject }.to change { model.count }.to(0)
|
|
74
74
|
end
|
|
75
75
|
end
|
|
76
76
|
|
|
77
|
-
context
|
|
77
|
+
context "with record that is not expired" do
|
|
78
78
|
before do
|
|
79
79
|
FactoryBot.create model_name, created_at: expiry_border + 1.minute
|
|
80
80
|
end
|
|
81
81
|
|
|
82
|
-
it
|
|
82
|
+
it "keeps the record" do
|
|
83
83
|
expect { subject }.not_to(change { model.count })
|
|
84
84
|
end
|
|
85
85
|
end
|