doorkeeper 5.1.2 → 5.2.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of doorkeeper might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +812 -0
- data/CONTRIBUTING.md +4 -9
- data/Dangerfile +1 -1
- data/Gemfile +2 -1
- data/NEWS.md +1 -819
- data/README.md +2 -2
- data/RELEASING.md +6 -5
- data/app/controllers/doorkeeper/applications_controller.rb +5 -3
- data/app/controllers/doorkeeper/authorized_applications_controller.rb +1 -1
- data/app/controllers/doorkeeper/tokens_controller.rb +18 -8
- data/app/validators/redirect_uri_validator.rb +19 -9
- data/app/views/doorkeeper/applications/_form.html.erb +0 -6
- data/app/views/doorkeeper/applications/show.html.erb +1 -1
- data/config/locales/en.yml +3 -1
- data/doorkeeper.gemspec +1 -1
- data/gemfiles/rails_5_0.gemfile +1 -0
- data/gemfiles/rails_5_1.gemfile +1 -0
- data/gemfiles/rails_5_2.gemfile +1 -0
- data/gemfiles/rails_6_0.gemfile +2 -1
- data/gemfiles/rails_master.gemfile +1 -0
- data/lib/doorkeeper.rb +3 -0
- data/lib/doorkeeper/config.rb +30 -3
- data/lib/doorkeeper/config/option.rb +13 -7
- data/lib/doorkeeper/grape/helpers.rb +5 -1
- data/lib/doorkeeper/helpers/controller.rb +16 -3
- data/lib/doorkeeper/oauth/authorization/code.rb +10 -8
- data/lib/doorkeeper/oauth/authorization/token.rb +1 -1
- data/lib/doorkeeper/oauth/code_response.rb +2 -2
- data/lib/doorkeeper/oauth/error_response.rb +1 -1
- data/lib/doorkeeper/oauth/helpers/uri_checker.rb +18 -4
- data/lib/doorkeeper/oauth/nonstandard.rb +39 -0
- data/lib/doorkeeper/oauth/refresh_token_request.rb +8 -8
- data/lib/doorkeeper/oauth/token_introspection.rb +13 -12
- data/lib/doorkeeper/orm/active_record.rb +17 -1
- data/lib/doorkeeper/orm/active_record/access_grant.rb +1 -1
- data/lib/doorkeeper/orm/active_record/access_token.rb +2 -2
- data/lib/doorkeeper/orm/active_record/application.rb +5 -65
- data/lib/doorkeeper/stale_records_cleaner.rb +6 -2
- data/lib/doorkeeper/version.rb +3 -3
- data/lib/generators/doorkeeper/previous_refresh_token_generator.rb +6 -6
- data/lib/generators/doorkeeper/templates/initializer.rb +41 -9
- data/lib/generators/doorkeeper/templates/migration.rb.erb +3 -0
- data/spec/controllers/applications_controller_spec.rb +93 -0
- data/spec/controllers/protected_resources_controller_spec.rb +3 -3
- data/spec/controllers/tokens_controller_spec.rb +71 -3
- data/spec/dummy/config/application.rb +3 -1
- data/spec/dummy/config/initializers/doorkeeper.rb +27 -9
- data/spec/lib/config_spec.rb +11 -0
- data/spec/lib/oauth/helpers/uri_checker_spec.rb +17 -2
- data/spec/lib/oauth/pre_authorization_spec.rb +0 -15
- data/spec/models/doorkeeper/application_spec.rb +268 -373
- data/spec/requests/flows/authorization_code_spec.rb +16 -4
- data/spec/requests/flows/revoke_token_spec.rb +19 -11
- data/spec/support/doorkeeper_rspec.rb +1 -1
- data/spec/validators/redirect_uri_validator_spec.rb +39 -14
- metadata +7 -15
- data/.coveralls.yml +0 -1
- data/.github/ISSUE_TEMPLATE.md +0 -25
- data/.github/PULL_REQUEST_TEMPLATE.md +0 -17
- data/.gitignore +0 -20
- data/.gitlab-ci.yml +0 -16
- data/.hound.yml +0 -3
- data/.rspec +0 -1
- data/.rubocop.yml +0 -50
- data/.travis.yml +0 -35
@@ -36,6 +36,9 @@ class CreateDoorkeeperTables < ActiveRecord::Migration<%= migration_version %>
|
|
36
36
|
|
37
37
|
create_table :oauth_access_tokens do |t|
|
38
38
|
t.references :resource_owner, index: true
|
39
|
+
|
40
|
+
# Remove `null: false` if you are planning to use Password
|
41
|
+
# Credentials Grant flow that doesn't require an application.
|
39
42
|
t.references :application, null: false
|
40
43
|
|
41
44
|
# If you use a custom token generator you may need to change this column
|
@@ -26,6 +26,10 @@ module Doorkeeper
|
|
26
26
|
|
27
27
|
expect(json_response).to include("id", "name", "uid", "secret", "redirect_uri", "scopes")
|
28
28
|
|
29
|
+
application = Application.last
|
30
|
+
secret_from_response = json_response["secret"]
|
31
|
+
expect(application.secret_matches?(secret_from_response)).to be_truthy
|
32
|
+
|
29
33
|
expect(json_response["name"]).to eq("Example")
|
30
34
|
expect(json_response["redirect_uri"]).to eq("https://example.com")
|
31
35
|
end
|
@@ -44,6 +48,21 @@ module Doorkeeper
|
|
44
48
|
expect(json_response).to include("errors")
|
45
49
|
end
|
46
50
|
|
51
|
+
it "returns validations on wrong create params (unspecified scheme)" do
|
52
|
+
expect do
|
53
|
+
post :create, params: {
|
54
|
+
doorkeeper_application: {
|
55
|
+
name: "Example",
|
56
|
+
redirect_uri: "app.com:80",
|
57
|
+
}, format: :json,
|
58
|
+
}
|
59
|
+
end.not_to(change { Doorkeeper::Application.count })
|
60
|
+
|
61
|
+
expect(response).to have_http_status(422)
|
62
|
+
|
63
|
+
expect(json_response).to include("errors")
|
64
|
+
end
|
65
|
+
|
47
66
|
it "returns application info" do
|
48
67
|
application = FactoryBot.create(:application, name: "Change me")
|
49
68
|
|
@@ -121,6 +140,72 @@ module Doorkeeper
|
|
121
140
|
end
|
122
141
|
|
123
142
|
context "when admin is authenticated" do
|
143
|
+
context "when application secrets are hashed" do
|
144
|
+
before do
|
145
|
+
allow(Doorkeeper.configuration).to receive(:application_secret_strategy).and_return(Doorkeeper::SecretStoring::Sha256Hash)
|
146
|
+
end
|
147
|
+
|
148
|
+
it "shows the application secret after creating a new application" do
|
149
|
+
expect do
|
150
|
+
post :create, params: {
|
151
|
+
doorkeeper_application: {
|
152
|
+
name: "Example",
|
153
|
+
redirect_uri: "https://example.com",
|
154
|
+
},
|
155
|
+
}
|
156
|
+
end.to change { Doorkeeper::Application.count }.by(1)
|
157
|
+
|
158
|
+
application = Application.last
|
159
|
+
|
160
|
+
secret_from_flash = flash[:application_secret]
|
161
|
+
expect(secret_from_flash).not_to be_empty
|
162
|
+
expect(application.secret_matches?(secret_from_flash)).to be_truthy
|
163
|
+
expect(response).to redirect_to(controller.main_app.oauth_application_url(application.id))
|
164
|
+
|
165
|
+
get :show, params: { id: application.id, format: :html }
|
166
|
+
|
167
|
+
# We don't know the application secret here (because its hashed) so we can not assert its text on the page
|
168
|
+
# Instead, we read it from the page and then check if it matches the application secret
|
169
|
+
code_element = %r{<code.*id="secret".*>(.*)<\/code>}.match(response.body)
|
170
|
+
secret_from_page = code_element[1]
|
171
|
+
|
172
|
+
expect(response.body).to have_selector("code#application_id", text: application.uid)
|
173
|
+
expect(response.body).to have_selector("code#secret")
|
174
|
+
expect(secret_from_page).not_to be_empty
|
175
|
+
expect(application.secret_matches?(secret_from_page)).to be_truthy
|
176
|
+
end
|
177
|
+
|
178
|
+
it "does not show an application secret when application did already exist" do
|
179
|
+
application = FactoryBot.create(:application)
|
180
|
+
get :show, params: { id: application.id, format: :html }
|
181
|
+
|
182
|
+
expect(response.body).to have_selector("code#application_id", text: application.uid)
|
183
|
+
expect(response.body).to have_selector("code#secret", text: "")
|
184
|
+
end
|
185
|
+
|
186
|
+
it "returns the application details in a json response" do
|
187
|
+
expect do
|
188
|
+
post :create, params: {
|
189
|
+
doorkeeper_application: {
|
190
|
+
name: "Example",
|
191
|
+
redirect_uri: "https://example.com",
|
192
|
+
}, format: :json,
|
193
|
+
}
|
194
|
+
end.to(change { Doorkeeper::Application.count })
|
195
|
+
|
196
|
+
expect(response).to be_successful
|
197
|
+
|
198
|
+
expect(json_response).to include("id", "name", "uid", "secret", "redirect_uri", "scopes")
|
199
|
+
|
200
|
+
application = Application.last
|
201
|
+
secret_from_response = json_response["secret"]
|
202
|
+
expect(application.secret_matches?(secret_from_response)).to be_truthy
|
203
|
+
|
204
|
+
expect(json_response["name"]).to eq("Example")
|
205
|
+
expect(json_response["redirect_uri"]).to eq("https://example.com")
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
124
209
|
render_views
|
125
210
|
|
126
211
|
before do
|
@@ -151,6 +236,14 @@ module Doorkeeper
|
|
151
236
|
expect(response).to be_redirect
|
152
237
|
end
|
153
238
|
|
239
|
+
it "shows application details" do
|
240
|
+
application = FactoryBot.create(:application)
|
241
|
+
get :show, params: { id: application.id, format: :html }
|
242
|
+
|
243
|
+
expect(response.body).to have_selector("code#application_id", text: application.uid)
|
244
|
+
expect(response.body).to have_selector("code#secret", text: application.plaintext_secret)
|
245
|
+
end
|
246
|
+
|
154
247
|
it "does not allow mass assignment of uid or secret" do
|
155
248
|
application = FactoryBot.create(:application)
|
156
249
|
put :update, params: {
|
@@ -166,7 +166,7 @@ describe "doorkeeper authorize filter" do
|
|
166
166
|
it "it renders a custom JSON response", token: :invalid do
|
167
167
|
get :index, params: { access_token: token_string }
|
168
168
|
expect(response.status).to eq 401
|
169
|
-
expect(response.content_type).to
|
169
|
+
expect(response.content_type).to eq("application/json")
|
170
170
|
expect(response.header["WWW-Authenticate"]).to match(/^Bearer/)
|
171
171
|
|
172
172
|
expect(json_response).not_to be_nil
|
@@ -196,7 +196,7 @@ describe "doorkeeper authorize filter" do
|
|
196
196
|
it "it renders a custom text response", token: :invalid do
|
197
197
|
get :index, params: { access_token: token_string }
|
198
198
|
expect(response.status).to eq 401
|
199
|
-
expect(response.content_type).to
|
199
|
+
expect(response.content_type).to eq("text/plain")
|
200
200
|
expect(response.header["WWW-Authenticate"]).to match(/^Bearer/)
|
201
201
|
expect(response.body).to eq("Unauthorized")
|
202
202
|
end
|
@@ -246,7 +246,7 @@ describe "doorkeeper authorize filter" do
|
|
246
246
|
it "renders a custom JSON response" do
|
247
247
|
get :index, params: { access_token: token_string }
|
248
248
|
expect(response.header).to_not include("WWW-Authenticate")
|
249
|
-
expect(response.content_type).to
|
249
|
+
expect(response.content_type).to eq("application/json")
|
250
250
|
expect(response.status).to eq 403
|
251
251
|
|
252
252
|
expect(json_response).not_to be_nil
|
@@ -102,10 +102,10 @@ describe Doorkeeper::TokensController do
|
|
102
102
|
let(:some_other_client) { FactoryBot.create(:application, confidential: true) }
|
103
103
|
let(:oauth_client) { Doorkeeper::OAuth::Client.new(some_other_client) }
|
104
104
|
|
105
|
-
it "returns
|
105
|
+
it "returns 403" do
|
106
106
|
post :revoke, params: { token: access_token.token }
|
107
107
|
|
108
|
-
expect(response.status).to eq
|
108
|
+
expect(response.status).to eq 403
|
109
109
|
end
|
110
110
|
|
111
111
|
it "does not revoke the access token" do
|
@@ -147,7 +147,7 @@ describe Doorkeeper::TokensController do
|
|
147
147
|
end
|
148
148
|
end
|
149
149
|
|
150
|
-
context "authorized using
|
150
|
+
context "authorized using Client Credentials of the client that token is issued to" do
|
151
151
|
it "responds with full token introspection" do
|
152
152
|
request.headers["Authorization"] = basic_auth_header_for_client(client)
|
153
153
|
|
@@ -159,6 +159,24 @@ describe Doorkeeper::TokensController do
|
|
159
159
|
end
|
160
160
|
end
|
161
161
|
|
162
|
+
context "configured token introspection disabled" do
|
163
|
+
before do
|
164
|
+
Doorkeeper.configure do
|
165
|
+
orm DOORKEEPER_ORM
|
166
|
+
allow_token_introspection false
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
it "responds with just active: false response" do
|
171
|
+
request.headers["Authorization"] = "Bearer #{access_token.token}"
|
172
|
+
|
173
|
+
post :introspect, params: { token: token_for_introspection.token }
|
174
|
+
|
175
|
+
should_have_json "active", false
|
176
|
+
expect(json_response).not_to include("client_id", "token_type", "exp", "iat")
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
162
180
|
context "using custom introspection response" do
|
163
181
|
before do
|
164
182
|
Doorkeeper.configure do
|
@@ -212,6 +230,56 @@ describe Doorkeeper::TokensController do
|
|
212
230
|
end
|
213
231
|
end
|
214
232
|
|
233
|
+
context "introspection request authorized by a client and allow_token_introspection is true" do
|
234
|
+
let(:different_client) { FactoryBot.create(:application) }
|
235
|
+
|
236
|
+
before do
|
237
|
+
allow(Doorkeeper.configuration).to receive(:allow_token_introspection).and_return(proc do
|
238
|
+
true
|
239
|
+
end)
|
240
|
+
end
|
241
|
+
|
242
|
+
it "responds with full token introspection" do
|
243
|
+
request.headers["Authorization"] = basic_auth_header_for_client(different_client)
|
244
|
+
|
245
|
+
post :introspect, params: { token: token_for_introspection.token }
|
246
|
+
|
247
|
+
should_have_json "active", true
|
248
|
+
expect(json_response).to include("client_id", "token_type", "exp", "iat")
|
249
|
+
should_have_json "client_id", client.uid
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
context "allow_token_introspection requires authorized token with special scope" do
|
254
|
+
let(:access_token) { FactoryBot.create(:access_token, scopes: "introspection") }
|
255
|
+
|
256
|
+
before do
|
257
|
+
allow(Doorkeeper.configuration).to receive(:allow_token_introspection).and_return(proc do |_token, _client, authorized_token|
|
258
|
+
authorized_token.scopes.include?("introspection")
|
259
|
+
end)
|
260
|
+
end
|
261
|
+
|
262
|
+
it "responds with full token introspection if authorized token has introspection scope" do
|
263
|
+
request.headers["Authorization"] = "Bearer #{access_token.token}"
|
264
|
+
|
265
|
+
post :introspect, params: { token: token_for_introspection.token }
|
266
|
+
|
267
|
+
should_have_json "active", true
|
268
|
+
expect(json_response).to include("client_id", "token_type", "exp", "iat")
|
269
|
+
end
|
270
|
+
|
271
|
+
it "responds with just active status if authorized token doesn't have introspection scope" do
|
272
|
+
access_token.update(scopes: "read write")
|
273
|
+
|
274
|
+
request.headers["Authorization"] = "Bearer #{access_token.token}"
|
275
|
+
|
276
|
+
post :introspect, params: { token: token_for_introspection.token }
|
277
|
+
|
278
|
+
should_have_json "active", false
|
279
|
+
expect(json_response).not_to include("client_id", "token_type", "exp", "iat")
|
280
|
+
end
|
281
|
+
end
|
282
|
+
|
215
283
|
context "authorized using invalid Bearer token" do
|
216
284
|
let(:access_token) do
|
217
285
|
FactoryBot.create(:access_token, application: client, revoked_at: 1.day.ago)
|
@@ -5,11 +5,13 @@ require "rails"
|
|
5
5
|
%w[
|
6
6
|
action_controller/railtie
|
7
7
|
action_view/railtie
|
8
|
+
action_cable/engine
|
8
9
|
sprockets/railtie
|
9
10
|
].each do |railtie|
|
10
11
|
begin
|
11
12
|
require railtie
|
12
|
-
rescue LoadError
|
13
|
+
rescue LoadError => e
|
14
|
+
puts "Error loading '#{railtie}' (#{e.message})"
|
13
15
|
end
|
14
16
|
end
|
15
17
|
|
@@ -65,15 +65,6 @@ Doorkeeper.configure do
|
|
65
65
|
# Check out the wiki for more information on customization
|
66
66
|
# access_token_methods :from_bearer_authorization, :from_access_token_param, :from_bearer_param
|
67
67
|
|
68
|
-
# Change the native redirect uri for client apps
|
69
|
-
# When clients register with the following redirect uri, they won't be redirected to any server and
|
70
|
-
# the authorization code will be displayed within the provider
|
71
|
-
# The value can be any string. Use nil to disable this feature.
|
72
|
-
# When disabled, clients must provide a valid URL
|
73
|
-
# (Similar behaviour: https://developers.google.com/accounts/docs/OAuth2InstalledApp#choosingredirecturi)
|
74
|
-
#
|
75
|
-
# native_redirect_uri 'urn:ietf:wg:oauth:2.0:oob'
|
76
|
-
|
77
68
|
# Forces the usage of the HTTPS protocol in non-native redirect uris (enabled
|
78
69
|
# by default in non-development environments). OAuth2 delegates security in
|
79
70
|
# communication to the HTTPS protocol so it is wise to keep this enabled.
|
@@ -116,6 +107,33 @@ Doorkeeper.configure do
|
|
116
107
|
# client.superapp? or resource_owner.admin?
|
117
108
|
# end
|
118
109
|
|
110
|
+
# Implement constraints in case you use Client Credentials to authenticate
|
111
|
+
# the introspection endpoint.
|
112
|
+
# By default allow introspection if the introspected token belongs to authorized client,
|
113
|
+
# OR token doesn't belong to any client (public token). Otherwise disallow.
|
114
|
+
#
|
115
|
+
# Params:
|
116
|
+
# `token` - the token to be introspected (see Doorkeeper::AccessToken)
|
117
|
+
# `client` - the client application authorized for the endpoint (see Doorkeeper::Application)
|
118
|
+
#
|
119
|
+
# You can completely ignore it:
|
120
|
+
# allow_token_introspection do |_token, _client|
|
121
|
+
# false
|
122
|
+
# end
|
123
|
+
#
|
124
|
+
# Or you can define your custom check:
|
125
|
+
# Adding `protected_resource` boolean column to applications table
|
126
|
+
# to allow protected_resource client introspect the token of normal client.
|
127
|
+
# In this case, protected resource client must be confidential.
|
128
|
+
#
|
129
|
+
# allow_token_introspection do |token, client|
|
130
|
+
# if token.application
|
131
|
+
# token.application == client || client.protected_resource?
|
132
|
+
# else
|
133
|
+
# true
|
134
|
+
# end
|
135
|
+
# end
|
136
|
+
|
119
137
|
# WWW-Authenticate Realm (default "Doorkeeper").
|
120
138
|
realm "Doorkeeper"
|
121
139
|
end
|
data/spec/lib/config_spec.rb
CHANGED
@@ -694,4 +694,15 @@ describe Doorkeeper, "configuration" do
|
|
694
694
|
end
|
695
695
|
end
|
696
696
|
end
|
697
|
+
|
698
|
+
describe "options deprecation" do
|
699
|
+
it "prints a warning message when an option is deprecated" do
|
700
|
+
expect(Kernel).to receive(:warn).with(
|
701
|
+
"[DOORKEEPER] native_redirect_uri has been deprecated and will soon be removed"
|
702
|
+
)
|
703
|
+
Doorkeeper.configure do
|
704
|
+
native_redirect_uri "urn:ietf:wg:oauth:2.0:oob"
|
705
|
+
end
|
706
|
+
end
|
707
|
+
end
|
697
708
|
end
|
@@ -40,13 +40,28 @@ module Doorkeeper::OAuth::Helpers
|
|
40
40
|
expect(URIChecker.valid?(uri)).to be_falsey
|
41
41
|
end
|
42
42
|
|
43
|
+
it "is invalid if localhost is resolved as as scheme (no scheme specified)" do
|
44
|
+
uri = "localhost:8080"
|
45
|
+
expect(URIChecker.valid?(uri)).to be_falsey
|
46
|
+
end
|
47
|
+
|
48
|
+
it "is invalid if scheme is missing #2" do
|
49
|
+
uri = "app.co:80"
|
50
|
+
expect(URIChecker.valid?(uri)).to be_falsey
|
51
|
+
end
|
52
|
+
|
43
53
|
it "is invalid if is not an uri" do
|
44
54
|
uri = " "
|
45
55
|
expect(URIChecker.valid?(uri)).to be_falsey
|
46
56
|
end
|
47
57
|
|
48
|
-
it "is valid for
|
49
|
-
uri = "
|
58
|
+
it "is valid for custom schemes" do
|
59
|
+
uri = "com.example.app:/test"
|
60
|
+
expect(URIChecker.valid?(uri)).to be_truthy
|
61
|
+
end
|
62
|
+
|
63
|
+
it "is valid for custom schemes with authority marker (common misconfiguration)" do
|
64
|
+
uri = "com.example.app://test"
|
50
65
|
expect(URIChecker.valid?(uri)).to be_truthy
|
51
66
|
end
|
52
67
|
end
|
@@ -149,21 +149,6 @@ module Doorkeeper::OAuth
|
|
149
149
|
expect(subject.scopes).to eq(Scopes.from_string("default"))
|
150
150
|
end
|
151
151
|
|
152
|
-
context "with native redirect uri" do
|
153
|
-
let(:native_redirect_uri) { "urn:ietf:wg:oauth:2.0:oob" }
|
154
|
-
|
155
|
-
it "accepts redirect_uri when it matches with the client" do
|
156
|
-
subject.redirect_uri = native_redirect_uri
|
157
|
-
allow(subject.client).to receive(:redirect_uri) { native_redirect_uri }
|
158
|
-
expect(subject).to be_authorizable
|
159
|
-
end
|
160
|
-
|
161
|
-
it "invalidates redirect_uri when it does'n match with the client" do
|
162
|
-
subject.redirect_uri = "urn:ietf:wg:oauth:2.0:oob"
|
163
|
-
expect(subject).not_to be_authorizable
|
164
|
-
end
|
165
|
-
end
|
166
|
-
|
167
152
|
it "matches the redirect uri against client's one" do
|
168
153
|
subject.redirect_uri = "http://nothesame.com"
|
169
154
|
expect(subject).not_to be_authorizable
|
@@ -3,469 +3,364 @@
|
|
3
3
|
require "spec_helper"
|
4
4
|
require "bcrypt"
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
6
|
+
module Doorkeeper
|
7
|
+
describe Application do
|
8
|
+
let(:clazz) { Doorkeeper::Application }
|
9
|
+
let(:require_owner) { Doorkeeper.configuration.instance_variable_set("@confirm_application_owner", true) }
|
10
|
+
let(:unset_require_owner) { Doorkeeper.configuration.instance_variable_set("@confirm_application_owner", false) }
|
11
|
+
let(:new_application) { FactoryBot.build(:application) }
|
10
12
|
|
11
|
-
|
12
|
-
|
13
|
+
let(:uid) { SecureRandom.hex(8) }
|
14
|
+
let(:secret) { SecureRandom.hex(8) }
|
13
15
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
expect(new_application).not_to be_valid
|
22
|
-
end
|
23
|
-
|
24
|
-
it "generates uid on create" do
|
25
|
-
expect(new_application.uid).to be_nil
|
26
|
-
new_application.save
|
27
|
-
expect(new_application.uid).not_to be_nil
|
28
|
-
end
|
29
|
-
|
30
|
-
it "generates uid on create if an empty string" do
|
31
|
-
new_application.uid = ""
|
32
|
-
new_application.save
|
33
|
-
expect(new_application.uid).not_to be_blank
|
34
|
-
end
|
35
|
-
|
36
|
-
it "generates uid on create unless one is set" do
|
37
|
-
new_application.uid = uid
|
38
|
-
new_application.save
|
39
|
-
expect(new_application.uid).to eq(uid)
|
40
|
-
end
|
41
|
-
|
42
|
-
it "is invalid without uid" do
|
43
|
-
new_application.save
|
44
|
-
new_application.uid = nil
|
45
|
-
expect(new_application).not_to be_valid
|
46
|
-
end
|
47
|
-
|
48
|
-
it "checks uniqueness of uid" do
|
49
|
-
app1 = FactoryBot.create(:application)
|
50
|
-
app2 = FactoryBot.create(:application)
|
51
|
-
app2.uid = app1.uid
|
52
|
-
expect(app2).not_to be_valid
|
53
|
-
end
|
54
|
-
|
55
|
-
it "expects database to throw an error when uids are the same" do
|
56
|
-
app1 = FactoryBot.create(:application)
|
57
|
-
app2 = FactoryBot.create(:application)
|
58
|
-
app2.uid = app1.uid
|
59
|
-
expect { app2.save!(validate: false) }.to raise_error(uniqueness_error)
|
60
|
-
end
|
16
|
+
context "application_owner is enabled" do
|
17
|
+
before do
|
18
|
+
Doorkeeper.configure do
|
19
|
+
orm DOORKEEPER_ORM
|
20
|
+
enable_application_owner
|
21
|
+
end
|
22
|
+
end
|
61
23
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
end
|
24
|
+
context "application owner is not required" do
|
25
|
+
before(:each) do
|
26
|
+
unset_require_owner
|
27
|
+
end
|
67
28
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
end
|
29
|
+
it "is valid given valid attributes" do
|
30
|
+
expect(new_application).to be_valid
|
31
|
+
end
|
32
|
+
end
|
73
33
|
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
34
|
+
context "application owner is required" do
|
35
|
+
before(:each) do
|
36
|
+
require_owner
|
37
|
+
@owner = FactoryBot.build_stubbed(:doorkeeper_testing_user)
|
38
|
+
end
|
79
39
|
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
expect(new_application).not_to be_valid
|
84
|
-
end
|
40
|
+
it "is invalid without an owner" do
|
41
|
+
expect(new_application).not_to be_valid
|
42
|
+
end
|
85
43
|
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
enable_application_owner
|
44
|
+
it "is valid with an owner" do
|
45
|
+
new_application.owner = @owner
|
46
|
+
expect(new_application).to be_valid
|
47
|
+
end
|
91
48
|
end
|
92
49
|
end
|
93
50
|
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
end
|
98
|
-
|
99
|
-
it "is valid given valid attributes" do
|
100
|
-
expect(new_application).to be_valid
|
101
|
-
end
|
51
|
+
it "is invalid without a name" do
|
52
|
+
new_application.name = nil
|
53
|
+
expect(new_application).not_to be_valid
|
102
54
|
end
|
103
55
|
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
end
|
56
|
+
it "is invalid without determining confidentiality" do
|
57
|
+
new_application.confidential = nil
|
58
|
+
expect(new_application).not_to be_valid
|
59
|
+
end
|
109
60
|
|
110
|
-
|
111
|
-
|
112
|
-
|
61
|
+
it "generates uid on create" do
|
62
|
+
expect(new_application.uid).to be_nil
|
63
|
+
new_application.save
|
64
|
+
expect(new_application.uid).not_to be_nil
|
65
|
+
end
|
113
66
|
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
67
|
+
it "generates uid on create if an empty string" do
|
68
|
+
new_application.uid = ""
|
69
|
+
new_application.save
|
70
|
+
expect(new_application.uid).not_to be_blank
|
118
71
|
end
|
119
|
-
end
|
120
72
|
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
end
|
127
|
-
end
|
73
|
+
it "generates uid on create unless one is set" do
|
74
|
+
new_application.uid = uid
|
75
|
+
new_application.save
|
76
|
+
expect(new_application.uid).to eq(uid)
|
77
|
+
end
|
128
78
|
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
end
|
79
|
+
it "is invalid without uid" do
|
80
|
+
new_application.save
|
81
|
+
new_application.uid = nil
|
82
|
+
expect(new_application).not_to be_valid
|
134
83
|
end
|
135
84
|
|
136
|
-
context "
|
137
|
-
|
138
|
-
|
139
|
-
|
85
|
+
context "redirect URI" do
|
86
|
+
context "when grant flows allow blank redirect URI" do
|
87
|
+
before do
|
88
|
+
Doorkeeper.configure do
|
89
|
+
grant_flows %w[password client_credentials]
|
90
|
+
end
|
140
91
|
end
|
141
|
-
end
|
142
92
|
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
93
|
+
it "is valid without redirect_uri" do
|
94
|
+
new_application.save
|
95
|
+
new_application.redirect_uri = nil
|
96
|
+
expect(new_application).to be_valid
|
97
|
+
end
|
147
98
|
end
|
148
|
-
end
|
149
99
|
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
100
|
+
context "when grant flows require redirect URI" do
|
101
|
+
before do
|
102
|
+
Doorkeeper.configure do
|
103
|
+
grant_flows %w[password client_credentials authorization_code]
|
104
|
+
end
|
155
105
|
end
|
156
|
-
end
|
157
106
|
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
107
|
+
it "is invalid without redirect_uri" do
|
108
|
+
new_application.save
|
109
|
+
new_application.redirect_uri = nil
|
110
|
+
expect(new_application).not_to be_valid
|
111
|
+
end
|
162
112
|
end
|
163
|
-
end
|
164
|
-
end
|
165
|
-
|
166
|
-
context "with hashing enabled" do
|
167
|
-
include_context "with application hashing enabled"
|
168
|
-
let(:app) { FactoryBot.create :application }
|
169
|
-
let(:default_strategy) { Doorkeeper::SecretStoring::Sha256Hash }
|
170
|
-
|
171
|
-
it "uses SHA256 to avoid additional dependencies" do
|
172
|
-
# Ensure token was generated
|
173
|
-
app.validate
|
174
|
-
expect(app.secret).to eq(default_strategy.transform_secret(app.plaintext_secret))
|
175
|
-
end
|
176
113
|
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
114
|
+
context "when blank URI option disabled" do
|
115
|
+
before do
|
116
|
+
Doorkeeper.configure do
|
117
|
+
grant_flows %w[password client_credentials]
|
118
|
+
allow_blank_redirect_uri false
|
119
|
+
end
|
183
120
|
end
|
184
|
-
end
|
185
121
|
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
122
|
+
it "is invalid without redirect_uri" do
|
123
|
+
new_application.save
|
124
|
+
new_application.redirect_uri = nil
|
125
|
+
expect(new_application).not_to be_valid
|
126
|
+
end
|
191
127
|
end
|
192
128
|
end
|
193
129
|
|
194
|
-
it "
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
expect(lookup).to eq(app)
|
130
|
+
it "checks uniqueness of uid" do
|
131
|
+
app1 = FactoryBot.create(:application)
|
132
|
+
app2 = FactoryBot.create(:application)
|
133
|
+
app2.uid = app1.uid
|
134
|
+
expect(app2).not_to be_valid
|
200
135
|
end
|
201
136
|
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
expect(lookup).to eq(app)
|
208
|
-
|
209
|
-
lookup = described_class.by_uid_and_secret(app.uid, app.plaintext_secret)
|
210
|
-
expect(lookup).to eq(app)
|
211
|
-
end
|
137
|
+
it "expects database to throw an error when uids are the same" do
|
138
|
+
app1 = FactoryBot.create(:application)
|
139
|
+
app2 = FactoryBot.create(:application)
|
140
|
+
app2.uid = app1.uid
|
141
|
+
expect { app2.save!(validate: false) }.to raise_error(uniqueness_error)
|
212
142
|
end
|
213
143
|
|
214
|
-
it "
|
215
|
-
|
216
|
-
|
144
|
+
it "generate secret on create" do
|
145
|
+
expect(new_application.secret).to be_nil
|
146
|
+
new_application.save
|
147
|
+
expect(new_application.secret).not_to be_nil
|
217
148
|
end
|
218
|
-
end
|
219
149
|
|
220
|
-
|
221
|
-
|
150
|
+
it "generate secret on create if is blank string" do
|
151
|
+
new_application.secret = ""
|
222
152
|
new_application.save
|
153
|
+
expect(new_application.secret).not_to be_blank
|
223
154
|
end
|
224
155
|
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
:access_grant,
|
230
|
-
application: new_application,
|
231
|
-
resource_owner_id: resource_owner.id,
|
232
|
-
)
|
233
|
-
|
234
|
-
expect { new_application.destroy }.to change { Doorkeeper::AccessGrant.count }.by(-1)
|
156
|
+
it "generate secret on create unless one is set" do
|
157
|
+
new_application.secret = secret
|
158
|
+
new_application.save
|
159
|
+
expect(new_application.secret).to eq(secret)
|
235
160
|
end
|
236
161
|
|
237
|
-
it "
|
238
|
-
|
239
|
-
|
240
|
-
expect
|
241
|
-
new_application.destroy
|
242
|
-
end.to change { Doorkeeper::AccessToken.count }.by(-2)
|
162
|
+
it "is invalid without secret" do
|
163
|
+
new_application.save
|
164
|
+
new_application.secret = nil
|
165
|
+
expect(new_application).not_to be_valid
|
243
166
|
end
|
244
|
-
end
|
245
167
|
|
246
|
-
|
247
|
-
|
168
|
+
context "with hashing enabled" do
|
169
|
+
include_context "with application hashing enabled"
|
170
|
+
let(:app) { FactoryBot.create :application }
|
171
|
+
let(:default_strategy) { Doorkeeper::SecretStoring::Sha256Hash }
|
248
172
|
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
expect(
|
173
|
+
it "uses SHA256 to avoid additional dependencies" do
|
174
|
+
# Ensure token was generated
|
175
|
+
app.validate
|
176
|
+
expect(app.secret).to eq(default_strategy.transform_secret(app.plaintext_secret))
|
253
177
|
end
|
254
|
-
end
|
255
178
|
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
179
|
+
context "when bcrypt strategy is configured" do
|
180
|
+
# In this text context, we have bcrypt loaded so `bcrypt_present?`
|
181
|
+
# will always be true
|
182
|
+
before do
|
183
|
+
Doorkeeper.configure do
|
184
|
+
hash_application_secrets using: "Doorkeeper::SecretStoring::BCrypt"
|
185
|
+
end
|
186
|
+
end
|
263
187
|
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
end
|
271
|
-
context "when string of valid redirect_uris" do
|
272
|
-
it "should store as-is" do
|
273
|
-
new_application.redirect_uri = "http://localhost/callback1\nhttp://localhost/callback2"
|
274
|
-
expect(new_application.redirect_uri).to eq("http://localhost/callback1\nhttp://localhost/callback2")
|
188
|
+
it "holds a volatile plaintext and BCrypt secret" do
|
189
|
+
expect(app.secret_strategy).to eq Doorkeeper::SecretStoring::BCrypt
|
190
|
+
expect(app.plaintext_secret).to be_a(String)
|
191
|
+
expect(app.secret).not_to eq(app.plaintext_secret)
|
192
|
+
expect { ::BCrypt::Password.create(app.secret) }.not_to raise_error
|
193
|
+
end
|
275
194
|
end
|
276
|
-
end
|
277
|
-
end
|
278
195
|
|
279
|
-
|
280
|
-
|
281
|
-
|
196
|
+
it "does not fallback to plain lookup by default" do
|
197
|
+
lookup = clazz.by_uid_and_secret(app.uid, app.secret)
|
198
|
+
expect(lookup).to eq(nil)
|
282
199
|
|
283
|
-
|
284
|
-
|
285
|
-
|
200
|
+
lookup = clazz.by_uid_and_secret(app.uid, app.plaintext_secret)
|
201
|
+
expect(lookup).to eq(app)
|
202
|
+
end
|
286
203
|
|
287
|
-
|
288
|
-
|
289
|
-
:access_token,
|
290
|
-
resource_owner_id: other_resource_owner.id,
|
291
|
-
)
|
292
|
-
token = FactoryBot.create(
|
293
|
-
:access_token,
|
294
|
-
resource_owner_id: resource_owner.id,
|
295
|
-
)
|
296
|
-
expect(described_class.authorized_for(resource_owner)).to eq([token.application])
|
297
|
-
end
|
204
|
+
context "with fallback enabled" do
|
205
|
+
include_context "with token hashing and fallback lookup enabled"
|
298
206
|
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
resource_owner_id: resource_owner.id,
|
303
|
-
revoked_at: 2.days.ago,
|
304
|
-
)
|
305
|
-
expect(described_class.authorized_for(resource_owner)).to be_empty
|
306
|
-
end
|
207
|
+
it "provides plain and hashed lookup" do
|
208
|
+
lookup = clazz.by_uid_and_secret(app.uid, app.secret)
|
209
|
+
expect(lookup).to eq(app)
|
307
210
|
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
)
|
313
|
-
token2 = FactoryBot.create(
|
314
|
-
:access_token,
|
315
|
-
resource_owner_id: resource_owner.id,
|
316
|
-
)
|
317
|
-
expect(described_class.authorized_for(resource_owner))
|
318
|
-
.to eq([token1.application, token2.application])
|
319
|
-
end
|
211
|
+
lookup = clazz.by_uid_and_secret(app.uid, app.plaintext_secret)
|
212
|
+
expect(lookup).to eq(app)
|
213
|
+
end
|
214
|
+
end
|
320
215
|
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
resource_owner_id: resource_owner.id,
|
326
|
-
application: application,
|
327
|
-
)
|
328
|
-
FactoryBot.create(
|
329
|
-
:access_token,
|
330
|
-
resource_owner_id: resource_owner.id,
|
331
|
-
application: application,
|
332
|
-
)
|
333
|
-
expect(described_class.authorized_for(resource_owner)).to eq([application])
|
216
|
+
it "does not provide access to secret after loading" do
|
217
|
+
lookup = clazz.by_uid_and_secret(app.uid, app.plaintext_secret)
|
218
|
+
expect(lookup.plaintext_secret).to be_nil
|
219
|
+
end
|
334
220
|
end
|
335
|
-
end
|
336
221
|
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
.to
|
222
|
+
describe "destroy related models on cascade" do
|
223
|
+
before(:each) do
|
224
|
+
new_application.save
|
225
|
+
end
|
226
|
+
|
227
|
+
it "should destroy its access grants" do
|
228
|
+
FactoryBot.create(:access_grant, application: new_application)
|
229
|
+
expect { new_application.destroy }.to change { Doorkeeper::AccessGrant.count }.by(-1)
|
230
|
+
end
|
345
231
|
|
346
|
-
|
232
|
+
it "should destroy its access tokens" do
|
233
|
+
FactoryBot.create(:access_token, application: new_application)
|
234
|
+
FactoryBot.create(:access_token, application: new_application, revoked_at: Time.now.utc)
|
235
|
+
expect do
|
236
|
+
new_application.destroy
|
237
|
+
end.to change { Doorkeeper::AccessToken.count }.by(-2)
|
238
|
+
end
|
347
239
|
end
|
348
|
-
end
|
349
240
|
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
241
|
+
describe :ordered_by do
|
242
|
+
let(:applications) { FactoryBot.create_list(:application, 5) }
|
243
|
+
|
244
|
+
context "when a direction is not specified" do
|
245
|
+
it "calls order with a default order of asc" do
|
246
|
+
names = applications.map(&:name).sort
|
247
|
+
expect(Application.ordered_by(:name).map(&:name)).to eq(names)
|
248
|
+
end
|
356
249
|
end
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
expect(
|
250
|
+
|
251
|
+
context "when a direction is specified" do
|
252
|
+
it "calls order with specified direction" do
|
253
|
+
names = applications.map(&:name).sort.reverse
|
254
|
+
expect(Application.ordered_by(:name, :desc).map(&:name)).to eq(names)
|
362
255
|
end
|
363
256
|
end
|
364
257
|
end
|
365
258
|
|
366
|
-
|
367
|
-
context "when
|
368
|
-
it "should
|
369
|
-
|
370
|
-
|
371
|
-
expect(authenticated).to eq(app)
|
259
|
+
describe "#redirect_uri=" do
|
260
|
+
context "when array of valid redirect_uris" do
|
261
|
+
it "should join by newline" do
|
262
|
+
new_application.redirect_uri = ["http://localhost/callback1", "http://localhost/callback2"]
|
263
|
+
expect(new_application.redirect_uri).to eq("http://localhost/callback1\nhttp://localhost/callback2")
|
372
264
|
end
|
373
265
|
end
|
374
|
-
context "when
|
375
|
-
it "should
|
376
|
-
|
377
|
-
|
378
|
-
expect(authenticated).to eq(nil)
|
266
|
+
context "when string of valid redirect_uris" do
|
267
|
+
it "should store as-is" do
|
268
|
+
new_application.redirect_uri = "http://localhost/callback1\nhttp://localhost/callback2"
|
269
|
+
expect(new_application.redirect_uri).to eq("http://localhost/callback1\nhttp://localhost/callback2")
|
379
270
|
end
|
380
271
|
end
|
381
272
|
end
|
382
|
-
end
|
383
|
-
|
384
|
-
describe "#confidential?" do
|
385
|
-
subject { FactoryBot.create(:application, confidential: confidential).confidential? }
|
386
|
-
|
387
|
-
context "when application is private/confidential" do
|
388
|
-
let(:confidential) { true }
|
389
|
-
it { expect(subject).to eq(true) }
|
390
|
-
end
|
391
|
-
|
392
|
-
context "when application is public/non-confidential" do
|
393
|
-
let(:confidential) { false }
|
394
|
-
it { expect(subject).to eq(false) }
|
395
|
-
end
|
396
|
-
end
|
397
273
|
|
398
|
-
|
399
|
-
|
274
|
+
describe :authorized_for do
|
275
|
+
let(:resource_owner) { double(:resource_owner, id: 10) }
|
400
276
|
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
end
|
277
|
+
it "is empty if the application is not authorized for anyone" do
|
278
|
+
expect(Application.authorized_for(resource_owner)).to be_empty
|
279
|
+
end
|
405
280
|
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
expect(app.to_json(include_root_in_json: true)).to match(/application.+?:\{/)
|
411
|
-
ActiveRecord::Base.include_root_in_json = false
|
281
|
+
it "returns only application for a specific resource owner" do
|
282
|
+
FactoryBot.create(:access_token, resource_owner_id: resource_owner.id + 1)
|
283
|
+
token = FactoryBot.create(:access_token, resource_owner_id: resource_owner.id)
|
284
|
+
expect(Application.authorized_for(resource_owner)).to eq([token.application])
|
412
285
|
end
|
413
|
-
end
|
414
286
|
|
415
|
-
|
416
|
-
|
417
|
-
expect(
|
418
|
-
"id" => app.id,
|
419
|
-
"name" => app.name,
|
420
|
-
"created_at" => an_instance_of(String),
|
421
|
-
)
|
287
|
+
it "excludes revoked tokens" do
|
288
|
+
FactoryBot.create(:access_token, resource_owner_id: resource_owner.id, revoked_at: 2.days.ago)
|
289
|
+
expect(Application.authorized_for(resource_owner)).to be_empty
|
422
290
|
end
|
423
291
|
|
424
|
-
it "
|
425
|
-
|
292
|
+
it "returns all applications that have been authorized" do
|
293
|
+
token1 = FactoryBot.create(:access_token, resource_owner_id: resource_owner.id)
|
294
|
+
token2 = FactoryBot.create(:access_token, resource_owner_id: resource_owner.id)
|
295
|
+
expect(Application.authorized_for(resource_owner)).to eq([token1.application, token2.application])
|
296
|
+
end
|
426
297
|
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
)
|
298
|
+
it "returns only one application even if it has been authorized twice" do
|
299
|
+
application = FactoryBot.create(:application)
|
300
|
+
FactoryBot.create(:access_token, resource_owner_id: resource_owner.id, application: application)
|
301
|
+
FactoryBot.create(:access_token, resource_owner_id: resource_owner.id, application: application)
|
302
|
+
expect(Application.authorized_for(resource_owner)).to eq([application])
|
433
303
|
end
|
304
|
+
end
|
434
305
|
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
306
|
+
describe :revoke_tokens_and_grants_for do
|
307
|
+
it "revokes all access tokens and access grants" do
|
308
|
+
application_id = 42
|
309
|
+
resource_owner = double
|
310
|
+
expect(Doorkeeper::AccessToken)
|
311
|
+
.to receive(:revoke_all_for).with(application_id, resource_owner)
|
312
|
+
expect(Doorkeeper::AccessGrant)
|
313
|
+
.to receive(:revoke_all_for).with(application_id, resource_owner)
|
314
|
+
|
315
|
+
Application.revoke_tokens_and_grants_for(application_id, resource_owner)
|
442
316
|
end
|
443
317
|
end
|
444
318
|
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
319
|
+
describe :by_uid_and_secret do
|
320
|
+
context "when application is private/confidential" do
|
321
|
+
it "finds the application via uid/secret" do
|
322
|
+
app = FactoryBot.create :application
|
323
|
+
authenticated = Application.by_uid_and_secret(app.uid, app.secret)
|
324
|
+
expect(authenticated).to eq(app)
|
325
|
+
end
|
326
|
+
context "when secret is wrong" do
|
327
|
+
it "should not find the application" do
|
328
|
+
app = FactoryBot.create :application
|
329
|
+
authenticated = Application.by_uid_and_secret(app.uid, "bad")
|
330
|
+
expect(authenticated).to eq(nil)
|
331
|
+
end
|
332
|
+
end
|
333
|
+
end
|
449
334
|
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
335
|
+
context "when application is public/non-confidential" do
|
336
|
+
context "when secret is blank" do
|
337
|
+
it "should find the application" do
|
338
|
+
app = FactoryBot.create :application, confidential: false
|
339
|
+
authenticated = Application.by_uid_and_secret(app.uid, nil)
|
340
|
+
expect(authenticated).to eq(app)
|
341
|
+
end
|
342
|
+
end
|
343
|
+
context "when secret is wrong" do
|
344
|
+
it "should not find the application" do
|
345
|
+
app = FactoryBot.create :application, confidential: false
|
346
|
+
authenticated = Application.by_uid_and_secret(app.uid, "bad")
|
347
|
+
expect(authenticated).to eq(nil)
|
348
|
+
end
|
454
349
|
end
|
455
350
|
end
|
351
|
+
end
|
352
|
+
|
353
|
+
describe :confidential? do
|
354
|
+
subject { FactoryBot.create(:application, confidential: confidential).confidential? }
|
456
355
|
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
"secret" => "123123123",
|
461
|
-
"redirect_uri" => app.redirect_uri,
|
462
|
-
"uid" => app.uid,
|
463
|
-
)
|
356
|
+
context "when application is private/confidential" do
|
357
|
+
let(:confidential) { true }
|
358
|
+
it { expect(subject).to eq(true) }
|
464
359
|
end
|
465
360
|
|
466
|
-
|
467
|
-
|
468
|
-
|
361
|
+
context "when application is public/non-confidential" do
|
362
|
+
let(:confidential) { false }
|
363
|
+
it { expect(subject).to eq(false) }
|
469
364
|
end
|
470
365
|
end
|
471
366
|
end
|