diff --git a/app/models/scimitar/resources/base.rb b/app/models/scimitar/resources/base.rb index 74e7e6b..1163e2a 100644 --- a/app/models/scimitar/resources/base.rb +++ b/app/models/scimitar/resources/base.rb @@ -139,13 +139,23 @@ def constantize_complex_types(hash) def as_json(options = {}) self.meta = Meta.new unless self.meta && self.meta.is_a?(Meta) - meta.resourceType = self.class.resource_type_id - original_hash = super(options).except('errors') + self.meta.resourceType = self.class.resource_type_id + + non_returnable_attributes = self.class + .schemas + .flat_map(&:scim_attributes) + .filter_map { |attribute| attribute.name if attribute.returned == 'never' } + + non_returnable_attributes << 'errors' + + original_hash = super(options).except(*non_returnable_attributes) original_hash.merge!('schemas' => self.class.schemas.map(&:id)) + self.class.extended_schemas.each do |extension_schema| extension_attributes = extension_schema.scim_attributes.map(&:name) original_hash.merge!(extension_schema.id => original_hash.extract!(*extension_attributes)) end + original_hash end diff --git a/spec/apps/dummy/app/models/mock_user.rb b/spec/apps/dummy/app/models/mock_user.rb index 8a9be58..478ed1e 100644 --- a/spec/apps/dummy/app/models/mock_user.rb +++ b/spec/apps/dummy/app/models/mock_user.rb @@ -10,6 +10,7 @@ class MockUser < ActiveRecord::Base primary_key scim_uid username + password first_name last_name work_email_address @@ -46,6 +47,7 @@ def self.scim_attributes_map id: :primary_key, externalId: :scim_uid, userName: :username, + password: :password, name: { givenName: :first_name, familyName: :last_name diff --git a/spec/apps/dummy/db/migrate/20210304014602_create_mock_users.rb b/spec/apps/dummy/db/migrate/20210304014602_create_mock_users.rb index 6bc65a3..80c129b 100644 --- a/spec/apps/dummy/db/migrate/20210304014602_create_mock_users.rb +++ b/spec/apps/dummy/db/migrate/20210304014602_create_mock_users.rb @@ -7,6 +7,7 @@ def change # t.text :scim_uid t.text :username + t.text :password t.text :first_name t.text :last_name t.text :work_email_address diff --git a/spec/apps/dummy/db/schema.rb b/spec/apps/dummy/db/schema.rb index 72b030e..df811ff 100644 --- a/spec/apps/dummy/db/schema.rb +++ b/spec/apps/dummy/db/schema.rb @@ -33,6 +33,7 @@ t.datetime "updated_at", null: false t.text "scim_uid" t.text "username" + t.text "password" t.text "first_name" t.text "last_name" t.text "work_email_address" diff --git a/spec/models/scimitar/resources/base_spec.rb b/spec/models/scimitar/resources/base_spec.rb index dcb338c..adc4f23 100644 --- a/spec/models/scimitar/resources/base_spec.rb +++ b/spec/models/scimitar/resources/base_spec.rb @@ -14,7 +14,10 @@ def self.scim_attributes ), Scimitar::Schema::Attribute.new( name: 'names', multiValued: true, complexType: Scimitar::ComplexTypes::Name, required: false - ) + ), + Scimitar::Schema::Attribute.new( + name: 'privateName', complexType: Scimitar::ComplexTypes::Name, required: false, returned: false + ), ] end end @@ -30,6 +33,10 @@ def self.scim_attributes name: { givenName: 'John', familyName: 'Smith' + }, + privateName: { + givenName: 'Alt John', + familyName: 'Alt Smith' } } @@ -39,6 +46,9 @@ def self.scim_attributes expect(resource.name.is_a?(Scimitar::ComplexTypes::Name)).to be(true) expect(resource.name.givenName).to eql('John') expect(resource.name.familyName).to eql('Smith') + expect(resource.privateName.is_a?(Scimitar::ComplexTypes::Name)).to be(true) + expect(resource.privateName.givenName).to eql('Alt John') + expect(resource.privateName.familyName).to eql('Alt Smith') end it 'which builds an array of nested resources' do @@ -101,14 +111,38 @@ def self.scim_attributes context '#as_json' do it 'renders the json with the resourceType' do resource = CustomResourse.new(name: { - givenName: 'John', + givenName: 'John', familyName: 'Smith' }) result = resource.as_json - expect(result['schemas']).to eql(['custom-id']) + + expect(result['schemas'] ).to eql(['custom-id']) + expect(result['meta']['resourceType']).to eql('CustomResourse') + expect(result['errors'] ).to be_nil + end + + it 'excludes attributes that are flagged as do-not-return' do + resource = CustomResourse.new( + name: { + givenName: 'John', + familyName: 'Smith' + }, + privateName: { + givenName: 'Alt John', + familyName: 'Alt Smith' + } + ) + + result = resource.as_json + + expect(result['schemas'] ).to eql(['custom-id']) expect(result['meta']['resourceType']).to eql('CustomResourse') - expect(result['errors']).to be_nil + expect(result['errors'] ).to be_nil + expect(result['name'] ).to be_present + expect(result['name']['givenName'] ).to eql('John') + expect(result['name']['familyName'] ).to eql('Smith') + expect(result['privateName'] ).to be_present end end # "context '#as_json' do" diff --git a/spec/models/scimitar/resources/mixin_spec.rb b/spec/models/scimitar/resources/mixin_spec.rb index dc38c25..e92f0ad 100644 --- a/spec/models/scimitar/resources/mixin_spec.rb +++ b/spec/models/scimitar/resources/mixin_spec.rb @@ -160,13 +160,14 @@ def self.scim_queryable_attributes context '#to_scim' do context 'with a UUID, renamed primary key column' do - it 'compiles instance attribute values into a SCIM representation' do + it 'compiles instance attribute values into a SCIM representation, but omits do-not-return fields' do uuid = SecureRandom.uuid instance = MockUser.new instance.primary_key = uuid instance.scim_uid = 'AA02984' instance.username = 'foo' + instance.password = 'correcthorsebatterystaple' instance.first_name = 'Foo' instance.last_name = 'Bar' instance.work_email_address = 'foo.bar@test.com' @@ -404,6 +405,7 @@ def self.scim_timestamps_map it 'ignoring read-only lists' do hash = { 'userName' => 'foo', + 'password' => 'staplebatteryhorsecorrect', 'name' => {'givenName' => 'Foo', 'familyName' => 'Bar'}, 'active' => true, 'emails' => [{'type' => 'work', 'primary' => true, 'value' => 'foo.bar@test.com'}], @@ -428,6 +430,7 @@ def self.scim_timestamps_map expect(instance.scim_uid ).to eql('AA02984') expect(instance.username ).to eql('foo') + expect(instance.password ).to eql('staplebatteryhorsecorrect') expect(instance.first_name ).to eql('Foo') expect(instance.last_name ).to eql('Bar') expect(instance.work_email_address).to eql('foo.bar@test.com')