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.
Files changed (99) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +314 -0
  4. data/Rakefile +34 -0
  5. data/app/controllers/concerns/scim_rails/exception_handler.rb +119 -0
  6. data/app/controllers/concerns/scim_rails/response.rb +94 -0
  7. data/app/controllers/scim_rails/application_controller.rb +72 -0
  8. data/app/controllers/scim_rails/scim_groups_controller.rb +96 -0
  9. data/app/controllers/scim_rails/scim_users_controller.rb +124 -0
  10. data/app/helpers/scim_rails/application_helper.rb +4 -0
  11. data/app/models/scim_rails/application_record.rb +5 -0
  12. data/app/models/scim_rails/authorize_api_request.rb +40 -0
  13. data/app/models/scim_rails/scim_count.rb +38 -0
  14. data/app/models/scim_rails/scim_query_parser.rb +47 -0
  15. data/config/initializers/mime_types.rb +5 -0
  16. data/config/routes.rb +12 -0
  17. data/lib/generators/scim_rails/USAGE +8 -0
  18. data/lib/generators/scim_rails/scim_rails_generator.rb +7 -0
  19. data/lib/generators/scim_rails/templates/initializer.rb +166 -0
  20. data/lib/scim_rails/config.rb +85 -0
  21. data/lib/scim_rails/encoder.rb +25 -0
  22. data/lib/scim_rails/engine.rb +12 -0
  23. data/lib/scim_rails/version.rb +5 -0
  24. data/lib/scim_rails.rb +6 -0
  25. data/lib/tasks/scim_rails_tasks.rake +4 -0
  26. data/spec/controllers/scim_rails/scim_groups_controller_spec.rb +494 -0
  27. data/spec/controllers/scim_rails/scim_groups_request_spec.rb +68 -0
  28. data/spec/controllers/scim_rails/scim_users_controller_spec.rb +681 -0
  29. data/spec/controllers/scim_rails/scim_users_request_spec.rb +77 -0
  30. data/spec/dummy/Rakefile +6 -0
  31. data/spec/dummy/app/assets/config/manifest.js +5 -0
  32. data/spec/dummy/app/assets/javascripts/application.js +13 -0
  33. data/spec/dummy/app/assets/javascripts/cable.js +13 -0
  34. data/spec/dummy/app/assets/stylesheets/application.css +15 -0
  35. data/spec/dummy/app/channels/application_cable/channel.rb +4 -0
  36. data/spec/dummy/app/channels/application_cable/connection.rb +4 -0
  37. data/spec/dummy/app/controllers/application_controller.rb +3 -0
  38. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  39. data/spec/dummy/app/jobs/application_job.rb +2 -0
  40. data/spec/dummy/app/mailers/application_mailer.rb +4 -0
  41. data/spec/dummy/app/models/application_record.rb +3 -0
  42. data/spec/dummy/app/models/company.rb +4 -0
  43. data/spec/dummy/app/models/group.rb +15 -0
  44. data/spec/dummy/app/models/group_user.rb +6 -0
  45. data/spec/dummy/app/models/user.rb +39 -0
  46. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  47. data/spec/dummy/app/views/layouts/mailer.html.erb +13 -0
  48. data/spec/dummy/app/views/layouts/mailer.text.erb +1 -0
  49. data/spec/dummy/bin/bundle +3 -0
  50. data/spec/dummy/bin/rails +4 -0
  51. data/spec/dummy/bin/rake +4 -0
  52. data/spec/dummy/bin/setup +34 -0
  53. data/spec/dummy/bin/update +29 -0
  54. data/spec/dummy/config/application.rb +15 -0
  55. data/spec/dummy/config/boot.rb +5 -0
  56. data/spec/dummy/config/cable.yml +9 -0
  57. data/spec/dummy/config/database.yml +25 -0
  58. data/spec/dummy/config/environment.rb +5 -0
  59. data/spec/dummy/config/environments/development.rb +54 -0
  60. data/spec/dummy/config/environments/production.rb +86 -0
  61. data/spec/dummy/config/environments/test.rb +42 -0
  62. data/spec/dummy/config/initializers/application_controller_renderer.rb +6 -0
  63. data/spec/dummy/config/initializers/assets.rb +11 -0
  64. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  65. data/spec/dummy/config/initializers/cookies_serializer.rb +5 -0
  66. data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  67. data/spec/dummy/config/initializers/inflections.rb +16 -0
  68. data/spec/dummy/config/initializers/mime_types.rb +4 -0
  69. data/spec/dummy/config/initializers/new_framework_defaults.rb +24 -0
  70. data/spec/dummy/config/initializers/scim_rails_config.rb +85 -0
  71. data/spec/dummy/config/initializers/session_store.rb +3 -0
  72. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  73. data/spec/dummy/config/locales/en.yml +23 -0
  74. data/spec/dummy/config/puma.rb +47 -0
  75. data/spec/dummy/config/routes.rb +3 -0
  76. data/spec/dummy/config/secrets.yml +22 -0
  77. data/spec/dummy/config/spring.rb +6 -0
  78. data/spec/dummy/config.ru +5 -0
  79. data/spec/dummy/db/migrate/20181206184304_create_users.rb +15 -0
  80. data/spec/dummy/db/migrate/20181206184313_create_companies.rb +11 -0
  81. data/spec/dummy/db/migrate/20210423075859_create_groups.rb +10 -0
  82. data/spec/dummy/db/migrate/20210423075950_create_group_users.rb +10 -0
  83. data/spec/dummy/db/schema.rb +53 -0
  84. data/spec/dummy/db/seeds.rb +14 -0
  85. data/spec/dummy/public/404.html +67 -0
  86. data/spec/dummy/public/422.html +67 -0
  87. data/spec/dummy/public/500.html +66 -0
  88. data/spec/dummy/public/apple-touch-icon-precomposed.png +0 -0
  89. data/spec/dummy/public/apple-touch-icon.png +0 -0
  90. data/spec/dummy/public/favicon.ico +0 -0
  91. data/spec/factories/company.rb +10 -0
  92. data/spec/factories/group.rb +11 -0
  93. data/spec/factories/user.rb +9 -0
  94. data/spec/lib/scim_rails/encoder_spec.rb +62 -0
  95. data/spec/spec_helper.rb +17 -0
  96. data/spec/support/auth_helper.rb +7 -0
  97. data/spec/support/factory_bot.rb +3 -0
  98. data/spec/support/scim_rails_config.rb +59 -0
  99. 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