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,83 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe Scimitar::SchemasController do
|
4
|
+
routes { Scimitar::Engine.routes }
|
5
|
+
|
6
|
+
before(:each) { allow(controller).to receive(:authenticated?).and_return(true) }
|
7
|
+
|
8
|
+
controller do
|
9
|
+
def index
|
10
|
+
super
|
11
|
+
end
|
12
|
+
end
|
13
|
+
context '#index' do
|
14
|
+
it 'returns a collection of supported schemas' do
|
15
|
+
get :index, params: { format: :scim }
|
16
|
+
expect(response).to be_ok
|
17
|
+
parsed_body = JSON.parse(response.body)
|
18
|
+
expect(parsed_body.length).to eql(3)
|
19
|
+
schema_names = parsed_body.map {|schema| schema['name']}
|
20
|
+
expect(schema_names).to match_array(['User', 'ExtendedUser', 'Group'])
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'returns only the User schema when its id is provided' do
|
24
|
+
get :index, params: { name: Scimitar::Schema::User.id, format: :scim }
|
25
|
+
expect(response).to be_ok
|
26
|
+
parsed_body = JSON.parse(response.body)
|
27
|
+
expect(parsed_body['name']).to eql('User')
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'includes the controller customised schema location' do
|
31
|
+
get :index, params: { name: Scimitar::Schema::User.id, format: :scim }
|
32
|
+
expect(response).to be_ok
|
33
|
+
parsed_body = JSON.parse(response.body)
|
34
|
+
expect(parsed_body.dig('meta', 'location')).to eq scim_schemas_url(name: Scimitar::Schema::User.id, test: 1)
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'returns only the Group schema when its id is provided' do
|
38
|
+
get :index, params: { name: Scimitar::Schema::Group.id, format: :scim }
|
39
|
+
expect(response).to be_ok
|
40
|
+
parsed_body = JSON.parse(response.body)
|
41
|
+
expect(parsed_body['name']).to eql('Group')
|
42
|
+
end
|
43
|
+
|
44
|
+
context 'with custom resource types' do
|
45
|
+
around :each do | example |
|
46
|
+
example.run()
|
47
|
+
ensure
|
48
|
+
Scimitar::Engine.reset_custom_resources
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'returns only the License schemas when its id is provided' do
|
52
|
+
license_schema = Class.new(Scimitar::Schema::Base) do
|
53
|
+
def initialize(options = {})
|
54
|
+
super(name: 'License',
|
55
|
+
id: self.class.id,
|
56
|
+
description: 'Represents a License')
|
57
|
+
end
|
58
|
+
def self.id
|
59
|
+
'License'
|
60
|
+
end
|
61
|
+
def self.scim_attributes
|
62
|
+
[]
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
license_resource = Class.new(Scimitar::Resources::Base) do
|
67
|
+
set_schema license_schema
|
68
|
+
def self.endopint
|
69
|
+
'/Gaga'
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
Scimitar::Engine.add_custom_resource(license_resource)
|
74
|
+
|
75
|
+
get :index, params: { name: license_schema.id, format: :scim }
|
76
|
+
expect(response).to be_ok
|
77
|
+
parsed_body = JSON.parse(response.body)
|
78
|
+
expect(parsed_body['name']).to eql('License')
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe Scimitar::ServiceProviderConfigurationsController do
|
4
|
+
|
5
|
+
before(:each) { allow(controller).to receive(:authenticated?).and_return(true) }
|
6
|
+
|
7
|
+
controller do
|
8
|
+
def show
|
9
|
+
super
|
10
|
+
end
|
11
|
+
end
|
12
|
+
context '#show' do
|
13
|
+
it 'renders the servive provider configurations' do
|
14
|
+
get :show, params: { id: 'fake', format: :scim }
|
15
|
+
|
16
|
+
expect(response).to be_ok
|
17
|
+
expect(JSON.parse(response.body)).to include('patch' => {'supported' => true})
|
18
|
+
expect(JSON.parse(response.body)).to include('filter' => {'maxResults' => Scimitar::Filter::MAX_RESULTS_DEFAULT, 'supported' => true})
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe Scimitar::ComplexTypes::Address do
|
4
|
+
context '#as_json' do
|
5
|
+
it 'assumes no defaults' do
|
6
|
+
expect(described_class.new.as_json).to eq({})
|
7
|
+
end
|
8
|
+
|
9
|
+
it 'allows a custom address type' do
|
10
|
+
expect(described_class.new(type: 'home').as_json).to eq('type' => 'home')
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'shows the set address' do
|
14
|
+
expect(described_class.new(country: 'NZ').as_json).to eq('country' => 'NZ')
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe Scimitar::ComplexTypes::Email do
|
4
|
+
context '#as_json' do
|
5
|
+
it 'assumes no defaults' do
|
6
|
+
expect(described_class.new.as_json).to eq({})
|
7
|
+
end
|
8
|
+
|
9
|
+
it 'allows a custom email type' do
|
10
|
+
expect(described_class.new(type: 'home').as_json).to eq('type' => 'home')
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'allows a non-primary email' do
|
14
|
+
expect(described_class.new(primary: false).as_json).to eq('primary' => false)
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'shows the set email' do
|
18
|
+
expect(described_class.new(value: 'a@b.c').as_json).to eq('value' => 'a@b.c')
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,147 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe Scimitar::Lists::Count do
|
4
|
+
before :each do
|
5
|
+
@instance = described_class.new
|
6
|
+
end
|
7
|
+
|
8
|
+
# ===========================================================================
|
9
|
+
# LIMIT
|
10
|
+
# ===========================================================================
|
11
|
+
|
12
|
+
context '#limit' do
|
13
|
+
it 'defaults to 100' do
|
14
|
+
expect(@instance.limit).to eql(100)
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'converts input strings to integers' do
|
18
|
+
@instance.limit = '50'
|
19
|
+
expect(@instance.limit).to eql(50)
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'ignores "nil"' do
|
23
|
+
expect { @instance.limit = nil }.to_not raise_error
|
24
|
+
expect(@instance.limit).to eql(100)
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'ignores blank' do
|
28
|
+
expect { @instance.limit = ' ' }.to_not raise_error
|
29
|
+
expect(@instance.limit).to eql(100)
|
30
|
+
end
|
31
|
+
|
32
|
+
context 'error checking' do
|
33
|
+
it 'complains about attempts to set non-numeric values' do
|
34
|
+
expect { @instance.limit = 'A' }.to raise_error(RuntimeError)
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'complains about attempts to set zero values' do
|
38
|
+
expect { @instance.limit = '0' }.to raise_error(RuntimeError)
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'complains about attempts to set zero values' do
|
42
|
+
|
43
|
+
expect { @instance.limit = '-10' }.to raise_error(RuntimeError)
|
44
|
+
end
|
45
|
+
end # "context 'on-read error checking' do"
|
46
|
+
end # "context '#limit' do"
|
47
|
+
|
48
|
+
# ===========================================================================
|
49
|
+
# START INDEX
|
50
|
+
# ===========================================================================
|
51
|
+
|
52
|
+
context '#start_index' do
|
53
|
+
it 'defaults to 1' do
|
54
|
+
expect(@instance.start_index).to eql(1)
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'accepts input integers' do
|
58
|
+
@instance.start_index = 12
|
59
|
+
expect(@instance.start_index).to eql(12)
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'converts input strings to integers' do
|
63
|
+
@instance.start_index = '12'
|
64
|
+
expect(@instance.start_index).to eql(12)
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'bounds zero values to 1' do
|
68
|
+
@instance.start_index = '0'
|
69
|
+
expect(@instance.start_index).to eql(1)
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'ignores "nil"' do
|
73
|
+
expect { @instance.start_index = nil }.to_not raise_error
|
74
|
+
expect(@instance.start_index).to eql(1)
|
75
|
+
end
|
76
|
+
|
77
|
+
it 'ignores blank' do
|
78
|
+
expect { @instance.start_index = ' ' }.to_not raise_error
|
79
|
+
expect(@instance.start_index).to eql(1)
|
80
|
+
end
|
81
|
+
|
82
|
+
context 'error checking' do
|
83
|
+
it 'complains about attempts to set non-numeric values' do
|
84
|
+
|
85
|
+
expect { @instance.start_index = 'A' }.to raise_error(RuntimeError)
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'complains about attempts to set negative values' do
|
89
|
+
expect { @instance.start_index = '-10' }.to raise_error(RuntimeError)
|
90
|
+
end
|
91
|
+
end # "context 'on-read error checking' do"
|
92
|
+
end # "context '#start_index' do"
|
93
|
+
|
94
|
+
# ===========================================================================
|
95
|
+
# OFFSET
|
96
|
+
# ===========================================================================
|
97
|
+
|
98
|
+
context '#offset' do
|
99
|
+
it 'defaults to 0' do
|
100
|
+
expect(@instance.offset).to eql(0)
|
101
|
+
end
|
102
|
+
|
103
|
+
it 'returns the #start_index minus one (set by integer)' do
|
104
|
+
@instance.start_index = 12
|
105
|
+
expect(@instance.offset).to eql(11)
|
106
|
+
end
|
107
|
+
|
108
|
+
it 'returns the #start_index minus one by (set by string)' do
|
109
|
+
@instance.start_index = '12'
|
110
|
+
expect(@instance.offset).to eql(11)
|
111
|
+
end
|
112
|
+
|
113
|
+
it 'is read-only' do
|
114
|
+
expect { @instance.offset = 42 }.to raise_error(NoMethodError)
|
115
|
+
end
|
116
|
+
end # "context '#offset' do"
|
117
|
+
|
118
|
+
# ===========================================================================
|
119
|
+
# TOTAL
|
120
|
+
# ===========================================================================
|
121
|
+
|
122
|
+
context '#total' do
|
123
|
+
it 'defaults to "nil" as "unknown"' do
|
124
|
+
expect(@instance.total).to be_nil
|
125
|
+
end
|
126
|
+
|
127
|
+
it 'is read/write' do
|
128
|
+
@instance.total = 42
|
129
|
+
expect(@instance.total).to eql(42)
|
130
|
+
end
|
131
|
+
end # "context '#total' do"
|
132
|
+
|
133
|
+
# ===========================================================================
|
134
|
+
# INSTANTIATION
|
135
|
+
# ===========================================================================
|
136
|
+
|
137
|
+
context 'instantiation' do
|
138
|
+
it 'instantiates with parameters' do
|
139
|
+
instance = described_class.new(start_index: '5', total: 45)
|
140
|
+
|
141
|
+
expect(instance.limit ).to eql(100)
|
142
|
+
expect(instance.start_index).to eql(5)
|
143
|
+
expect(instance.offset ).to eql(4)
|
144
|
+
expect(instance.total ).to eql(45)
|
145
|
+
end
|
146
|
+
end # "context 'instantiation' do"
|
147
|
+
end # "RSpec.describe Scimitar::Lists::Count do"
|