scim_rails 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 86825e382a5c558d2802904c2adc98b7f7b5fb1c
4
- data.tar.gz: 66d58b555f21eefd7f0c829feef30caf08446534
3
+ metadata.gz: 852439c711dfe1b37da47988060c40324985ff23
4
+ data.tar.gz: ef61b7184ed183976e3c48833ba8b330e0ef773e
5
5
  SHA512:
6
- metadata.gz: '077238f948c1c027b5e98ea30b465e90d576b4ff3b07e3b150046d5acc9376fdcc8a7725329fe82dc8b57d9beae9285a231207afa1b56c488964e501485012b3'
7
- data.tar.gz: eb0b98dbad28e4a22bc5ed48859c8a546263d91a43757d717c3284382ade77f11c45f6f0e51f33eea41e2ee6e38482637893728df586bc2100b36072c45f20c0
6
+ metadata.gz: b056aceb8507e3587bc33dcc6387f0cf0ec2f29bbfce0d00102056676285fd1dad15a1387e3b2d2041a918ec1b9fbf7e0a150b614757ade503196558e6ff6f93
7
+ data.tar.gz: 1d2340490c77f232f87e05f7775d1c482333aba9974a74efc599e55a8819f3b8df439249300c5d1c6c3adc3ef23d6426048c7779d21f6a90b5abfe1b91666c15
data/README.md CHANGED
@@ -4,7 +4,7 @@ NOTE: This Gem is not yet fully SCIM complaint. It was developed with the main f
4
4
 
5
5
  #### What is SCIM?
6
6
 
7
- SCIM stands for System for Cross-domain Identity Management. At its core, it is a set of rules defining how apps should interact for the purpose of creating, updating, and deprovisioning users. SCIM requests and responses can be sent in XML or JSON and this Gem uses JSON for ease of readabilty.
7
+ SCIM stands for System for Cross-domain Identity Management. At its core, it is a set of rules defining how apps should interact for the purpose of creating, updating, and deprovisioning users. SCIM requests and responses can be sent in XML or JSON and this Gem uses JSON for ease of readability.
8
8
 
9
9
  To learn more about SCIM 2.0 you can read the documentation at [RFC 7643](https://tools.ietf.org/html/rfc7643) and [RFC 7644](https://tools.ietf.org/html/rfc7644).
10
10
 
@@ -92,7 +92,7 @@ $ curl -X GET 'http://username:password@localhost:3000/scim/v2/Users'
92
92
 
93
93
  This Gem provides two pagination filters; `startIndex` and `count`.
94
94
 
95
- `startIndex` is the positional number you would like to start at. This parameter can accept any integer but anything less than 1 will be interpreted as 1. If you visualize an array with all your user records in the array, `startIndex` is basically what element you would like to start at. If you are familiar with SQL this parameter is directly correlated to the query offset. **The default value for this fitler is 1.**
95
+ `startIndex` is the positional number you would like to start at. This parameter can accept any integer but anything less than 1 will be interpreted as 1. If you visualize an array with all your user records in the array, `startIndex` is basically what element you would like to start at. If you are familiar with SQL this parameter is directly correlated to the query offset. **The default value for this filter is 1.**
96
96
 
97
97
  `count` is the number of records you would like present in the response. **The default value for this filter is 100.**
98
98
 
@@ -108,7 +108,7 @@ The pagination filters may be used on their own or in addition to the query filt
108
108
 
109
109
  ##### Querying
110
110
 
111
- Currently the only filter supported is a single level `eq`. More operators can be added failry easily in future releases. The SCIM RFC documents nested querying which is something we would like to implement in the future.
111
+ Currently the only filter supported is a single level `eq`. More operators can be added fairly easily in future releases. The SCIM RFC documents nested querying which is something we would like to implement in the future.
112
112
 
113
113
  **Queryable attributes can be mapped in the configuration file.**
114
114
 
@@ -121,7 +121,7 @@ filter=formattedName eq Test User
121
121
  filter=id eq 1
122
122
  ```
123
123
 
124
- Unsuppored filter:
124
+ Unsupported filter:
125
125
 
126
126
  ```
127
127
  filter=(email eq test@example.com) or (userName eq test@example.com)
@@ -183,16 +183,16 @@ Sample request:
183
183
  $ curl -X PUT 'http://username:password@localhost:3000/scim/v2/Users/1' -d '{"schemas":["urn:ietf:params:scim:schemas:core:2.0:User"],"userName":"test@example.com","name":{"givenName":"Test","familyName":"User"},"emails":[{"primary":true,"value":"test@example.com","type":"work"}],"displayName":"Test User","active":true}' -H 'Content-Type: application/scim+json'
184
184
  ```
185
185
 
186
- ### Deprovision
186
+ ### Deprovision / Reprovision
187
187
 
188
- The PATCH request was implemented to work with Okta. Okta updates profiles with PUT and deprovisions with PATCH. This implemention of PATCH is not SCIM compliant as it does not update a single attribute on the user profile but instead only sends a deprovision request.
188
+ The PATCH request was implemented to work with Okta. Okta updates profiles with PUT and deprovisions / reprovisions with PATCH. This implementation of PATCH is not SCIM compliant as it does not update a single attribute on the user profile but instead only sends a status update request to the record.
189
189
 
190
190
  We would like to implement PATCH to be fully SCIM compliant in future releases.
191
191
 
192
192
  Sample request:
193
193
 
194
194
  ```bash
195
- $ curl -X PATCH 'http://username:password@localhost:3000/scim/v2/Users/1'
195
+ $ curl -X PATCH 'http://username:password@localhost:3000/scim/v2/Users/1' -d '{"schemas": ["urn:ietf:params:scim:api:messages:2.0:PatchOp"], "Operations": [{"op": "replace", "value": { "active": false }}]}' -H 'Content-Type: application/scim+json'
196
196
  ```
197
197
 
198
198
  ## Contributing
@@ -8,6 +8,9 @@ module ScimRails
8
8
  class InvalidQuery < StandardError
9
9
  end
10
10
 
11
+ class UnsupportedPatchRequest < StandardError
12
+ end
13
+
11
14
  included do
12
15
  rescue_from ScimRails::ExceptionHandler::InvalidCredentials do
13
16
  json_response(
@@ -32,6 +35,17 @@ module ScimRails
32
35
  )
33
36
  end
34
37
 
38
+ rescue_from ScimRails::ExceptionHandler::UnsupportedPatchRequest do
39
+ json_response(
40
+ {
41
+ schemas: ["urn:ietf:params:scim:api:messages:2.0:Error"],
42
+ detail: "Invalid PATCH request. This PATCH endpoint only supports deprovisioning and reprovisioning records.",
43
+ status: "422"
44
+ },
45
+ :unprocessable_entity
46
+ )
47
+ end
48
+
35
49
  rescue_from ActiveRecord::RecordNotFound do |e|
36
50
  json_response(
37
51
  {
@@ -28,7 +28,7 @@ module ScimRails
28
28
 
29
29
  def create
30
30
  user = @company.public_send(ScimRails.config.scim_users_scope).create!(permitted_user_params)
31
- update_status(user) unless params[:active].nil?
31
+ update_status(user) unless put_active_param.nil?
32
32
  json_scim_response(object: user, status: :created)
33
33
  end
34
34
 
@@ -39,16 +39,15 @@ module ScimRails
39
39
 
40
40
  def put_update
41
41
  user = @company.public_send(ScimRails.config.scim_users_scope).find(params[:id])
42
- update_status(user) unless params[:active].nil?
42
+ update_status(user) unless put_active_param.nil?
43
43
  user.update!(permitted_user_params)
44
44
  json_scim_response(object: user)
45
45
  end
46
46
 
47
- # TODO: PATCH will only deprovision users regardless of params.
47
+ # TODO: PATCH will only deprovision or reprovision users.
48
48
  # This will work just fine for Okta but is not SCIM compliant.
49
49
  def patch_update
50
50
  user = @company.public_send(ScimRails.config.scim_users_scope).find(params[:id])
51
- params[:active] = false
52
51
  update_status(user)
53
52
  json_scim_response(object: user)
54
53
  end
@@ -99,7 +98,8 @@ module ScimRails
99
98
  end
100
99
 
101
100
  def active?
102
- case params[:active]
101
+ active = put_active_param || patch_active_param
102
+ case active
103
103
  when true, "true", 1
104
104
  true
105
105
  when false, "false", 0
@@ -108,5 +108,15 @@ module ScimRails
108
108
  raise ActiveRecord::RecordInvalid
109
109
  end
110
110
  end
111
+
112
+ def put_active_param
113
+ params[:active]
114
+ end
115
+
116
+ def patch_active_param
117
+ active = params.dig("Operations", 0, "value", "active")
118
+ raise ScimRails::ExceptionHandler::UnsupportedPatchRequest if active.nil?
119
+ active
120
+ end
111
121
  end
112
122
  end
@@ -1,3 +1,3 @@
1
1
  module ScimRails
2
- VERSION = '0.1.0'
2
+ VERSION = '0.1.1'
3
3
  end
@@ -457,13 +457,13 @@ RSpec.describe ScimRails::ScimUsersController, type: :controller do
457
457
 
458
458
  context "when unauthorized" do
459
459
  it "returns scim+json content type" do
460
- patch :patch_update, params: { id: 1 }
460
+ patch :patch_update, params: patch_params(id: 1)
461
461
 
462
462
  expect(response.content_type).to eq "application/scim+json, application/json"
463
463
  end
464
464
 
465
465
  it "fails with no credentials" do
466
- patch :patch_update, params: { id: 1 }
466
+ patch :patch_update, params: patch_params(id: 1)
467
467
 
468
468
  expect(response.status).to eq 401
469
469
  end
@@ -471,7 +471,7 @@ RSpec.describe ScimRails::ScimUsersController, type: :controller do
471
471
  it "fails with invalid credentials" do
472
472
  request.env['HTTP_AUTHORIZATION'] = ActionController::HttpAuthentication::Basic.encode_credentials("unauthorized","123456")
473
473
 
474
- patch :patch_update, params: { id: 1 }
474
+ patch :patch_update, params: patch_params(id: 1)
475
475
 
476
476
  expect(response.status).to eq 401
477
477
  end
@@ -485,19 +485,19 @@ RSpec.describe ScimRails::ScimUsersController, type: :controller do
485
485
  end
486
486
 
487
487
  it "returns scim+json content type" do
488
- patch :patch_update, params: { id: 1 }
488
+ patch :patch_update, params: patch_params(id: 1)
489
489
 
490
490
  expect(response.content_type).to eq "application/scim+json, application/json"
491
491
  end
492
492
 
493
493
  it "is successful with valid credentials" do
494
- patch :patch_update, params: { id: 1 }
494
+ patch :patch_update, params: patch_params(id: 1)
495
495
 
496
496
  expect(response.status).to eq 200
497
497
  end
498
498
 
499
499
  it "returns :not_found for id that cannot be found" do
500
- get :patch_update, params: { id: "fake_id" }
500
+ get :patch_update, params: patch_params(id: "fake_id")
501
501
 
502
502
  expect(response.status).to eq 404
503
503
  end
@@ -506,7 +506,7 @@ RSpec.describe ScimRails::ScimUsersController, type: :controller do
506
506
  new_company = create(:company)
507
507
  create(:user, company: new_company, id: 1000)
508
508
 
509
- get :patch_update, params: { id: 1000 }
509
+ get :patch_update, params: patch_params(id: 1000)
510
510
 
511
511
  expect(response.status).to eq 404
512
512
  end
@@ -516,13 +516,60 @@ RSpec.describe ScimRails::ScimUsersController, type: :controller do
516
516
  user = company.users.first
517
517
  expect(user.archived?).to eq false
518
518
 
519
- patch :patch_update, params: { id: 1 }
519
+ patch :patch_update, params: patch_params(id: 1)
520
520
 
521
521
  expect(response.status).to eq 200
522
522
  expect(company.users.count).to eq 1
523
523
  user.reload
524
524
  expect(user.archived?).to eq true
525
525
  end
526
+
527
+ it "sucessfully restores user" do
528
+ expect(company.users.count).to eq 1
529
+ user = company.users.first.tap(&:archive!)
530
+ expect(user.archived?).to eq true
531
+
532
+ patch :patch_update, params: patch_params(id: 1, active: true)
533
+
534
+ expect(response.status).to eq 200
535
+ expect(company.users.count).to eq 1
536
+ user.reload
537
+ expect(user.archived?).to eq false
538
+ end
539
+
540
+ it "throws an error for non status updates" do
541
+ patch :patch_update, params: {
542
+ id: 1,
543
+ Operations: [
544
+ {
545
+ op: "replace",
546
+ value: {
547
+ name: {
548
+ givenName: "Francis"
549
+ }
550
+ }
551
+ }
552
+ ]
553
+ }
554
+
555
+ expect(response.status).to eq 422
556
+ response_body = JSON.parse(response.body)
557
+ expect(response_body.dig("schemas", 0)).to eq "urn:ietf:params:scim:api:messages:2.0:Error"
558
+ end
526
559
  end
527
560
  end
561
+
562
+ def patch_params(id:, active: false)
563
+ {
564
+ id: id,
565
+ Operations: [
566
+ {
567
+ op: "replace",
568
+ value: {
569
+ active: active
570
+ }
571
+ }
572
+ ]
573
+ }
574
+ end
528
575
  end
Binary file