scimaenaga 0.6.2 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/app/controllers/concerns/scim_rails/exception_handler.rb +43 -1
- data/app/controllers/scim_rails/scim_groups_controller.rb +13 -2
- data/app/controllers/scim_rails/scim_users_controller.rb +21 -0
- data/app/libraries/scim_patch.rb +1 -2
- data/app/libraries/scim_patch_operation.rb +105 -36
- data/config/routes.rb +1 -0
- data/lib/scim_rails/config.rb +1 -0
- data/lib/scim_rails/version.rb +1 -1
- data/spec/controllers/scim_rails/scim_groups_controller_spec.rb +25 -7
- data/spec/controllers/scim_rails/scim_users_controller_spec.rb +361 -220
- data/spec/dummy/app/models/user.rb +9 -0
- data/spec/dummy/config/initializers/scim_rails_config.rb +3 -0
- data/spec/dummy/db/development.sqlite3 +0 -0
- data/spec/dummy/db/migrate/20220131090107_add_deletable_to_users.rb +5 -0
- data/spec/dummy/db/schema.rb +2 -1
- data/spec/dummy/db/seeds.rb +10 -1
- data/spec/dummy/db/test.sqlite3 +0 -0
- data/spec/dummy/log/development.log +0 -0
- data/spec/dummy/log/test.log +5770 -0
- data/spec/dummy/put_group.http +5 -0
- data/spec/dummy/tmp/restart.txt +0 -0
- data/spec/factories/user.rb +2 -0
- data/spec/libraries/scim_patch_operation_spec.rb +51 -31
- data/spec/libraries/scim_patch_spec.rb +31 -33
- metadata +81 -67
@@ -1,32 +1,32 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require 'spec_helper'
|
4
4
|
|
5
5
|
RSpec.describe ScimRails::ScimUsersController, type: :controller do
|
6
6
|
include AuthHelper
|
7
7
|
|
8
8
|
routes { ScimRails::Engine.routes }
|
9
9
|
|
10
|
-
describe
|
10
|
+
describe 'index' do
|
11
11
|
let(:company) { create(:company) }
|
12
12
|
|
13
|
-
context
|
14
|
-
it
|
13
|
+
context 'when unauthorized' do
|
14
|
+
it 'returns scim+json content type' do
|
15
15
|
get :index, as: :json
|
16
16
|
|
17
|
-
expect(response.media_type).to eq
|
17
|
+
expect(response.media_type).to eq 'application/scim+json'
|
18
18
|
end
|
19
19
|
|
20
|
-
it
|
20
|
+
it 'fails with no credentials' do
|
21
21
|
get :index, as: :json
|
22
22
|
|
23
23
|
expect(response.status).to eq 401
|
24
24
|
end
|
25
25
|
|
26
|
-
it
|
27
|
-
request.env[
|
26
|
+
it 'fails with invalid credentials' do
|
27
|
+
request.env['HTTP_AUTHORIZATION'] =
|
28
28
|
ActionController::HttpAuthentication::Basic
|
29
|
-
.encode_credentials(
|
29
|
+
.encode_credentials('unauthorized', '123456')
|
30
30
|
|
31
31
|
get :index, as: :json
|
32
32
|
|
@@ -34,56 +34,57 @@ RSpec.describe ScimRails::ScimUsersController, type: :controller do
|
|
34
34
|
end
|
35
35
|
end
|
36
36
|
|
37
|
-
context
|
37
|
+
context 'when when authorized' do
|
38
38
|
before :each do
|
39
39
|
http_login(company)
|
40
40
|
end
|
41
41
|
|
42
|
-
it
|
42
|
+
it 'returns scim+json content type' do
|
43
43
|
get :index, as: :json
|
44
44
|
|
45
|
-
expect(response.media_type).to eq
|
45
|
+
expect(response.media_type).to eq 'application/scim+json'
|
46
46
|
end
|
47
47
|
|
48
|
-
it
|
48
|
+
it 'is successful with valid credentials' do
|
49
49
|
get :index, as: :json
|
50
50
|
|
51
51
|
expect(response.status).to eq 200
|
52
52
|
end
|
53
53
|
|
54
|
-
it
|
54
|
+
it 'returns all results' do
|
55
55
|
create_list(:user, 10, company: company)
|
56
56
|
|
57
57
|
get :index, as: :json
|
58
58
|
response_body = JSON.parse(response.body)
|
59
|
-
expect(response_body.dig(
|
60
|
-
|
59
|
+
expect(response_body.dig('schemas',
|
60
|
+
0)).to eq 'urn:ietf:params:scim:api:messages:2.0:ListResponse'
|
61
|
+
expect(response_body['totalResults']).to eq 10
|
61
62
|
end
|
62
63
|
|
63
|
-
it
|
64
|
+
it 'defaults to 100 results' do
|
64
65
|
create_list(:user, 300, company: company)
|
65
66
|
|
66
67
|
get :index, as: :json
|
67
68
|
response_body = JSON.parse(response.body)
|
68
|
-
expect(response_body[
|
69
|
-
expect(response_body[
|
69
|
+
expect(response_body['totalResults']).to eq 300
|
70
|
+
expect(response_body['Resources'].count).to eq 100
|
70
71
|
end
|
71
72
|
|
72
|
-
it
|
73
|
+
it 'paginates results' do
|
73
74
|
create_list(:user, 400, company: company)
|
74
75
|
expect(company.users.first.id).to eq 1
|
75
76
|
|
76
77
|
get :index, params: {
|
77
78
|
startIndex: 101,
|
78
|
-
count: 200
|
79
|
+
count: 200,
|
79
80
|
}, as: :json
|
80
81
|
response_body = JSON.parse(response.body)
|
81
|
-
expect(response_body[
|
82
|
-
expect(response_body[
|
83
|
-
expect(response_body.dig(
|
82
|
+
expect(response_body['totalResults']).to eq 400
|
83
|
+
expect(response_body['Resources'].count).to eq 200
|
84
|
+
expect(response_body.dig('Resources', 0, 'id')).to eq 101
|
84
85
|
end
|
85
86
|
|
86
|
-
it
|
87
|
+
it 'paginates results by configurable scim_users_list_order' do
|
87
88
|
allow(ScimRails.config).to receive(:scim_users_list_order).and_return({ created_at: :desc })
|
88
89
|
|
89
90
|
create_list(:user, 400, company: company)
|
@@ -91,78 +92,79 @@ RSpec.describe ScimRails::ScimUsersController, type: :controller do
|
|
91
92
|
|
92
93
|
get :index, params: {
|
93
94
|
startIndex: 1,
|
94
|
-
count: 10
|
95
|
+
count: 10,
|
95
96
|
}, as: :json
|
96
97
|
response_body = JSON.parse(response.body)
|
97
|
-
expect(response_body[
|
98
|
-
expect(response_body[
|
99
|
-
expect(response_body.dig(
|
98
|
+
expect(response_body['totalResults']).to eq 400
|
99
|
+
expect(response_body['Resources'].count).to eq 10
|
100
|
+
expect(response_body.dig('Resources', 0, 'id')).to eq 400
|
100
101
|
end
|
101
102
|
|
102
|
-
it
|
103
|
-
create(:user, email:
|
104
|
-
create(:user, email:
|
103
|
+
it 'filters results by provided email filter' do
|
104
|
+
create(:user, email: 'test1@example.com', company: company)
|
105
|
+
create(:user, email: 'test2@example.com', company: company)
|
105
106
|
|
106
107
|
get :index, params: {
|
107
|
-
filter:
|
108
|
+
filter: 'email eq test1@example.com',
|
108
109
|
}, as: :json
|
109
110
|
response_body = JSON.parse(response.body)
|
110
|
-
expect(response_body[
|
111
|
-
expect(response_body[
|
111
|
+
expect(response_body['totalResults']).to eq 1
|
112
|
+
expect(response_body['Resources'].count).to eq 1
|
112
113
|
end
|
113
114
|
|
114
|
-
it
|
115
|
-
create(:user, first_name:
|
116
|
-
create(:user, first_name:
|
115
|
+
it 'filters results by provided name filter' do
|
116
|
+
create(:user, first_name: 'Chidi', last_name: 'Anagonye', company: company)
|
117
|
+
create(:user, first_name: 'Eleanor', last_name: 'Shellstrop', company: company)
|
117
118
|
|
118
119
|
get :index, params: {
|
119
|
-
filter:
|
120
|
+
filter: 'familyName eq Shellstrop',
|
120
121
|
}, as: :json
|
121
122
|
response_body = JSON.parse(response.body)
|
122
|
-
expect(response_body[
|
123
|
-
expect(response_body[
|
123
|
+
expect(response_body['totalResults']).to eq 1
|
124
|
+
expect(response_body['Resources'].count).to eq 1
|
124
125
|
end
|
125
126
|
|
126
|
-
it
|
127
|
+
it 'returns no results for unfound filter parameters' do
|
127
128
|
get :index, params: {
|
128
|
-
filter:
|
129
|
+
filter: 'familyName eq fake_not_there',
|
129
130
|
}, as: :json
|
130
131
|
response_body = JSON.parse(response.body)
|
131
|
-
expect(response_body[
|
132
|
-
expect(response_body[
|
132
|
+
expect(response_body['totalResults']).to eq 0
|
133
|
+
expect(response_body['Resources'].count).to eq 0
|
133
134
|
end
|
134
135
|
|
135
|
-
it
|
136
|
+
it 'returns no results for undefined filter queries' do
|
136
137
|
get :index, params: {
|
137
|
-
filter:
|
138
|
+
filter: 'address eq 101 Nowhere USA',
|
138
139
|
}, as: :json
|
139
140
|
expect(response.status).to eq 400
|
140
141
|
response_body = JSON.parse(response.body)
|
141
|
-
expect(response_body.dig(
|
142
|
+
expect(response_body.dig('schemas',
|
143
|
+
0)).to eq 'urn:ietf:params:scim:api:messages:2.0:Error'
|
142
144
|
end
|
143
145
|
end
|
144
146
|
end
|
145
147
|
|
146
|
-
describe
|
148
|
+
describe 'show' do
|
147
149
|
let(:company) { create(:company) }
|
148
150
|
|
149
|
-
context
|
150
|
-
it
|
151
|
+
context 'when unauthorized' do
|
152
|
+
it 'returns scim+json content type' do
|
151
153
|
get :show, params: { id: 1 }, as: :json
|
152
154
|
|
153
|
-
expect(response.media_type).to eq
|
155
|
+
expect(response.media_type).to eq 'application/scim+json'
|
154
156
|
end
|
155
157
|
|
156
|
-
it
|
158
|
+
it 'fails with no credentials' do
|
157
159
|
get :show, params: { id: 1 }, as: :json
|
158
160
|
|
159
161
|
expect(response.status).to eq 401
|
160
162
|
end
|
161
163
|
|
162
|
-
it
|
163
|
-
request.env[
|
164
|
+
it 'fails with invalid credentials' do
|
165
|
+
request.env['HTTP_AUTHORIZATION'] =
|
164
166
|
ActionController::HttpAuthentication::Basic
|
165
|
-
.encode_credentials(
|
167
|
+
.encode_credentials('unauthorized', '123456')
|
166
168
|
|
167
169
|
get :show, params: { id: 1 }, as: :json
|
168
170
|
|
@@ -170,31 +172,31 @@ RSpec.describe ScimRails::ScimUsersController, type: :controller do
|
|
170
172
|
end
|
171
173
|
end
|
172
174
|
|
173
|
-
context
|
175
|
+
context 'when authorized' do
|
174
176
|
before :each do
|
175
177
|
http_login(company)
|
176
178
|
end
|
177
179
|
|
178
|
-
it
|
180
|
+
it 'returns scim+json content type' do
|
179
181
|
get :show, params: { id: 1 }, as: :json
|
180
182
|
|
181
|
-
expect(response.media_type).to eq
|
183
|
+
expect(response.media_type).to eq 'application/scim+json'
|
182
184
|
end
|
183
185
|
|
184
|
-
it
|
186
|
+
it 'is successful with valid credentials' do
|
185
187
|
create(:user, id: 1, company: company)
|
186
188
|
get :show, params: { id: 1 }, as: :json
|
187
189
|
|
188
190
|
expect(response.status).to eq 200
|
189
191
|
end
|
190
192
|
|
191
|
-
it
|
192
|
-
get :show, params: { id:
|
193
|
+
it 'returns :not_found for id that cannot be found' do
|
194
|
+
get :show, params: { id: 'fake_id' }, as: :json
|
193
195
|
|
194
196
|
expect(response.status).to eq 404
|
195
197
|
end
|
196
198
|
|
197
|
-
it
|
199
|
+
it 'returns :not_found for a correct id but unauthorized company' do
|
198
200
|
new_company = create(:company)
|
199
201
|
create(:user, company: new_company, id: 1)
|
200
202
|
|
@@ -205,26 +207,26 @@ RSpec.describe ScimRails::ScimUsersController, type: :controller do
|
|
205
207
|
end
|
206
208
|
end
|
207
209
|
|
208
|
-
describe
|
210
|
+
describe 'create' do
|
209
211
|
let(:company) { create(:company) }
|
210
212
|
|
211
|
-
context
|
212
|
-
it
|
213
|
+
context 'when unauthorized' do
|
214
|
+
it 'returns scim+json content type' do
|
213
215
|
post :create, as: :json
|
214
216
|
|
215
|
-
expect(response.media_type).to eq
|
217
|
+
expect(response.media_type).to eq 'application/scim+json'
|
216
218
|
end
|
217
219
|
|
218
|
-
it
|
220
|
+
it 'fails with no credentials' do
|
219
221
|
post :create, as: :json
|
220
222
|
|
221
223
|
expect(response.status).to eq 401
|
222
224
|
end
|
223
225
|
|
224
|
-
it
|
225
|
-
request.env[
|
226
|
+
it 'fails with invalid credentials' do
|
227
|
+
request.env['HTTP_AUTHORIZATION'] =
|
226
228
|
ActionController::HttpAuthentication::Basic
|
227
|
-
.encode_credentials(
|
229
|
+
.encode_credentials('unauthorized', '123456')
|
228
230
|
|
229
231
|
post :create, as: :json
|
230
232
|
|
@@ -232,139 +234,139 @@ RSpec.describe ScimRails::ScimUsersController, type: :controller do
|
|
232
234
|
end
|
233
235
|
end
|
234
236
|
|
235
|
-
context
|
237
|
+
context 'when authorized' do
|
236
238
|
before :each do
|
237
239
|
http_login(company)
|
238
240
|
end
|
239
241
|
|
240
|
-
it
|
242
|
+
it 'returns scim+json content type' do
|
241
243
|
post :create, params: {
|
242
244
|
name: {
|
243
|
-
givenName:
|
244
|
-
familyName:
|
245
|
+
givenName: 'New',
|
246
|
+
familyName: 'User',
|
245
247
|
},
|
246
248
|
emails: [
|
247
249
|
{
|
248
|
-
value:
|
250
|
+
value: 'new@example.com',
|
249
251
|
}
|
250
|
-
]
|
252
|
+
],
|
251
253
|
}, as: :json
|
252
254
|
|
253
|
-
expect(response.media_type).to eq
|
255
|
+
expect(response.media_type).to eq 'application/scim+json'
|
254
256
|
end
|
255
257
|
|
256
|
-
it
|
258
|
+
it 'is successful with valid credentials' do
|
257
259
|
expect(company.users.count).to eq 0
|
258
260
|
|
259
261
|
post :create, params: {
|
260
262
|
name: {
|
261
|
-
givenName:
|
262
|
-
familyName:
|
263
|
+
givenName: 'New',
|
264
|
+
familyName: 'User',
|
263
265
|
},
|
264
266
|
emails: [
|
265
267
|
{
|
266
|
-
value:
|
268
|
+
value: 'new@example.com',
|
267
269
|
}
|
268
|
-
]
|
270
|
+
],
|
269
271
|
}, as: :json
|
270
272
|
|
271
273
|
expect(response.status).to eq 201
|
272
274
|
expect(company.users.count).to eq 1
|
273
275
|
user = company.users.first
|
274
276
|
expect(user.persisted?).to eq true
|
275
|
-
expect(user.first_name).to eq
|
276
|
-
expect(user.last_name).to eq
|
277
|
-
expect(user.email).to eq
|
277
|
+
expect(user.first_name).to eq 'New'
|
278
|
+
expect(user.last_name).to eq 'User'
|
279
|
+
expect(user.email).to eq 'new@example.com'
|
278
280
|
end
|
279
281
|
|
280
|
-
it
|
282
|
+
it 'ignores unconfigured params' do
|
281
283
|
post :create, params: {
|
282
284
|
name: {
|
283
|
-
formattedName:
|
284
|
-
givenName:
|
285
|
-
familyName:
|
285
|
+
formattedName: 'New User',
|
286
|
+
givenName: 'New',
|
287
|
+
familyName: 'User',
|
286
288
|
},
|
287
289
|
emails: [
|
288
290
|
{
|
289
|
-
value:
|
291
|
+
value: 'new@example.com',
|
290
292
|
}
|
291
|
-
]
|
293
|
+
],
|
292
294
|
}, as: :json
|
293
295
|
|
294
296
|
expect(response.status).to eq 201
|
295
297
|
expect(company.users.count).to eq 1
|
296
298
|
end
|
297
299
|
|
298
|
-
it
|
300
|
+
it 'returns 422 if required params are missing' do
|
299
301
|
post :create, params: {
|
300
302
|
name: {
|
301
|
-
familyName:
|
303
|
+
familyName: 'User',
|
302
304
|
},
|
303
305
|
emails: [
|
304
306
|
{
|
305
|
-
value:
|
307
|
+
value: 'new@example.com',
|
306
308
|
}
|
307
|
-
]
|
309
|
+
],
|
308
310
|
}, as: :json
|
309
311
|
|
310
312
|
expect(response.status).to eq 422
|
311
313
|
expect(company.users.count).to eq 0
|
312
314
|
end
|
313
315
|
|
314
|
-
it
|
315
|
-
create(:user, email:
|
316
|
+
it 'returns 201 if user already exists and updates user' do
|
317
|
+
create(:user, email: 'new@example.com', company: company)
|
316
318
|
|
317
319
|
post :create, params: {
|
318
320
|
name: {
|
319
|
-
givenName:
|
320
|
-
familyName:
|
321
|
+
givenName: 'Not New',
|
322
|
+
familyName: 'User',
|
321
323
|
},
|
322
324
|
emails: [
|
323
325
|
{
|
324
|
-
value:
|
326
|
+
value: 'new@example.com',
|
325
327
|
}
|
326
|
-
]
|
328
|
+
],
|
327
329
|
}, as: :json
|
328
330
|
|
329
331
|
expect(response.status).to eq 201
|
330
332
|
expect(company.users.count).to eq 1
|
331
|
-
expect(company.users.first.first_name).to eq
|
333
|
+
expect(company.users.first.first_name).to eq 'Not New'
|
332
334
|
end
|
333
335
|
|
334
|
-
it
|
336
|
+
it 'returns 409 if user already exists and config.scim_user_prevent_update_on_create is set to true' do
|
335
337
|
allow(ScimRails.config).to receive(:scim_user_prevent_update_on_create).and_return(true)
|
336
|
-
create(:user, email:
|
338
|
+
create(:user, email: 'new@example.com', company: company)
|
337
339
|
|
338
340
|
post :create, params: {
|
339
341
|
name: {
|
340
|
-
givenName:
|
341
|
-
familyName:
|
342
|
+
givenName: 'Not New',
|
343
|
+
familyName: 'User',
|
342
344
|
},
|
343
345
|
emails: [
|
344
346
|
{
|
345
|
-
value:
|
347
|
+
value: 'new@example.com',
|
346
348
|
}
|
347
|
-
]
|
349
|
+
],
|
348
350
|
}, as: :json
|
349
351
|
|
350
352
|
expect(response.status).to eq 409
|
351
353
|
expect(company.users.count).to eq 1
|
352
354
|
end
|
353
355
|
|
354
|
-
it
|
356
|
+
it 'creates and archives inactive user' do
|
355
357
|
post :create, params: {
|
356
358
|
id: 1,
|
357
|
-
userName:
|
359
|
+
userName: 'test@example.com',
|
358
360
|
name: {
|
359
|
-
givenName:
|
360
|
-
familyName:
|
361
|
+
givenName: 'Test',
|
362
|
+
familyName: 'User',
|
361
363
|
},
|
362
364
|
emails: [
|
363
365
|
{
|
364
|
-
value:
|
366
|
+
value: 'test@example.com',
|
365
367
|
}
|
366
368
|
],
|
367
|
-
active: false
|
369
|
+
active: false,
|
368
370
|
}, as: :json
|
369
371
|
|
370
372
|
expect(response.status).to eq 201
|
@@ -375,26 +377,26 @@ RSpec.describe ScimRails::ScimUsersController, type: :controller do
|
|
375
377
|
end
|
376
378
|
end
|
377
379
|
|
378
|
-
describe
|
380
|
+
describe 'put update' do
|
379
381
|
let(:company) { create(:company) }
|
380
382
|
|
381
|
-
context
|
382
|
-
it
|
383
|
+
context 'when unauthorized' do
|
384
|
+
it 'returns scim+json content type' do
|
383
385
|
put :put_update, params: { id: 1 }, as: :json
|
384
386
|
|
385
|
-
expect(response.media_type).to eq
|
387
|
+
expect(response.media_type).to eq 'application/scim+json'
|
386
388
|
end
|
387
389
|
|
388
|
-
it
|
390
|
+
it 'fails with no credentials' do
|
389
391
|
put :put_update, params: { id: 1 }, as: :json
|
390
392
|
|
391
393
|
expect(response.status).to eq 401
|
392
394
|
end
|
393
395
|
|
394
|
-
it
|
395
|
-
request.env[
|
396
|
+
it 'fails with invalid credentials' do
|
397
|
+
request.env['HTTP_AUTHORIZATION'] =
|
396
398
|
ActionController::HttpAuthentication::Basic
|
397
|
-
.encode_credentials(
|
399
|
+
.encode_credentials('unauthorized', '123456')
|
398
400
|
|
399
401
|
put :put_update, params: { id: 1 }, as: :json
|
400
402
|
|
@@ -402,56 +404,56 @@ RSpec.describe ScimRails::ScimUsersController, type: :controller do
|
|
402
404
|
end
|
403
405
|
end
|
404
406
|
|
405
|
-
context
|
407
|
+
context 'when authorized' do
|
406
408
|
let!(:user) { create(:user, id: 1, company: company) }
|
407
409
|
|
408
410
|
before :each do
|
409
411
|
http_login(company)
|
410
412
|
end
|
411
413
|
|
412
|
-
it
|
414
|
+
it 'returns scim+json content type' do
|
413
415
|
put :put_update, params: put_params, as: :json
|
414
416
|
|
415
|
-
expect(response.media_type).to eq
|
417
|
+
expect(response.media_type).to eq 'application/scim+json'
|
416
418
|
end
|
417
419
|
|
418
|
-
it
|
420
|
+
it 'is successful with valid credentials' do
|
419
421
|
put :put_update, params: put_params, as: :json
|
420
422
|
|
421
423
|
expect(response.status).to eq 200
|
422
424
|
end
|
423
425
|
|
424
|
-
it
|
426
|
+
it 'successfully change user email' do
|
425
427
|
put :put_update, params: put_params(id: user.id), as: :json
|
426
428
|
|
427
429
|
expect(user.reload.email).to eq 'test@example.com'
|
428
430
|
end
|
429
431
|
|
430
|
-
it
|
431
|
-
request.content_type =
|
432
|
+
it 'deprovisions an active record' do
|
433
|
+
request.content_type = 'application/scim+json'
|
432
434
|
put :put_update, params: put_params(active: false), as: :json
|
433
435
|
|
434
436
|
expect(response.status).to eq 200
|
435
437
|
expect(user.reload.active?).to eq false
|
436
438
|
end
|
437
439
|
|
438
|
-
it
|
440
|
+
it 'reprovisions an inactive record' do
|
439
441
|
user.archive!
|
440
442
|
expect(user.reload.active?).to eq false
|
441
|
-
request.content_type =
|
443
|
+
request.content_type = 'application/scim+json'
|
442
444
|
put :put_update, params: put_params(active: true), as: :json
|
443
445
|
|
444
446
|
expect(response.status).to eq 200
|
445
447
|
expect(user.reload.active?).to eq true
|
446
448
|
end
|
447
449
|
|
448
|
-
it
|
449
|
-
put :put_update, params: { id:
|
450
|
+
it 'returns :not_found for id that cannot be found' do
|
451
|
+
put :put_update, params: { id: 'fake_id' }, as: :json
|
450
452
|
|
451
453
|
expect(response.status).to eq 404
|
452
454
|
end
|
453
455
|
|
454
|
-
it
|
456
|
+
it 'returns :not_found for a correct id but unauthorized company' do
|
455
457
|
new_company = create(:company)
|
456
458
|
create(:user, company: new_company, id: 1000)
|
457
459
|
|
@@ -460,16 +462,16 @@ RSpec.describe ScimRails::ScimUsersController, type: :controller do
|
|
460
462
|
expect(response.status).to eq 404
|
461
463
|
end
|
462
464
|
|
463
|
-
it
|
465
|
+
it 'is returns 422 with incomplete request' do
|
464
466
|
put :put_update, params: {
|
465
467
|
id: 1,
|
466
|
-
userName:
|
468
|
+
userName: 'test@example.com',
|
467
469
|
emails: [
|
468
470
|
{
|
469
|
-
value:
|
471
|
+
value: 'test@example.com',
|
470
472
|
}
|
471
473
|
],
|
472
|
-
active:
|
474
|
+
active: 'true',
|
473
475
|
}, as: :json
|
474
476
|
|
475
477
|
expect(response.status).to eq 422
|
@@ -477,26 +479,26 @@ RSpec.describe ScimRails::ScimUsersController, type: :controller do
|
|
477
479
|
end
|
478
480
|
end
|
479
481
|
|
480
|
-
describe
|
482
|
+
describe 'patch update' do
|
481
483
|
let(:company) { create(:company) }
|
482
484
|
|
483
|
-
context
|
484
|
-
it
|
485
|
+
context 'when unauthorized' do
|
486
|
+
it 'returns scim+json content type' do
|
485
487
|
patch :patch_update, params: patch_params(id: 1), as: :json
|
486
488
|
|
487
|
-
expect(response.media_type).to eq
|
489
|
+
expect(response.media_type).to eq 'application/scim+json'
|
488
490
|
end
|
489
491
|
|
490
|
-
it
|
492
|
+
it 'fails with no credentials' do
|
491
493
|
patch :patch_update, params: patch_params(id: 1), as: :json
|
492
494
|
|
493
495
|
expect(response.status).to eq 401
|
494
496
|
end
|
495
497
|
|
496
|
-
it
|
497
|
-
request.env[
|
498
|
+
it 'fails with invalid credentials' do
|
499
|
+
request.env['HTTP_AUTHORIZATION'] =
|
498
500
|
ActionController::HttpAuthentication::Basic
|
499
|
-
.encode_credentials(
|
501
|
+
.encode_credentials('unauthorized', '123456')
|
500
502
|
|
501
503
|
patch :patch_update, params: patch_params(id: 1), as: :json
|
502
504
|
|
@@ -504,20 +506,20 @@ RSpec.describe ScimRails::ScimUsersController, type: :controller do
|
|
504
506
|
end
|
505
507
|
end
|
506
508
|
|
507
|
-
context
|
509
|
+
context 'when authorized' do
|
508
510
|
let!(:user) { create(:user, id: 1, company: company) }
|
509
511
|
|
510
512
|
before :each do
|
511
513
|
http_login(company)
|
512
514
|
end
|
513
515
|
|
514
|
-
it
|
516
|
+
it 'returns scim+json content type' do
|
515
517
|
patch :patch_update, params: patch_params(id: user.id), as: :json
|
516
518
|
|
517
|
-
expect(response.media_type).to eq
|
519
|
+
expect(response.media_type).to eq 'application/scim+json'
|
518
520
|
end
|
519
521
|
|
520
|
-
it
|
522
|
+
it 'is successful with valid credentials' do
|
521
523
|
patch :patch_update, params: patch_params(id: user.id), as: :json
|
522
524
|
|
523
525
|
expect(response.status).to eq 200
|
@@ -526,33 +528,33 @@ RSpec.describe ScimRails::ScimUsersController, type: :controller do
|
|
526
528
|
it 'rollback all changes when contains any invalid operation' do
|
527
529
|
expect do
|
528
530
|
patch :patch_update, params: {
|
529
|
-
schemas: [
|
531
|
+
schemas: ['urn:ietf:params:scim:api:messages:2.0:PatchOp'],
|
530
532
|
id: user.id,
|
531
533
|
Operations: [
|
532
534
|
{
|
533
|
-
op:
|
534
|
-
path:
|
535
|
-
value:
|
535
|
+
op: 'Replace',
|
536
|
+
path: 'emails[type eq "work"].value',
|
537
|
+
value: 'change@example.com',
|
536
538
|
},
|
537
539
|
{
|
538
|
-
op:
|
539
|
-
value:
|
540
|
+
op: 'Replace',
|
541
|
+
value: 'hoge',
|
540
542
|
}
|
541
|
-
]
|
543
|
+
],
|
542
544
|
},
|
543
|
-
|
545
|
+
as: :json
|
544
546
|
end.to_not change { user.reload.email }
|
545
547
|
|
546
548
|
expect(response.status).to eq 422
|
547
549
|
end
|
548
550
|
|
549
|
-
it
|
550
|
-
get :patch_update, params: patch_params(id:
|
551
|
+
it 'returns :not_found for id that cannot be found' do
|
552
|
+
get :patch_update, params: patch_params(id: 'fake_id'), as: :json
|
551
553
|
|
552
554
|
expect(response.status).to eq 404
|
553
555
|
end
|
554
556
|
|
555
|
-
it
|
557
|
+
it 'returns :not_found for a correct id but unauthorized company' do
|
556
558
|
new_company = create(:company)
|
557
559
|
create(:user, company: new_company, id: 1000)
|
558
560
|
|
@@ -561,7 +563,7 @@ RSpec.describe ScimRails::ScimUsersController, type: :controller do
|
|
561
563
|
expect(response.status).to eq 404
|
562
564
|
end
|
563
565
|
|
564
|
-
it
|
566
|
+
it 'successfully archives user' do
|
565
567
|
expect(company.users.count).to eq 1
|
566
568
|
user = company.users.first
|
567
569
|
expect(user.archived?).to eq false
|
@@ -577,7 +579,7 @@ RSpec.describe ScimRails::ScimUsersController, type: :controller do
|
|
577
579
|
expect(user.archived?).to eq true
|
578
580
|
end
|
579
581
|
|
580
|
-
it
|
582
|
+
it 'successfully restores user' do
|
581
583
|
expect(company.users.count).to eq 1
|
582
584
|
user = company.users.first.tap(&:archive!)
|
583
585
|
expect(user.archived?).to eq true
|
@@ -593,7 +595,7 @@ RSpec.describe ScimRails::ScimUsersController, type: :controller do
|
|
593
595
|
expect(user.archived?).to eq false
|
594
596
|
end
|
595
597
|
|
596
|
-
it
|
598
|
+
it 'successfully change user email' do
|
597
599
|
expect(company.users.count).to eq 1
|
598
600
|
user = company.users.first
|
599
601
|
user.update(email: 'test@example.com')
|
@@ -610,19 +612,19 @@ RSpec.describe ScimRails::ScimUsersController, type: :controller do
|
|
610
612
|
expect(user.email).to eq 'change@example.com'
|
611
613
|
end
|
612
614
|
|
613
|
-
it
|
615
|
+
it 'is case insensetive for op value' do
|
614
616
|
# Note, this is for backward compatibility. op should always
|
615
617
|
# be lower case and support for case insensitivity will be removed
|
616
618
|
patch :patch_update, params: {
|
617
|
-
schemas: [
|
619
|
+
schemas: ['urn:ietf:params:scim:api:messages:2.0:PatchOp'],
|
618
620
|
id: 1,
|
619
621
|
Operations: [
|
620
|
-
|
621
|
-
op:
|
622
|
-
path:
|
623
|
-
value:
|
622
|
+
{
|
623
|
+
op: 'Replace',
|
624
|
+
path: 'emails[type eq "work"].value',
|
625
|
+
value: 'test@example.com',
|
624
626
|
}
|
625
|
-
]
|
627
|
+
],
|
626
628
|
}, as: :json
|
627
629
|
|
628
630
|
expect(response.status).to eq 200
|
@@ -631,137 +633,276 @@ RSpec.describe ScimRails::ScimUsersController, type: :controller do
|
|
631
633
|
it "don't update if not included in mutable attributes" do
|
632
634
|
expect do
|
633
635
|
patch :patch_update, params: {
|
634
|
-
schemas: [
|
636
|
+
schemas: ['urn:ietf:params:scim:api:messages:2.0:PatchOp'],
|
635
637
|
id: user.id,
|
636
638
|
Operations: [
|
637
639
|
{
|
638
|
-
op:
|
639
|
-
path:
|
640
|
-
value:
|
640
|
+
op: 'Replace',
|
641
|
+
path: 'emails[type eq "work"].value',
|
642
|
+
value: 'change@example.com',
|
641
643
|
},
|
642
644
|
{
|
643
|
-
op:
|
644
|
-
path:
|
645
|
-
value:
|
646
|
-
}
|
647
|
-
]
|
645
|
+
op: 'Replace',
|
646
|
+
path: 'country',
|
647
|
+
value: 'Japan',
|
648
|
+
}
|
649
|
+
],
|
648
650
|
}, as: :json
|
649
651
|
end.not_to change { user.reload.country }
|
650
652
|
|
651
653
|
expect(response.status).to eq 422
|
652
654
|
end
|
653
655
|
|
654
|
-
xit
|
656
|
+
xit 'returns 422 when value is not an object' do
|
655
657
|
patch :patch_update, params: {
|
656
|
-
schemas: [
|
658
|
+
schemas: ['urn:ietf:params:scim:api:messages:2.0:PatchOp'],
|
657
659
|
id: 1,
|
658
660
|
Operations: [
|
659
661
|
{
|
660
|
-
op:
|
661
|
-
path:
|
662
|
-
value:
|
662
|
+
op: 'replace',
|
663
|
+
path: 'emails[type eq "work"].value',
|
664
|
+
value: 'francis@example.com',
|
663
665
|
}
|
664
|
-
]
|
666
|
+
],
|
665
667
|
}
|
666
668
|
|
667
669
|
expect(response.status).to eq 422
|
668
670
|
response_body = JSON.parse(response.body)
|
669
|
-
expect(response_body.dig(
|
671
|
+
expect(response_body.dig('schemas',
|
672
|
+
0)).to eq 'urn:ietf:params:scim:api:messages:2.0:Error'
|
670
673
|
end
|
671
674
|
|
672
|
-
it
|
675
|
+
it 'returns 422 when value is missing' do
|
673
676
|
patch :patch_update, params: {
|
674
|
-
schemas: [
|
677
|
+
schemas: ['urn:ietf:params:scim:api:messages:2.0:PatchOp'],
|
675
678
|
id: 1,
|
676
679
|
Operations: [
|
677
680
|
{
|
678
|
-
op:
|
679
|
-
path:
|
681
|
+
op: 'replace',
|
682
|
+
path: 'emails[type eq "work"].value',
|
680
683
|
}
|
681
|
-
]
|
684
|
+
],
|
682
685
|
}, as: :json
|
683
686
|
|
684
687
|
expect(response.status).to eq 422
|
685
688
|
response_body = JSON.parse(response.body)
|
686
|
-
expect(response_body.dig(
|
689
|
+
expect(response_body.dig('schemas',
|
690
|
+
0)).to eq 'urn:ietf:params:scim:api:messages:2.0:Error'
|
687
691
|
end
|
688
692
|
|
689
|
-
it
|
693
|
+
it 'returns 422 when path is missing' do
|
690
694
|
patch :patch_update, params: {
|
691
|
-
schemas: [
|
695
|
+
schemas: ['urn:ietf:params:scim:api:messages:2.0:PatchOp'],
|
692
696
|
id: 1,
|
693
697
|
Operations: [
|
694
698
|
{
|
695
|
-
op:
|
699
|
+
op: 'replace',
|
696
700
|
}
|
697
|
-
]
|
701
|
+
],
|
698
702
|
}, as: :json
|
699
703
|
|
700
704
|
expect(response.status).to eq 422
|
701
705
|
response_body = JSON.parse(response.body)
|
702
|
-
expect(response_body.dig(
|
706
|
+
expect(response_body.dig('schemas',
|
707
|
+
0)).to eq 'urn:ietf:params:scim:api:messages:2.0:Error'
|
703
708
|
end
|
704
709
|
|
705
|
-
it
|
710
|
+
it 'returns 422 operations key is missing' do
|
706
711
|
patch :patch_update, params: {
|
707
|
-
schemas: [
|
712
|
+
schemas: ['urn:ietf:params:scim:api:messages:2.0:PatchOp'],
|
708
713
|
id: 1,
|
709
714
|
Foobars: [
|
710
715
|
{
|
711
|
-
op:
|
716
|
+
op: 'replace',
|
712
717
|
}
|
713
|
-
]
|
718
|
+
],
|
714
719
|
}, as: :json
|
715
720
|
|
716
721
|
expect(response.status).to eq 422
|
717
722
|
response_body = JSON.parse(response.body)
|
718
|
-
expect(response_body.dig(
|
723
|
+
expect(response_body.dig('schemas',
|
724
|
+
0)).to eq 'urn:ietf:params:scim:api:messages:2.0:Error'
|
725
|
+
end
|
726
|
+
|
727
|
+
it 'successfully change multiple attributes' do
|
728
|
+
patch :patch_update, params: {
|
729
|
+
schemas: ['urn:ietf:params:scim:api:messages:2.0:PatchOp'],
|
730
|
+
id: 1,
|
731
|
+
Operations: [
|
732
|
+
{
|
733
|
+
op: 'Replace',
|
734
|
+
path: 'emails[type eq "work"].value',
|
735
|
+
value: 'changed@example.com',
|
736
|
+
},
|
737
|
+
{
|
738
|
+
op: 'Replace',
|
739
|
+
value: {
|
740
|
+
'name.givenName': 'changedGivenName',
|
741
|
+
'name.familyName': 'changedFamilyName',
|
742
|
+
},
|
743
|
+
}
|
744
|
+
],
|
745
|
+
}, as: :json
|
746
|
+
|
747
|
+
user.reload
|
748
|
+
expect(user.email).to eq 'changed@example.com'
|
749
|
+
expect(user.first_name).to eq 'changedGivenName'
|
750
|
+
expect(user.last_name).to eq 'changedFamilyName'
|
751
|
+
end
|
752
|
+
end
|
753
|
+
end
|
754
|
+
|
755
|
+
describe 'destroy' do
|
756
|
+
let(:company) { create(:company) }
|
757
|
+
|
758
|
+
context "when unauthorized" do
|
759
|
+
it "returns scim+json content type" do
|
760
|
+
delete :destroy, params: { id: 1 }, as: :json
|
761
|
+
|
762
|
+
expect(response.media_type).to eq "application/scim+json"
|
763
|
+
end
|
764
|
+
|
765
|
+
it "fails with no credentials" do
|
766
|
+
delete :destroy, params: { id: 1 }, as: :json
|
767
|
+
|
768
|
+
expect(response.status).to eq 401
|
769
|
+
end
|
770
|
+
|
771
|
+
it "fails with invalid credentials" do
|
772
|
+
request.env["HTTP_AUTHORIZATION"] =
|
773
|
+
ActionController::HttpAuthentication::Basic
|
774
|
+
.encode_credentials("unauthorized", "123456")
|
775
|
+
|
776
|
+
delete :destroy, params: { id: 1 }, as: :json
|
777
|
+
|
778
|
+
expect(response.status).to eq 401
|
779
|
+
end
|
780
|
+
end
|
781
|
+
|
782
|
+
context 'when authorized' do
|
783
|
+
let!(:user) { create(:user, id: 1, company: company) }
|
784
|
+
|
785
|
+
before :each do
|
786
|
+
http_login(company)
|
787
|
+
end
|
788
|
+
|
789
|
+
context 'when User destroy method is configured' do
|
790
|
+
|
791
|
+
it 'is sucessful with valid credentials' do
|
792
|
+
delete :destroy, params: { id: 1 }, as: :json
|
793
|
+
|
794
|
+
expect(response.status).to eq 204
|
795
|
+
end
|
796
|
+
|
797
|
+
it 'returns empty response' do
|
798
|
+
delete :destroy, params: { id: 1 }, as: :json
|
799
|
+
|
800
|
+
expect(response.body).to be_empty
|
801
|
+
end
|
802
|
+
|
803
|
+
it 'successfully deletes User' do
|
804
|
+
expect do
|
805
|
+
delete :destroy, params: { id: 1 }, as: :json
|
806
|
+
end.to change { company.users.reload.count }.from(1).to(0)
|
807
|
+
|
808
|
+
expect(response.status).to eq 204
|
809
|
+
end
|
810
|
+
end
|
811
|
+
|
812
|
+
context 'when User destroy method is not configured' do
|
813
|
+
it 'does not delete User' do
|
814
|
+
allow(ScimRails.config).to(
|
815
|
+
receive(:user_destroy_method).and_return(nil)
|
816
|
+
)
|
817
|
+
|
818
|
+
expect do
|
819
|
+
delete :destroy, params: { id: 1 }, as: :json
|
820
|
+
end.not_to change { company.users.reload.count }.from(1)
|
821
|
+
|
822
|
+
expect(response.status).to eq 500
|
823
|
+
end
|
824
|
+
end
|
825
|
+
|
826
|
+
context 'when User destroy method is invalid' do
|
827
|
+
it 'does not delete User' do
|
828
|
+
allow(ScimRails.config).to(
|
829
|
+
receive(:user_destroy_method).and_return('destory!')
|
830
|
+
)
|
831
|
+
|
832
|
+
expect do
|
833
|
+
delete :destroy, params: { id: 1 }, as: :json
|
834
|
+
end.not_to change { company.users.reload.count }.from(1)
|
835
|
+
|
836
|
+
expect(response.status).to eq 500
|
837
|
+
end
|
838
|
+
end
|
839
|
+
|
840
|
+
context 'when target User is not found' do
|
841
|
+
it 'return 404 not found' do
|
842
|
+
expect do
|
843
|
+
delete :destroy, params: { id: 999999 }, as: :json
|
844
|
+
end.not_to change { company.users.reload.count }.from(1)
|
845
|
+
|
846
|
+
expect(response.status).to eq 404
|
847
|
+
end
|
848
|
+
end
|
849
|
+
|
850
|
+
context 'when target User are not allowed to delete' do
|
851
|
+
let!(:user) { create(:user, id: 1, company: company, deletable: false) }
|
852
|
+
|
853
|
+
it 'does not delete user' do
|
854
|
+
expect do
|
855
|
+
delete :destroy, params: { id: 1 }, as: :json
|
856
|
+
end.not_to change { company.users.reload.count }.from(1)
|
857
|
+
|
858
|
+
expect(response.status).to eq 400
|
859
|
+
end
|
719
860
|
end
|
720
861
|
end
|
721
862
|
end
|
722
863
|
|
723
|
-
def patch_params(id:)
|
864
|
+
def patch_params(id:, active: false)
|
724
865
|
{
|
725
|
-
schemas: [
|
866
|
+
schemas: ['urn:ietf:params:scim:api:messages:2.0:PatchOp'],
|
726
867
|
id: id,
|
727
868
|
Operations: [
|
728
869
|
{
|
729
|
-
op:
|
730
|
-
path:
|
731
|
-
value:
|
870
|
+
op: 'Replace',
|
871
|
+
path: 'emails[type eq "work"].value',
|
872
|
+
value: 'change@example.com',
|
732
873
|
}
|
733
|
-
]
|
874
|
+
],
|
734
875
|
}
|
735
876
|
end
|
736
877
|
|
737
878
|
def patch_active_params(id:, active: false)
|
738
879
|
{
|
739
|
-
schemas: [
|
880
|
+
schemas: ['urn:ietf:params:scim:api:messages:2.0:PatchOp'],
|
740
881
|
id: id,
|
741
882
|
Operations: [
|
742
883
|
{
|
743
|
-
op:
|
744
|
-
path:
|
745
|
-
value: active
|
884
|
+
op: 'Replace',
|
885
|
+
path: 'active',
|
886
|
+
value: active,
|
746
887
|
}
|
747
|
-
]
|
888
|
+
],
|
748
889
|
}
|
749
890
|
end
|
750
891
|
|
751
892
|
def put_params(id: 1, active: true)
|
752
893
|
{
|
753
894
|
id: id,
|
754
|
-
userName:
|
895
|
+
userName: 'test@example.com',
|
755
896
|
name: {
|
756
|
-
givenName:
|
757
|
-
familyName:
|
897
|
+
givenName: 'Test',
|
898
|
+
familyName: 'User',
|
758
899
|
},
|
759
900
|
emails: [
|
760
901
|
{
|
761
|
-
value:
|
902
|
+
value: 'test@example.com',
|
762
903
|
}
|
763
904
|
],
|
764
|
-
active: active
|
905
|
+
active: active,
|
765
906
|
}
|
766
907
|
end
|
767
908
|
end
|