scimaenaga 0.4.1 → 0.6.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -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