Commit 1930828f5410697bf16454965cf2d111586713ba

Authored by Ross Reinhardt
Committed by Kyle Werner
1 parent a67fa0e6
Exists in master

Fix patch endpoint archiving and case sensitivity

fixes #32

After a fix shipped in #29, you could no longer de-provision a user
because when false was passed in as the value for active, it thought
there was no value for active.

fixes #33

Technically according to the specifications, the value for op is only
valid if it is one of three lower case values. However, our previous
implementation accepted a case insensitive version. Because of this, we
are adding backward compatibility for case insensitivity until we have a
chance to properly make a breaking change and only allow lower case.
app/controllers/scim_rails/scim_users_controller.rb
... ... @@ -140,9 +140,9 @@ module ScimRails
140 140 end
141 141  
142 142 def valid_patch_operation?(operation)
143   - operation["op"] == "replace" &&
  143 + operation["op"].casecmp("replace") &&
144 144 operation["value"] &&
145   - operation["value"]["active"]
  145 + [true, false].include?(operation["value"]["active"])
146 146 end
147 147 end
148 148 end
... ...
spec/controllers/scim_rails/scim_users_controller_spec.rb
... ... @@ -10,13 +10,13 @@ RSpec.describe ScimRails::ScimUsersController, type: :controller do
10 10  
11 11 context "when unauthorized" do
12 12 it "returns scim+json content type" do
13   - get :index
  13 + get :index, as: :json
14 14  
15 15 expect(response.media_type).to eq "application/scim+json"
16 16 end
17 17  
18 18 it "fails with no credentials" do
19   - get :index
  19 + get :index, as: :json
20 20  
21 21 expect(response.status).to eq 401
22 22 end
... ... @@ -24,7 +24,7 @@ RSpec.describe ScimRails::ScimUsersController, type: :controller do
24 24 it "fails with invalid credentials" do
25 25 request.env['HTTP_AUTHORIZATION'] = ActionController::HttpAuthentication::Basic.encode_credentials("unauthorized","123456")
26 26  
27   - get :index
  27 + get :index, as: :json
28 28  
29 29 expect(response.status).to eq 401
30 30 end
... ... @@ -36,13 +36,13 @@ RSpec.describe ScimRails::ScimUsersController, type: :controller do
36 36 end
37 37  
38 38 it "returns scim+json content type" do
39   - get :index
  39 + get :index, as: :json
40 40  
41 41 expect(response.media_type).to eq "application/scim+json"
42 42 end
43 43  
44 44 it "is successful with valid credentials" do
45   - get :index
  45 + get :index, as: :json
46 46  
47 47 expect(response.status).to eq 200
48 48 end
... ... @@ -50,7 +50,7 @@ RSpec.describe ScimRails::ScimUsersController, type: :controller do
50 50 it "returns all results" do
51 51 create_list(:user, 10, company: company)
52 52  
53   - get :index
  53 + get :index, as: :json
54 54 response_body = JSON.parse(response.body)
55 55 expect(response_body.dig("schemas", 0)).to eq "urn:ietf:params:scim:api:messages:2.0:ListResponse"
56 56 expect(response_body["totalResults"]).to eq 10
... ... @@ -59,7 +59,7 @@ RSpec.describe ScimRails::ScimUsersController, type: :controller do
59 59 it "defaults to 100 results" do
60 60 create_list(:user, 300, company: company)
61 61  
62   - get :index
  62 + get :index, as: :json
63 63 response_body = JSON.parse(response.body)
64 64 expect(response_body["totalResults"]).to eq 300
65 65 expect(response_body["Resources"].count).to eq 100
... ... @@ -72,7 +72,7 @@ RSpec.describe ScimRails::ScimUsersController, type: :controller do
72 72 get :index, params: {
73 73 startIndex: 101,
74 74 count: 200,
75   - }
  75 + }, as: :json
76 76 response_body = JSON.parse(response.body)
77 77 expect(response_body["totalResults"]).to eq 400
78 78 expect(response_body["Resources"].count).to eq 200
... ... @@ -88,7 +88,7 @@ RSpec.describe ScimRails::ScimUsersController, type: :controller do
88 88 get :index, params: {
89 89 startIndex: 1,
90 90 count: 10,
91   - }
  91 + }, as: :json
92 92 response_body = JSON.parse(response.body)
93 93 expect(response_body["totalResults"]).to eq 400
94 94 expect(response_body["Resources"].count).to eq 10
... ... @@ -101,7 +101,7 @@ RSpec.describe ScimRails::ScimUsersController, type: :controller do
101 101  
102 102 get :index, params: {
103 103 filter: "email eq test1@example.com"
104   - }
  104 + }, as: :json
105 105 response_body = JSON.parse(response.body)
106 106 expect(response_body["totalResults"]).to eq 1
107 107 expect(response_body["Resources"].count).to eq 1
... ... @@ -113,7 +113,7 @@ RSpec.describe ScimRails::ScimUsersController, type: :controller do
113 113  
114 114 get :index, params: {
115 115 filter: "familyName eq Shellstrop"
116   - }
  116 + }, as: :json
117 117 response_body = JSON.parse(response.body)
118 118 expect(response_body["totalResults"]).to eq 1
119 119 expect(response_body["Resources"].count).to eq 1
... ... @@ -122,7 +122,7 @@ RSpec.describe ScimRails::ScimUsersController, type: :controller do
122 122 it "returns no results for unfound filter parameters" do
123 123 get :index, params: {
124 124 filter: "familyName eq fake_not_there"
125   - }
  125 + }, as: :json
126 126 response_body = JSON.parse(response.body)
127 127 expect(response_body["totalResults"]).to eq 0
128 128 expect(response_body["Resources"].count).to eq 0
... ... @@ -131,7 +131,7 @@ RSpec.describe ScimRails::ScimUsersController, type: :controller do
131 131 it "returns no results for undefined filter queries" do
132 132 get :index, params: {
133 133 filter: "address eq 101 Nowhere USA"
134   - }
  134 + }, as: :json
135 135 expect(response.status).to eq 400
136 136 response_body = JSON.parse(response.body)
137 137 expect(response_body.dig("schemas", 0)).to eq "urn:ietf:params:scim:api:messages:2.0:Error"
... ... @@ -145,13 +145,13 @@ RSpec.describe ScimRails::ScimUsersController, type: :controller do
145 145  
146 146 context "when unauthorized" do
147 147 it "returns scim+json content type" do
148   - get :show, params: { id: 1 }
  148 + get :show, params: { id: 1 }, as: :json
149 149  
150 150 expect(response.media_type).to eq "application/scim+json"
151 151 end
152 152  
153 153 it "fails with no credentials" do
154   - get :show, params: { id: 1 }
  154 + get :show, params: { id: 1 }, as: :json
155 155  
156 156 expect(response.status).to eq 401
157 157 end
... ... @@ -159,7 +159,7 @@ RSpec.describe ScimRails::ScimUsersController, type: :controller do
159 159 it "fails with invalid credentials" do
160 160 request.env['HTTP_AUTHORIZATION'] = ActionController::HttpAuthentication::Basic.encode_credentials("unauthorized","123456")
161 161  
162   - get :show, params: { id: 1 }
  162 + get :show, params: { id: 1 }, as: :json
163 163  
164 164 expect(response.status).to eq 401
165 165 end
... ... @@ -171,20 +171,20 @@ RSpec.describe ScimRails::ScimUsersController, type: :controller do
171 171 end
172 172  
173 173 it "returns scim+json content type" do
174   - get :show, params: { id: 1 }
  174 + get :show, params: { id: 1 }, as: :json
175 175  
176 176 expect(response.media_type).to eq "application/scim+json"
177 177 end
178 178  
179 179 it "is successful with valid credentials" do
180 180 create(:user, id: 1, company: company)
181   - get :show, params: { id: 1 }
  181 + get :show, params: { id: 1 }, as: :json
182 182  
183 183 expect(response.status).to eq 200
184 184 end
185 185  
186 186 it "returns :not_found for id that cannot be found" do
187   - get :show, params: { id: "fake_id" }
  187 + get :show, params: { id: "fake_id" }, as: :json
188 188  
189 189 expect(response.status).to eq 404
190 190 end
... ... @@ -193,7 +193,7 @@ RSpec.describe ScimRails::ScimUsersController, type: :controller do
193 193 new_company = create(:company)
194 194 create(:user, company: new_company, id: 1)
195 195  
196   - get :show, params: { id: 1 }
  196 + get :show, params: { id: 1 }, as: :json
197 197  
198 198 expect(response.status).to eq 404
199 199 end
... ... @@ -206,13 +206,13 @@ RSpec.describe ScimRails::ScimUsersController, type: :controller do
206 206  
207 207 context "when unauthorized" do
208 208 it "returns scim+json content type" do
209   - post :create
  209 + post :create, as: :json
210 210  
211 211 expect(response.media_type).to eq "application/scim+json"
212 212 end
213 213  
214 214 it "fails with no credentials" do
215   - post :create
  215 + post :create, as: :json
216 216  
217 217 expect(response.status).to eq 401
218 218 end
... ... @@ -220,7 +220,7 @@ RSpec.describe ScimRails::ScimUsersController, type: :controller do
220 220 it "fails with invalid credentials" do
221 221 request.env['HTTP_AUTHORIZATION'] = ActionController::HttpAuthentication::Basic.encode_credentials("unauthorized","123456")
222 222  
223   - post :create
  223 + post :create, as: :json
224 224  
225 225 expect(response.status).to eq 401
226 226 end
... ... @@ -242,7 +242,7 @@ RSpec.describe ScimRails::ScimUsersController, type: :controller do
242 242 value: "new@example.com"
243 243 }
244 244 ]
245   - }
  245 + }, as: :json
246 246  
247 247 expect(response.media_type).to eq "application/scim+json"
248 248 end
... ... @@ -260,7 +260,7 @@ RSpec.describe ScimRails::ScimUsersController, type: :controller do
260 260 value: "new@example.com"
261 261 }
262 262 ]
263   - }
  263 + }, as: :json
264 264  
265 265 expect(response.status).to eq 201
266 266 expect(company.users.count).to eq 1
... ... @@ -283,7 +283,7 @@ RSpec.describe ScimRails::ScimUsersController, type: :controller do
283 283 value: "new@example.com"
284 284 }
285 285 ]
286   - }
  286 + }, as: :json
287 287  
288 288 expect(response.status).to eq 201
289 289 expect(company.users.count).to eq 1
... ... @@ -299,7 +299,7 @@ RSpec.describe ScimRails::ScimUsersController, type: :controller do
299 299 value: "new@example.com"
300 300 }
301 301 ]
302   - }
  302 + }, as: :json
303 303  
304 304 expect(response.status).to eq 422
305 305 expect(company.users.count).to eq 0
... ... @@ -318,7 +318,7 @@ RSpec.describe ScimRails::ScimUsersController, type: :controller do
318 318 value: "new@example.com"
319 319 }
320 320 ]
321   - }
  321 + }, as: :json
322 322  
323 323 expect(response.status).to eq 201
324 324 expect(company.users.count).to eq 1
... ... @@ -339,7 +339,7 @@ RSpec.describe ScimRails::ScimUsersController, type: :controller do
339 339 value: "new@example.com"
340 340 }
341 341 ]
342   - }
  342 + }, as: :json
343 343  
344 344 expect(response.status).to eq 409
345 345 expect(company.users.count).to eq 1
... ... @@ -359,7 +359,7 @@ RSpec.describe ScimRails::ScimUsersController, type: :controller do
359 359 },
360 360 ],
361 361 active: "false"
362   - }
  362 + }, as: :json
363 363  
364 364 expect(response.status).to eq 201
365 365 expect(company.users.count).to eq 1
... ... @@ -375,13 +375,13 @@ RSpec.describe ScimRails::ScimUsersController, type: :controller do
375 375  
376 376 context "when unauthorized" do
377 377 it "returns scim+json content type" do
378   - put :put_update, params: { id: 1 }
  378 + put :put_update, params: { id: 1 }, as: :json
379 379  
380 380 expect(response.media_type).to eq "application/scim+json"
381 381 end
382 382  
383 383 it "fails with no credentials" do
384   - put :put_update, params: { id: 1 }
  384 + put :put_update, params: { id: 1 }, as: :json
385 385  
386 386 expect(response.status).to eq 401
387 387 end
... ... @@ -389,7 +389,7 @@ RSpec.describe ScimRails::ScimUsersController, type: :controller do
389 389 it "fails with invalid credentials" do
390 390 request.env['HTTP_AUTHORIZATION'] = ActionController::HttpAuthentication::Basic.encode_credentials("unauthorized","123456")
391 391  
392   - put :put_update, params: { id: 1 }
  392 + put :put_update, params: { id: 1 }, as: :json
393 393  
394 394 expect(response.status).to eq 401
395 395 end
... ... @@ -403,20 +403,20 @@ RSpec.describe ScimRails::ScimUsersController, type: :controller do
403 403 end
404 404  
405 405 it "returns scim+json content type" do
406   - put :put_update, params: put_params
  406 + put :put_update, params: put_params, as: :json
407 407  
408 408 expect(response.media_type).to eq "application/scim+json"
409 409 end
410 410  
411 411 it "is successful with with valid credentials" do
412   - put :put_update, params: put_params
  412 + put :put_update, params: put_params, as: :json
413 413  
414 414 expect(response.status).to eq 200
415 415 end
416 416  
417 417 it "deprovisions an active record" do
418 418 request.content_type = "application/scim+json"
419   - put :put_update, params: put_params(active: false)
  419 + put :put_update, params: put_params(active: false), as: :json
420 420  
421 421 expect(response.status).to eq 200
422 422 expect(user.reload.active?).to eq false
... ... @@ -426,14 +426,14 @@ RSpec.describe ScimRails::ScimUsersController, type: :controller do
426 426 user.archive!
427 427 expect(user.reload.active?).to eq false
428 428 request.content_type = "application/scim+json"
429   - put :put_update, params: put_params(active: true)
  429 + put :put_update, params: put_params(active: true), as: :json
430 430  
431 431 expect(response.status).to eq 200
432 432 expect(user.reload.active?).to eq true
433 433 end
434 434  
435 435 it "returns :not_found for id that cannot be found" do
436   - get :put_update, params: { id: "fake_id" }
  436 + get :put_update, params: { id: "fake_id" }, as: :json
437 437  
438 438 expect(response.status).to eq 404
439 439 end
... ... @@ -442,7 +442,7 @@ RSpec.describe ScimRails::ScimUsersController, type: :controller do
442 442 new_company = create(:company)
443 443 create(:user, company: new_company, id: 1000)
444 444  
445   - get :put_update, params: { id: 1000 }
  445 + get :put_update, params: { id: 1000 }, as: :json
446 446  
447 447 expect(response.status).to eq 404
448 448 end
... ... @@ -457,7 +457,7 @@ RSpec.describe ScimRails::ScimUsersController, type: :controller do
457 457 },
458 458 ],
459 459 active: "true"
460   - }
  460 + }, as: :json
461 461  
462 462 expect(response.status).to eq 422
463 463 end
... ... @@ -470,13 +470,13 @@ RSpec.describe ScimRails::ScimUsersController, type: :controller do
470 470  
471 471 context "when unauthorized" do
472 472 it "returns scim+json content type" do
473   - patch :patch_update, params: patch_params(id: 1)
  473 + patch :patch_update, params: patch_params(id: 1), as: :json
474 474  
475 475 expect(response.media_type).to eq "application/scim+json"
476 476 end
477 477  
478 478 it "fails with no credentials" do
479   - patch :patch_update, params: patch_params(id: 1)
  479 + patch :patch_update, params: patch_params(id: 1), as: :json
480 480  
481 481 expect(response.status).to eq 401
482 482 end
... ... @@ -484,7 +484,7 @@ RSpec.describe ScimRails::ScimUsersController, type: :controller do
484 484 it "fails with invalid credentials" do
485 485 request.env['HTTP_AUTHORIZATION'] = ActionController::HttpAuthentication::Basic.encode_credentials("unauthorized","123456")
486 486  
487   - patch :patch_update, params: patch_params(id: 1)
  487 + patch :patch_update, params: patch_params(id: 1), as: :json
488 488  
489 489 expect(response.status).to eq 401
490 490 end
... ... @@ -498,19 +498,19 @@ RSpec.describe ScimRails::ScimUsersController, type: :controller do
498 498 end
499 499  
500 500 it "returns scim+json content type" do
501   - patch :patch_update, params: patch_params(id: 1)
  501 + patch :patch_update, params: patch_params(id: 1), as: :json
502 502  
503 503 expect(response.media_type).to eq "application/scim+json"
504 504 end
505 505  
506 506 it "is successful with valid credentials" do
507   - patch :patch_update, params: patch_params(id: 1)
  507 + patch :patch_update, params: patch_params(id: 1), as: :json
508 508  
509 509 expect(response.status).to eq 200
510 510 end
511 511  
512 512 it "returns :not_found for id that cannot be found" do
513   - get :patch_update, params: patch_params(id: "fake_id")
  513 + get :patch_update, params: patch_params(id: "fake_id"), as: :json
514 514  
515 515 expect(response.status).to eq 404
516 516 end
... ... @@ -519,7 +519,7 @@ RSpec.describe ScimRails::ScimUsersController, type: :controller do
519 519 new_company = create(:company)
520 520 create(:user, company: new_company, id: 1000)
521 521  
522   - get :patch_update, params: patch_params(id: 1000)
  522 + get :patch_update, params: patch_params(id: 1000), as: :json
523 523  
524 524 expect(response.status).to eq 404
525 525 end
... ... @@ -529,7 +529,7 @@ RSpec.describe ScimRails::ScimUsersController, type: :controller do
529 529 user = company.users.first
530 530 expect(user.archived?).to eq false
531 531  
532   - patch :patch_update, params: patch_params(id: 1)
  532 + patch :patch_update, params: patch_params(id: 1), as: :json
533 533  
534 534 expect(response.status).to eq 200
535 535 expect(company.users.count).to eq 1
... ... @@ -542,7 +542,7 @@ RSpec.describe ScimRails::ScimUsersController, type: :controller do
542 542 user = company.users.first.tap(&:archive!)
543 543 expect(user.archived?).to eq true
544 544  
545   - patch :patch_update, params: patch_params(id: 1, active: true)
  545 + patch :patch_update, params: patch_params(id: 1, active: true), as: :json
546 546  
547 547 expect(response.status).to eq 200
548 548 expect(company.users.count).to eq 1
... ... @@ -550,6 +550,24 @@ RSpec.describe ScimRails::ScimUsersController, type: :controller do
550 550 expect(user.archived?).to eq false
551 551 end
552 552  
  553 + it "is case insensetive for op value" do
  554 + # Note, this is for backward compatibility. op should always
  555 + # be lower case and support for case insensitivity will be removed
  556 + patch :patch_update, params: {
  557 + id: 1,
  558 + Operations: [
  559 + {
  560 + op: "Replace",
  561 + value: {
  562 + active: false
  563 + }
  564 + }
  565 + ]
  566 + }, as: :json
  567 +
  568 + expect(response.status).to eq 200
  569 + end
  570 +
553 571 it "throws an error for non status updates" do
554 572 patch :patch_update, params: {
555 573 id: 1,
... ... @@ -563,14 +581,14 @@ RSpec.describe ScimRails::ScimUsersController, type: :controller do
563 581 }
564 582 }
565 583 ]
566   - }
  584 + }, as: :json
567 585  
568 586 expect(response.status).to eq 422
569 587 response_body = JSON.parse(response.body)
570 588 expect(response_body.dig("schemas", 0)).to eq "urn:ietf:params:scim:api:messages:2.0:Error"
571 589 end
572 590  
573   - it "returns 422 when value is " do
  591 + it "returns 422 when value is not an object" do
574 592 patch :patch_update, params: {
575 593 id: 1,
576 594 Operations: [
... ... @@ -595,7 +613,7 @@ RSpec.describe ScimRails::ScimUsersController, type: :controller do
595 613 op: "replace"
596 614 }
597 615 ]
598   - }
  616 + }, as: :json
599 617  
600 618 expect(response.status).to eq 422
601 619 response_body = JSON.parse(response.body)
... ... @@ -610,7 +628,7 @@ RSpec.describe ScimRails::ScimUsersController, type: :controller do
610 628 op: "replace"
611 629 }
612 630 ]
613   - }
  631 + }, as: :json
614 632  
615 633 expect(response.status).to eq 422
616 634 response_body = JSON.parse(response.body)
... ...
spec/controllers/scim_rails/scim_users_request_spec.rb
... ... @@ -8,7 +8,7 @@ RSpec.describe ScimRails::ScimUsersController, type: :request do
8 8 def post_request(content_type = "application/scim+json")
9 9 # params need to be transformed into a string to test if they are being parsed by Rack
10 10  
11   - post "/scim_rails/scim/v2/Users",
  11 + post "/scim/v2/Users",
12 12 params: {
13 13 name: {
14 14 givenName: "New",
... ...
spec/dummy/config/routes.rb
1 1 Rails.application.routes.draw do
2   - mount ScimRails::Engine => "/scim_rails"
  2 + mount ScimRails::Engine => "/"
3 3 end
... ...