scimaenaga 0.4.1
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 +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +314 -0
- data/Rakefile +34 -0
- data/app/controllers/concerns/scim_rails/exception_handler.rb +119 -0
- data/app/controllers/concerns/scim_rails/response.rb +94 -0
- data/app/controllers/scim_rails/application_controller.rb +72 -0
- data/app/controllers/scim_rails/scim_groups_controller.rb +96 -0
- data/app/controllers/scim_rails/scim_users_controller.rb +124 -0
- data/app/helpers/scim_rails/application_helper.rb +4 -0
- data/app/models/scim_rails/application_record.rb +5 -0
- data/app/models/scim_rails/authorize_api_request.rb +40 -0
- data/app/models/scim_rails/scim_count.rb +38 -0
- data/app/models/scim_rails/scim_query_parser.rb +47 -0
- data/config/initializers/mime_types.rb +5 -0
- data/config/routes.rb +12 -0
- data/lib/generators/scim_rails/USAGE +8 -0
- data/lib/generators/scim_rails/scim_rails_generator.rb +7 -0
- data/lib/generators/scim_rails/templates/initializer.rb +166 -0
- data/lib/scim_rails/config.rb +85 -0
- data/lib/scim_rails/encoder.rb +25 -0
- data/lib/scim_rails/engine.rb +12 -0
- data/lib/scim_rails/version.rb +5 -0
- data/lib/scim_rails.rb +6 -0
- data/lib/tasks/scim_rails_tasks.rake +4 -0
- data/spec/controllers/scim_rails/scim_groups_controller_spec.rb +494 -0
- data/spec/controllers/scim_rails/scim_groups_request_spec.rb +68 -0
- data/spec/controllers/scim_rails/scim_users_controller_spec.rb +681 -0
- data/spec/controllers/scim_rails/scim_users_request_spec.rb +77 -0
- data/spec/dummy/Rakefile +6 -0
- data/spec/dummy/app/assets/config/manifest.js +5 -0
- data/spec/dummy/app/assets/javascripts/application.js +13 -0
- data/spec/dummy/app/assets/javascripts/cable.js +13 -0
- data/spec/dummy/app/assets/stylesheets/application.css +15 -0
- data/spec/dummy/app/channels/application_cable/channel.rb +4 -0
- data/spec/dummy/app/channels/application_cable/connection.rb +4 -0
- data/spec/dummy/app/controllers/application_controller.rb +3 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/jobs/application_job.rb +2 -0
- data/spec/dummy/app/mailers/application_mailer.rb +4 -0
- data/spec/dummy/app/models/application_record.rb +3 -0
- data/spec/dummy/app/models/company.rb +4 -0
- data/spec/dummy/app/models/group.rb +15 -0
- data/spec/dummy/app/models/group_user.rb +6 -0
- data/spec/dummy/app/models/user.rb +39 -0
- data/spec/dummy/app/views/layouts/application.html.erb +14 -0
- data/spec/dummy/app/views/layouts/mailer.html.erb +13 -0
- data/spec/dummy/app/views/layouts/mailer.text.erb +1 -0
- data/spec/dummy/bin/bundle +3 -0
- data/spec/dummy/bin/rails +4 -0
- data/spec/dummy/bin/rake +4 -0
- data/spec/dummy/bin/setup +34 -0
- data/spec/dummy/bin/update +29 -0
- data/spec/dummy/config/application.rb +15 -0
- data/spec/dummy/config/boot.rb +5 -0
- data/spec/dummy/config/cable.yml +9 -0
- data/spec/dummy/config/database.yml +25 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +54 -0
- data/spec/dummy/config/environments/production.rb +86 -0
- data/spec/dummy/config/environments/test.rb +42 -0
- data/spec/dummy/config/initializers/application_controller_renderer.rb +6 -0
- data/spec/dummy/config/initializers/assets.rb +11 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/cookies_serializer.rb +5 -0
- data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/spec/dummy/config/initializers/inflections.rb +16 -0
- data/spec/dummy/config/initializers/mime_types.rb +4 -0
- data/spec/dummy/config/initializers/new_framework_defaults.rb +24 -0
- data/spec/dummy/config/initializers/scim_rails_config.rb +85 -0
- data/spec/dummy/config/initializers/session_store.rb +3 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/en.yml +23 -0
- data/spec/dummy/config/puma.rb +47 -0
- data/spec/dummy/config/routes.rb +3 -0
- data/spec/dummy/config/secrets.yml +22 -0
- data/spec/dummy/config/spring.rb +6 -0
- data/spec/dummy/config.ru +5 -0
- data/spec/dummy/db/migrate/20181206184304_create_users.rb +15 -0
- data/spec/dummy/db/migrate/20181206184313_create_companies.rb +11 -0
- data/spec/dummy/db/migrate/20210423075859_create_groups.rb +10 -0
- data/spec/dummy/db/migrate/20210423075950_create_group_users.rb +10 -0
- data/spec/dummy/db/schema.rb +53 -0
- data/spec/dummy/db/seeds.rb +14 -0
- data/spec/dummy/public/404.html +67 -0
- data/spec/dummy/public/422.html +67 -0
- data/spec/dummy/public/500.html +66 -0
- data/spec/dummy/public/apple-touch-icon-precomposed.png +0 -0
- data/spec/dummy/public/apple-touch-icon.png +0 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/factories/company.rb +10 -0
- data/spec/factories/group.rb +11 -0
- data/spec/factories/user.rb +9 -0
- data/spec/lib/scim_rails/encoder_spec.rb +62 -0
- data/spec/spec_helper.rb +17 -0
- data/spec/support/auth_helper.rb +7 -0
- data/spec/support/factory_bot.rb +3 -0
- data/spec/support/scim_rails_config.rb +59 -0
- metadata +339 -0
|
@@ -0,0 +1,681 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "spec_helper"
|
|
4
|
+
|
|
5
|
+
RSpec.describe ScimRails::ScimUsersController, type: :controller do
|
|
6
|
+
include AuthHelper
|
|
7
|
+
|
|
8
|
+
routes { ScimRails::Engine.routes }
|
|
9
|
+
|
|
10
|
+
describe "index" do
|
|
11
|
+
let(:company) { create(:company) }
|
|
12
|
+
|
|
13
|
+
context "when unauthorized" do
|
|
14
|
+
it "returns scim+json content type" do
|
|
15
|
+
get :index, as: :json
|
|
16
|
+
|
|
17
|
+
expect(response.media_type).to eq "application/scim+json"
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
it "fails with no credentials" do
|
|
21
|
+
get :index, as: :json
|
|
22
|
+
|
|
23
|
+
expect(response.status).to eq 401
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
it "fails with invalid credentials" do
|
|
27
|
+
request.env["HTTP_AUTHORIZATION"] =
|
|
28
|
+
ActionController::HttpAuthentication::Basic
|
|
29
|
+
.encode_credentials("unauthorized", "123456")
|
|
30
|
+
|
|
31
|
+
get :index, as: :json
|
|
32
|
+
|
|
33
|
+
expect(response.status).to eq 401
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
context "when when authorized" do
|
|
38
|
+
before :each do
|
|
39
|
+
http_login(company)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
it "returns scim+json content type" do
|
|
43
|
+
get :index, as: :json
|
|
44
|
+
|
|
45
|
+
expect(response.media_type).to eq "application/scim+json"
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
it "is successful with valid credentials" do
|
|
49
|
+
get :index, as: :json
|
|
50
|
+
|
|
51
|
+
expect(response.status).to eq 200
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
it "returns all results" do
|
|
55
|
+
create_list(:user, 10, company: company)
|
|
56
|
+
|
|
57
|
+
get :index, as: :json
|
|
58
|
+
response_body = JSON.parse(response.body)
|
|
59
|
+
expect(response_body.dig("schemas", 0)).to eq "urn:ietf:params:scim:api:messages:2.0:ListResponse"
|
|
60
|
+
expect(response_body["totalResults"]).to eq 10
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
it "defaults to 100 results" do
|
|
64
|
+
create_list(:user, 300, company: company)
|
|
65
|
+
|
|
66
|
+
get :index, as: :json
|
|
67
|
+
response_body = JSON.parse(response.body)
|
|
68
|
+
expect(response_body["totalResults"]).to eq 300
|
|
69
|
+
expect(response_body["Resources"].count).to eq 100
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
it "paginates results" do
|
|
73
|
+
create_list(:user, 400, company: company)
|
|
74
|
+
expect(company.users.first.id).to eq 1
|
|
75
|
+
|
|
76
|
+
get :index, params: {
|
|
77
|
+
startIndex: 101,
|
|
78
|
+
count: 200
|
|
79
|
+
}, as: :json
|
|
80
|
+
response_body = JSON.parse(response.body)
|
|
81
|
+
expect(response_body["totalResults"]).to eq 400
|
|
82
|
+
expect(response_body["Resources"].count).to eq 200
|
|
83
|
+
expect(response_body.dig("Resources", 0, "id")).to eq 101
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
it "paginates results by configurable scim_users_list_order" do
|
|
87
|
+
allow(ScimRails.config).to receive(:scim_users_list_order).and_return({ created_at: :desc })
|
|
88
|
+
|
|
89
|
+
create_list(:user, 400, company: company)
|
|
90
|
+
expect(company.users.first.id).to eq 1
|
|
91
|
+
|
|
92
|
+
get :index, params: {
|
|
93
|
+
startIndex: 1,
|
|
94
|
+
count: 10
|
|
95
|
+
}, as: :json
|
|
96
|
+
response_body = JSON.parse(response.body)
|
|
97
|
+
expect(response_body["totalResults"]).to eq 400
|
|
98
|
+
expect(response_body["Resources"].count).to eq 10
|
|
99
|
+
expect(response_body.dig("Resources", 0, "id")).to eq 400
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
it "filters results by provided email filter" do
|
|
103
|
+
create(:user, email: "test1@example.com", company: company)
|
|
104
|
+
create(:user, email: "test2@example.com", company: company)
|
|
105
|
+
|
|
106
|
+
get :index, params: {
|
|
107
|
+
filter: "email eq test1@example.com"
|
|
108
|
+
}, as: :json
|
|
109
|
+
response_body = JSON.parse(response.body)
|
|
110
|
+
expect(response_body["totalResults"]).to eq 1
|
|
111
|
+
expect(response_body["Resources"].count).to eq 1
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
it "filters results by provided name filter" do
|
|
115
|
+
create(:user, first_name: "Chidi", last_name: "Anagonye", company: company)
|
|
116
|
+
create(:user, first_name: "Eleanor", last_name: "Shellstrop", company: company)
|
|
117
|
+
|
|
118
|
+
get :index, params: {
|
|
119
|
+
filter: "familyName eq Shellstrop"
|
|
120
|
+
}, as: :json
|
|
121
|
+
response_body = JSON.parse(response.body)
|
|
122
|
+
expect(response_body["totalResults"]).to eq 1
|
|
123
|
+
expect(response_body["Resources"].count).to eq 1
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
it "returns no results for unfound filter parameters" do
|
|
127
|
+
get :index, params: {
|
|
128
|
+
filter: "familyName eq fake_not_there"
|
|
129
|
+
}, as: :json
|
|
130
|
+
response_body = JSON.parse(response.body)
|
|
131
|
+
expect(response_body["totalResults"]).to eq 0
|
|
132
|
+
expect(response_body["Resources"].count).to eq 0
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
it "returns no results for undefined filter queries" do
|
|
136
|
+
get :index, params: {
|
|
137
|
+
filter: "address eq 101 Nowhere USA"
|
|
138
|
+
}, as: :json
|
|
139
|
+
expect(response.status).to eq 400
|
|
140
|
+
response_body = JSON.parse(response.body)
|
|
141
|
+
expect(response_body.dig("schemas", 0)).to eq "urn:ietf:params:scim:api:messages:2.0:Error"
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
describe "show" do
|
|
147
|
+
let(:company) { create(:company) }
|
|
148
|
+
|
|
149
|
+
context "when unauthorized" do
|
|
150
|
+
it "returns scim+json content type" do
|
|
151
|
+
get :show, params: { id: 1 }, as: :json
|
|
152
|
+
|
|
153
|
+
expect(response.media_type).to eq "application/scim+json"
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
it "fails with no credentials" do
|
|
157
|
+
get :show, params: { id: 1 }, as: :json
|
|
158
|
+
|
|
159
|
+
expect(response.status).to eq 401
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
it "fails with invalid credentials" do
|
|
163
|
+
request.env["HTTP_AUTHORIZATION"] =
|
|
164
|
+
ActionController::HttpAuthentication::Basic
|
|
165
|
+
.encode_credentials("unauthorized", "123456")
|
|
166
|
+
|
|
167
|
+
get :show, params: { id: 1 }, as: :json
|
|
168
|
+
|
|
169
|
+
expect(response.status).to eq 401
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
context "when authorized" do
|
|
174
|
+
before :each do
|
|
175
|
+
http_login(company)
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
it "returns scim+json content type" do
|
|
179
|
+
get :show, params: { id: 1 }, as: :json
|
|
180
|
+
|
|
181
|
+
expect(response.media_type).to eq "application/scim+json"
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
it "is successful with valid credentials" do
|
|
185
|
+
create(:user, id: 1, company: company)
|
|
186
|
+
get :show, params: { id: 1 }, as: :json
|
|
187
|
+
|
|
188
|
+
expect(response.status).to eq 200
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
it "returns :not_found for id that cannot be found" do
|
|
192
|
+
get :show, params: { id: "fake_id" }, as: :json
|
|
193
|
+
|
|
194
|
+
expect(response.status).to eq 404
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
it "returns :not_found for a correct id but unauthorized company" do
|
|
198
|
+
new_company = create(:company)
|
|
199
|
+
create(:user, company: new_company, id: 1)
|
|
200
|
+
|
|
201
|
+
get :show, params: { id: 1 }, as: :json
|
|
202
|
+
|
|
203
|
+
expect(response.status).to eq 404
|
|
204
|
+
end
|
|
205
|
+
end
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
describe "create" do
|
|
209
|
+
let(:company) { create(:company) }
|
|
210
|
+
|
|
211
|
+
context "when unauthorized" do
|
|
212
|
+
it "returns scim+json content type" do
|
|
213
|
+
post :create, as: :json
|
|
214
|
+
|
|
215
|
+
expect(response.media_type).to eq "application/scim+json"
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
it "fails with no credentials" do
|
|
219
|
+
post :create, as: :json
|
|
220
|
+
|
|
221
|
+
expect(response.status).to eq 401
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
it "fails with invalid credentials" do
|
|
225
|
+
request.env["HTTP_AUTHORIZATION"] =
|
|
226
|
+
ActionController::HttpAuthentication::Basic
|
|
227
|
+
.encode_credentials("unauthorized", "123456")
|
|
228
|
+
|
|
229
|
+
post :create, as: :json
|
|
230
|
+
|
|
231
|
+
expect(response.status).to eq 401
|
|
232
|
+
end
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
context "when authorized" do
|
|
236
|
+
before :each do
|
|
237
|
+
http_login(company)
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
it "returns scim+json content type" do
|
|
241
|
+
post :create, params: {
|
|
242
|
+
name: {
|
|
243
|
+
givenName: "New",
|
|
244
|
+
familyName: "User"
|
|
245
|
+
},
|
|
246
|
+
emails: [
|
|
247
|
+
{
|
|
248
|
+
value: "new@example.com"
|
|
249
|
+
}
|
|
250
|
+
]
|
|
251
|
+
}, as: :json
|
|
252
|
+
|
|
253
|
+
expect(response.media_type).to eq "application/scim+json"
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
it "is successful with valid credentials" do
|
|
257
|
+
expect(company.users.count).to eq 0
|
|
258
|
+
|
|
259
|
+
post :create, params: {
|
|
260
|
+
name: {
|
|
261
|
+
givenName: "New",
|
|
262
|
+
familyName: "User"
|
|
263
|
+
},
|
|
264
|
+
emails: [
|
|
265
|
+
{
|
|
266
|
+
value: "new@example.com"
|
|
267
|
+
}
|
|
268
|
+
]
|
|
269
|
+
}, as: :json
|
|
270
|
+
|
|
271
|
+
expect(response.status).to eq 201
|
|
272
|
+
expect(company.users.count).to eq 1
|
|
273
|
+
user = company.users.first
|
|
274
|
+
expect(user.persisted?).to eq true
|
|
275
|
+
expect(user.first_name).to eq "New"
|
|
276
|
+
expect(user.last_name).to eq "User"
|
|
277
|
+
expect(user.email).to eq "new@example.com"
|
|
278
|
+
end
|
|
279
|
+
|
|
280
|
+
it "ignores unconfigured params" do
|
|
281
|
+
post :create, params: {
|
|
282
|
+
name: {
|
|
283
|
+
formattedName: "New User",
|
|
284
|
+
givenName: "New",
|
|
285
|
+
familyName: "User"
|
|
286
|
+
},
|
|
287
|
+
emails: [
|
|
288
|
+
{
|
|
289
|
+
value: "new@example.com"
|
|
290
|
+
}
|
|
291
|
+
]
|
|
292
|
+
}, as: :json
|
|
293
|
+
|
|
294
|
+
expect(response.status).to eq 201
|
|
295
|
+
expect(company.users.count).to eq 1
|
|
296
|
+
end
|
|
297
|
+
|
|
298
|
+
it "returns 422 if required params are missing" do
|
|
299
|
+
post :create, params: {
|
|
300
|
+
name: {
|
|
301
|
+
familyName: "User"
|
|
302
|
+
},
|
|
303
|
+
emails: [
|
|
304
|
+
{
|
|
305
|
+
value: "new@example.com"
|
|
306
|
+
}
|
|
307
|
+
]
|
|
308
|
+
}, as: :json
|
|
309
|
+
|
|
310
|
+
expect(response.status).to eq 422
|
|
311
|
+
expect(company.users.count).to eq 0
|
|
312
|
+
end
|
|
313
|
+
|
|
314
|
+
it "returns 201 if user already exists and updates user" do
|
|
315
|
+
create(:user, email: "new@example.com", company: company)
|
|
316
|
+
|
|
317
|
+
post :create, params: {
|
|
318
|
+
name: {
|
|
319
|
+
givenName: "Not New",
|
|
320
|
+
familyName: "User"
|
|
321
|
+
},
|
|
322
|
+
emails: [
|
|
323
|
+
{
|
|
324
|
+
value: "new@example.com"
|
|
325
|
+
}
|
|
326
|
+
]
|
|
327
|
+
}, as: :json
|
|
328
|
+
|
|
329
|
+
expect(response.status).to eq 201
|
|
330
|
+
expect(company.users.count).to eq 1
|
|
331
|
+
expect(company.users.first.first_name).to eq "Not New"
|
|
332
|
+
end
|
|
333
|
+
|
|
334
|
+
it "returns 409 if user already exists and config.scim_user_prevent_update_on_create is set to true" do
|
|
335
|
+
allow(ScimRails.config).to receive(:scim_user_prevent_update_on_create).and_return(true)
|
|
336
|
+
create(:user, email: "new@example.com", company: company)
|
|
337
|
+
|
|
338
|
+
post :create, params: {
|
|
339
|
+
name: {
|
|
340
|
+
givenName: "Not New",
|
|
341
|
+
familyName: "User"
|
|
342
|
+
},
|
|
343
|
+
emails: [
|
|
344
|
+
{
|
|
345
|
+
value: "new@example.com"
|
|
346
|
+
}
|
|
347
|
+
]
|
|
348
|
+
}, as: :json
|
|
349
|
+
|
|
350
|
+
expect(response.status).to eq 409
|
|
351
|
+
expect(company.users.count).to eq 1
|
|
352
|
+
end
|
|
353
|
+
|
|
354
|
+
it "creates and archives inactive user" do
|
|
355
|
+
post :create, params: {
|
|
356
|
+
id: 1,
|
|
357
|
+
userName: "test@example.com",
|
|
358
|
+
name: {
|
|
359
|
+
givenName: "Test",
|
|
360
|
+
familyName: "User"
|
|
361
|
+
},
|
|
362
|
+
emails: [
|
|
363
|
+
{
|
|
364
|
+
value: "test@example.com"
|
|
365
|
+
}
|
|
366
|
+
],
|
|
367
|
+
active: "false"
|
|
368
|
+
}, as: :json
|
|
369
|
+
|
|
370
|
+
expect(response.status).to eq 201
|
|
371
|
+
expect(company.users.count).to eq 1
|
|
372
|
+
user = company.users.first
|
|
373
|
+
expect(user.archived?).to eq true
|
|
374
|
+
end
|
|
375
|
+
end
|
|
376
|
+
end
|
|
377
|
+
|
|
378
|
+
describe "put update" do
|
|
379
|
+
let(:company) { create(:company) }
|
|
380
|
+
|
|
381
|
+
context "when unauthorized" do
|
|
382
|
+
it "returns scim+json content type" do
|
|
383
|
+
put :put_update, params: { id: 1 }, as: :json
|
|
384
|
+
|
|
385
|
+
expect(response.media_type).to eq "application/scim+json"
|
|
386
|
+
end
|
|
387
|
+
|
|
388
|
+
it "fails with no credentials" do
|
|
389
|
+
put :put_update, params: { id: 1 }, as: :json
|
|
390
|
+
|
|
391
|
+
expect(response.status).to eq 401
|
|
392
|
+
end
|
|
393
|
+
|
|
394
|
+
it "fails with invalid credentials" do
|
|
395
|
+
request.env["HTTP_AUTHORIZATION"] =
|
|
396
|
+
ActionController::HttpAuthentication::Basic
|
|
397
|
+
.encode_credentials("unauthorized", "123456")
|
|
398
|
+
|
|
399
|
+
put :put_update, params: { id: 1 }, as: :json
|
|
400
|
+
|
|
401
|
+
expect(response.status).to eq 401
|
|
402
|
+
end
|
|
403
|
+
end
|
|
404
|
+
|
|
405
|
+
context "when authorized" do
|
|
406
|
+
let!(:user) { create(:user, id: 1, company: company) }
|
|
407
|
+
|
|
408
|
+
before :each do
|
|
409
|
+
http_login(company)
|
|
410
|
+
end
|
|
411
|
+
|
|
412
|
+
it "returns scim+json content type" do
|
|
413
|
+
put :put_update, params: put_params, as: :json
|
|
414
|
+
|
|
415
|
+
expect(response.media_type).to eq "application/scim+json"
|
|
416
|
+
end
|
|
417
|
+
|
|
418
|
+
it "is successful with with valid credentials" do
|
|
419
|
+
put :put_update, params: put_params, as: :json
|
|
420
|
+
|
|
421
|
+
expect(response.status).to eq 200
|
|
422
|
+
end
|
|
423
|
+
|
|
424
|
+
it "deprovisions an active record" do
|
|
425
|
+
request.content_type = "application/scim+json"
|
|
426
|
+
put :put_update, params: put_params(active: false), as: :json
|
|
427
|
+
|
|
428
|
+
expect(response.status).to eq 200
|
|
429
|
+
expect(user.reload.active?).to eq false
|
|
430
|
+
end
|
|
431
|
+
|
|
432
|
+
it "reprovisions an inactive record" do
|
|
433
|
+
user.archive!
|
|
434
|
+
expect(user.reload.active?).to eq false
|
|
435
|
+
request.content_type = "application/scim+json"
|
|
436
|
+
put :put_update, params: put_params(active: true), as: :json
|
|
437
|
+
|
|
438
|
+
expect(response.status).to eq 200
|
|
439
|
+
expect(user.reload.active?).to eq true
|
|
440
|
+
end
|
|
441
|
+
|
|
442
|
+
it "returns :not_found for id that cannot be found" do
|
|
443
|
+
put :put_update, params: { id: "fake_id" }, as: :json
|
|
444
|
+
|
|
445
|
+
expect(response.status).to eq 404
|
|
446
|
+
end
|
|
447
|
+
|
|
448
|
+
it "returns :not_found for a correct id but unauthorized company" do
|
|
449
|
+
new_company = create(:company)
|
|
450
|
+
create(:user, company: new_company, id: 1000)
|
|
451
|
+
|
|
452
|
+
put :put_update, params: { id: 1000 }, as: :json
|
|
453
|
+
|
|
454
|
+
expect(response.status).to eq 404
|
|
455
|
+
end
|
|
456
|
+
|
|
457
|
+
it "is returns 422 with incomplete request" do
|
|
458
|
+
put :put_update, params: {
|
|
459
|
+
id: 1,
|
|
460
|
+
userName: "test@example.com",
|
|
461
|
+
emails: [
|
|
462
|
+
{
|
|
463
|
+
value: "test@example.com"
|
|
464
|
+
}
|
|
465
|
+
],
|
|
466
|
+
active: "true"
|
|
467
|
+
}, as: :json
|
|
468
|
+
|
|
469
|
+
expect(response.status).to eq 422
|
|
470
|
+
end
|
|
471
|
+
end
|
|
472
|
+
end
|
|
473
|
+
|
|
474
|
+
describe "patch update" do
|
|
475
|
+
let(:company) { create(:company) }
|
|
476
|
+
|
|
477
|
+
context "when unauthorized" do
|
|
478
|
+
it "returns scim+json content type" do
|
|
479
|
+
patch :patch_update, params: patch_params(id: 1), as: :json
|
|
480
|
+
|
|
481
|
+
expect(response.media_type).to eq "application/scim+json"
|
|
482
|
+
end
|
|
483
|
+
|
|
484
|
+
it "fails with no credentials" do
|
|
485
|
+
patch :patch_update, params: patch_params(id: 1), as: :json
|
|
486
|
+
|
|
487
|
+
expect(response.status).to eq 401
|
|
488
|
+
end
|
|
489
|
+
|
|
490
|
+
it "fails with invalid credentials" do
|
|
491
|
+
request.env["HTTP_AUTHORIZATION"] =
|
|
492
|
+
ActionController::HttpAuthentication::Basic
|
|
493
|
+
.encode_credentials("unauthorized", "123456")
|
|
494
|
+
|
|
495
|
+
patch :patch_update, params: patch_params(id: 1), as: :json
|
|
496
|
+
|
|
497
|
+
expect(response.status).to eq 401
|
|
498
|
+
end
|
|
499
|
+
end
|
|
500
|
+
|
|
501
|
+
context "when authorized" do
|
|
502
|
+
let!(:user) { create(:user, id: 1, company: company) }
|
|
503
|
+
|
|
504
|
+
before :each do
|
|
505
|
+
http_login(company)
|
|
506
|
+
end
|
|
507
|
+
|
|
508
|
+
it "returns scim+json content type" do
|
|
509
|
+
patch :patch_update, params: patch_params(id: 1), as: :json
|
|
510
|
+
|
|
511
|
+
expect(response.media_type).to eq "application/scim+json"
|
|
512
|
+
end
|
|
513
|
+
|
|
514
|
+
it "is successful with valid credentials" do
|
|
515
|
+
patch :patch_update, params: patch_params(id: 1), as: :json
|
|
516
|
+
|
|
517
|
+
expect(response.status).to eq 200
|
|
518
|
+
end
|
|
519
|
+
|
|
520
|
+
it "returns :not_found for id that cannot be found" do
|
|
521
|
+
get :patch_update, params: patch_params(id: "fake_id"), as: :json
|
|
522
|
+
|
|
523
|
+
expect(response.status).to eq 404
|
|
524
|
+
end
|
|
525
|
+
|
|
526
|
+
it "returns :not_found for a correct id but unauthorized company" do
|
|
527
|
+
new_company = create(:company)
|
|
528
|
+
create(:user, company: new_company, id: 1000)
|
|
529
|
+
|
|
530
|
+
get :patch_update, params: patch_params(id: 1000), as: :json
|
|
531
|
+
|
|
532
|
+
expect(response.status).to eq 404
|
|
533
|
+
end
|
|
534
|
+
|
|
535
|
+
it "successfully archives user" do
|
|
536
|
+
expect(company.users.count).to eq 1
|
|
537
|
+
user = company.users.first
|
|
538
|
+
expect(user.archived?).to eq false
|
|
539
|
+
|
|
540
|
+
patch :patch_update, params: patch_params(id: 1), as: :json
|
|
541
|
+
|
|
542
|
+
expect(response.status).to eq 200
|
|
543
|
+
expect(company.users.count).to eq 1
|
|
544
|
+
user.reload
|
|
545
|
+
expect(user.archived?).to eq true
|
|
546
|
+
end
|
|
547
|
+
|
|
548
|
+
it "successfully restores user" do
|
|
549
|
+
expect(company.users.count).to eq 1
|
|
550
|
+
user = company.users.first.tap(&:archive!)
|
|
551
|
+
expect(user.archived?).to eq true
|
|
552
|
+
|
|
553
|
+
patch \
|
|
554
|
+
:patch_update,
|
|
555
|
+
params: patch_params(id: 1, active: true),
|
|
556
|
+
as: :json
|
|
557
|
+
|
|
558
|
+
expect(response.status).to eq 200
|
|
559
|
+
expect(company.users.count).to eq 1
|
|
560
|
+
user.reload
|
|
561
|
+
expect(user.archived?).to eq false
|
|
562
|
+
end
|
|
563
|
+
|
|
564
|
+
it "is case insensetive for op value" do
|
|
565
|
+
# Note, this is for backward compatibility. op should always
|
|
566
|
+
# be lower case and support for case insensitivity will be removed
|
|
567
|
+
patch :patch_update, params: {
|
|
568
|
+
id: 1,
|
|
569
|
+
Operations: [
|
|
570
|
+
{
|
|
571
|
+
op: "Replace",
|
|
572
|
+
value: {
|
|
573
|
+
active: false
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
]
|
|
577
|
+
}, as: :json
|
|
578
|
+
|
|
579
|
+
expect(response.status).to eq 200
|
|
580
|
+
end
|
|
581
|
+
|
|
582
|
+
it "throws an error for non status updates" do
|
|
583
|
+
patch :patch_update, params: {
|
|
584
|
+
id: 1,
|
|
585
|
+
Operations: [
|
|
586
|
+
{
|
|
587
|
+
op: "replace",
|
|
588
|
+
value: {
|
|
589
|
+
name: {
|
|
590
|
+
givenName: "Francis"
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
]
|
|
595
|
+
}, as: :json
|
|
596
|
+
|
|
597
|
+
expect(response.status).to eq 422
|
|
598
|
+
response_body = JSON.parse(response.body)
|
|
599
|
+
expect(response_body.dig("schemas", 0)).to eq "urn:ietf:params:scim:api:messages:2.0:Error"
|
|
600
|
+
end
|
|
601
|
+
|
|
602
|
+
it "returns 422 when value is not an object" do
|
|
603
|
+
patch :patch_update, params: {
|
|
604
|
+
id: 1,
|
|
605
|
+
Operations: [
|
|
606
|
+
{
|
|
607
|
+
op: "replace",
|
|
608
|
+
path: "displayName",
|
|
609
|
+
value: "Francis"
|
|
610
|
+
}
|
|
611
|
+
]
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
expect(response.status).to eq 422
|
|
615
|
+
response_body = JSON.parse(response.body)
|
|
616
|
+
expect(response_body.dig("schemas", 0)).to eq "urn:ietf:params:scim:api:messages:2.0:Error"
|
|
617
|
+
end
|
|
618
|
+
|
|
619
|
+
it "returns 422 when value is missing" do
|
|
620
|
+
patch :patch_update, params: {
|
|
621
|
+
id: 1,
|
|
622
|
+
Operations: [
|
|
623
|
+
{
|
|
624
|
+
op: "replace"
|
|
625
|
+
}
|
|
626
|
+
]
|
|
627
|
+
}, as: :json
|
|
628
|
+
|
|
629
|
+
expect(response.status).to eq 422
|
|
630
|
+
response_body = JSON.parse(response.body)
|
|
631
|
+
expect(response_body.dig("schemas", 0)).to eq "urn:ietf:params:scim:api:messages:2.0:Error"
|
|
632
|
+
end
|
|
633
|
+
|
|
634
|
+
it "returns 422 operations key is missing" do
|
|
635
|
+
patch :patch_update, params: {
|
|
636
|
+
id: 1,
|
|
637
|
+
Foobars: [
|
|
638
|
+
{
|
|
639
|
+
op: "replace"
|
|
640
|
+
}
|
|
641
|
+
]
|
|
642
|
+
}, as: :json
|
|
643
|
+
|
|
644
|
+
expect(response.status).to eq 422
|
|
645
|
+
response_body = JSON.parse(response.body)
|
|
646
|
+
expect(response_body.dig("schemas", 0)).to eq "urn:ietf:params:scim:api:messages:2.0:Error"
|
|
647
|
+
end
|
|
648
|
+
end
|
|
649
|
+
end
|
|
650
|
+
|
|
651
|
+
def patch_params(id:, active: false)
|
|
652
|
+
{
|
|
653
|
+
id: id,
|
|
654
|
+
Operations: [
|
|
655
|
+
{
|
|
656
|
+
op: "replace",
|
|
657
|
+
value: {
|
|
658
|
+
active: active
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
]
|
|
662
|
+
}
|
|
663
|
+
end
|
|
664
|
+
|
|
665
|
+
def put_params(active: true)
|
|
666
|
+
{
|
|
667
|
+
id: 1,
|
|
668
|
+
userName: "test@example.com",
|
|
669
|
+
name: {
|
|
670
|
+
givenName: "Test",
|
|
671
|
+
familyName: "User"
|
|
672
|
+
},
|
|
673
|
+
emails: [
|
|
674
|
+
{
|
|
675
|
+
value: "test@example.com"
|
|
676
|
+
}
|
|
677
|
+
],
|
|
678
|
+
active: active
|
|
679
|
+
}
|
|
680
|
+
end
|
|
681
|
+
end
|