scimaenaga 0.4.1 → 0.6.2

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.
@@ -364,7 +364,7 @@ RSpec.describe ScimRails::ScimUsersController, type: :controller do
364
364
  value: "test@example.com"
365
365
  }
366
366
  ],
367
- active: "false"
367
+ active: false
368
368
  }, as: :json
369
369
 
370
370
  expect(response.status).to eq 201
@@ -415,12 +415,18 @@ RSpec.describe ScimRails::ScimUsersController, type: :controller do
415
415
  expect(response.media_type).to eq "application/scim+json"
416
416
  end
417
417
 
418
- it "is successful with with valid credentials" do
418
+ it "is successful with valid credentials" do
419
419
  put :put_update, params: put_params, as: :json
420
420
 
421
421
  expect(response.status).to eq 200
422
422
  end
423
423
 
424
+ it "successfully change user email" do
425
+ put :put_update, params: put_params(id: user.id), as: :json
426
+
427
+ expect(user.reload.email).to eq 'test@example.com'
428
+ end
429
+
424
430
  it "deprovisions an active record" do
425
431
  request.content_type = "application/scim+json"
426
432
  put :put_update, params: put_params(active: false), as: :json
@@ -506,17 +512,40 @@ RSpec.describe ScimRails::ScimUsersController, type: :controller do
506
512
  end
507
513
 
508
514
  it "returns scim+json content type" do
509
- patch :patch_update, params: patch_params(id: 1), as: :json
515
+ patch :patch_update, params: patch_params(id: user.id), as: :json
510
516
 
511
517
  expect(response.media_type).to eq "application/scim+json"
512
518
  end
513
519
 
514
520
  it "is successful with valid credentials" do
515
- patch :patch_update, params: patch_params(id: 1), as: :json
521
+ patch :patch_update, params: patch_params(id: user.id), as: :json
516
522
 
517
523
  expect(response.status).to eq 200
518
524
  end
519
525
 
526
+ it 'rollback all changes when contains any invalid operation' do
527
+ expect do
528
+ patch :patch_update, params: {
529
+ schemas: ["urn:ietf:params:scim:api:messages:2.0:PatchOp"],
530
+ id: user.id,
531
+ Operations: [
532
+ {
533
+ op: "Replace",
534
+ path: "emails[type eq \"work\"].value",
535
+ value: "change@example.com"
536
+ },
537
+ {
538
+ op: "Replace",
539
+ value: "hoge"
540
+ }
541
+ ]
542
+ },
543
+ as: :json
544
+ end.to_not change { user.reload.email }
545
+
546
+ expect(response.status).to eq 422
547
+ end
548
+
520
549
  it "returns :not_found for id that cannot be found" do
521
550
  get :patch_update, params: patch_params(id: "fake_id"), as: :json
522
551
 
@@ -537,7 +566,10 @@ RSpec.describe ScimRails::ScimUsersController, type: :controller do
537
566
  user = company.users.first
538
567
  expect(user.archived?).to eq false
539
568
 
540
- patch :patch_update, params: patch_params(id: 1), as: :json
569
+ patch \
570
+ :patch_update,
571
+ params: patch_active_params(id: user.id, active: false),
572
+ as: :json
541
573
 
542
574
  expect(response.status).to eq 200
543
575
  expect(company.users.count).to eq 1
@@ -552,7 +584,7 @@ RSpec.describe ScimRails::ScimUsersController, type: :controller do
552
584
 
553
585
  patch \
554
586
  :patch_update,
555
- params: patch_params(id: 1, active: true),
587
+ params: patch_active_params(id: 1, active: true),
556
588
  as: :json
557
589
 
558
590
  expect(response.status).to eq 200
@@ -561,17 +593,34 @@ RSpec.describe ScimRails::ScimUsersController, type: :controller do
561
593
  expect(user.archived?).to eq false
562
594
  end
563
595
 
596
+ it "successfully change user email" do
597
+ expect(company.users.count).to eq 1
598
+ user = company.users.first
599
+ user.update(email: 'test@example.com')
600
+ expect(user.reload.email).to eq 'test@example.com'
601
+
602
+ patch \
603
+ :patch_update,
604
+ params: patch_params(id: 1),
605
+ as: :json
606
+
607
+ expect(response.status).to eq 200
608
+ expect(company.users.count).to eq 1
609
+ user.reload
610
+ expect(user.email).to eq 'change@example.com'
611
+ end
612
+
564
613
  it "is case insensetive for op value" do
565
614
  # Note, this is for backward compatibility. op should always
566
615
  # be lower case and support for case insensitivity will be removed
567
616
  patch :patch_update, params: {
617
+ schemas: ["urn:ietf:params:scim:api:messages:2.0:PatchOp"],
568
618
  id: 1,
569
619
  Operations: [
570
- {
620
+ {
571
621
  op: "Replace",
572
- value: {
573
- active: false
574
- }
622
+ path: "emails[type eq \"work\"].value",
623
+ value: "test@example.com"
575
624
  }
576
625
  ]
577
626
  }, as: :json
@@ -579,45 +628,67 @@ RSpec.describe ScimRails::ScimUsersController, type: :controller do
579
628
  expect(response.status).to eq 200
580
629
  end
581
630
 
582
- it "throws an error for non status updates" do
631
+ it "don't update if not included in mutable attributes" do
632
+ expect do
633
+ patch :patch_update, params: {
634
+ schemas: ["urn:ietf:params:scim:api:messages:2.0:PatchOp"],
635
+ id: user.id,
636
+ Operations: [
637
+ {
638
+ op: "Replace",
639
+ path: "emails[type eq \"work\"].value",
640
+ value: "change@example.com"
641
+ },
642
+ {
643
+ op: "Replace",
644
+ path: "country",
645
+ value: "Japan"
646
+ },
647
+ ]
648
+ }, as: :json
649
+ end.not_to change { user.reload.country }
650
+
651
+ expect(response.status).to eq 422
652
+ end
653
+
654
+ xit "returns 422 when value is not an object" do
583
655
  patch :patch_update, params: {
656
+ schemas: ["urn:ietf:params:scim:api:messages:2.0:PatchOp"],
584
657
  id: 1,
585
658
  Operations: [
586
659
  {
587
660
  op: "replace",
588
- value: {
589
- name: {
590
- givenName: "Francis"
591
- }
592
- }
661
+ path: "emails[type eq \"work\"].value",
662
+ value: "francis@example.com"
593
663
  }
594
664
  ]
595
- }, as: :json
665
+ }
596
666
 
597
667
  expect(response.status).to eq 422
598
668
  response_body = JSON.parse(response.body)
599
669
  expect(response_body.dig("schemas", 0)).to eq "urn:ietf:params:scim:api:messages:2.0:Error"
600
670
  end
601
671
 
602
- it "returns 422 when value is not an object" do
672
+ it "returns 422 when value is missing" do
603
673
  patch :patch_update, params: {
674
+ schemas: ["urn:ietf:params:scim:api:messages:2.0:PatchOp"],
604
675
  id: 1,
605
676
  Operations: [
606
677
  {
607
678
  op: "replace",
608
- path: "displayName",
609
- value: "Francis"
679
+ path: "emails[type eq \"work\"].value"
610
680
  }
611
681
  ]
612
- }
682
+ }, as: :json
613
683
 
614
684
  expect(response.status).to eq 422
615
685
  response_body = JSON.parse(response.body)
616
686
  expect(response_body.dig("schemas", 0)).to eq "urn:ietf:params:scim:api:messages:2.0:Error"
617
687
  end
618
688
 
619
- it "returns 422 when value is missing" do
689
+ it "returns 422 when path is missing" do
620
690
  patch :patch_update, params: {
691
+ schemas: ["urn:ietf:params:scim:api:messages:2.0:PatchOp"],
621
692
  id: 1,
622
693
  Operations: [
623
694
  {
@@ -633,6 +704,7 @@ RSpec.describe ScimRails::ScimUsersController, type: :controller do
633
704
 
634
705
  it "returns 422 operations key is missing" do
635
706
  patch :patch_update, params: {
707
+ schemas: ["urn:ietf:params:scim:api:messages:2.0:PatchOp"],
636
708
  id: 1,
637
709
  Foobars: [
638
710
  {
@@ -648,23 +720,37 @@ RSpec.describe ScimRails::ScimUsersController, type: :controller do
648
720
  end
649
721
  end
650
722
 
651
- def patch_params(id:, active: false)
723
+ def patch_params(id:)
652
724
  {
725
+ schemas: ["urn:ietf:params:scim:api:messages:2.0:PatchOp"],
653
726
  id: id,
654
727
  Operations: [
655
728
  {
656
- op: "replace",
657
- value: {
658
- active: active
659
- }
729
+ op: "Replace",
730
+ path: "emails[type eq \"work\"].value",
731
+ value: "change@example.com"
660
732
  }
661
733
  ]
662
734
  }
663
735
  end
664
736
 
665
- def put_params(active: true)
737
+ def patch_active_params(id:, active: false)
666
738
  {
667
- id: 1,
739
+ schemas: ["urn:ietf:params:scim:api:messages:2.0:PatchOp"],
740
+ id: id,
741
+ Operations: [
742
+ {
743
+ op: "Replace",
744
+ path: "active",
745
+ value: active
746
+ }
747
+ ]
748
+ }
749
+ end
750
+
751
+ def put_params(id: 1, active: true)
752
+ {
753
+ id: id,
668
754
  userName: "test@example.com",
669
755
  name: {
670
756
  givenName: "Test",
@@ -15,6 +15,18 @@ class User < ApplicationRecord
15
15
  case_insensitive: true
16
16
  }
17
17
 
18
+ def active
19
+ return active?
20
+ end
21
+
22
+ def active=(active)
23
+ if active
24
+ self.archived_at = nil
25
+ else
26
+ self.archived_at ||= Time.now
27
+ end
28
+ end
29
+
18
30
  def active?
19
31
  archived_at.blank?
20
32
  end
data/spec/dummy/bin/setup CHANGED
@@ -22,6 +22,8 @@ chdir APP_ROOT do
22
22
  # unless File.exist?('config/database.yml')
23
23
  # cp 'config/database.yml.sample', 'config/database.yml'
24
24
  # end
25
+ puts "\n== Reset migration =="
26
+ system! 'bin/rails db:migrate:reset'
25
27
 
26
28
  puts "\n== Preparing database =="
27
29
  system! 'bin/rails db:setup'
@@ -12,13 +12,11 @@ ScimRails.configure do |config|
12
12
  config.signing_algorithm = "HS256"
13
13
  config.signing_secret = "2d6806dd11c2fece2e81b8ca76dcb0062f5b08e28e3264e8ba1c44bbd3578b70"
14
14
 
15
- config.user_deprovision_method = :archive!
16
- config.user_reprovision_method = :unarchive!
17
-
18
15
  config.mutable_user_attributes = [
19
16
  :first_name,
20
17
  :last_name,
21
- :email
18
+ :email,
19
+ :active
22
20
  ]
23
21
 
24
22
  config.queryable_user_attributes = {
@@ -37,7 +35,8 @@ ScimRails.configure do |config|
37
35
  {
38
36
  value: :email
39
37
  }
40
- ]
38
+ ],
39
+ active: :active
41
40
  }
42
41
 
43
42
  config.user_schema = {
@@ -0,0 +1,5 @@
1
+ class AddCountryToUsers < ActiveRecord::Migration[6.1]
2
+ def change
3
+ add_column :users, :country, :string
4
+ end
5
+ end
@@ -10,7 +10,7 @@
10
10
  #
11
11
  # It's strongly recommended that you check this file into your version control system.
12
12
 
13
- ActiveRecord::Schema.define(version: 2021_04_23_075950) do
13
+ ActiveRecord::Schema.define(version: 2022_01_17_095407) do
14
14
 
15
15
  create_table "companies", force: :cascade do |t|
16
16
  t.string "name", null: false
@@ -23,8 +23,8 @@ ActiveRecord::Schema.define(version: 2021_04_23_075950) do
23
23
  create_table "group_users", force: :cascade do |t|
24
24
  t.integer "group_id", null: false
25
25
  t.integer "user_id", null: false
26
- t.datetime "created_at", precision: 6, null: false
27
- t.datetime "updated_at", precision: 6, null: false
26
+ t.datetime "created_at", null: false
27
+ t.datetime "updated_at", null: false
28
28
  t.index ["group_id"], name: "index_group_users_on_group_id"
29
29
  t.index ["user_id"], name: "index_group_users_on_user_id"
30
30
  end
@@ -32,8 +32,8 @@ ActiveRecord::Schema.define(version: 2021_04_23_075950) do
32
32
  create_table "groups", force: :cascade do |t|
33
33
  t.string "name", null: false
34
34
  t.integer "company_id", null: false
35
- t.datetime "created_at", precision: 6, null: false
36
- t.datetime "updated_at", precision: 6, null: false
35
+ t.datetime "created_at", null: false
36
+ t.datetime "updated_at", null: false
37
37
  t.index ["company_id"], name: "index_groups_on_company_id"
38
38
  end
39
39
 
@@ -45,6 +45,7 @@ ActiveRecord::Schema.define(version: 2021_04_23_075950) do
45
45
  t.datetime "archived_at"
46
46
  t.datetime "created_at", null: false
47
47
  t.datetime "updated_at", null: false
48
+ t.string "country"
48
49
  end
49
50
 
50
51
  add_foreign_key "group_users", "groups"
@@ -4,6 +4,11 @@ company = Company.create(
4
4
  api_token: 1
5
5
  )
6
6
 
7
+ group = Group.create(
8
+ company: company,
9
+ name: 'Test Group'
10
+ )
11
+
7
12
  1.upto(1000) do |n|
8
13
  User.create(
9
14
  company: company,
@@ -0,0 +1,96 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ describe ScimPatchOperation do
6
+
7
+ let(:op) { 'Replace' }
8
+ let(:path) { 'userName' }
9
+ let(:value) { 'taro.suzuki' }
10
+ let(:mutable_attributes_schema) {
11
+ {
12
+ userName: :name,
13
+ displayName: :display_name,
14
+ emails: [
15
+ {
16
+ value: :email
17
+ }
18
+ ],
19
+ name: {
20
+ familyName: :family_name,
21
+ givenName: :given_name
22
+ },
23
+ active: :active
24
+ }
25
+ }
26
+ let(:operation) {
27
+ described_class.new(
28
+ op,
29
+ path,
30
+ value,
31
+ mutable_attributes_schema
32
+ )
33
+ }
34
+ describe '#initialize' do
35
+ context 'replace single attribute' do
36
+ it {
37
+ expect(operation.op).to eq :replace
38
+ expect(operation.path_scim).to eq path
39
+ expect(operation.path_sp).to eq :name
40
+ expect(operation.value).to eq value
41
+ }
42
+ end
43
+
44
+ context 'add single attribute' do
45
+ let(:op) { 'Add' }
46
+ it {
47
+ expect(operation.op).to eq :add
48
+ expect(operation.path_scim).to eq path
49
+ expect(operation.path_sp).to eq :name
50
+ expect(operation.value).to eq value
51
+ }
52
+ end
53
+
54
+ context 'remove single attribute' do
55
+ let(:op) { 'Remove' }
56
+ it {
57
+ expect(operation.op).to eq :remove
58
+ expect(operation.path_scim).to eq path
59
+ expect(operation.path_sp).to eq :name
60
+ expect(operation.value).to eq value
61
+ }
62
+ end
63
+
64
+ context 'replace email address' do
65
+ let(:path) { 'emails[type eq "work"].value' }
66
+ let(:value) { 'taro.suzuki@example.com' }
67
+ it {
68
+ expect(operation.op).to eq :replace
69
+ expect(operation.path_scim).to eq path
70
+ expect(operation.path_sp).to eq :email
71
+ expect(operation.value).to eq value
72
+ }
73
+ end
74
+
75
+ context 'replace name.familyName' do
76
+ let(:path) { 'name.familyName' }
77
+ let(:value) { 'Suzuki' }
78
+ it {
79
+ expect(operation.op).to eq :replace
80
+ expect(operation.path_scim).to eq path
81
+ expect(operation.path_sp).to eq :family_name
82
+ expect(operation.value).to eq value
83
+ }
84
+ end
85
+
86
+ context 'replace active' do
87
+ let(:path) { 'active' }
88
+ let(:value) { 'False' }
89
+
90
+ it 'convert string to bool' do
91
+ expect(operation.value).to eq false
92
+ end
93
+ end
94
+ end
95
+
96
+ end
@@ -0,0 +1,83 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe ScimPatch do
6
+
7
+ let(:params) {
8
+ {
9
+ 'schemas' => ['urn:ietf:params:scim:api:messages:2.0:PatchOp'],
10
+ 'Operations' => [
11
+ {
12
+ 'op' => 'Replace',
13
+ 'path' => 'userName',
14
+ 'value' => 'taro.suzuki'
15
+ },
16
+ {
17
+ 'op' => 'Replace',
18
+ 'path' => 'emails[type eq "work"].value',
19
+ 'value' => 'taro.suzuki@example.com'
20
+ },
21
+ {
22
+ 'op' => 'Replace',
23
+ 'path' => 'name.familyName',
24
+ 'value' => 'Suzuki'
25
+ },
26
+ {
27
+ 'op' => 'Replace',
28
+ 'path' => 'active',
29
+ 'value' => 'False'
30
+ }
31
+ ]
32
+ }
33
+ }
34
+
35
+ let(:mutable_attributes_schema) {
36
+ {
37
+ userName: :name,
38
+ displayName: :display_name,
39
+ emails: [
40
+ {
41
+ value: :email
42
+ }
43
+ ],
44
+ name: {
45
+ familyName: :family_name,
46
+ givenName: :given_name
47
+ },
48
+ active: :active
49
+ }
50
+ }
51
+
52
+ let(:patch) { described_class.new(params, mutable_attributes_schema) }
53
+
54
+ describe '#initialize' do
55
+ it {
56
+ expect(patch.operations[0].op).to eq :replace
57
+ expect(patch.operations[0].path_scim).to eq 'userName'
58
+ expect(patch.operations[0].path_sp).to eq :name
59
+ expect(patch.operations[0].value).to eq 'taro.suzuki'
60
+
61
+ expect(patch.operations[1].op).to eq :replace
62
+ expect(patch.operations[1].path_scim).to eq 'emails[type eq "work"].value'
63
+ expect(patch.operations[1].path_sp).to eq :email
64
+ expect(patch.operations[1].value).to eq 'taro.suzuki@example.com'
65
+
66
+ expect(patch.operations[2].op).to eq :replace
67
+ expect(patch.operations[2].path_scim).to eq 'name.familyName'
68
+ expect(patch.operations[2].path_sp).to eq :family_name
69
+ expect(patch.operations[2].value).to eq 'Suzuki'
70
+
71
+ expect(patch.operations[3].op).to eq :replace
72
+ expect(patch.operations[3].path_scim).to eq 'active'
73
+ expect(patch.operations[3].path_sp).to eq :active
74
+ expect(patch.operations[3].value).to eq false
75
+ }
76
+ end
77
+
78
+ # describe '#update' do
79
+ # create user by factory bot
80
+ # patch.update(user)
81
+ # end
82
+
83
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe ScimRails::ScimQueryParser do
6
+
7
+ let(:query_string) { 'userName eq "taro"' }
8
+ let(:queryable_attributes) {
9
+ {
10
+ userName: :name,
11
+ emails: [
12
+ {
13
+ value: :email
14
+ }
15
+ ]
16
+ }
17
+ }
18
+ let(:parser) { described_class.new(query_string, queryable_attributes) }
19
+
20
+ describe '#attribute' do
21
+ context 'userName' do
22
+ it { expect(parser.attribute).to eq :name }
23
+ end
24
+
25
+ context 'emails[type eq "work"].value' do
26
+ let(:query_string) { 'emails[type eq "work"].value eq "taro@example.com"' }
27
+ it { expect(parser.attribute).to eq :email }
28
+ end
29
+ end
30
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: scimaenaga
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.1
4
+ version: 0.6.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Studist Corporation
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-11-22 00:00:00.000000000 Z
11
+ date: 2022-01-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -149,6 +149,8 @@ files:
149
149
  - app/controllers/scim_rails/scim_groups_controller.rb
150
150
  - app/controllers/scim_rails/scim_users_controller.rb
151
151
  - app/helpers/scim_rails/application_helper.rb
152
+ - app/libraries/scim_patch.rb
153
+ - app/libraries/scim_patch_operation.rb
152
154
  - app/models/scim_rails/application_record.rb
153
155
  - app/models/scim_rails/authorize_api_request.rb
154
156
  - app/models/scim_rails/scim_count.rb
@@ -221,6 +223,7 @@ files:
221
223
  - spec/dummy/db/migrate/20181206184313_create_companies.rb
222
224
  - spec/dummy/db/migrate/20210423075859_create_groups.rb
223
225
  - spec/dummy/db/migrate/20210423075950_create_group_users.rb
226
+ - spec/dummy/db/migrate/20220117095407_add_country_to_users.rb
224
227
  - spec/dummy/db/schema.rb
225
228
  - spec/dummy/db/seeds.rb
226
229
  - spec/dummy/public/404.html
@@ -233,11 +236,13 @@ files:
233
236
  - spec/factories/group.rb
234
237
  - spec/factories/user.rb
235
238
  - spec/lib/scim_rails/encoder_spec.rb
239
+ - spec/libraries/scim_patch_operation_spec.rb
240
+ - spec/libraries/scim_patch_spec.rb
241
+ - spec/models/scim_query_parser_spec.rb
236
242
  - spec/spec_helper.rb
237
243
  - spec/support/auth_helper.rb
238
244
  - spec/support/factory_bot.rb
239
- - spec/support/scim_rails_config.rb
240
- homepage: https://github.com/StudistCorporation/scim_rails
245
+ homepage: https://github.com/StudistCorporation/scimaenaga
241
246
  licenses:
242
247
  - MIT
243
248
  metadata: {}
@@ -269,6 +274,7 @@ test_files:
269
274
  - spec/dummy/db/migrate/20181206184304_create_users.rb
270
275
  - spec/dummy/db/migrate/20210423075950_create_group_users.rb
271
276
  - spec/dummy/db/migrate/20210423075859_create_groups.rb
277
+ - spec/dummy/db/migrate/20220117095407_add_country_to_users.rb
272
278
  - spec/dummy/db/schema.rb
273
279
  - spec/dummy/db/seeds.rb
274
280
  - spec/dummy/config/spring.rb
@@ -326,14 +332,16 @@ test_files:
326
332
  - spec/dummy/public/apple-touch-icon.png
327
333
  - spec/dummy/public/422.html
328
334
  - spec/support/factory_bot.rb
329
- - spec/support/scim_rails_config.rb
330
335
  - spec/support/auth_helper.rb
331
336
  - spec/lib/scim_rails/encoder_spec.rb
332
337
  - spec/controllers/scim_rails/scim_users_controller_spec.rb
333
338
  - spec/controllers/scim_rails/scim_users_request_spec.rb
334
339
  - spec/controllers/scim_rails/scim_groups_request_spec.rb
335
340
  - spec/controllers/scim_rails/scim_groups_controller_spec.rb
341
+ - spec/libraries/scim_patch_spec.rb
342
+ - spec/libraries/scim_patch_operation_spec.rb
336
343
  - spec/factories/user.rb
337
344
  - spec/factories/group.rb
338
345
  - spec/factories/company.rb
339
346
  - spec/spec_helper.rb
347
+ - spec/models/scim_query_parser_spec.rb