scimaenaga 0.7.0 → 0.9.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +22 -7
- data/Rakefile +6 -8
- data/app/controllers/concerns/{scim_rails → scimaenaga}/exception_handler.rb +47 -37
- data/app/controllers/concerns/scimaenaga/response.rb +94 -0
- data/app/controllers/scimaenaga/application_controller.rb +72 -0
- data/app/controllers/{scim_rails → scimaenaga}/scim_groups_controller.rb +26 -26
- data/app/controllers/scimaenaga/scim_schemas_controller.rb +42 -0
- data/app/controllers/scimaenaga/scim_users_controller.rb +104 -0
- data/app/helpers/{scim_rails → scimaenaga}/application_helper.rb +1 -1
- data/app/libraries/scim_patch.rb +16 -9
- data/app/libraries/scim_patch_operation.rb +51 -141
- data/app/libraries/scim_patch_operation_converter.rb +90 -0
- data/app/libraries/scim_patch_operation_group.rb +100 -0
- data/app/libraries/scim_patch_operation_user.rb +53 -0
- data/app/models/{scim_rails → scimaenaga}/application_record.rb +1 -1
- data/app/models/scimaenaga/authorize_api_request.rb +39 -0
- data/app/models/{scim_rails → scimaenaga}/scim_count.rb +8 -4
- data/app/models/scimaenaga/scim_query_parser.rb +49 -0
- data/config/routes.rb +15 -13
- data/lib/generators/scimaenaga/USAGE +8 -0
- data/lib/generators/scimaenaga/scimaenaga_generator.rb +7 -0
- data/lib/generators/{scim_rails → scimaenaga}/templates/initializer.rb +128 -22
- data/lib/{scim_rails → scimaenaga}/config.rb +9 -7
- data/lib/scimaenaga/encoder.rb +27 -0
- data/lib/scimaenaga/engine.rb +12 -0
- data/lib/scimaenaga/version.rb +5 -0
- data/lib/scimaenaga.rb +6 -0
- data/lib/tasks/{scim_rails_tasks.rake → scimaenaga_tasks.rake} +1 -1
- data/spec/controllers/{scim_rails → scimaenaga}/scim_groups_controller_spec.rb +8 -8
- data/spec/controllers/{scim_rails → scimaenaga}/scim_groups_request_spec.rb +18 -18
- data/spec/controllers/scimaenaga/scim_schemas_controller_spec.rb +238 -0
- data/spec/controllers/scimaenaga/scim_schemas_request_spec.rb +39 -0
- data/spec/controllers/{scim_rails → scimaenaga}/scim_users_controller_spec.rb +14 -15
- data/spec/controllers/{scim_rails → scimaenaga}/scim_users_request_spec.rb +20 -20
- data/spec/dummy/app/assets/config/manifest.js +1 -1
- data/spec/dummy/config/application.rb +1 -2
- data/spec/dummy/config/initializers/{scim_rails_config.rb → scimaenaga_config.rb} +25 -25
- data/spec/dummy/config/routes.rb +1 -1
- data/spec/factories/company.rb +3 -3
- data/spec/lib/scimaenaga/encoder_spec.rb +64 -0
- data/spec/libraries/scim_patch_operation_group_spec.rb +165 -0
- data/spec/libraries/scim_patch_operation_user_spec.rb +101 -0
- data/spec/libraries/scim_patch_spec.rb +129 -45
- data/spec/models/scim_query_parser_spec.rb +5 -6
- metadata +107 -108
- data/app/controllers/concerns/scim_rails/response.rb +0 -94
- data/app/controllers/scim_rails/application_controller.rb +0 -72
- data/app/controllers/scim_rails/scim_users_controller.rb +0 -107
- data/app/models/scim_rails/authorize_api_request.rb +0 -40
- data/app/models/scim_rails/scim_query_parser.rb +0 -49
- data/lib/generators/scim_rails/USAGE +0 -8
- data/lib/generators/scim_rails/scim_rails_generator.rb +0 -7
- data/lib/scim_rails/encoder.rb +0 -25
- data/lib/scim_rails/engine.rb +0 -12
- data/lib/scim_rails/version.rb +0 -5
- data/lib/scim_rails.rb +0 -6
- data/spec/dummy/db/development.sqlite3 +0 -0
- data/spec/dummy/db/test.sqlite3 +0 -0
- data/spec/dummy/log/development.log +0 -0
- data/spec/dummy/log/test.log +0 -5770
- data/spec/dummy/put_group.http +0 -5
- data/spec/dummy/tmp/restart.txt +0 -0
- data/spec/lib/scim_rails/encoder_spec.rb +0 -62
- data/spec/libraries/scim_patch_operation_spec.rb +0 -116
@@ -0,0 +1,238 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
RSpec.describe Scimaenaga::ScimSchemasController, type: :controller do
|
6
|
+
include AuthHelper
|
7
|
+
|
8
|
+
routes { Scimaenaga::Engine.routes }
|
9
|
+
|
10
|
+
let(:schemas) do
|
11
|
+
[
|
12
|
+
{
|
13
|
+
schemas: ['urn:ietf:params:scim:schemas:core:2.0:Schema'],
|
14
|
+
id: 'urn:ietf:params:scim:schemas:core:2.0:User',
|
15
|
+
name: 'User',
|
16
|
+
description: 'User Account',
|
17
|
+
attributes: [
|
18
|
+
{
|
19
|
+
name: 'userName',
|
20
|
+
type: 'string',
|
21
|
+
multiValued: false,
|
22
|
+
description: 'Unique identifier for the User. REQUIRED.',
|
23
|
+
required: true,
|
24
|
+
caseExact: false,
|
25
|
+
mutability: 'readWrite',
|
26
|
+
returned: 'default',
|
27
|
+
uniqueness: 'server',
|
28
|
+
}
|
29
|
+
],
|
30
|
+
meta: {
|
31
|
+
resourceType: 'Schema',
|
32
|
+
location:
|
33
|
+
'/v2/Schemas/urn:ietf:params:scim:schemas:core:2.0:User',
|
34
|
+
},
|
35
|
+
},
|
36
|
+
{
|
37
|
+
schemas: ['urn:ietf:params:scim:schemas:core:2.0:Schema'],
|
38
|
+
id: 'urn:ietf:params:scim:schemas:core:2.0:Group',
|
39
|
+
name: 'Group',
|
40
|
+
description: 'Group',
|
41
|
+
attributes: [
|
42
|
+
{
|
43
|
+
name: 'displayName',
|
44
|
+
type: 'string',
|
45
|
+
multiValued: false,
|
46
|
+
description: 'A human-readable name for the Group. REQUIRED.',
|
47
|
+
required: false,
|
48
|
+
caseExact: false,
|
49
|
+
mutability: 'readWrite',
|
50
|
+
returned: 'default',
|
51
|
+
uniqueness: 'none',
|
52
|
+
}
|
53
|
+
],
|
54
|
+
meta: {
|
55
|
+
resourceType: 'Schema',
|
56
|
+
location: '/v2/Schemas/urn:ietf:params:scim:schemas:core:2.0:Group',
|
57
|
+
},
|
58
|
+
}
|
59
|
+
]
|
60
|
+
end
|
61
|
+
|
62
|
+
let(:schemas_110) do
|
63
|
+
[
|
64
|
+
{ id: 'dummy1' }, { id: 'dummy2' }, { id: 'dummy3' },
|
65
|
+
{ id: 'dummy4' }, { id: 'dummy5' }, { id: 'dummy6' },
|
66
|
+
{ id: 'dummy7' }, { id: 'dummy8' }, { id: 'dummy9' },
|
67
|
+
{ id: 'dummy10' }, { id: 'dummy11' }, { id: 'dummy12' },
|
68
|
+
{ id: 'dummy13' }, { id: 'dummy14' }, { id: 'dummy15' },
|
69
|
+
{ id: 'dummy16' }, { id: 'dummy17' }, { id: 'dummy18' },
|
70
|
+
{ id: 'dummy19' }, { id: 'dummy20' }, { id: 'dummy21' },
|
71
|
+
{ id: 'dummy22' }, { id: 'dummy23' }, { id: 'dummy24' },
|
72
|
+
{ id: 'dummy25' }, { id: 'dummy26' }, { id: 'dummy27' },
|
73
|
+
{ id: 'dummy28' }, { id: 'dummy29' }, { id: 'dummy30' },
|
74
|
+
{ id: 'dummy31' }, { id: 'dummy32' }, { id: 'dummy33' },
|
75
|
+
{ id: 'dummy34' }, { id: 'dummy35' }, { id: 'dummy36' },
|
76
|
+
{ id: 'dummy37' }, { id: 'dummy38' }, { id: 'dummy39' },
|
77
|
+
{ id: 'dummy40' }, { id: 'dummy41' }, { id: 'dummy42' },
|
78
|
+
{ id: 'dummy43' }, { id: 'dummy44' }, { id: 'dummy45' },
|
79
|
+
{ id: 'dummy46' }, { id: 'dummy47' }, { id: 'dummy48' },
|
80
|
+
{ id: 'dummy49' }, { id: 'dummy50' }, { id: 'dummy51' },
|
81
|
+
{ id: 'dummy52' }, { id: 'dummy53' }, { id: 'dummy54' },
|
82
|
+
{ id: 'dummy55' }, { id: 'dummy56' }, { id: 'dummy57' },
|
83
|
+
{ id: 'dummy58' }, { id: 'dummy59' }, { id: 'dummy60' },
|
84
|
+
{ id: 'dummy61' }, { id: 'dummy62' }, { id: 'dummy63' },
|
85
|
+
{ id: 'dummy64' }, { id: 'dummy65' }, { id: 'dummy66' },
|
86
|
+
{ id: 'dummy67' }, { id: 'dummy68' }, { id: 'dummy69' },
|
87
|
+
{ id: 'dummy70' }, { id: 'dummy71' }, { id: 'dummy72' },
|
88
|
+
{ id: 'dummy73' }, { id: 'dummy74' }, { id: 'dummy75' },
|
89
|
+
{ id: 'dummy76' }, { id: 'dummy77' }, { id: 'dummy78' },
|
90
|
+
{ id: 'dummy79' }, { id: 'dummy80' }, { id: 'dummy81' },
|
91
|
+
{ id: 'dummy82' }, { id: 'dummy83' }, { id: 'dummy84' },
|
92
|
+
{ id: 'dummy85' }, { id: 'dummy86' }, { id: 'dummy87' },
|
93
|
+
{ id: 'dummy88' }, { id: 'dummy89' }, { id: 'dummy90' },
|
94
|
+
{ id: 'dummy91' }, { id: 'dummy92' }, { id: 'dummy93' },
|
95
|
+
{ id: 'dummy94' }, { id: 'dummy95' }, { id: 'dummy96' },
|
96
|
+
{ id: 'dummy97' }, { id: 'dummy98' }, { id: 'dummy99' },
|
97
|
+
{ id: 'dummy100' }, { id: 'dummy101' }, { id: 'dummy102' },
|
98
|
+
{ id: 'dummy103' }, { id: 'dummy104' }, { id: 'dummy105' },
|
99
|
+
{ id: 'dummy106' }, { id: 'dummy107' }, { id: 'dummy108' },
|
100
|
+
{ id: 'dummy109' }, { id: 'dummy110' }
|
101
|
+
]
|
102
|
+
end
|
103
|
+
|
104
|
+
describe 'index' do
|
105
|
+
let(:company) { create(:company) }
|
106
|
+
|
107
|
+
context 'when unauthorized' do
|
108
|
+
it 'returns scim+json content type' do
|
109
|
+
get :index, as: :json
|
110
|
+
|
111
|
+
expect(response.media_type).to eq 'application/scim+json'
|
112
|
+
end
|
113
|
+
|
114
|
+
it 'fails with no credentials' do
|
115
|
+
get :index, as: :json
|
116
|
+
|
117
|
+
expect(response.status).to eq 401
|
118
|
+
end
|
119
|
+
|
120
|
+
it 'fails with invalid credentials' do
|
121
|
+
request.env['HTTP_AUTHORIZATION'] =
|
122
|
+
ActionController::HttpAuthentication::Basic
|
123
|
+
.encode_credentials('unauthorized', '123456')
|
124
|
+
|
125
|
+
get :index, as: :json
|
126
|
+
|
127
|
+
expect(response.status).to eq 401
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
context 'when authorized' do
|
132
|
+
before :each do
|
133
|
+
http_login(company)
|
134
|
+
end
|
135
|
+
|
136
|
+
it 'returns scim+json content type' do
|
137
|
+
get :index, as: :json
|
138
|
+
|
139
|
+
expect(response.media_type).to eq 'application/scim+json'
|
140
|
+
end
|
141
|
+
|
142
|
+
it 'is successful with valid credentials' do
|
143
|
+
get :index, as: :json
|
144
|
+
|
145
|
+
expect(response.status).to eq 200
|
146
|
+
end
|
147
|
+
|
148
|
+
it 'returns all results' do
|
149
|
+
allow(Scimaenaga.config).to(receive(:schemas).and_return(schemas))
|
150
|
+
get :index, as: :json
|
151
|
+
response_body = JSON.parse(response.body)
|
152
|
+
expect(response_body.dig('schemas', 0)).to(
|
153
|
+
eq 'urn:ietf:params:scim:api:messages:2.0:ListResponse'
|
154
|
+
)
|
155
|
+
expect(response_body['totalResults']).to eq 2
|
156
|
+
end
|
157
|
+
|
158
|
+
it 'defaults to 100 results' do
|
159
|
+
allow(Scimaenaga.config).to(receive(:schemas).and_return(schemas_110))
|
160
|
+
|
161
|
+
get :index, as: :json
|
162
|
+
response_body = JSON.parse(response.body)
|
163
|
+
expect(response_body['totalResults']).to eq 110
|
164
|
+
expect(response_body['startIndex']).to eq 1
|
165
|
+
expect(response_body['Resources'].count).to eq 100
|
166
|
+
end
|
167
|
+
|
168
|
+
it 'paginates results' do
|
169
|
+
allow(Scimaenaga.config).to(receive(:schemas).and_return(schemas_110))
|
170
|
+
get :index, params: {
|
171
|
+
startIndex: 101,
|
172
|
+
count: 5,
|
173
|
+
}, as: :json
|
174
|
+
response_body = JSON.parse(response.body)
|
175
|
+
expect(response_body['totalResults']).to eq 110
|
176
|
+
expect(response_body['startIndex']).to eq 101
|
177
|
+
expect(response_body['Resources'].count).to eq 5
|
178
|
+
expect(response_body.dig('Resources', 0, 'id')).to eq 'dummy101'
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
describe 'show' do
|
184
|
+
let(:company) { create(:company) }
|
185
|
+
|
186
|
+
context 'when unauthorized' do
|
187
|
+
it 'returns scim+json content type' do
|
188
|
+
get :show, params: { id: 1 }, as: :json
|
189
|
+
|
190
|
+
expect(response.media_type).to eq 'application/scim+json'
|
191
|
+
end
|
192
|
+
|
193
|
+
it 'fails with no credentials' do
|
194
|
+
get :show, params: { id: 1 }, as: :json
|
195
|
+
|
196
|
+
expect(response.status).to eq 401
|
197
|
+
end
|
198
|
+
|
199
|
+
it 'fails with invalid credentials' do
|
200
|
+
request.env['HTTP_AUTHORIZATION'] =
|
201
|
+
ActionController::HttpAuthentication::Basic
|
202
|
+
.encode_credentials('unauthorized', '123456')
|
203
|
+
|
204
|
+
get :show, params: { id: 1 }, as: :json
|
205
|
+
|
206
|
+
expect(response.status).to eq 401
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
context 'when authorized' do
|
211
|
+
before :each do
|
212
|
+
http_login(company)
|
213
|
+
end
|
214
|
+
|
215
|
+
it 'returns scim+json content type' do
|
216
|
+
allow(Scimaenaga.config).to(receive(:schemas).and_return(schemas))
|
217
|
+
get :show, params: { id: 'urn:ietf:params:scim:schemas:core:2.0:User' }, as: :json
|
218
|
+
|
219
|
+
expect(response.media_type).to eq 'application/scim+json'
|
220
|
+
end
|
221
|
+
|
222
|
+
it 'is successful with valid credentials' do
|
223
|
+
allow(Scimaenaga.config).to(receive(:schemas).and_return(schemas))
|
224
|
+
get :show, params: { id: 'urn:ietf:params:scim:schemas:core:2.0:User' }, as: :json
|
225
|
+
|
226
|
+
response_body = JSON.parse(response.body)
|
227
|
+
expect(response.status).to eq 200
|
228
|
+
expect(response_body['name']).to eq 'User'
|
229
|
+
end
|
230
|
+
|
231
|
+
it 'returns :not_found for id that cannot be found' do
|
232
|
+
get :show, params: { id: 'fake_id' }, as: :json
|
233
|
+
|
234
|
+
expect(response.status).to eq 404
|
235
|
+
end
|
236
|
+
end
|
237
|
+
end
|
238
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
RSpec.describe Scimaenaga::ScimSchemasController, type: :request do
|
6
|
+
let(:company) { create(:company) }
|
7
|
+
let(:credentials) do
|
8
|
+
Base64.encode64("#{company.subdomain}:#{company.api_token}")
|
9
|
+
end
|
10
|
+
let(:authorization) { "Basic #{credentials}" }
|
11
|
+
|
12
|
+
def get_request(content_type = 'application/scim+json')
|
13
|
+
get '/scim/v2/Schemas',
|
14
|
+
headers: {
|
15
|
+
Authorization: authorization,
|
16
|
+
'Content-Type': content_type,
|
17
|
+
}
|
18
|
+
end
|
19
|
+
|
20
|
+
context 'OAuth Bearer Authorization' do
|
21
|
+
context 'with valid token' do
|
22
|
+
let(:authorization) { "Bearer #{company.api_token}" }
|
23
|
+
|
24
|
+
it 'supports OAuth bearer authorization and succeeds' do
|
25
|
+
get_request
|
26
|
+
expect(response.status).to eq 200
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
context 'with invalid token' do
|
31
|
+
let(:authorization) { "Bearer #{SecureRandom.hex}" }
|
32
|
+
|
33
|
+
it 'The request fails' do
|
34
|
+
get_request
|
35
|
+
expect(response.status).to eq 401
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -2,10 +2,10 @@
|
|
2
2
|
|
3
3
|
require 'spec_helper'
|
4
4
|
|
5
|
-
RSpec.describe
|
5
|
+
RSpec.describe Scimaenaga::ScimUsersController, type: :controller do
|
6
6
|
include AuthHelper
|
7
7
|
|
8
|
-
routes {
|
8
|
+
routes { Scimaenaga::Engine.routes }
|
9
9
|
|
10
10
|
describe 'index' do
|
11
11
|
let(:company) { create(:company) }
|
@@ -85,7 +85,7 @@ RSpec.describe ScimRails::ScimUsersController, type: :controller do
|
|
85
85
|
end
|
86
86
|
|
87
87
|
it 'paginates results by configurable scim_users_list_order' do
|
88
|
-
allow(
|
88
|
+
allow(Scimaenaga.config).to receive(:scim_users_list_order).and_return({ created_at: :desc })
|
89
89
|
|
90
90
|
create_list(:user, 400, company: company)
|
91
91
|
expect(company.users.first.id).to eq 1
|
@@ -334,7 +334,7 @@ RSpec.describe ScimRails::ScimUsersController, type: :controller do
|
|
334
334
|
end
|
335
335
|
|
336
336
|
it 'returns 409 if user already exists and config.scim_user_prevent_update_on_create is set to true' do
|
337
|
-
allow(
|
337
|
+
allow(Scimaenaga.config).to receive(:scim_user_prevent_update_on_create).and_return(true)
|
338
338
|
create(:user, email: 'new@example.com', company: company)
|
339
339
|
|
340
340
|
post :create, params: {
|
@@ -755,23 +755,23 @@ RSpec.describe ScimRails::ScimUsersController, type: :controller do
|
|
755
755
|
describe 'destroy' do
|
756
756
|
let(:company) { create(:company) }
|
757
757
|
|
758
|
-
context
|
759
|
-
it
|
758
|
+
context 'when unauthorized' do
|
759
|
+
it 'returns scim+json content type' do
|
760
760
|
delete :destroy, params: { id: 1 }, as: :json
|
761
761
|
|
762
|
-
expect(response.media_type).to eq
|
762
|
+
expect(response.media_type).to eq 'application/scim+json'
|
763
763
|
end
|
764
764
|
|
765
|
-
it
|
765
|
+
it 'fails with no credentials' do
|
766
766
|
delete :destroy, params: { id: 1 }, as: :json
|
767
767
|
|
768
768
|
expect(response.status).to eq 401
|
769
769
|
end
|
770
770
|
|
771
|
-
it
|
772
|
-
request.env[
|
771
|
+
it 'fails with invalid credentials' do
|
772
|
+
request.env['HTTP_AUTHORIZATION'] =
|
773
773
|
ActionController::HttpAuthentication::Basic
|
774
|
-
.encode_credentials(
|
774
|
+
.encode_credentials('unauthorized', '123456')
|
775
775
|
|
776
776
|
delete :destroy, params: { id: 1 }, as: :json
|
777
777
|
|
@@ -787,7 +787,6 @@ RSpec.describe ScimRails::ScimUsersController, type: :controller do
|
|
787
787
|
end
|
788
788
|
|
789
789
|
context 'when User destroy method is configured' do
|
790
|
-
|
791
790
|
it 'is sucessful with valid credentials' do
|
792
791
|
delete :destroy, params: { id: 1 }, as: :json
|
793
792
|
|
@@ -811,7 +810,7 @@ RSpec.describe ScimRails::ScimUsersController, type: :controller do
|
|
811
810
|
|
812
811
|
context 'when User destroy method is not configured' do
|
813
812
|
it 'does not delete User' do
|
814
|
-
allow(
|
813
|
+
allow(Scimaenaga.config).to(
|
815
814
|
receive(:user_destroy_method).and_return(nil)
|
816
815
|
)
|
817
816
|
|
@@ -825,7 +824,7 @@ RSpec.describe ScimRails::ScimUsersController, type: :controller do
|
|
825
824
|
|
826
825
|
context 'when User destroy method is invalid' do
|
827
826
|
it 'does not delete User' do
|
828
|
-
allow(
|
827
|
+
allow(Scimaenaga.config).to(
|
829
828
|
receive(:user_destroy_method).and_return('destory!')
|
830
829
|
)
|
831
830
|
|
@@ -840,7 +839,7 @@ RSpec.describe ScimRails::ScimUsersController, type: :controller do
|
|
840
839
|
context 'when target User is not found' do
|
841
840
|
it 'return 404 not found' do
|
842
841
|
expect do
|
843
|
-
delete :destroy, params: { id:
|
842
|
+
delete :destroy, params: { id: 999_999 }, as: :json
|
844
843
|
end.not_to change { company.users.reload.count }.from(1)
|
845
844
|
|
846
845
|
expect(response.status).to eq 404
|
@@ -1,51 +1,51 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require 'spec_helper'
|
4
4
|
|
5
|
-
RSpec.describe
|
5
|
+
RSpec.describe Scimaenaga::ScimUsersController, type: :request do
|
6
6
|
let(:company) { create(:company) }
|
7
7
|
let(:credentials) do
|
8
8
|
Base64.encode64("#{company.subdomain}:#{company.api_token}")
|
9
9
|
end
|
10
10
|
let(:authorization) { "Basic #{credentials}" }
|
11
11
|
|
12
|
-
def post_request(content_type =
|
12
|
+
def post_request(content_type = 'application/scim+json')
|
13
13
|
# params need to be transformed into a string to test if they are being parsed by Rack
|
14
14
|
|
15
|
-
post
|
15
|
+
post '/scim/v2/Users',
|
16
16
|
params: {
|
17
17
|
name: {
|
18
|
-
givenName:
|
19
|
-
familyName:
|
18
|
+
givenName: 'New',
|
19
|
+
familyName: 'User',
|
20
20
|
},
|
21
21
|
emails: [
|
22
22
|
{
|
23
|
-
value:
|
23
|
+
value: 'new@example.com',
|
24
24
|
}
|
25
|
-
]
|
25
|
+
],
|
26
26
|
}.to_json,
|
27
27
|
headers: {
|
28
28
|
Authorization: authorization,
|
29
|
-
'Content-Type': content_type
|
29
|
+
'Content-Type': content_type,
|
30
30
|
}
|
31
31
|
end
|
32
32
|
|
33
|
-
describe
|
34
|
-
it
|
33
|
+
describe 'Content-Type' do
|
34
|
+
it 'accepts scim+json' do
|
35
35
|
expect(company.users.count).to eq 0
|
36
36
|
|
37
|
-
post_request(
|
37
|
+
post_request('application/scim+json')
|
38
38
|
|
39
39
|
expect(request.params).to include :name
|
40
40
|
expect(response.status).to eq 201
|
41
|
-
expect(response.media_type).to eq
|
41
|
+
expect(response.media_type).to eq 'application/scim+json'
|
42
42
|
expect(company.users.count).to eq 1
|
43
43
|
end
|
44
44
|
|
45
|
-
it
|
45
|
+
it 'can not parse unfamiliar content types' do
|
46
46
|
expect(company.users.count).to eq 0
|
47
47
|
|
48
|
-
post_request(
|
48
|
+
post_request('text/csv')
|
49
49
|
|
50
50
|
expect(request.params).not_to include :name
|
51
51
|
expect(response.status).to eq 422
|
@@ -53,21 +53,21 @@ RSpec.describe ScimRails::ScimUsersController, type: :request do
|
|
53
53
|
end
|
54
54
|
end
|
55
55
|
|
56
|
-
context
|
57
|
-
context
|
56
|
+
context 'OAuth Bearer Authorization' do
|
57
|
+
context 'with valid token' do
|
58
58
|
let(:authorization) { "Bearer #{company.api_token}" }
|
59
59
|
|
60
|
-
it
|
60
|
+
it 'supports OAuth bearer authorization and succeeds' do
|
61
61
|
expect { post_request }.to change(company.users, :count).from(0).to(1)
|
62
62
|
|
63
63
|
expect(response.status).to eq 201
|
64
64
|
end
|
65
65
|
end
|
66
66
|
|
67
|
-
context
|
67
|
+
context 'with invalid token' do
|
68
68
|
let(:authorization) { "Bearer #{SecureRandom.hex}" }
|
69
69
|
|
70
|
-
it
|
70
|
+
it 'The request fails' do
|
71
71
|
expect { post_request }.not_to change(company.users, :count)
|
72
72
|
|
73
73
|
expect(response.status).to eq 401
|
@@ -3,7 +3,7 @@ require_relative 'boot'
|
|
3
3
|
require 'rails/all'
|
4
4
|
|
5
5
|
Bundler.require(*Rails.groups)
|
6
|
-
require
|
6
|
+
require 'scimaenaga'
|
7
7
|
|
8
8
|
module Dummy
|
9
9
|
class Application < Rails::Application
|
@@ -12,4 +12,3 @@ module Dummy
|
|
12
12
|
# -- all .rb files in that directory are automatically loaded.
|
13
13
|
end
|
14
14
|
end
|
15
|
-
|
@@ -1,7 +1,7 @@
|
|
1
|
-
|
2
|
-
config.basic_auth_model =
|
3
|
-
config.scim_users_model =
|
4
|
-
config.scim_groups_model =
|
1
|
+
Scimaenaga.configure do |config|
|
2
|
+
config.basic_auth_model = 'Company'
|
3
|
+
config.scim_users_model = 'User'
|
4
|
+
config.scim_groups_model = 'Group'
|
5
5
|
|
6
6
|
config.basic_auth_model_searchable_attribute = :subdomain
|
7
7
|
config.basic_auth_model_authenticatable_attribute = :api_token
|
@@ -9,57 +9,57 @@ ScimRails.configure do |config|
|
|
9
9
|
config.scim_users_list_order = :id
|
10
10
|
config.scim_groups_scope = :groups
|
11
11
|
|
12
|
-
config.signing_algorithm =
|
13
|
-
config.signing_secret =
|
12
|
+
config.signing_algorithm = 'HS256'
|
13
|
+
config.signing_secret = '2d6806dd11c2fece2e81b8ca76dcb0062f5b08e28e3264e8ba1c44bbd3578b70'
|
14
14
|
|
15
15
|
config.user_destroy_method = :destroy!
|
16
16
|
config.group_destroy_method = :destroy!
|
17
17
|
|
18
|
-
config.mutable_user_attributes = [
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
18
|
+
config.mutable_user_attributes = %i[
|
19
|
+
first_name
|
20
|
+
last_name
|
21
|
+
email
|
22
|
+
active
|
23
23
|
]
|
24
24
|
|
25
25
|
config.queryable_user_attributes = {
|
26
26
|
userName: :email,
|
27
27
|
givenName: :first_name,
|
28
28
|
familyName: :last_name,
|
29
|
-
email: :email
|
29
|
+
email: :email,
|
30
30
|
}
|
31
31
|
|
32
32
|
config.mutable_user_attributes_schema = {
|
33
33
|
name: {
|
34
34
|
givenName: :first_name,
|
35
|
-
familyName: :last_name
|
35
|
+
familyName: :last_name,
|
36
36
|
},
|
37
37
|
emails: [
|
38
38
|
{
|
39
|
-
value: :email
|
39
|
+
value: :email,
|
40
40
|
}
|
41
41
|
],
|
42
|
-
active: :active
|
42
|
+
active: :active,
|
43
43
|
}
|
44
44
|
|
45
45
|
config.user_schema = {
|
46
|
-
schemas: [
|
46
|
+
schemas: ['urn:ietf:params:scim:schemas:core:2.0:User'],
|
47
47
|
id: :id,
|
48
48
|
userName: :email,
|
49
49
|
name: {
|
50
50
|
givenName: :first_name,
|
51
|
-
familyName: :last_name
|
51
|
+
familyName: :last_name,
|
52
52
|
},
|
53
53
|
emails: [
|
54
54
|
{
|
55
|
-
value: :email
|
56
|
-
}
|
55
|
+
value: :email,
|
56
|
+
}
|
57
57
|
],
|
58
|
-
active: :unarchived
|
58
|
+
active: :unarchived?,
|
59
59
|
}
|
60
60
|
|
61
61
|
config.queryable_group_attributes = {
|
62
|
-
displayName: :name
|
62
|
+
displayName: :name,
|
63
63
|
}
|
64
64
|
|
65
65
|
config.mutable_group_attributes = [
|
@@ -67,21 +67,21 @@ ScimRails.configure do |config|
|
|
67
67
|
]
|
68
68
|
|
69
69
|
config.mutable_group_attributes_schema = {
|
70
|
-
displayName: :name
|
70
|
+
displayName: :name,
|
71
71
|
}
|
72
72
|
|
73
73
|
config.group_member_relation_attribute = :user_ids
|
74
74
|
config.group_member_relation_schema = { value: :user_ids }
|
75
75
|
|
76
76
|
config.group_schema = {
|
77
|
-
schemas: [
|
77
|
+
schemas: ['urn:ietf:params:scim:schemas:core:2.0:Group'],
|
78
78
|
id: :id,
|
79
79
|
displayName: :name,
|
80
|
-
members: :users
|
80
|
+
members: :users,
|
81
81
|
}
|
82
82
|
|
83
83
|
config.group_abbreviated_schema = {
|
84
84
|
value: :id,
|
85
|
-
display: :name
|
85
|
+
display: :name,
|
86
86
|
}
|
87
87
|
end
|
data/spec/dummy/config/routes.rb
CHANGED
data/spec/factories/company.rb
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
FactoryBot.define do
|
2
2
|
factory :company do
|
3
|
-
name {
|
4
|
-
subdomain {
|
3
|
+
name { 'Test Company' }
|
4
|
+
subdomain { 'test' }
|
5
5
|
|
6
6
|
after(:build) do |company|
|
7
|
-
company.api_token =
|
7
|
+
company.api_token = Scimaenaga::Encoder.encode(company)
|
8
8
|
end
|
9
9
|
end
|
10
10
|
end
|