powerhome-scimitar 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE.txt +21 -0
- data/README.md +708 -0
- data/Rakefile +16 -0
- data/app/controllers/scimitar/active_record_backed_resources_controller.rb +257 -0
- data/app/controllers/scimitar/application_controller.rb +157 -0
- data/app/controllers/scimitar/resource_types_controller.rb +28 -0
- data/app/controllers/scimitar/resources_controller.rb +203 -0
- data/app/controllers/scimitar/schemas_controller.rb +21 -0
- data/app/controllers/scimitar/service_provider_configurations_controller.rb +8 -0
- data/app/models/scimitar/authentication_error.rb +9 -0
- data/app/models/scimitar/authentication_scheme.rb +18 -0
- data/app/models/scimitar/bulk.rb +8 -0
- data/app/models/scimitar/complex_types/address.rb +12 -0
- data/app/models/scimitar/complex_types/base.rb +83 -0
- data/app/models/scimitar/complex_types/email.rb +12 -0
- data/app/models/scimitar/complex_types/entitlement.rb +12 -0
- data/app/models/scimitar/complex_types/ims.rb +12 -0
- data/app/models/scimitar/complex_types/name.rb +12 -0
- data/app/models/scimitar/complex_types/phone_number.rb +12 -0
- data/app/models/scimitar/complex_types/photo.rb +12 -0
- data/app/models/scimitar/complex_types/reference_group.rb +12 -0
- data/app/models/scimitar/complex_types/reference_member.rb +12 -0
- data/app/models/scimitar/complex_types/role.rb +12 -0
- data/app/models/scimitar/complex_types/x509_certificate.rb +12 -0
- data/app/models/scimitar/engine_configuration.rb +32 -0
- data/app/models/scimitar/error_response.rb +32 -0
- data/app/models/scimitar/errors.rb +14 -0
- data/app/models/scimitar/filter.rb +11 -0
- data/app/models/scimitar/filter_error.rb +22 -0
- data/app/models/scimitar/invalid_syntax_error.rb +9 -0
- data/app/models/scimitar/lists/count.rb +64 -0
- data/app/models/scimitar/lists/query_parser.rb +745 -0
- data/app/models/scimitar/meta.rb +7 -0
- data/app/models/scimitar/not_found_error.rb +10 -0
- data/app/models/scimitar/resource_invalid_error.rb +9 -0
- data/app/models/scimitar/resource_type.rb +29 -0
- data/app/models/scimitar/resources/base.rb +190 -0
- data/app/models/scimitar/resources/group.rb +13 -0
- data/app/models/scimitar/resources/mixin.rb +1524 -0
- data/app/models/scimitar/resources/user.rb +13 -0
- data/app/models/scimitar/schema/address.rb +25 -0
- data/app/models/scimitar/schema/attribute.rb +132 -0
- data/app/models/scimitar/schema/base.rb +90 -0
- data/app/models/scimitar/schema/derived_attributes.rb +24 -0
- data/app/models/scimitar/schema/email.rb +10 -0
- data/app/models/scimitar/schema/entitlement.rb +10 -0
- data/app/models/scimitar/schema/group.rb +27 -0
- data/app/models/scimitar/schema/ims.rb +10 -0
- data/app/models/scimitar/schema/name.rb +20 -0
- data/app/models/scimitar/schema/phone_number.rb +10 -0
- data/app/models/scimitar/schema/photo.rb +10 -0
- data/app/models/scimitar/schema/reference_group.rb +23 -0
- data/app/models/scimitar/schema/reference_member.rb +21 -0
- data/app/models/scimitar/schema/role.rb +10 -0
- data/app/models/scimitar/schema/user.rb +52 -0
- data/app/models/scimitar/schema/vdtp.rb +18 -0
- data/app/models/scimitar/schema/x509_certificate.rb +22 -0
- data/app/models/scimitar/service_provider_configuration.rb +60 -0
- data/app/models/scimitar/supportable.rb +14 -0
- data/app/views/layouts/scimitar/application.html.erb +14 -0
- data/config/initializers/scimitar.rb +111 -0
- data/config/routes.rb +6 -0
- data/lib/scimitar/engine.rb +63 -0
- data/lib/scimitar/support/hash_with_indifferent_case_insensitive_access.rb +216 -0
- data/lib/scimitar/support/utilities.rb +51 -0
- data/lib/scimitar/version.rb +13 -0
- data/lib/scimitar.rb +29 -0
- data/spec/apps/dummy/app/controllers/custom_create_mock_users_controller.rb +25 -0
- data/spec/apps/dummy/app/controllers/custom_destroy_mock_users_controller.rb +24 -0
- data/spec/apps/dummy/app/controllers/custom_replace_mock_users_controller.rb +25 -0
- data/spec/apps/dummy/app/controllers/custom_request_verifiers_controller.rb +30 -0
- data/spec/apps/dummy/app/controllers/custom_save_mock_users_controller.rb +24 -0
- data/spec/apps/dummy/app/controllers/custom_update_mock_users_controller.rb +25 -0
- data/spec/apps/dummy/app/controllers/mock_groups_controller.rb +13 -0
- data/spec/apps/dummy/app/controllers/mock_users_controller.rb +13 -0
- data/spec/apps/dummy/app/models/mock_group.rb +83 -0
- data/spec/apps/dummy/app/models/mock_user.rb +132 -0
- data/spec/apps/dummy/config/application.rb +18 -0
- data/spec/apps/dummy/config/boot.rb +2 -0
- data/spec/apps/dummy/config/environment.rb +2 -0
- data/spec/apps/dummy/config/environments/test.rb +38 -0
- data/spec/apps/dummy/config/initializers/cookies_serializer.rb +3 -0
- data/spec/apps/dummy/config/initializers/scimitar.rb +61 -0
- data/spec/apps/dummy/config/initializers/session_store.rb +3 -0
- data/spec/apps/dummy/config/routes.rb +45 -0
- data/spec/apps/dummy/db/migrate/20210304014602_create_mock_users.rb +24 -0
- data/spec/apps/dummy/db/migrate/20210308020313_create_mock_groups.rb +10 -0
- data/spec/apps/dummy/db/migrate/20210308044214_create_join_table_mock_groups_mock_users.rb +13 -0
- data/spec/apps/dummy/db/schema.rb +48 -0
- data/spec/controllers/scimitar/application_controller_spec.rb +296 -0
- data/spec/controllers/scimitar/resource_types_controller_spec.rb +94 -0
- data/spec/controllers/scimitar/resources_controller_spec.rb +247 -0
- data/spec/controllers/scimitar/schemas_controller_spec.rb +83 -0
- data/spec/controllers/scimitar/service_provider_configurations_controller_spec.rb +22 -0
- data/spec/models/scimitar/complex_types/address_spec.rb +18 -0
- data/spec/models/scimitar/complex_types/email_spec.rb +21 -0
- data/spec/models/scimitar/lists/count_spec.rb +147 -0
- data/spec/models/scimitar/lists/query_parser_spec.rb +830 -0
- data/spec/models/scimitar/resource_type_spec.rb +21 -0
- data/spec/models/scimitar/resources/base_spec.rb +485 -0
- data/spec/models/scimitar/resources/base_validation_spec.rb +86 -0
- data/spec/models/scimitar/resources/mixin_spec.rb +3562 -0
- data/spec/models/scimitar/resources/user_spec.rb +68 -0
- data/spec/models/scimitar/schema/attribute_spec.rb +99 -0
- data/spec/models/scimitar/schema/base_spec.rb +64 -0
- data/spec/models/scimitar/schema/group_spec.rb +87 -0
- data/spec/models/scimitar/schema/user_spec.rb +720 -0
- data/spec/requests/active_record_backed_resources_controller_spec.rb +1354 -0
- data/spec/requests/application_controller_spec.rb +61 -0
- data/spec/requests/controller_configuration_spec.rb +17 -0
- data/spec/requests/engine_spec.rb +45 -0
- data/spec/spec_helper.rb +101 -0
- data/spec/spec_helper_spec.rb +30 -0
- data/spec/support/hash_with_indifferent_case_insensitive_access_spec.rb +169 -0
- metadata +321 -0
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe Scimitar::Resources::User do
|
4
|
+
context '#name' do
|
5
|
+
it 'allows a setter for a valid name' do
|
6
|
+
user = described_class.new(name: Scimitar::ComplexTypes::Name.new(
|
7
|
+
familyName: 'Smith',
|
8
|
+
givenName: 'John',
|
9
|
+
formatted: 'John Smith'
|
10
|
+
))
|
11
|
+
|
12
|
+
expect(user.name.familyName).to eql('Smith')
|
13
|
+
expect(user.name.givenName).to eql('John')
|
14
|
+
expect(user.name.formatted).to eql('John Smith')
|
15
|
+
expect(user.as_json['name']['errors']).to be_nil
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'treats attributes as case-insensitive' do
|
19
|
+
user = described_class.new(name: Scimitar::ComplexTypes::Name.new(
|
20
|
+
FAMILYNAME: 'Smith',
|
21
|
+
GIVENNAME: 'John',
|
22
|
+
FORMATTED: 'John Smith'
|
23
|
+
))
|
24
|
+
|
25
|
+
expect(user.name.familyName).to eql('Smith')
|
26
|
+
expect(user.name.givenName).to eql('John')
|
27
|
+
expect(user.name.formatted).to eql('John Smith')
|
28
|
+
expect(user.as_json['name']['errors']).to be_nil
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'validates that the provided name matches the name schema' do
|
32
|
+
user = described_class.new(name: Scimitar::ComplexTypes::Email.new(
|
33
|
+
value: 'john@smoth.com',
|
34
|
+
primary: true
|
35
|
+
))
|
36
|
+
|
37
|
+
expect(user.valid?).to be(false)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
context '#add_errors_from_hash' do
|
42
|
+
let(:user) { described_class.new }
|
43
|
+
|
44
|
+
it 'adds the error when the value is a string' do
|
45
|
+
user.add_errors_from_hash(errors_hash: {key: 'some error'})
|
46
|
+
expect(user.errors.messages.to_h).to eql({key: ['some error']})
|
47
|
+
expect(user.errors.full_messages).to eql(['Key some error'])
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'adds the error when the value is an array' do
|
51
|
+
user.add_errors_from_hash(errors_hash: {key: ['error1', 'error2']})
|
52
|
+
expect(user.errors.messages.to_h).to eql({key: ['error1', 'error2']})
|
53
|
+
expect(user.errors.full_messages).to eql(['Key error1', 'Key error2'])
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'adds the error with prefix when the value is a string' do
|
57
|
+
user.add_errors_from_hash(errors_hash: {key: 'some error'}, prefix: :pre)
|
58
|
+
expect(user.errors.messages.to_h).to eql({:'pre.key' => ['some error']})
|
59
|
+
expect(user.errors.full_messages).to eql(['Pre key some error'])
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'adds the error wity prefix when the value is an array' do
|
63
|
+
user.add_errors_from_hash(errors_hash: {key: ['error1', 'error2']}, prefix: :pre)
|
64
|
+
expect(user.errors.messages.to_h).to eql({:'pre.key' => ['error1', 'error2']})
|
65
|
+
expect(user.errors.full_messages).to eql(['Pre key error1', 'Pre key error2'])
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe Scimitar::Schema::Attribute do
|
4
|
+
context '#initialize' do
|
5
|
+
it 'sets the default properties' do
|
6
|
+
attribute = described_class.new
|
7
|
+
expect(attribute.multiValued).to be(false)
|
8
|
+
expect(attribute.required).to be(false)
|
9
|
+
expect(attribute.caseExact).to be(false)
|
10
|
+
expect(attribute.mutability).to eql('readWrite')
|
11
|
+
expect(attribute.uniqueness).to eql('none')
|
12
|
+
expect(attribute.returned).to eql('default')
|
13
|
+
end
|
14
|
+
it 'lets override the default properties' do
|
15
|
+
attribute = described_class.new(multiValued: true)
|
16
|
+
expect(attribute.multiValued).to be(true)
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'transforms complexTypes into subAttributes' do
|
20
|
+
name = described_class.new(name: 'name', complexType: Scimitar::ComplexTypes::Name)
|
21
|
+
expect(name.type).to eql('complex')
|
22
|
+
expect(name.subAttributes).to eql(Scimitar::Schema::Name.scim_attributes)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
context '#valid?' do
|
27
|
+
it 'is invalid if attribute is required but value is blank' do
|
28
|
+
attribute = described_class.new(name: 'userName', type: 'string', required: true)
|
29
|
+
expect(attribute.valid?(nil)).to be(false)
|
30
|
+
expect(attribute.errors.messages.to_h).to eql({userName: ['is required']})
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'is valid if attribute is not required and value is blank' do
|
34
|
+
attribute = described_class.new(name: 'userName', type: 'string', required: false)
|
35
|
+
expect(attribute.valid?(nil)).to be(true)
|
36
|
+
expect(attribute.errors.messages.to_h).to eql({})
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'is valid if type is string and given value is string' do
|
40
|
+
expect(described_class.new(name: 'name', type: 'string').valid?('something')).to be(true)
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'is invalid if type is string and given value is not string' do
|
44
|
+
attribute = described_class.new(name: 'userName', type: 'string')
|
45
|
+
expect(attribute.valid?(10)).to be(false)
|
46
|
+
expect(attribute.errors.messages.to_h).to eql({userName: ['has the wrong type. It has to be a(n) string.']})
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'is valid if multi-valued and type is string and given value is an array of strings' do
|
50
|
+
attribute = described_class.new(name: 'scopes', multiValued: true, type: 'string')
|
51
|
+
expect(attribute.valid?(['something', 'something else'])).to be(true)
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'is valid if multi-valued and type is string and given value is an empty array' do
|
55
|
+
attribute = described_class.new(name: 'scopes', multiValued: true, type: 'string')
|
56
|
+
expect(attribute.valid?([])).to be(true)
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'is invalid if multi-valued and type is string and given value is not an array' do
|
60
|
+
attribute = described_class.new(name: 'scopes', multiValued: true, type: 'string')
|
61
|
+
expect(attribute.valid?('something')).to be(false)
|
62
|
+
expect(attribute.errors.messages.to_h).to eql({scopes: ['or one of its elements has the wrong type. It has to be an array of strings.']})
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'is invalid if multi-valued and type is string and given value is an array containing another type' do
|
66
|
+
attribute = described_class.new(name: 'scopes', multiValued: true, type: 'string')
|
67
|
+
expect(attribute.valid?(['something', 123])).to be(false)
|
68
|
+
expect(attribute.errors.messages.to_h).to eql({scopes: ['or one of its elements has the wrong type. It has to be an array of strings.']})
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'is valid if type is boolean and given value is boolean' do
|
72
|
+
expect(described_class.new(name: 'name', type: 'boolean').valid?(false)).to be(true)
|
73
|
+
expect(described_class.new(name: 'name', type: 'boolean').valid?(true)).to be(true)
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'is valid if type is complex and the schema is same' do
|
77
|
+
expect(described_class.new(name: 'name', complexType: Scimitar::ComplexTypes::Name).valid?(Scimitar::ComplexTypes::Name.new(givenName: 'a', familyName: 'b'))).to be(true)
|
78
|
+
end
|
79
|
+
|
80
|
+
it 'is valid if type is integer and given value is integer (duh)' do
|
81
|
+
expect(described_class.new(name: 'quantity', type: 'integer').valid?(123)).to be(true)
|
82
|
+
end
|
83
|
+
|
84
|
+
it 'is not valid if type is integer and given value is not an integer' do
|
85
|
+
expect(described_class.new(name: 'quantity', type: 'integer').valid?(123.3)).to be(false)
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'is valid if type is dateTime and given value is an ISO8601 date time' do
|
89
|
+
expect(described_class.new(name: 'startDate', type: 'dateTime').valid?('2018-07-26T11:59:43-06:00')).to be(true)
|
90
|
+
end
|
91
|
+
|
92
|
+
it 'is not valid if type is dateTime and given value is a valid date but not in ISO8601 format' do
|
93
|
+
expect(described_class.new(name: 'startDate', type: 'dateTime').valid?('2018-07-26')).to be(false)
|
94
|
+
end
|
95
|
+
it 'is not valid if type is dateTime and given value is not a valid date' do
|
96
|
+
expect(described_class.new(name: 'startDate', type: 'dateTime').valid?('gaga')).to be(false)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe Scimitar::Schema::Base do
|
4
|
+
context '#as_json' do
|
5
|
+
it 'converts the scim_attributes to attributes' do
|
6
|
+
attribute = Scimitar::Schema::Attribute.new(name: 'nickName')
|
7
|
+
schema = described_class.new(scim_attributes: [attribute])
|
8
|
+
expect(schema.as_json['attributes']).to eql([attribute.as_json])
|
9
|
+
expect(schema.as_json['scim_attributes']).to be_nil
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
context '#initialize' do
|
14
|
+
it 'creates "meta"' do
|
15
|
+
schema = described_class.new
|
16
|
+
expect(schema.meta.resourceType).to eql('Schema')
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
context '.find_attribute' do
|
21
|
+
it 'finds at top level' do
|
22
|
+
found = Scimitar::Schema::User.find_attribute('password')
|
23
|
+
expect(found).to be_present
|
24
|
+
expect(found.name).to eql('password')
|
25
|
+
expect(found.mutability).to eql('writeOnly')
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'finds nested' do
|
29
|
+
found = Scimitar::Schema::User.find_attribute('name', 'givenName')
|
30
|
+
expect(found).to be_present
|
31
|
+
expect(found.name).to eql('givenName')
|
32
|
+
expect(found.mutability).to eql('readWrite')
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'finds in multi-valued types, without index' do
|
36
|
+
found = Scimitar::Schema::User.find_attribute('groups', 'type')
|
37
|
+
expect(found).to be_present
|
38
|
+
expect(found.name).to eql('type')
|
39
|
+
expect(found.mutability).to eql('readOnly')
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'finds in multi-valued types, ignoring index' do
|
43
|
+
found = Scimitar::Schema::User.find_attribute('groups', 42, 'type')
|
44
|
+
expect(found).to be_present
|
45
|
+
expect(found.name).to eql('type')
|
46
|
+
expect(found.mutability).to eql('readOnly')
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'does not find bad names' do
|
50
|
+
found = Scimitar::Schema::User.find_attribute('foo')
|
51
|
+
expect(found).to be_nil
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'does not find nested bad names' do
|
55
|
+
found = Scimitar::Schema::User.find_attribute('name', 'foo')
|
56
|
+
expect(found).to be_nil
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'handles attempting to read sub-attributes when there are none' do
|
60
|
+
found = Scimitar::Schema::User.find_attribute('password', 'foo')
|
61
|
+
expect(found).to be_nil
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe Scimitar::Schema::Group do
|
4
|
+
let(:expected_attributes) {
|
5
|
+
<<-EOJ
|
6
|
+
[
|
7
|
+
{
|
8
|
+
"multiValued": false,
|
9
|
+
"required": true,
|
10
|
+
"caseExact": false,
|
11
|
+
"mutability": "readWrite",
|
12
|
+
"uniqueness": "none",
|
13
|
+
"returned": "default",
|
14
|
+
"name": "displayName",
|
15
|
+
"type": "string"
|
16
|
+
},
|
17
|
+
{
|
18
|
+
"multiValued": true,
|
19
|
+
"required": false,
|
20
|
+
"caseExact": false,
|
21
|
+
"mutability": "readWrite",
|
22
|
+
"uniqueness": "none",
|
23
|
+
"returned": "default",
|
24
|
+
"name": "members",
|
25
|
+
"type": "complex",
|
26
|
+
"subAttributes": [
|
27
|
+
{
|
28
|
+
"multiValued": false,
|
29
|
+
"required": true,
|
30
|
+
"caseExact": false,
|
31
|
+
"mutability": "immutable",
|
32
|
+
"uniqueness": "none",
|
33
|
+
"returned": "default",
|
34
|
+
"name": "value",
|
35
|
+
"type": "string"
|
36
|
+
},
|
37
|
+
{
|
38
|
+
"multiValued": false,
|
39
|
+
"required": false,
|
40
|
+
"caseExact": false,
|
41
|
+
"mutability": "immutable",
|
42
|
+
"uniqueness": "none",
|
43
|
+
"returned": "default",
|
44
|
+
"name": "type",
|
45
|
+
"type": "string"
|
46
|
+
},
|
47
|
+
{
|
48
|
+
"multiValued": false,
|
49
|
+
"required": false,
|
50
|
+
"caseExact": false,
|
51
|
+
"mutability": "immutable",
|
52
|
+
"uniqueness": "none",
|
53
|
+
"returned": "default",
|
54
|
+
"name": "display",
|
55
|
+
"type": "string"
|
56
|
+
}
|
57
|
+
]
|
58
|
+
}
|
59
|
+
]
|
60
|
+
EOJ
|
61
|
+
}
|
62
|
+
|
63
|
+
let(:expected_full_schema) {
|
64
|
+
<<-EOJ
|
65
|
+
{
|
66
|
+
"name": "Group",
|
67
|
+
"id": "urn:ietf:params:scim:schemas:core:2.0:Group",
|
68
|
+
"description": "Represents a Group",
|
69
|
+
"meta": {
|
70
|
+
"resourceType": "Schema",
|
71
|
+
"location": "/Schemas?name=urn%3Aietf%3Aparams%3Ascim%3Aschemas%3Acore%3A2.0%3AGroup"
|
72
|
+
},
|
73
|
+
"attributes": #{expected_attributes()}
|
74
|
+
}
|
75
|
+
EOJ
|
76
|
+
}
|
77
|
+
|
78
|
+
it 'returns Group schema as JSON' do
|
79
|
+
actual_full_schema = Scimitar::Schema::Group.new
|
80
|
+
expect(JSON.parse(actual_full_schema.to_json)).to eql(JSON.parse(expected_full_schema()))
|
81
|
+
end
|
82
|
+
|
83
|
+
it 'returns the schema attributes as JSON' do
|
84
|
+
actual_attributes = Scimitar::Schema::Group.scim_attributes
|
85
|
+
expect(JSON.parse(actual_attributes.to_json)).to eql(JSON.parse(expected_attributes()))
|
86
|
+
end
|
87
|
+
end
|