workos 2.2.1 → 2.5.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/Gemfile.lock +2 -2
- data/README.md +4 -1
- data/lib/workos/audit_trail.rb +1 -1
- data/lib/workos/challenge.rb +1 -1
- data/lib/workos/client.rb +14 -5
- data/lib/workos/configuration.rb +17 -0
- data/lib/workos/directory_group.rb +22 -1
- data/lib/workos/directory_sync.rb +3 -1
- data/lib/workos/directory_user.rb +12 -1
- data/lib/workos/errors.rb +3 -0
- data/lib/workos/factor.rb +1 -6
- data/lib/workos/mfa.rb +22 -7
- data/lib/workos/organizations.rb +1 -1
- data/lib/workos/passwordless.rb +0 -1
- data/lib/workos/portal.rb +0 -1
- data/lib/workos/sso.rb +2 -2
- data/lib/workos/types/challenge_struct.rb +1 -1
- data/lib/workos/types/directory_group_struct.rb +6 -0
- data/lib/workos/types/directory_user_struct.rb +2 -0
- data/lib/workos/types/factor_struct.rb +0 -1
- data/lib/workos/types/{verify_factor_struct.rb → verify_challenge_struct.rb} +3 -3
- data/lib/workos/types.rb +1 -1
- data/lib/workos/{verify_factor.rb → verify_challenge.rb} +5 -6
- data/lib/workos/version.rb +1 -1
- data/lib/workos.rb +17 -7
- data/spec/lib/workos/configuration_spec.rb +61 -0
- data/spec/lib/workos/directory_sync_spec.rb +26 -19
- data/spec/lib/workos/directory_user_spec.rb +36 -0
- data/spec/lib/workos/mfa_spec.rb +93 -74
- data/spec/lib/workos/sso_spec.rb +1 -1
- data/spec/spec_helper.rb +2 -2
- data/spec/support/fixtures/vcr_cassettes/directory_sync/get_group.yml +47 -29
- data/spec/support/fixtures/vcr_cassettes/directory_sync/get_user.yml +28 -31
- data/spec/support/fixtures/vcr_cassettes/directory_sync/list_groups/with_after.yml +46 -32
- data/spec/support/fixtures/vcr_cassettes/directory_sync/list_groups/with_before.yml +47 -31
- data/spec/support/fixtures/vcr_cassettes/directory_sync/list_groups/with_directory.yml +46 -34
- data/spec/support/fixtures/vcr_cassettes/directory_sync/list_groups/with_limit.yml +41 -31
- data/spec/support/fixtures/vcr_cassettes/directory_sync/list_groups/with_no_options.yml +36 -26
- data/spec/support/fixtures/vcr_cassettes/directory_sync/list_groups/with_user.yml +38 -28
- data/spec/support/fixtures/vcr_cassettes/mfa/challenge_factor_generic_valid.yml +2 -2
- data/spec/support/fixtures/vcr_cassettes/mfa/challenge_factor_sms_valid.yml +2 -2
- data/spec/support/fixtures/vcr_cassettes/mfa/challenge_factor_totp_valid.yml +3 -3
- data/spec/support/fixtures/vcr_cassettes/mfa/enroll_factor_generic_valid.yml +1 -1
- data/spec/support/fixtures/vcr_cassettes/mfa/enroll_factor_sms_valid.yml +1 -1
- data/spec/support/fixtures/vcr_cassettes/mfa/enroll_factor_totp_valid.yml +1 -1
- data/spec/support/fixtures/vcr_cassettes/mfa/get_factor_valid.yml +1 -1
- data/spec/support/fixtures/vcr_cassettes/mfa/{verify_factor_generic_expired.yml → verify_challenge_generic_expired.yml} +2 -2
- data/spec/support/fixtures/vcr_cassettes/mfa/{verify_factor_generic_invalid.yml → verify_challenge_generic_invalid.yml} +2 -2
- data/spec/support/fixtures/vcr_cassettes/mfa/{verify_factor_generic_valid.yml → verify_challenge_generic_valid.yml} +2 -2
- data/spec/support/fixtures/vcr_cassettes/mfa/{verify_factor_generic_valid_is_false.yml → verify_challenge_generic_valid_is_false.yml} +2 -2
- metadata +18 -16
- data/lib/workos/base.rb +0 -18
- data/spec/lib/workos/base_spec.rb +0 -30
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# typed: false
|
|
3
|
+
|
|
4
|
+
describe WorkOS do
|
|
5
|
+
describe '.configure' do
|
|
6
|
+
context 'with key and no timeout' do
|
|
7
|
+
before do
|
|
8
|
+
WorkOS.configure do |config|
|
|
9
|
+
config.key = 'example_api_key'
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
it 'sets the key and default timeout configuration' do
|
|
14
|
+
expect(WorkOS.config.key).to eq('example_api_key')
|
|
15
|
+
expect(WorkOS.config.timeout).to eq(60)
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
context 'with key and timeout' do
|
|
20
|
+
before do
|
|
21
|
+
WorkOS.configure do |config|
|
|
22
|
+
config.key = 'example_api_key'
|
|
23
|
+
config.timeout = 120
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
it 'sets the key and timeout configuration' do
|
|
28
|
+
expect(WorkOS.config.key).to eq('example_api_key')
|
|
29
|
+
expect(WorkOS.config.timeout).to eq(120)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
describe WorkOS::Configuration do
|
|
36
|
+
describe '.key!' do
|
|
37
|
+
context 'with key set' do
|
|
38
|
+
before do
|
|
39
|
+
WorkOS.config.key = 'example_api_key'
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
it 'returns the key' do
|
|
43
|
+
expect(WorkOS.config.key!).to eq('example_api_key')
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
context 'with key not set' do
|
|
48
|
+
before do
|
|
49
|
+
WorkOS.config.key = nil
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
it 'throws an error' do
|
|
53
|
+
expect do
|
|
54
|
+
WorkOS.config.key!
|
|
55
|
+
end.to raise_error(
|
|
56
|
+
'`WorkOS.config.key` not set',
|
|
57
|
+
)
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
@@ -189,7 +189,7 @@ describe WorkOS::DirectorySync do
|
|
|
189
189
|
context 'with directory option' do
|
|
190
190
|
it 'forms the proper request to the API' do
|
|
191
191
|
request_args = [
|
|
192
|
-
'/directory_groups?directory=
|
|
192
|
+
'/directory_groups?directory=directory_01G2Z8ADK5NPMVTWF48MVVE4HT',
|
|
193
193
|
'Content-Type' => 'application/json'
|
|
194
194
|
]
|
|
195
195
|
|
|
@@ -200,7 +200,7 @@ describe WorkOS::DirectorySync do
|
|
|
200
200
|
|
|
201
201
|
VCR.use_cassette 'directory_sync/list_groups/with_directory' do
|
|
202
202
|
groups = described_class.list_groups(
|
|
203
|
-
directory: '
|
|
203
|
+
directory: 'directory_01G2Z8ADK5NPMVTWF48MVVE4HT',
|
|
204
204
|
)
|
|
205
205
|
|
|
206
206
|
expect(groups.data.size).to eq(10)
|
|
@@ -212,7 +212,7 @@ describe WorkOS::DirectorySync do
|
|
|
212
212
|
context 'with user option' do
|
|
213
213
|
it 'forms the proper request to the API' do
|
|
214
214
|
request_args = [
|
|
215
|
-
'/directory_groups?user=
|
|
215
|
+
'/directory_groups?user=directory_user_01G2Z8D4FDB28ZNSRRBVCF2E0P',
|
|
216
216
|
'Content-Type' => 'application/json'
|
|
217
217
|
]
|
|
218
218
|
|
|
@@ -223,7 +223,7 @@ describe WorkOS::DirectorySync do
|
|
|
223
223
|
|
|
224
224
|
VCR.use_cassette 'directory_sync/list_groups/with_user' do
|
|
225
225
|
groups = described_class.list_groups(
|
|
226
|
-
user: '
|
|
226
|
+
user: 'directory_user_01G2Z8D4FDB28ZNSRRBVCF2E0P',
|
|
227
227
|
)
|
|
228
228
|
|
|
229
229
|
expect(groups.data.size).to eq(3)
|
|
@@ -234,8 +234,8 @@ describe WorkOS::DirectorySync do
|
|
|
234
234
|
context 'with the before option' do
|
|
235
235
|
it 'forms the proper request to the API' do
|
|
236
236
|
request_args = [
|
|
237
|
-
'/directory_groups?before=
|
|
238
|
-
'directory=
|
|
237
|
+
'/directory_groups?before=directory_group_01G2Z8D4ZR8RJ03Y1W7P9K8NMG&' \
|
|
238
|
+
'directory=directory_01G2Z8ADK5NPMVTWF48MVVE4HT',
|
|
239
239
|
'Content-Type' => 'application/json'
|
|
240
240
|
]
|
|
241
241
|
|
|
@@ -246,11 +246,11 @@ describe WorkOS::DirectorySync do
|
|
|
246
246
|
|
|
247
247
|
VCR.use_cassette 'directory_sync/list_groups/with_before' do
|
|
248
248
|
groups = described_class.list_groups(
|
|
249
|
-
before: '
|
|
250
|
-
directory: '
|
|
249
|
+
before: 'directory_group_01G2Z8D4ZR8RJ03Y1W7P9K8NMG',
|
|
250
|
+
directory: 'directory_01G2Z8ADK5NPMVTWF48MVVE4HT',
|
|
251
251
|
)
|
|
252
252
|
|
|
253
|
-
expect(groups.data.size).to eq(
|
|
253
|
+
expect(groups.data.size).to eq(10)
|
|
254
254
|
end
|
|
255
255
|
end
|
|
256
256
|
end
|
|
@@ -258,8 +258,8 @@ describe WorkOS::DirectorySync do
|
|
|
258
258
|
context 'with the after option' do
|
|
259
259
|
it 'forms the proper request to the API' do
|
|
260
260
|
request_args = [
|
|
261
|
-
'/directory_groups?after=
|
|
262
|
-
'directory=
|
|
261
|
+
'/directory_groups?after=directory_group_01G2Z8D4ZR8RJ03Y1W7P9K8NMG&' \
|
|
262
|
+
'directory=directory_01G2Z8ADK5NPMVTWF48MVVE4HT',
|
|
263
263
|
'Content-Type' => 'application/json'
|
|
264
264
|
]
|
|
265
265
|
|
|
@@ -270,11 +270,11 @@ describe WorkOS::DirectorySync do
|
|
|
270
270
|
|
|
271
271
|
VCR.use_cassette 'directory_sync/list_groups/with_after' do
|
|
272
272
|
groups = described_class.list_groups(
|
|
273
|
-
after: '
|
|
274
|
-
directory: '
|
|
273
|
+
after: 'directory_group_01G2Z8D4ZR8RJ03Y1W7P9K8NMG',
|
|
274
|
+
directory: 'directory_01G2Z8ADK5NPMVTWF48MVVE4HT',
|
|
275
275
|
)
|
|
276
276
|
|
|
277
|
-
expect(groups.data.size).to eq(
|
|
277
|
+
expect(groups.data.size).to eq(9)
|
|
278
278
|
end
|
|
279
279
|
end
|
|
280
280
|
end
|
|
@@ -283,7 +283,7 @@ describe WorkOS::DirectorySync do
|
|
|
283
283
|
it 'forms the proper request to the API' do
|
|
284
284
|
request_args = [
|
|
285
285
|
'/directory_groups?limit=2&' \
|
|
286
|
-
'directory=
|
|
286
|
+
'directory=directory_01G2Z8ADK5NPMVTWF48MVVE4HT',
|
|
287
287
|
'Content-Type' => 'application/json'
|
|
288
288
|
]
|
|
289
289
|
|
|
@@ -295,7 +295,7 @@ describe WorkOS::DirectorySync do
|
|
|
295
295
|
VCR.use_cassette 'directory_sync/list_groups/with_limit' do
|
|
296
296
|
groups = described_class.list_groups(
|
|
297
297
|
limit: 2,
|
|
298
|
-
directory: '
|
|
298
|
+
directory: 'directory_01G2Z8ADK5NPMVTWF48MVVE4HT',
|
|
299
299
|
)
|
|
300
300
|
|
|
301
301
|
expect(groups.data.size).to eq(2)
|
|
@@ -438,11 +438,16 @@ describe WorkOS::DirectorySync do
|
|
|
438
438
|
it 'returns a group' do
|
|
439
439
|
VCR.use_cassette('directory_sync/get_group') do
|
|
440
440
|
group = WorkOS::DirectorySync.get_group(
|
|
441
|
-
'
|
|
441
|
+
'directory_group_01G2Z8D4ZR8RJ03Y1W7P9K8NMG',
|
|
442
442
|
)
|
|
443
443
|
|
|
444
|
-
expect(group['
|
|
445
|
-
expect(group
|
|
444
|
+
expect(group['directory_id']).to eq('directory_01G2Z8ADK5NPMVTWF48MVVE4HT')
|
|
445
|
+
expect(group['organization_id']).to eq('org_01EGS4P7QR31EZ4YWD1Z1XA176')
|
|
446
|
+
expect(group['idp_id']).to eq('01jlao4614two3d')
|
|
447
|
+
expect(group['name']).to eq('Sales')
|
|
448
|
+
expect(group.name).to eq('Sales')
|
|
449
|
+
expect(group['created_at']).to eq('2022-05-13T17:45:31.732Z')
|
|
450
|
+
expect(group['updated_at']).to eq('2022-07-13T17:45:42.618Z')
|
|
446
451
|
end
|
|
447
452
|
end
|
|
448
453
|
end
|
|
@@ -467,6 +472,8 @@ describe WorkOS::DirectorySync do
|
|
|
467
472
|
)
|
|
468
473
|
|
|
469
474
|
expect(user['first_name']).to eq('Logan')
|
|
475
|
+
expect(user.directory_id).to eq('directory_01FAZYMST676QMTFN1DDJZZX87')
|
|
476
|
+
expect(user.organization_id).to eq('org_01FAZWCWR03DVWA83NCJYKKD54')
|
|
470
477
|
expect(user.first_name).to eq('Logan')
|
|
471
478
|
end
|
|
472
479
|
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# typed: false
|
|
3
|
+
|
|
4
|
+
describe WorkOS::DirectoryUser do
|
|
5
|
+
# rubocop:disable Layout/LineLength
|
|
6
|
+
describe '.get_primary_email' do
|
|
7
|
+
context 'with one primary email' do
|
|
8
|
+
it 'returns the primary email' do
|
|
9
|
+
user = WorkOS::DirectoryUser.new('{"object":"directory_user","id":"directory_user_01FAZYNPC8M0HRYTKFP2GNX852","directory_id":"directory_01FAZYMST676QMTFN1DDJZZX87","idp_id":"6092c280a3f1e19ef6d8cef8","username":"logan@workos.com","emails":[{"primary":true,"value":"logan@workos.com"}, {"primary":false,"value":"logan@gmail.com"}],"first_name":"Logan","last_name":"Gingerich","state":"active","raw_attributes":{},"custom_attributes":{},"groups":[]}')
|
|
10
|
+
expect(user.primary_email).to eq('logan@workos.com')
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
context 'with multiple primary emails' do
|
|
15
|
+
it 'returns the first email marked as primary' do
|
|
16
|
+
user = WorkOS::DirectoryUser.new('{"object":"directory_user","id":"directory_user_01FAZYNPC8M0HRYTKFP2GNX852","directory_id":"directory_01FAZYMST676QMTFN1DDJZZX87","idp_id":"6092c280a3f1e19ef6d8cef8","username":"logan@workos.com","emails":[{"primary":true,"value":"logan@workos.com"}, {"primary":true,"value":"logan@gmail.com"}],"first_name":"Logan","last_name":"Gingerich","state":"active","raw_attributes":{},"custom_attributes":{},"groups":[]}')
|
|
17
|
+
expect(user.primary_email).to eq('logan@workos.com')
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
context 'with no primary emails' do
|
|
22
|
+
it 'returns nil' do
|
|
23
|
+
user = WorkOS::DirectoryUser.new('{"object":"directory_user","id":"directory_user_01FAZYNPC8M0HRYTKFP2GNX852","directory_id":"directory_01FAZYMST676QMTFN1DDJZZX87","idp_id":"6092c280a3f1e19ef6d8cef8","username":"logan@workos.com","emails":[{"primary":false,"value":"logan@gmail.com"}],"first_name":"Logan","last_name":"Gingerich","state":"active","raw_attributes":{},"custom_attributes":{},"groups":[]}')
|
|
24
|
+
expect(user.primary_email).to eq(nil)
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
context 'with an empty email array' do
|
|
29
|
+
it 'returns nil' do
|
|
30
|
+
user = WorkOS::DirectoryUser.new('{"object":"directory_user","id":"directory_user_01FAZYNPC8M0HRYTKFP2GNX852","directory_id":"directory_01FAZYMST676QMTFN1DDJZZX87","idp_id":"6092c280a3f1e19ef6d8cef8","username":"logan@workos.com","emails":[],"first_name":"Logan","last_name":"Gingerich","state":"active","raw_attributes":{},"custom_attributes":{},"groups":[]}')
|
|
31
|
+
expect(user.primary_email).to eq(nil)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
# rubocop:enable Layout/LineLength
|
|
36
|
+
end
|
data/spec/lib/workos/mfa_spec.rb
CHANGED
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
describe WorkOS::MFA do
|
|
5
5
|
it_behaves_like 'client'
|
|
6
6
|
|
|
7
|
-
describe 'enroll_factor
|
|
8
|
-
context '
|
|
7
|
+
describe '.enroll_factor' do
|
|
8
|
+
context 'with valid generic argument' do
|
|
9
9
|
it 'returns a valid factor object' do
|
|
10
10
|
VCR.use_cassette 'mfa/enroll_factor_generic_valid' do
|
|
11
11
|
factor = described_class.enroll_factor(
|
|
@@ -16,7 +16,7 @@ describe WorkOS::MFA do
|
|
|
16
16
|
end
|
|
17
17
|
end
|
|
18
18
|
|
|
19
|
-
context '
|
|
19
|
+
context 'with valid totp arguments' do
|
|
20
20
|
it 'returns a valid factor object' do
|
|
21
21
|
VCR.use_cassette 'mfa/enroll_factor_totp_valid' do
|
|
22
22
|
factor = described_class.enroll_factor(
|
|
@@ -29,7 +29,7 @@ describe WorkOS::MFA do
|
|
|
29
29
|
end
|
|
30
30
|
end
|
|
31
31
|
|
|
32
|
-
context '
|
|
32
|
+
context 'with valid sms arguments' do
|
|
33
33
|
it 'returns a valid factor object' do
|
|
34
34
|
VCR.use_cassette 'mfa/enroll_factor_sms_valid' do
|
|
35
35
|
factor = described_class.enroll_factor(
|
|
@@ -40,10 +40,8 @@ describe WorkOS::MFA do
|
|
|
40
40
|
end
|
|
41
41
|
end
|
|
42
42
|
end
|
|
43
|
-
end
|
|
44
43
|
|
|
45
|
-
|
|
46
|
-
context 'enroll factor throws error if type is not sms or totp' do
|
|
44
|
+
context 'when type is not sms or totp' do
|
|
47
45
|
it 'returns an error' do
|
|
48
46
|
expect do
|
|
49
47
|
described_class.enroll_factor(
|
|
@@ -57,7 +55,7 @@ describe WorkOS::MFA do
|
|
|
57
55
|
end
|
|
58
56
|
end
|
|
59
57
|
|
|
60
|
-
context '
|
|
58
|
+
context 'when type is totp but missing arguments' do
|
|
61
59
|
it 'returns an error' do
|
|
62
60
|
expect do
|
|
63
61
|
described_class.enroll_factor(
|
|
@@ -70,7 +68,7 @@ describe WorkOS::MFA do
|
|
|
70
68
|
)
|
|
71
69
|
end
|
|
72
70
|
end
|
|
73
|
-
context '
|
|
71
|
+
context 'when type is sms and phone number is nil' do
|
|
74
72
|
it 'returns an error' do
|
|
75
73
|
expect do
|
|
76
74
|
described_class.enroll_factor(
|
|
@@ -84,7 +82,7 @@ describe WorkOS::MFA do
|
|
|
84
82
|
end
|
|
85
83
|
end
|
|
86
84
|
|
|
87
|
-
describe '
|
|
85
|
+
describe '.challenge_factor' do
|
|
88
86
|
context 'challenge with totp' do
|
|
89
87
|
it 'returns challenge factor object for totp' do
|
|
90
88
|
VCR.use_cassette 'mfa/challenge_factor_totp_valid' do
|
|
@@ -118,9 +116,7 @@ describe WorkOS::MFA do
|
|
|
118
116
|
end
|
|
119
117
|
end
|
|
120
118
|
end
|
|
121
|
-
end
|
|
122
119
|
|
|
123
|
-
describe 'challenge factor with invalid arguments' do
|
|
124
120
|
context 'challenge with totp mssing authentication_factor_id' do
|
|
125
121
|
it 'returns argument error' do
|
|
126
122
|
expect do
|
|
@@ -133,48 +129,58 @@ describe WorkOS::MFA do
|
|
|
133
129
|
end
|
|
134
130
|
end
|
|
135
131
|
|
|
136
|
-
describe '
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
VCR.use_cassette 'mfa/
|
|
140
|
-
|
|
132
|
+
describe '.verify_factor' do
|
|
133
|
+
it 'throws a warning' do
|
|
134
|
+
expect do
|
|
135
|
+
VCR.use_cassette 'mfa/verify_challenge_generic_valid' do
|
|
136
|
+
described_class.verify_factor(
|
|
141
137
|
authentication_challenge_id: 'auth_challenge_01FZ4YVRBMXP5ZM0A7BP4AJ12J',
|
|
142
138
|
code: '897792',
|
|
143
139
|
)
|
|
144
|
-
expect(verify_factor.valid == 'true')
|
|
145
140
|
end
|
|
146
|
-
end
|
|
141
|
+
end.to output("[DEPRECATION] `verify_factor` is deprecated. Please use `verify_challenge` instead.\n").to_stderr
|
|
147
142
|
end
|
|
148
143
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
expect(verify_factor.valid == 'false')
|
|
157
|
-
end
|
|
144
|
+
it 'calls verify_challenge' do
|
|
145
|
+
VCR.use_cassette 'mfa/verify_challenge_generic_valid' do
|
|
146
|
+
verify_factor = described_class.verify_factor(
|
|
147
|
+
authentication_challenge_id: 'auth_challenge_01FZ4YVRBMXP5ZM0A7BP4AJ12J',
|
|
148
|
+
code: '897792',
|
|
149
|
+
)
|
|
150
|
+
expect(verify_factor.valid == 'true')
|
|
158
151
|
end
|
|
159
152
|
end
|
|
153
|
+
end
|
|
160
154
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
155
|
+
describe '.verify_challenge' do
|
|
156
|
+
context 'with generic otp' do
|
|
157
|
+
context 'and the challenge has not been verified' do
|
|
158
|
+
it 'returns true if the code is correct' do
|
|
159
|
+
VCR.use_cassette 'mfa/verify_challenge_generic_valid' do
|
|
160
|
+
verify_challenge = described_class.verify_challenge(
|
|
166
161
|
authentication_challenge_id: 'auth_challenge_01FZ4YVRBMXP5ZM0A7BP4AJ12J',
|
|
167
162
|
code: '897792',
|
|
168
163
|
)
|
|
169
|
-
|
|
164
|
+
expect(verify_challenge.valid == 'true')
|
|
165
|
+
end
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
it 'returns false if the code is incorrect' do
|
|
169
|
+
VCR.use_cassette 'mfa/verify_challenge_generic_valid_is_false' do
|
|
170
|
+
verify_challenge = described_class.verify_challenge(
|
|
171
|
+
authentication_challenge_id: 'auth_challenge_01FZ4YVRBMXP5ZM0A7BP4AJ12J',
|
|
172
|
+
code: '897792',
|
|
173
|
+
)
|
|
174
|
+
expect(verify_challenge.valid == 'false')
|
|
175
|
+
end
|
|
170
176
|
end
|
|
171
177
|
end
|
|
172
178
|
|
|
173
|
-
context '
|
|
174
|
-
it 'returns error
|
|
175
|
-
VCR.use_cassette 'mfa/
|
|
179
|
+
context 'and the challenge has already been verified' do
|
|
180
|
+
it 'returns an error' do
|
|
181
|
+
VCR.use_cassette 'mfa/verify_challenge_generic_invalid' do
|
|
176
182
|
expect do
|
|
177
|
-
described_class.
|
|
183
|
+
described_class.verify_challenge(
|
|
178
184
|
authentication_challenge_id: 'auth_challenge_01FZ4YVRBMXP5ZM0A7BP4AJ12J',
|
|
179
185
|
code: '897792',
|
|
180
186
|
)
|
|
@@ -182,51 +188,62 @@ describe WorkOS::MFA do
|
|
|
182
188
|
end
|
|
183
189
|
end
|
|
184
190
|
end
|
|
185
|
-
end
|
|
186
|
-
end
|
|
187
191
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
192
|
+
context 'and the challenge has expired' do
|
|
193
|
+
it 'returns an error' do
|
|
194
|
+
VCR.use_cassette 'mfa/verify_challenge_generic_expired' do
|
|
195
|
+
expect do
|
|
196
|
+
described_class.verify_challenge(
|
|
197
|
+
authentication_challenge_id: 'auth_challenge_01FZ4YVRBMXP5ZM0A7BP4AJ12J',
|
|
198
|
+
code: '897792',
|
|
199
|
+
)
|
|
200
|
+
end.to raise_error(WorkOS::InvalidRequestError)
|
|
201
|
+
end
|
|
202
|
+
end
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
context 'with missing code argument' do
|
|
206
|
+
it 'returns an argument error' do
|
|
207
|
+
expect do
|
|
208
|
+
described_class.verify_challenge(
|
|
209
|
+
authentication_challenge_id: 'auth_challenge_01FZ4YVRBMXP5ZM0A7BP4AJ12J',
|
|
210
|
+
)
|
|
211
|
+
end.to raise_error(
|
|
212
|
+
ArgumentError,
|
|
213
|
+
"Incomplete arguments: 'authentication_challenge_id' and 'code' are required arguments",
|
|
194
214
|
)
|
|
195
|
-
end
|
|
196
|
-
ArgumentError,
|
|
197
|
-
"Incomplete arguments: 'authentication_challenge_id' and 'code' are required arguments",
|
|
198
|
-
)
|
|
215
|
+
end
|
|
199
216
|
end
|
|
200
|
-
end
|
|
201
217
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
218
|
+
context 'with missing authentication_challenge_id argument' do
|
|
219
|
+
it 'returns an error' do
|
|
220
|
+
expect do
|
|
221
|
+
described_class.verify_challenge(
|
|
222
|
+
code: '897792',
|
|
223
|
+
)
|
|
224
|
+
end.to raise_error(
|
|
225
|
+
ArgumentError,
|
|
226
|
+
"Incomplete arguments: 'authentication_challenge_id' and 'code' are required arguments",
|
|
207
227
|
)
|
|
208
|
-
end
|
|
209
|
-
ArgumentError,
|
|
210
|
-
"Incomplete arguments: 'authentication_challenge_id' and 'code' are required arguments",
|
|
211
|
-
)
|
|
228
|
+
end
|
|
212
229
|
end
|
|
213
|
-
end
|
|
214
230
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
231
|
+
context 'with missing code and authentication_challenge_id arguments' do
|
|
232
|
+
it 'returns an argument error' do
|
|
233
|
+
expect do
|
|
234
|
+
described_class.verify_challenge
|
|
235
|
+
end.to raise_error(
|
|
236
|
+
ArgumentError,
|
|
237
|
+
"Incomplete arguments: 'authentication_challenge_id' and 'code' are required arguments",
|
|
238
|
+
)
|
|
239
|
+
end
|
|
223
240
|
end
|
|
224
241
|
end
|
|
225
242
|
end
|
|
226
243
|
|
|
227
|
-
describe '
|
|
228
|
-
context '
|
|
229
|
-
it '
|
|
244
|
+
describe '.get_factor' do
|
|
245
|
+
context 'with a valid id' do
|
|
246
|
+
it 'returns a factor' do
|
|
230
247
|
VCR.use_cassette 'mfa/get_factor_valid' do
|
|
231
248
|
factor = described_class.get_factor(
|
|
232
249
|
id: 'auth_factor_01FZ4WMXXA09XF6NK1XMKNWB3M',
|
|
@@ -236,8 +253,8 @@ describe WorkOS::MFA do
|
|
|
236
253
|
end
|
|
237
254
|
end
|
|
238
255
|
|
|
239
|
-
context 'invalid
|
|
240
|
-
it '
|
|
256
|
+
context 'with an invalid id' do
|
|
257
|
+
it 'returns an error' do
|
|
241
258
|
VCR.use_cassette 'mfa/get_factor_invalid' do
|
|
242
259
|
expect do
|
|
243
260
|
described_class.get_factor(
|
|
@@ -247,7 +264,9 @@ describe WorkOS::MFA do
|
|
|
247
264
|
end
|
|
248
265
|
end
|
|
249
266
|
end
|
|
267
|
+
end
|
|
250
268
|
|
|
269
|
+
describe '.delete_factor' do
|
|
251
270
|
context 'deletes facotr' do
|
|
252
271
|
it 'uses delete_factor to delete factor' do
|
|
253
272
|
VCR.use_cassette 'mfa/delete_factor' do
|
data/spec/lib/workos/sso_spec.rb
CHANGED
data/spec/spec_helper.rb
CHANGED
|
@@ -25,7 +25,7 @@ SPEC_ROOT = File.dirname __FILE__
|
|
|
25
25
|
|
|
26
26
|
VCR.configure do |config|
|
|
27
27
|
config.cassette_library_dir = 'spec/support/fixtures/vcr_cassettes'
|
|
28
|
-
config.filter_sensitive_data('<API_KEY>') { WorkOS.key }
|
|
28
|
+
config.filter_sensitive_data('<API_KEY>') { WorkOS.config.key }
|
|
29
29
|
config.hook_into :webmock
|
|
30
30
|
end
|
|
31
31
|
|
|
@@ -51,6 +51,6 @@ RSpec.configure do |config|
|
|
|
51
51
|
end
|
|
52
52
|
end)
|
|
53
53
|
|
|
54
|
-
config.before(:all) { WorkOS.key ||= '' }
|
|
54
|
+
config.before(:all) { WorkOS.config.key ||= '' }
|
|
55
55
|
config.before(:each) { VCR.turn_on! }
|
|
56
56
|
end
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
http_interactions:
|
|
3
3
|
- request:
|
|
4
4
|
method: get
|
|
5
|
-
uri: https://api.workos.com/directory_groups/
|
|
5
|
+
uri: https://api.workos.com/directory_groups/directory_group_01G2Z8D4ZR8RJ03Y1W7P9K8NMG
|
|
6
6
|
body:
|
|
7
7
|
encoding: US-ASCII
|
|
8
8
|
string: ''
|
|
@@ -14,7 +14,7 @@ http_interactions:
|
|
|
14
14
|
Accept:
|
|
15
15
|
- "*/*"
|
|
16
16
|
User-Agent:
|
|
17
|
-
- WorkOS; ruby/2.7.
|
|
17
|
+
- WorkOS; ruby/2.7.2; arm64-darwin21; v2.3.0
|
|
18
18
|
Authorization:
|
|
19
19
|
- Bearer <API_KEY>
|
|
20
20
|
response:
|
|
@@ -22,41 +22,59 @@ http_interactions:
|
|
|
22
22
|
code: 200
|
|
23
23
|
message: OK
|
|
24
24
|
headers:
|
|
25
|
-
|
|
26
|
-
-
|
|
25
|
+
Date:
|
|
26
|
+
- Thu, 14 Jul 2022 16:49:09 GMT
|
|
27
|
+
Content-Type:
|
|
28
|
+
- application/json; charset=utf-8
|
|
29
|
+
Transfer-Encoding:
|
|
30
|
+
- chunked
|
|
27
31
|
Connection:
|
|
28
32
|
- keep-alive
|
|
29
|
-
Vary:
|
|
30
|
-
- Origin, Accept-Encoding
|
|
31
33
|
Access-Control-Allow-Credentials:
|
|
32
34
|
- 'true'
|
|
33
|
-
|
|
34
|
-
- '
|
|
35
|
-
|
|
36
|
-
|
|
35
|
+
Content-Security-Policy:
|
|
36
|
+
- 'default-src ''self'';base-uri ''self'';block-all-mixed-content;font-src ''self''
|
|
37
|
+
https: data:;frame-ancestors ''self'';img-src ''self'' data:;object-src ''none'';script-src
|
|
38
|
+
''self'';script-src-attr ''none'';style-src ''self'' https: ''unsafe-inline'';upgrade-insecure-requests'
|
|
39
|
+
Etag:
|
|
40
|
+
- W/"277-8j8DgAIILf/mCF7LCmvrqcqdwK4"
|
|
41
|
+
Expect-Ct:
|
|
42
|
+
- max-age=0
|
|
43
|
+
Referrer-Policy:
|
|
44
|
+
- no-referrer
|
|
37
45
|
Strict-Transport-Security:
|
|
38
46
|
- max-age=15552000; includeSubDomains
|
|
39
|
-
|
|
40
|
-
-
|
|
47
|
+
Vary:
|
|
48
|
+
- Origin, Accept-Encoding
|
|
49
|
+
Via:
|
|
50
|
+
- 1.1 spaces-router (b642bf20b975)
|
|
41
51
|
X-Content-Type-Options:
|
|
42
52
|
- nosniff
|
|
43
|
-
X-
|
|
44
|
-
-
|
|
53
|
+
X-Dns-Prefetch-Control:
|
|
54
|
+
- 'off'
|
|
55
|
+
X-Download-Options:
|
|
56
|
+
- noopen
|
|
57
|
+
X-Frame-Options:
|
|
58
|
+
- SAMEORIGIN
|
|
59
|
+
X-Permitted-Cross-Domain-Policies:
|
|
60
|
+
- none
|
|
45
61
|
X-Request-Id:
|
|
46
|
-
-
|
|
47
|
-
|
|
48
|
-
-
|
|
49
|
-
|
|
50
|
-
-
|
|
51
|
-
|
|
52
|
-
-
|
|
53
|
-
|
|
54
|
-
-
|
|
55
|
-
|
|
56
|
-
-
|
|
62
|
+
- 0f21c2f3-e24a-e3a2-85d3-41ee9e45b3e2
|
|
63
|
+
X-Xss-Protection:
|
|
64
|
+
- '0'
|
|
65
|
+
Cf-Cache-Status:
|
|
66
|
+
- DYNAMIC
|
|
67
|
+
Report-To:
|
|
68
|
+
- '{"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v3?s=Hnm%2BEiBTG2ROFxqX2mdwcp0HvQ173SgQlQDCmTmBQEbLv9w2dkcl2qMqYh44OSHRABBCkRfuJ2MtnHuqb6sQ5RjHRMKSCfRqklsOrgd%2FHo0PEE6mW0u%2BlZqBMIlN1BEp"}],"group":"cf-nel","max_age":604800}'
|
|
69
|
+
Nel:
|
|
70
|
+
- '{"success_fraction":0,"report_to":"cf-nel","max_age":604800}'
|
|
71
|
+
Server:
|
|
72
|
+
- cloudflare
|
|
73
|
+
Cf-Ray:
|
|
74
|
+
- 72abc002fbd9f039-EWR
|
|
57
75
|
body:
|
|
58
|
-
encoding:
|
|
59
|
-
string: '{"id":"
|
|
60
|
-
http_version:
|
|
61
|
-
recorded_at: Thu,
|
|
76
|
+
encoding: ASCII-8BIT
|
|
77
|
+
string: '{"object":"directory_group","id":"directory_group_01G2Z8D4ZR8RJ03Y1W7P9K8NMG","idp_id":"01jlao4614two3d","directory_id":"directory_01G2Z8ADK5NPMVTWF48MVVE4HT","organization_id":"org_01EGS4P7QR31EZ4YWD1Z1XA176","name":"Sales","created_at":"2022-05-13T17:45:31.732Z","updated_at":"2022-07-13T17:45:42.618Z","raw_attributes":{"id":"01jlao4614two3d","etag":"\"SEQQBYC70u6XQ2UUjmjNYw6b0a5EzY0mTMShjiZga8A/uLYJ0Hrx1gXXVg9z-zGLBZET2Wo\"","kind":"admin#directory#group","name":"Sales","email":"sales@foo-corp.com","description":"","adminCreated":true,"directMembersCount":"1","nonEditableAliases":["sales@foo-corp.com.test-google-a.com"]}}'
|
|
78
|
+
http_version:
|
|
79
|
+
recorded_at: Thu, 14 Jul 2022 16:49:09 GMT
|
|
62
80
|
recorded_with: VCR 5.0.0
|