scimitar 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (106) hide show
  1. checksums.yaml +7 -0
  2. data/Rakefile +16 -0
  3. data/app/controllers/scimitar/active_record_backed_resources_controller.rb +180 -0
  4. data/app/controllers/scimitar/application_controller.rb +129 -0
  5. data/app/controllers/scimitar/resource_types_controller.rb +28 -0
  6. data/app/controllers/scimitar/resources_controller.rb +203 -0
  7. data/app/controllers/scimitar/schemas_controller.rb +16 -0
  8. data/app/controllers/scimitar/service_provider_configurations_controller.rb +8 -0
  9. data/app/models/scimitar/authentication_error.rb +9 -0
  10. data/app/models/scimitar/authentication_scheme.rb +18 -0
  11. data/app/models/scimitar/bulk.rb +8 -0
  12. data/app/models/scimitar/complex_types/address.rb +18 -0
  13. data/app/models/scimitar/complex_types/base.rb +41 -0
  14. data/app/models/scimitar/complex_types/email.rb +12 -0
  15. data/app/models/scimitar/complex_types/entitlement.rb +12 -0
  16. data/app/models/scimitar/complex_types/ims.rb +12 -0
  17. data/app/models/scimitar/complex_types/name.rb +12 -0
  18. data/app/models/scimitar/complex_types/phone_number.rb +12 -0
  19. data/app/models/scimitar/complex_types/photo.rb +12 -0
  20. data/app/models/scimitar/complex_types/reference_group.rb +12 -0
  21. data/app/models/scimitar/complex_types/reference_member.rb +12 -0
  22. data/app/models/scimitar/complex_types/role.rb +12 -0
  23. data/app/models/scimitar/complex_types/x509_certificate.rb +12 -0
  24. data/app/models/scimitar/engine_configuration.rb +24 -0
  25. data/app/models/scimitar/error_response.rb +20 -0
  26. data/app/models/scimitar/errors.rb +14 -0
  27. data/app/models/scimitar/filter.rb +11 -0
  28. data/app/models/scimitar/filter_error.rb +22 -0
  29. data/app/models/scimitar/invalid_syntax_error.rb +9 -0
  30. data/app/models/scimitar/lists/count.rb +64 -0
  31. data/app/models/scimitar/lists/query_parser.rb +730 -0
  32. data/app/models/scimitar/meta.rb +7 -0
  33. data/app/models/scimitar/not_found_error.rb +10 -0
  34. data/app/models/scimitar/resource_invalid_error.rb +9 -0
  35. data/app/models/scimitar/resource_type.rb +29 -0
  36. data/app/models/scimitar/resources/base.rb +159 -0
  37. data/app/models/scimitar/resources/group.rb +13 -0
  38. data/app/models/scimitar/resources/mixin.rb +964 -0
  39. data/app/models/scimitar/resources/user.rb +13 -0
  40. data/app/models/scimitar/schema/address.rb +24 -0
  41. data/app/models/scimitar/schema/attribute.rb +123 -0
  42. data/app/models/scimitar/schema/base.rb +86 -0
  43. data/app/models/scimitar/schema/derived_attributes.rb +24 -0
  44. data/app/models/scimitar/schema/email.rb +10 -0
  45. data/app/models/scimitar/schema/entitlement.rb +10 -0
  46. data/app/models/scimitar/schema/group.rb +27 -0
  47. data/app/models/scimitar/schema/ims.rb +10 -0
  48. data/app/models/scimitar/schema/name.rb +20 -0
  49. data/app/models/scimitar/schema/phone_number.rb +10 -0
  50. data/app/models/scimitar/schema/photo.rb +10 -0
  51. data/app/models/scimitar/schema/reference_group.rb +23 -0
  52. data/app/models/scimitar/schema/reference_member.rb +21 -0
  53. data/app/models/scimitar/schema/role.rb +10 -0
  54. data/app/models/scimitar/schema/user.rb +52 -0
  55. data/app/models/scimitar/schema/vdtp.rb +18 -0
  56. data/app/models/scimitar/schema/x509_certificate.rb +22 -0
  57. data/app/models/scimitar/service_provider_configuration.rb +49 -0
  58. data/app/models/scimitar/supportable.rb +14 -0
  59. data/app/views/layouts/scimitar/application.html.erb +14 -0
  60. data/config/initializers/scimitar.rb +82 -0
  61. data/config/routes.rb +6 -0
  62. data/lib/scimitar.rb +23 -0
  63. data/lib/scimitar/engine.rb +63 -0
  64. data/lib/scimitar/version.rb +13 -0
  65. data/spec/apps/dummy/app/controllers/custom_destroy_mock_users_controller.rb +24 -0
  66. data/spec/apps/dummy/app/controllers/custom_request_verifiers_controller.rb +30 -0
  67. data/spec/apps/dummy/app/controllers/mock_groups_controller.rb +13 -0
  68. data/spec/apps/dummy/app/controllers/mock_users_controller.rb +13 -0
  69. data/spec/apps/dummy/app/models/mock_group.rb +83 -0
  70. data/spec/apps/dummy/app/models/mock_user.rb +104 -0
  71. data/spec/apps/dummy/config/application.rb +17 -0
  72. data/spec/apps/dummy/config/boot.rb +2 -0
  73. data/spec/apps/dummy/config/environment.rb +2 -0
  74. data/spec/apps/dummy/config/environments/test.rb +15 -0
  75. data/spec/apps/dummy/config/initializers/cookies_serializer.rb +3 -0
  76. data/spec/apps/dummy/config/initializers/scimitar.rb +14 -0
  77. data/spec/apps/dummy/config/initializers/session_store.rb +3 -0
  78. data/spec/apps/dummy/config/routes.rb +24 -0
  79. data/spec/apps/dummy/db/migrate/20210304014602_create_mock_users.rb +15 -0
  80. data/spec/apps/dummy/db/migrate/20210308020313_create_mock_groups.rb +10 -0
  81. data/spec/apps/dummy/db/migrate/20210308044214_create_join_table_mock_groups_mock_users.rb +8 -0
  82. data/spec/apps/dummy/db/schema.rb +42 -0
  83. data/spec/controllers/scimitar/application_controller_spec.rb +173 -0
  84. data/spec/controllers/scimitar/resource_types_controller_spec.rb +94 -0
  85. data/spec/controllers/scimitar/resources_controller_spec.rb +247 -0
  86. data/spec/controllers/scimitar/schemas_controller_spec.rb +75 -0
  87. data/spec/controllers/scimitar/service_provider_configurations_controller_spec.rb +22 -0
  88. data/spec/models/scimitar/complex_types/address_spec.rb +19 -0
  89. data/spec/models/scimitar/complex_types/email_spec.rb +23 -0
  90. data/spec/models/scimitar/lists/count_spec.rb +147 -0
  91. data/spec/models/scimitar/lists/query_parser_spec.rb +763 -0
  92. data/spec/models/scimitar/resource_type_spec.rb +21 -0
  93. data/spec/models/scimitar/resources/base_spec.rb +289 -0
  94. data/spec/models/scimitar/resources/base_validation_spec.rb +61 -0
  95. data/spec/models/scimitar/resources/mixin_spec.rb +2127 -0
  96. data/spec/models/scimitar/resources/user_spec.rb +55 -0
  97. data/spec/models/scimitar/schema/attribute_spec.rb +80 -0
  98. data/spec/models/scimitar/schema/base_spec.rb +64 -0
  99. data/spec/models/scimitar/schema/group_spec.rb +87 -0
  100. data/spec/models/scimitar/schema/user_spec.rb +710 -0
  101. data/spec/requests/active_record_backed_resources_controller_spec.rb +569 -0
  102. data/spec/requests/application_controller_spec.rb +49 -0
  103. data/spec/requests/controller_configuration_spec.rb +17 -0
  104. data/spec/requests/engine_spec.rb +20 -0
  105. data/spec/spec_helper.rb +66 -0
  106. metadata +315 -0
@@ -0,0 +1,55 @@
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 'validates that the provided name matches the name schema' do
19
+ user = described_class.new(name: Scimitar::ComplexTypes::Email.new(
20
+ value: 'john@smoth.com',
21
+ primary: true
22
+ ))
23
+
24
+ expect(user.valid?).to be(false)
25
+ end
26
+ end
27
+
28
+ context '#add_errors_from_hash' do
29
+ let(:user) { described_class.new }
30
+
31
+ it 'adds the error when the value is a string' do
32
+ user.add_errors_from_hash(key: 'some error')
33
+ expect(user.errors.messages.to_h).to eql({key: ['some error']})
34
+ expect(user.errors.full_messages).to eql(['Key some error'])
35
+ end
36
+
37
+ it 'adds the error when the value is an array' do
38
+ user.add_errors_from_hash(key: ['error1', 'error2'])
39
+ expect(user.errors.messages.to_h).to eql({key: ['error1', 'error2']})
40
+ expect(user.errors.full_messages).to eql(['Key error1', 'Key error2'])
41
+ end
42
+
43
+ it 'adds the error with prefix when the value is a string' do
44
+ user.add_errors_from_hash({key: 'some error'}, prefix: :pre)
45
+ expect(user.errors.messages.to_h).to eql({:'pre.key' => ['some error']})
46
+ expect(user.errors.full_messages).to eql(['Pre key some error'])
47
+ end
48
+
49
+ it 'adds the error wity prefix when the value is an array' do
50
+ user.add_errors_from_hash({key: ['error1', 'error2']}, prefix: :pre)
51
+ expect(user.errors.messages.to_h).to eql({:'pre.key' => ['error1', 'error2']})
52
+ expect(user.errors.full_messages).to eql(['Pre key error1', 'Pre key error2'])
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,80 @@
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
+
25
+ end
26
+
27
+
28
+ context '#valid?' do
29
+ it 'is invalid if attribute is required but value is blank' do
30
+ attribute = described_class.new(name: 'userName', type: 'string', required: true)
31
+ expect(attribute.valid?(nil)).to be(false)
32
+ expect(attribute.errors.messages.to_h).to eql({userName: ['is required']})
33
+ end
34
+
35
+ it 'is valid if attribute is not required and value is blank' do
36
+ attribute = described_class.new(name: 'userName', type: 'string', required: false)
37
+ expect(attribute.valid?(nil)).to be(true)
38
+ expect(attribute.errors.messages.to_h).to eql({})
39
+ end
40
+
41
+ it 'is valid if type is string and given value is string' do
42
+ expect(described_class.new(name: 'name', type: 'string').valid?('something')).to be(true)
43
+ end
44
+
45
+ it 'is invalid if type is string and given value is not string' do
46
+ attribute = described_class.new(name: 'userName', type: 'string')
47
+ expect(attribute.valid?(10)).to be(false)
48
+ expect(attribute.errors.messages.to_h).to eql({userName: ['has the wrong type. It has to be a(n) string.']})
49
+ end
50
+
51
+ it 'is valid if type is boolean and given value is boolean' do
52
+ expect(described_class.new(name: 'name', type: 'boolean').valid?(false)).to be(true)
53
+ expect(described_class.new(name: 'name', type: 'boolean').valid?(true)).to be(true)
54
+ end
55
+
56
+ it 'is valid if type is complex and the schema is same' do
57
+ expect(described_class.new(name: 'name', complexType: Scimitar::ComplexTypes::Name).valid?(Scimitar::ComplexTypes::Name.new(givenName: 'a', familyName: 'b'))).to be(true)
58
+ end
59
+
60
+ it 'is valid if type is integer and given value is integer (duh)' do
61
+ expect(described_class.new(name: 'quantity', type: 'integer').valid?(123)).to be(true)
62
+ end
63
+
64
+ it 'is not valid if type is integer and given value is not an integer' do
65
+ expect(described_class.new(name: 'quantity', type: 'integer').valid?(123.3)).to be(false)
66
+ end
67
+
68
+ it 'is valid if type is dateTime and given value is an ISO8601 date time' do
69
+ expect(described_class.new(name: 'startDate', type: 'dateTime').valid?('2018-07-26T11:59:43-06:00')).to be(true)
70
+ end
71
+
72
+ it 'is not valid if type is dateTime and given value is a valid date but not in ISO8601 format' do
73
+ expect(described_class.new(name: 'startDate', type: 'dateTime').valid?('2018-07-26')).to be(false)
74
+ end
75
+ it 'is not valid if type is dateTime and given value is not a valid date' do
76
+ expect(described_class.new(name: 'startDate', type: 'dateTime').valid?('gaga')).to be(false)
77
+ end
78
+ end
79
+
80
+ 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 a 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
@@ -0,0 +1,710 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe Scimitar::Schema::User do
4
+ let(:expected_attributes) {
5
+ <<-EOJ
6
+ [
7
+ {
8
+ "multiValued": false,
9
+ "required": true,
10
+ "caseExact": false,
11
+ "mutability": "readWrite",
12
+ "uniqueness": "server",
13
+ "returned": "default",
14
+ "name": "userName",
15
+ "type": "string"
16
+ },
17
+
18
+ {
19
+ "multiValued": false,
20
+ "required": false,
21
+ "caseExact": false,
22
+ "mutability": "readWrite",
23
+ "uniqueness": "none",
24
+ "returned": "default",
25
+ "name": "name",
26
+ "type": "complex",
27
+ "subAttributes": [
28
+ {
29
+ "multiValued": false,
30
+ "required": true,
31
+ "caseExact": false,
32
+ "mutability": "readWrite",
33
+ "uniqueness": "none",
34
+ "returned": "default",
35
+ "name": "familyName",
36
+ "type": "string"
37
+ },
38
+ {
39
+ "multiValued": false,
40
+ "required": true,
41
+ "caseExact": false,
42
+ "mutability": "readWrite",
43
+ "uniqueness": "none",
44
+ "returned": "default",
45
+ "name": "givenName",
46
+ "type": "string"
47
+ },
48
+ {
49
+ "multiValued": false,
50
+ "required": false,
51
+ "caseExact": false,
52
+ "mutability": "readWrite",
53
+ "uniqueness": "none",
54
+ "returned": "default",
55
+ "name": "middleName",
56
+ "type": "string"
57
+ },
58
+ {
59
+ "multiValued": false,
60
+ "required": false,
61
+ "caseExact": false,
62
+ "mutability": "readWrite",
63
+ "uniqueness": "none",
64
+ "returned": "default",
65
+ "name": "formatted",
66
+ "type": "string"
67
+ },
68
+ {
69
+ "multiValued": false,
70
+ "required": false,
71
+ "caseExact": false,
72
+ "mutability": "readWrite",
73
+ "uniqueness": "none",
74
+ "returned": "default",
75
+ "name": "honorificPrefix",
76
+ "type": "string"
77
+ },
78
+ {
79
+ "multiValued": false,
80
+ "required": false,
81
+ "caseExact": false,
82
+ "mutability": "readWrite",
83
+ "uniqueness": "none",
84
+ "returned": "default",
85
+ "name": "honorificSuffix",
86
+ "type": "string"
87
+ }
88
+ ]
89
+ },
90
+
91
+ {
92
+ "multiValued": false,
93
+ "required": false,
94
+ "caseExact": false,
95
+ "mutability": "readWrite",
96
+ "uniqueness": "none",
97
+ "returned": "default",
98
+ "name": "displayName",
99
+ "type": "string"
100
+ },
101
+ {
102
+ "multiValued": false,
103
+ "required": false,
104
+ "caseExact": false,
105
+ "mutability": "readWrite",
106
+ "uniqueness": "none",
107
+ "returned": "default",
108
+ "name": "nickName",
109
+ "type": "string"
110
+ },
111
+ {
112
+ "multiValued": false,
113
+ "required": false,
114
+ "caseExact": false,
115
+ "mutability": "readWrite",
116
+ "uniqueness": "none",
117
+ "returned": "default",
118
+ "name": "profileUrl",
119
+ "type": "string"
120
+ },
121
+ {
122
+ "multiValued": false,
123
+ "required": false,
124
+ "caseExact": false,
125
+ "mutability": "readWrite",
126
+ "uniqueness": "none",
127
+ "returned": "default",
128
+ "name": "title",
129
+ "type": "string"
130
+ },
131
+ {
132
+ "multiValued": false,
133
+ "required": false,
134
+ "caseExact": false,
135
+ "mutability": "readWrite",
136
+ "uniqueness": "none",
137
+ "returned": "default",
138
+ "name": "userType",
139
+ "type": "string"
140
+ },
141
+ {
142
+ "multiValued": false,
143
+ "required": false,
144
+ "caseExact": false,
145
+ "mutability": "readWrite",
146
+ "uniqueness": "none",
147
+ "returned": "default",
148
+ "name": "preferredLanguage",
149
+ "type": "string"
150
+ },
151
+ {
152
+ "multiValued": false,
153
+ "required": false,
154
+ "caseExact": false,
155
+ "mutability": "readWrite",
156
+ "uniqueness": "none",
157
+ "returned": "default",
158
+ "name": "locale",
159
+ "type": "string"
160
+ },
161
+ {
162
+ "multiValued": false,
163
+ "required": false,
164
+ "caseExact": false,
165
+ "mutability": "readWrite",
166
+ "uniqueness": "none",
167
+ "returned": "default",
168
+ "name": "timezone",
169
+ "type": "string"
170
+ },
171
+
172
+ {
173
+ "multiValued": false,
174
+ "required": false,
175
+ "caseExact": false,
176
+ "mutability": "readWrite",
177
+ "uniqueness": "none",
178
+ "returned": "default",
179
+ "name": "active",
180
+ "type": "boolean"
181
+ },
182
+
183
+ {
184
+ "multiValued": false,
185
+ "required": false,
186
+ "caseExact": false,
187
+ "mutability": "writeOnly",
188
+ "uniqueness": "none",
189
+ "returned": "never",
190
+ "name": "password",
191
+ "type": "string"
192
+ },
193
+
194
+ {
195
+ "multiValued": true,
196
+ "required": false,
197
+ "caseExact": false,
198
+ "mutability": "readWrite",
199
+ "uniqueness": "none",
200
+ "returned": "default",
201
+ "name": "emails",
202
+ "type": "complex",
203
+ "subAttributes": [
204
+ {
205
+ "multiValued": false,
206
+ "required": true,
207
+ "caseExact": false,
208
+ "mutability": "readWrite",
209
+ "uniqueness": "none",
210
+ "returned": "default",
211
+ "name": "value",
212
+ "type": "string"
213
+ },
214
+ {
215
+ "multiValued": false,
216
+ "required": false,
217
+ "caseExact": false,
218
+ "mutability": "readOnly",
219
+ "uniqueness": "none",
220
+ "returned": "default",
221
+ "name": "display",
222
+ "type": "string"
223
+ },
224
+ {
225
+ "multiValued": false,
226
+ "required": false,
227
+ "caseExact": false,
228
+ "mutability": "readWrite",
229
+ "uniqueness": "none",
230
+ "returned": "default",
231
+ "name": "type",
232
+ "type": "string"
233
+ },
234
+ {
235
+ "multiValued": false,
236
+ "required": false,
237
+ "caseExact": false,
238
+ "mutability": "readWrite",
239
+ "uniqueness": "none",
240
+ "returned": "default",
241
+ "name": "primary",
242
+ "type": "boolean"
243
+ }
244
+ ]
245
+ },
246
+ {
247
+ "multiValued": true,
248
+ "required": false,
249
+ "caseExact": false,
250
+ "mutability": "readWrite",
251
+ "uniqueness": "none",
252
+ "returned": "default",
253
+ "name": "phoneNumbers",
254
+ "type": "complex",
255
+ "subAttributes": [
256
+ {
257
+ "multiValued": false,
258
+ "required": true,
259
+ "caseExact": false,
260
+ "mutability": "readWrite",
261
+ "uniqueness": "none",
262
+ "returned": "default",
263
+ "name": "value",
264
+ "type": "string"
265
+ },
266
+ {
267
+ "multiValued": false,
268
+ "required": false,
269
+ "caseExact": false,
270
+ "mutability": "readOnly",
271
+ "uniqueness": "none",
272
+ "returned": "default",
273
+ "name": "display",
274
+ "type": "string"
275
+ },
276
+ {
277
+ "multiValued": false,
278
+ "required": false,
279
+ "caseExact": false,
280
+ "mutability": "readWrite",
281
+ "uniqueness": "none",
282
+ "returned": "default",
283
+ "name": "type",
284
+ "type": "string"
285
+ },
286
+ {
287
+ "multiValued": false,
288
+ "required": false,
289
+ "caseExact": false,
290
+ "mutability": "readWrite",
291
+ "uniqueness": "none",
292
+ "returned": "default",
293
+ "name": "primary",
294
+ "type": "boolean"
295
+ }
296
+ ]
297
+ },
298
+ {
299
+ "multiValued": true,
300
+ "required": false,
301
+ "caseExact": false,
302
+ "mutability": "readWrite",
303
+ "uniqueness": "none",
304
+ "returned": "default",
305
+ "name": "ims",
306
+ "type": "complex",
307
+ "subAttributes": [
308
+ {
309
+ "multiValued": false,
310
+ "required": true,
311
+ "caseExact": false,
312
+ "mutability": "readWrite",
313
+ "uniqueness": "none",
314
+ "returned": "default",
315
+ "name": "value",
316
+ "type": "string"
317
+ },
318
+ {
319
+ "multiValued": false,
320
+ "required": false,
321
+ "caseExact": false,
322
+ "mutability": "readOnly",
323
+ "uniqueness": "none",
324
+ "returned": "default",
325
+ "name": "display",
326
+ "type": "string"
327
+ },
328
+ {
329
+ "multiValued": false,
330
+ "required": false,
331
+ "caseExact": false,
332
+ "mutability": "readWrite",
333
+ "uniqueness": "none",
334
+ "returned": "default",
335
+ "name": "type",
336
+ "type": "string"
337
+ },
338
+ {
339
+ "multiValued": false,
340
+ "required": false,
341
+ "caseExact": false,
342
+ "mutability": "readWrite",
343
+ "uniqueness": "none",
344
+ "returned": "default",
345
+ "name": "primary",
346
+ "type": "boolean"
347
+ }
348
+ ]
349
+ },
350
+ {
351
+ "multiValued": true,
352
+ "required": false,
353
+ "caseExact": false,
354
+ "mutability": "readWrite",
355
+ "uniqueness": "none",
356
+ "returned": "default",
357
+ "name": "photos",
358
+ "type": "complex",
359
+ "subAttributes": [
360
+ {
361
+ "multiValued": false,
362
+ "required": true,
363
+ "caseExact": false,
364
+ "mutability": "readWrite",
365
+ "uniqueness": "none",
366
+ "returned": "default",
367
+ "name": "value",
368
+ "type": "string"
369
+ },
370
+ {
371
+ "multiValued": false,
372
+ "required": false,
373
+ "caseExact": false,
374
+ "mutability": "readOnly",
375
+ "uniqueness": "none",
376
+ "returned": "default",
377
+ "name": "display",
378
+ "type": "string"
379
+ },
380
+ {
381
+ "multiValued": false,
382
+ "required": false,
383
+ "caseExact": false,
384
+ "mutability": "readWrite",
385
+ "uniqueness": "none",
386
+ "returned": "default",
387
+ "name": "type",
388
+ "type": "string"
389
+ },
390
+ {
391
+ "multiValued": false,
392
+ "required": false,
393
+ "caseExact": false,
394
+ "mutability": "readWrite",
395
+ "uniqueness": "none",
396
+ "returned": "default",
397
+ "name": "primary",
398
+ "type": "boolean"
399
+ }
400
+ ]
401
+ },
402
+ {
403
+ "multiValued": true,
404
+ "required": false,
405
+ "caseExact": false,
406
+ "mutability": "readWrite",
407
+ "uniqueness": "none",
408
+ "returned": "default",
409
+ "name": "addresses",
410
+ "type": "complex",
411
+ "subAttributes": [
412
+ {
413
+ "multiValued": false,
414
+ "required": false,
415
+ "caseExact": false,
416
+ "mutability": "readWrite",
417
+ "uniqueness": "none",
418
+ "returned": "default",
419
+ "name": "type",
420
+ "type": "string"
421
+ },
422
+ {
423
+ "multiValued": false,
424
+ "required": false,
425
+ "caseExact": false,
426
+ "mutability": "readWrite",
427
+ "uniqueness": "none",
428
+ "returned": "default",
429
+ "name": "formatted",
430
+ "type": "string"
431
+ },
432
+ {
433
+ "multiValued": false,
434
+ "required": false,
435
+ "caseExact": false,
436
+ "mutability": "readWrite",
437
+ "uniqueness": "none",
438
+ "returned": "default",
439
+ "name": "streetAddress",
440
+ "type": "string"
441
+ },
442
+ {
443
+ "multiValued": false,
444
+ "required": false,
445
+ "caseExact": false,
446
+ "mutability": "readWrite",
447
+ "uniqueness": "none",
448
+ "returned": "default",
449
+ "name": "locality",
450
+ "type": "string"
451
+ },
452
+ {
453
+ "multiValued": false,
454
+ "required": false,
455
+ "caseExact": false,
456
+ "mutability": "readWrite",
457
+ "uniqueness": "none",
458
+ "returned": "default",
459
+ "name": "region",
460
+ "type": "string"
461
+ },
462
+ {
463
+ "multiValued": false,
464
+ "required": false,
465
+ "caseExact": false,
466
+ "mutability": "readWrite",
467
+ "uniqueness": "none",
468
+ "returned": "default",
469
+ "name": "postalCode",
470
+ "type": "string"
471
+ },
472
+ {
473
+ "multiValued": false,
474
+ "required": false,
475
+ "caseExact": false,
476
+ "mutability": "readWrite",
477
+ "uniqueness": "none",
478
+ "returned": "default",
479
+ "name": "country",
480
+ "type": "string"
481
+ }
482
+ ]
483
+ },
484
+ {
485
+ "multiValued": true,
486
+ "required": false,
487
+ "caseExact": false,
488
+ "mutability": "readOnly",
489
+ "uniqueness": "none",
490
+ "returned": "default",
491
+ "name": "groups",
492
+ "type": "complex",
493
+ "subAttributes": [
494
+ {
495
+ "multiValued": false,
496
+ "required": true,
497
+ "caseExact": false,
498
+ "mutability": "readOnly",
499
+ "uniqueness": "none",
500
+ "returned": "default",
501
+ "name": "value",
502
+ "type": "string"
503
+ },
504
+ {
505
+ "multiValued": false,
506
+ "required": false,
507
+ "caseExact": false,
508
+ "mutability": "readOnly",
509
+ "uniqueness": "none",
510
+ "returned": "default",
511
+ "name": "display",
512
+ "type": "string"
513
+ },
514
+ {
515
+ "multiValued": false,
516
+ "required": false,
517
+ "caseExact": false,
518
+ "mutability": "readOnly",
519
+ "uniqueness": "none",
520
+ "returned": "default",
521
+ "name": "type",
522
+ "type": "string"
523
+ }
524
+ ]
525
+ },
526
+ {
527
+ "multiValued": true,
528
+ "required": false,
529
+ "caseExact": false,
530
+ "mutability": "readWrite",
531
+ "uniqueness": "none",
532
+ "returned": "default",
533
+ "name": "entitlements",
534
+ "type": "complex",
535
+ "subAttributes": [
536
+ {
537
+ "multiValued": false,
538
+ "required": true,
539
+ "caseExact": false,
540
+ "mutability": "readWrite",
541
+ "uniqueness": "none",
542
+ "returned": "default",
543
+ "name": "value",
544
+ "type": "string"
545
+ },
546
+ {
547
+ "multiValued": false,
548
+ "required": false,
549
+ "caseExact": false,
550
+ "mutability": "readOnly",
551
+ "uniqueness": "none",
552
+ "returned": "default",
553
+ "name": "display",
554
+ "type": "string"
555
+ },
556
+ {
557
+ "multiValued": false,
558
+ "required": false,
559
+ "caseExact": false,
560
+ "mutability": "readWrite",
561
+ "uniqueness": "none",
562
+ "returned": "default",
563
+ "name": "type",
564
+ "type": "string"
565
+ },
566
+ {
567
+ "multiValued": false,
568
+ "required": false,
569
+ "caseExact": false,
570
+ "mutability": "readWrite",
571
+ "uniqueness": "none",
572
+ "returned": "default",
573
+ "name": "primary",
574
+ "type": "boolean"
575
+ }
576
+ ]
577
+ },
578
+ {
579
+ "multiValued": true,
580
+ "required": false,
581
+ "caseExact": false,
582
+ "mutability": "readWrite",
583
+ "uniqueness": "none",
584
+ "returned": "default",
585
+ "name": "roles",
586
+ "type": "complex",
587
+ "subAttributes": [
588
+ {
589
+ "multiValued": false,
590
+ "required": true,
591
+ "caseExact": false,
592
+ "mutability": "readWrite",
593
+ "uniqueness": "none",
594
+ "returned": "default",
595
+ "name": "value",
596
+ "type": "string"
597
+ },
598
+ {
599
+ "multiValued": false,
600
+ "required": false,
601
+ "caseExact": false,
602
+ "mutability": "readOnly",
603
+ "uniqueness": "none",
604
+ "returned": "default",
605
+ "name": "display",
606
+ "type": "string"
607
+ },
608
+ {
609
+ "multiValued": false,
610
+ "required": false,
611
+ "caseExact": false,
612
+ "mutability": "readWrite",
613
+ "uniqueness": "none",
614
+ "returned": "default",
615
+ "name": "type",
616
+ "type": "string"
617
+ },
618
+ {
619
+ "multiValued": false,
620
+ "required": false,
621
+ "caseExact": false,
622
+ "mutability": "readWrite",
623
+ "uniqueness": "none",
624
+ "returned": "default",
625
+ "name": "primary",
626
+ "type": "boolean"
627
+ }
628
+ ]
629
+ },
630
+ {
631
+ "multiValued": true,
632
+ "required": false,
633
+ "caseExact": false,
634
+ "mutability": "readWrite",
635
+ "uniqueness": "none",
636
+ "returned": "default",
637
+ "name": "x509Certificates",
638
+ "type": "complex",
639
+ "subAttributes": [
640
+ {
641
+ "multiValued": false,
642
+ "required": true,
643
+ "caseExact": false,
644
+ "mutability": "readWrite",
645
+ "uniqueness": "none",
646
+ "returned": "default",
647
+ "name": "value",
648
+ "type": "binary"
649
+ },
650
+ {
651
+ "multiValued": false,
652
+ "required": false,
653
+ "caseExact": false,
654
+ "mutability": "readOnly",
655
+ "uniqueness": "none",
656
+ "returned": "default",
657
+ "name": "display",
658
+ "type": "string"
659
+ },
660
+ {
661
+ "multiValued": false,
662
+ "required": false,
663
+ "caseExact": false,
664
+ "mutability": "readWrite",
665
+ "uniqueness": "none",
666
+ "returned": "default",
667
+ "name": "type",
668
+ "type": "string"
669
+ },
670
+ {
671
+ "multiValued": false,
672
+ "required": false,
673
+ "caseExact": false,
674
+ "mutability": "readWrite",
675
+ "uniqueness": "none",
676
+ "returned": "default",
677
+ "name": "primary",
678
+ "type": "boolean"
679
+ }
680
+ ]
681
+ }
682
+ ]
683
+ EOJ
684
+ }
685
+
686
+ let(:expected_full_schema) {
687
+ <<-EOJ
688
+ {
689
+ "name": "User",
690
+ "id": "urn:ietf:params:scim:schemas:core:2.0:User",
691
+ "description": "Represents a User",
692
+ "meta": {
693
+ "resourceType": "Schema",
694
+ "location": "/Schemas?name=urn%3Aietf%3Aparams%3Ascim%3Aschemas%3Acore%3A2.0%3AUser"
695
+ },
696
+ "attributes": #{expected_attributes()}
697
+ }
698
+ EOJ
699
+ }
700
+
701
+ it 'returns User schema as JSON' do
702
+ actual_full_schema = Scimitar::Schema::User.new
703
+ expect(JSON.parse(actual_full_schema.to_json)).to eql(JSON.parse(expected_full_schema()))
704
+ end
705
+
706
+ it 'returns the schema attributes as JSON' do
707
+ actual_attributes = Scimitar::Schema::User.scim_attributes
708
+ expect(JSON.parse(actual_attributes.to_json)).to eql(JSON.parse(expected_attributes()))
709
+ end
710
+ end