synapse 2.176.0__py311-none-any.whl → 2.178.0__py311-none-any.whl
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.
Potentially problematic release.
This version of synapse might be problematic. Click here for more details.
- synapse/axon.py +24 -9
- synapse/cortex.py +337 -172
- synapse/cryotank.py +46 -37
- synapse/datamodel.py +17 -4
- synapse/exc.py +19 -0
- synapse/lib/agenda.py +7 -13
- synapse/lib/aha.py +361 -88
- synapse/lib/auth.py +1520 -0
- synapse/lib/base.py +27 -9
- synapse/lib/cell.py +422 -163
- synapse/lib/config.py +15 -11
- synapse/lib/coro.py +13 -0
- synapse/lib/grammar.py +5 -0
- synapse/lib/hive.py +24 -3
- synapse/lib/hiveauth.py +6 -32
- synapse/lib/layer.py +7 -9
- synapse/lib/link.py +22 -18
- synapse/lib/lmdbslab.py +152 -3
- synapse/lib/modelrev.py +1 -1
- synapse/lib/nexus.py +24 -12
- synapse/lib/schemas.py +136 -0
- synapse/lib/storm.py +61 -29
- synapse/lib/stormlib/aha.py +1 -1
- synapse/lib/stormlib/auth.py +185 -10
- synapse/lib/stormlib/cortex.py +16 -5
- synapse/lib/stormlib/gen.py +80 -0
- synapse/lib/stormlib/imap.py +6 -2
- synapse/lib/stormlib/model.py +55 -0
- synapse/lib/stormlib/modelext.py +60 -0
- synapse/lib/stormlib/smtp.py +12 -2
- synapse/lib/stormlib/tabular.py +212 -0
- synapse/lib/stormtypes.py +14 -1
- synapse/lib/trigger.py +1 -1
- synapse/lib/version.py +2 -2
- synapse/lib/view.py +55 -28
- synapse/models/base.py +7 -0
- synapse/models/biz.py +4 -0
- synapse/models/files.py +8 -1
- synapse/models/inet.py +8 -0
- synapse/telepath.py +32 -17
- synapse/tests/files/aha/certs/cas/synapse.crt +28 -0
- synapse/tests/files/aha/certs/cas/synapse.key +51 -0
- synapse/tests/files/aha/certs/hosts/00.aha.loop.vertex.link.crt +30 -0
- synapse/tests/files/aha/certs/hosts/00.aha.loop.vertex.link.key +51 -0
- synapse/tests/files/aha/certs/users/root@synapse.crt +29 -0
- synapse/tests/files/aha/certs/users/root@synapse.key +51 -0
- synapse/tests/files/changelog/model_2.176.0_16ee721a6b7221344eaf946c3ab4602dda546b1a.yaml.gz +0 -0
- synapse/tests/files/changelog/model_2.176.0_2a25c58bbd344716cd7cbc3f4304d8925b0f4ef2.yaml.gz +0 -0
- synapse/tests/files/rstorm/testsvc.py +1 -1
- synapse/tests/test_axon.py +8 -5
- synapse/tests/test_cortex.py +149 -141
- synapse/tests/test_cryotank.py +4 -4
- synapse/tests/test_datamodel.py +7 -0
- synapse/tests/test_lib_agenda.py +10 -3
- synapse/tests/test_lib_aha.py +336 -490
- synapse/tests/{test_lib_hiveauth.py → test_lib_auth.py} +314 -11
- synapse/tests/test_lib_base.py +20 -0
- synapse/tests/test_lib_cell.py +210 -30
- synapse/tests/test_lib_config.py +4 -3
- synapse/tests/test_lib_httpapi.py +18 -14
- synapse/tests/test_lib_layer.py +33 -33
- synapse/tests/test_lib_link.py +42 -1
- synapse/tests/test_lib_lmdbslab.py +68 -0
- synapse/tests/test_lib_nexus.py +12 -4
- synapse/tests/test_lib_node.py +0 -7
- synapse/tests/test_lib_storm.py +45 -0
- synapse/tests/test_lib_stormlib_aha.py +35 -36
- synapse/tests/test_lib_stormlib_auth.py +21 -0
- synapse/tests/test_lib_stormlib_cell.py +4 -15
- synapse/tests/test_lib_stormlib_cortex.py +12 -12
- synapse/tests/test_lib_stormlib_gen.py +99 -0
- synapse/tests/test_lib_stormlib_imap.py +14 -3
- synapse/tests/test_lib_stormlib_model.py +108 -0
- synapse/tests/test_lib_stormlib_modelext.py +64 -0
- synapse/tests/test_lib_stormlib_smtp.py +51 -0
- synapse/tests/test_lib_stormlib_tabular.py +226 -0
- synapse/tests/test_lib_stormsvc.py +4 -1
- synapse/tests/test_lib_stormtypes.py +10 -0
- synapse/tests/test_model_base.py +3 -0
- synapse/tests/test_model_biz.py +3 -0
- synapse/tests/test_model_files.py +12 -2
- synapse/tests/test_model_inet.py +24 -0
- synapse/tests/test_tools_aha.py +78 -101
- synapse/tests/test_tools_changelog.py +196 -0
- synapse/tests/test_tools_healthcheck.py +4 -3
- synapse/tests/utils.py +87 -121
- synapse/tools/aha/clone.py +50 -0
- synapse/tools/aha/enroll.py +2 -1
- synapse/tools/backup.py +2 -2
- synapse/tools/changelog.py +776 -15
- {synapse-2.176.0.dist-info → synapse-2.178.0.dist-info}/METADATA +48 -48
- {synapse-2.176.0.dist-info → synapse-2.178.0.dist-info}/RECORD +95 -82
- {synapse-2.176.0.dist-info → synapse-2.178.0.dist-info}/WHEEL +1 -1
- {synapse-2.176.0.dist-info → synapse-2.178.0.dist-info}/LICENSE +0 -0
- {synapse-2.176.0.dist-info → synapse-2.178.0.dist-info}/top_level.txt +0 -0
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import string
|
|
1
2
|
import pathlib
|
|
2
3
|
|
|
3
4
|
import synapse.exc as s_exc
|
|
@@ -9,7 +10,7 @@ import synapse.tests.utils as s_test
|
|
|
9
10
|
|
|
10
11
|
class AuthTest(s_test.SynTest):
|
|
11
12
|
|
|
12
|
-
async def
|
|
13
|
+
async def test_auth(self):
|
|
13
14
|
|
|
14
15
|
async with self.getTestCore() as core:
|
|
15
16
|
|
|
@@ -30,6 +31,9 @@ class AuthTest(s_test.SynTest):
|
|
|
30
31
|
with self.raises(s_exc.DupRoleName):
|
|
31
32
|
await auth.addRole('ninjas')
|
|
32
33
|
|
|
34
|
+
self.none(await auth._addUser(user.iden, 'visi@vertex.link'))
|
|
35
|
+
self.none(await auth._addRole(user.iden, 'ninjas'))
|
|
36
|
+
|
|
33
37
|
self.nn(user)
|
|
34
38
|
|
|
35
39
|
with self.raises(s_exc.AuthDeny):
|
|
@@ -92,9 +96,13 @@ class AuthTest(s_test.SynTest):
|
|
|
92
96
|
|
|
93
97
|
await user.revoke(role.iden)
|
|
94
98
|
self.none(user.allowed(('baz', 'faz')))
|
|
99
|
+
# second revoke does nothing
|
|
100
|
+
await user.revoke(role.iden)
|
|
95
101
|
|
|
96
102
|
await user.grant(role.iden)
|
|
97
103
|
self.true(user.allowed(('baz', 'faz')))
|
|
104
|
+
# second grant does nothing
|
|
105
|
+
await user.grant(role.iden)
|
|
98
106
|
|
|
99
107
|
await self.asyncraises(s_exc.NoSuchRole, auth.delRole('accountants'))
|
|
100
108
|
|
|
@@ -106,6 +114,8 @@ class AuthTest(s_test.SynTest):
|
|
|
106
114
|
await auth.delUser(user.iden)
|
|
107
115
|
self.false(user.allowed(('baz', 'faz')))
|
|
108
116
|
|
|
117
|
+
self.none(await auth._delUser(user.iden))
|
|
118
|
+
|
|
109
119
|
role = await auth.addRole('lolusers')
|
|
110
120
|
role2 = await auth.addRole('lolusers2')
|
|
111
121
|
|
|
@@ -133,6 +143,15 @@ class AuthTest(s_test.SynTest):
|
|
|
133
143
|
self.nn(await auth.getUserByName('user2'))
|
|
134
144
|
self.none(await auth.getUserByName('user1'))
|
|
135
145
|
|
|
146
|
+
with self.raises(s_exc.NoSuchRole):
|
|
147
|
+
await auth.reqRoleByName('newp')
|
|
148
|
+
|
|
149
|
+
with self.raises(s_exc.NoSuchAuthGate):
|
|
150
|
+
await auth.delAuthGate('newp')
|
|
151
|
+
|
|
152
|
+
with self.raises(s_exc.InconsistentStorage):
|
|
153
|
+
await auth.addAuthGate(core.view.iden, 'newp')
|
|
154
|
+
|
|
136
155
|
async def test_hive_tele_auth(self):
|
|
137
156
|
|
|
138
157
|
# confirm that the primitives used by higher level APIs
|
|
@@ -144,7 +163,7 @@ class AuthTest(s_test.SynTest):
|
|
|
144
163
|
|
|
145
164
|
auth = core.auth
|
|
146
165
|
|
|
147
|
-
user = await auth.
|
|
166
|
+
user = await auth.addUser('lowuser')
|
|
148
167
|
await user.setPasswd('secret')
|
|
149
168
|
|
|
150
169
|
# tryPasswd
|
|
@@ -152,7 +171,7 @@ class AuthTest(s_test.SynTest):
|
|
|
152
171
|
self.false(await user.tryPasswd('beep'))
|
|
153
172
|
self.false(await user.tryPasswd(None))
|
|
154
173
|
|
|
155
|
-
#
|
|
174
|
+
# passwords must be non-zero length strings
|
|
156
175
|
with self.raises(s_exc.BadArg):
|
|
157
176
|
await user.setPasswd('')
|
|
158
177
|
with self.raises(s_exc.BadArg):
|
|
@@ -173,23 +192,23 @@ class AuthTest(s_test.SynTest):
|
|
|
173
192
|
await user.setLocked(True)
|
|
174
193
|
|
|
175
194
|
with self.raises(s_exc.AuthDeny):
|
|
176
|
-
await s_telepath.openurl(turl, user='
|
|
195
|
+
await s_telepath.openurl(turl, user='lowuser', passwd='secret')
|
|
177
196
|
|
|
178
197
|
await user.setLocked(False)
|
|
179
198
|
|
|
180
199
|
# User can't access after being unlocked with wrong password
|
|
181
200
|
with self.raises(s_exc.AuthDeny):
|
|
182
|
-
await s_telepath.openurl(turl, user='
|
|
201
|
+
await s_telepath.openurl(turl, user='lowuser', passwd='newpnewp')
|
|
183
202
|
|
|
184
203
|
# User can access with correct password after being unlocked with
|
|
185
|
-
async with await s_telepath.openurl(turl, user='
|
|
204
|
+
async with await s_telepath.openurl(turl, user='lowuser', passwd='secret') as proxy:
|
|
186
205
|
await proxy.getCellInfo()
|
|
187
206
|
|
|
188
|
-
async def
|
|
207
|
+
async def test_authgate_perms(self):
|
|
189
208
|
|
|
190
209
|
async with self.getTestCoreAndProxy() as (core, prox):
|
|
191
210
|
|
|
192
|
-
# We can retrieve the
|
|
211
|
+
# We can retrieve the authgate information
|
|
193
212
|
gate = await prox.getAuthGate(core.view.iden)
|
|
194
213
|
self.eq(gate['users'][0], {
|
|
195
214
|
'iden': core.auth.rootuser.iden,
|
|
@@ -286,15 +305,24 @@ class AuthTest(s_test.SynTest):
|
|
|
286
305
|
await prox.delRole(friends['iden'])
|
|
287
306
|
await self.asyncraises(s_exc.AuthDeny, fredcore.count('test:int=11 [:loc=ru]', opts=viewopts))
|
|
288
307
|
|
|
308
|
+
friends = await prox.addRole('friends')
|
|
309
|
+
await prox.addRoleRule(friends['iden'], rule, gateiden=layriden)
|
|
310
|
+
|
|
311
|
+
friends = await prox.getRoleInfo('friends')
|
|
312
|
+
self.isin(layriden, friends['authgates'])
|
|
313
|
+
|
|
289
314
|
wlyr = view2.layers[0]
|
|
290
315
|
|
|
291
316
|
await core.delView(view2.iden)
|
|
292
317
|
await core.delLayer(wlyr.iden)
|
|
293
318
|
|
|
294
|
-
# Verify that trashing the layer and view deletes the authgate
|
|
319
|
+
# Verify that trashing the layer and view deletes the authgate
|
|
295
320
|
self.none(core.auth.getAuthGate(wlyr.iden))
|
|
296
321
|
self.none(core.auth.getAuthGate(view2.iden))
|
|
297
322
|
|
|
323
|
+
friends = await prox.getRoleInfo('friends')
|
|
324
|
+
self.notin(layriden, friends['authgates'])
|
|
325
|
+
|
|
298
326
|
# Verify that trashing the write layer deletes the remaining rules and backing store
|
|
299
327
|
self.false(pathlib.Path(wlyr.dirn).exists())
|
|
300
328
|
fred = await core.auth.getUserByName('fred')
|
|
@@ -302,7 +330,7 @@ class AuthTest(s_test.SynTest):
|
|
|
302
330
|
self.len(0, fred.getRules(gateiden=wlyr.iden))
|
|
303
331
|
self.len(0, fred.getRules(gateiden=view2.iden))
|
|
304
332
|
|
|
305
|
-
async def
|
|
333
|
+
async def test_auth_persistence(self):
|
|
306
334
|
|
|
307
335
|
with self.getTestDir() as fdir:
|
|
308
336
|
|
|
@@ -345,15 +373,19 @@ class AuthTest(s_test.SynTest):
|
|
|
345
373
|
self.none(await core.auth.getUserByName('fred'))
|
|
346
374
|
self.none(await core.auth.getRoleByName('friends'))
|
|
347
375
|
|
|
348
|
-
async def
|
|
376
|
+
async def test_auth_invalid(self):
|
|
349
377
|
|
|
350
378
|
async with self.getTestCore() as core:
|
|
351
379
|
with self.raises(s_exc.BadArg):
|
|
352
380
|
await core.auth.setRoleName(core.auth.allrole.iden, 'ninjas')
|
|
353
381
|
with self.raises(s_exc.BadArg):
|
|
354
382
|
await core.auth.rootuser.setName(1)
|
|
383
|
+
with self.raises(s_exc.BadArg):
|
|
384
|
+
await core.auth.rootuser.setName('secretroot')
|
|
355
385
|
with self.raises(s_exc.BadArg):
|
|
356
386
|
await core.auth.allrole.setName(1)
|
|
387
|
+
with self.raises(s_exc.BadArg):
|
|
388
|
+
await core.auth.allrole.setName('nobody')
|
|
357
389
|
with self.raises(s_exc.SchemaViolation):
|
|
358
390
|
await core.auth.rootuser.addRule('vi.si')
|
|
359
391
|
with self.raises(s_exc.SchemaViolation):
|
|
@@ -362,10 +394,16 @@ class AuthTest(s_test.SynTest):
|
|
|
362
394
|
await core.auth.allrole.setRules(None)
|
|
363
395
|
with self.raises(s_exc.BadArg):
|
|
364
396
|
await core.auth.rootuser.setAdmin('lol')
|
|
397
|
+
with self.raises(s_exc.BadArg):
|
|
398
|
+
await core.auth.rootuser.setAdmin(False)
|
|
365
399
|
with self.raises(s_exc.BadArg):
|
|
366
400
|
await core.auth.rootuser.setLocked('lol')
|
|
401
|
+
with self.raises(s_exc.BadArg):
|
|
402
|
+
await core.auth.rootuser.setLocked(True)
|
|
367
403
|
with self.raises(s_exc.BadArg):
|
|
368
404
|
await core.auth.rootuser.setArchived('lol')
|
|
405
|
+
with self.raises(s_exc.BadArg):
|
|
406
|
+
await core.auth.rootuser.setArchived(True)
|
|
369
407
|
with self.raises(s_exc.SchemaViolation):
|
|
370
408
|
await core.auth.allrole.addRule((1, ('hehe', 'haha')))
|
|
371
409
|
with self.raises(s_exc.SchemaViolation):
|
|
@@ -373,6 +411,271 @@ class AuthTest(s_test.SynTest):
|
|
|
373
411
|
with self.raises(s_exc.SchemaViolation):
|
|
374
412
|
await core.auth.allrole.setRules([(True, )])
|
|
375
413
|
|
|
414
|
+
async def test_auth_password_policy(self):
|
|
415
|
+
policy = {
|
|
416
|
+
'complexity': {
|
|
417
|
+
'length': 12,
|
|
418
|
+
'sequences': 3,
|
|
419
|
+
'upper:count': 2,
|
|
420
|
+
'lower:count': 2,
|
|
421
|
+
'lower:valid': string.ascii_lowercase + 'αβγ',
|
|
422
|
+
'special:count': 2,
|
|
423
|
+
'number:count': 2,
|
|
424
|
+
},
|
|
425
|
+
'attempts': 3,
|
|
426
|
+
'previous': 2,
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
pass1 = 'jhf9_gaf-xaw-QBX4dqp'
|
|
430
|
+
pass2 = 'rek@hjv6VBV2rwe2qwd!'
|
|
431
|
+
pass3 = 'ZXN-pyv7ber-kzq2kgh'
|
|
432
|
+
|
|
433
|
+
conf = {'auth:passwd:policy': policy}
|
|
434
|
+
async with self.getTestCore(conf=conf) as core:
|
|
435
|
+
auth = core.auth
|
|
436
|
+
self.nn(auth.policy)
|
|
437
|
+
|
|
438
|
+
user = await auth.addUser('blackout@vertex.link')
|
|
439
|
+
|
|
440
|
+
# Compliant passwords
|
|
441
|
+
await core.setUserPasswd(user.iden, pass1)
|
|
442
|
+
await core.setUserPasswd(user.iden, pass2)
|
|
443
|
+
await core.setUserPasswd(user.iden, pass3)
|
|
444
|
+
|
|
445
|
+
# Test password attempt reset
|
|
446
|
+
await core.tryUserPasswd(user.name, 'foo')
|
|
447
|
+
self.eq(user.info.get('policy:attempts'), 1)
|
|
448
|
+
|
|
449
|
+
await core.tryUserPasswd(user.name, pass3)
|
|
450
|
+
self.eq(user.info.get('policy:attempts'), 0)
|
|
451
|
+
|
|
452
|
+
# Test lockout from too many invalid attempts
|
|
453
|
+
self.false(await core.tryUserPasswd(user.name, 'foo'))
|
|
454
|
+
self.false(await core.tryUserPasswd(user.name, 'foo'))
|
|
455
|
+
self.false(await core.tryUserPasswd(user.name, 'foo'))
|
|
456
|
+
self.eq(user.info.get('policy:attempts'), 3)
|
|
457
|
+
self.true(user.info.get('locked'))
|
|
458
|
+
|
|
459
|
+
await user.setLocked(False)
|
|
460
|
+
self.eq(user.info.get('policy:attempts'), 0)
|
|
461
|
+
|
|
462
|
+
# Test reusing previous password
|
|
463
|
+
with self.raises(s_exc.BadArg) as exc:
|
|
464
|
+
await core.setUserPasswd(user.iden, pass2)
|
|
465
|
+
self.eq(exc.exception.get('failures'), [
|
|
466
|
+
'Password cannot be the same as previous 2 password(s).'
|
|
467
|
+
])
|
|
468
|
+
|
|
469
|
+
await core.setUserPasswd(user.iden, pass1)
|
|
470
|
+
|
|
471
|
+
# Test password that doesn't meet complexity requirements
|
|
472
|
+
with self.raises(s_exc.BadArg) as exc:
|
|
473
|
+
await core.setUserPasswd(user.iden, 'Ff1!')
|
|
474
|
+
self.eq(exc.exception.get('failures'), [
|
|
475
|
+
'Password must be at least 12 characters.',
|
|
476
|
+
'Password must contain at least 2 uppercase characters, 1 found.',
|
|
477
|
+
'Password must contain at least 2 lowercase characters, 1 found.',
|
|
478
|
+
'Password must contain at least 2 special characters, 1 found.',
|
|
479
|
+
'Password must contain at least 2 digit characters, 1 found.'
|
|
480
|
+
])
|
|
481
|
+
|
|
482
|
+
# Check sequences
|
|
483
|
+
seqmsg = f'Password must not contain forward/reverse sequences longer than 3 characters.'
|
|
484
|
+
passwords = [
|
|
485
|
+
# letters
|
|
486
|
+
'abcA', 'dcbA', 'Abcd', 'Acba',
|
|
487
|
+
|
|
488
|
+
# numbers
|
|
489
|
+
'123A', '432A', 'A234', 'A321',
|
|
490
|
+
|
|
491
|
+
# greek alphabet (unicode test)
|
|
492
|
+
'αβγA', 'Aαβγ', 'γβαA', 'Aγβα',
|
|
493
|
+
|
|
494
|
+
]
|
|
495
|
+
|
|
496
|
+
for password in passwords:
|
|
497
|
+
with self.raises(s_exc.BadArg) as exc:
|
|
498
|
+
await core.setUserPasswd(user.iden, password)
|
|
499
|
+
self.isin(seqmsg, exc.exception.get('failures'))
|
|
500
|
+
|
|
501
|
+
with self.raises(s_exc.BadArg) as exc:
|
|
502
|
+
await core.setUserPasswd(user.iden, 'AAAA')
|
|
503
|
+
self.eq(exc.exception.get('failures'), [
|
|
504
|
+
'Password must be at least 12 characters.',
|
|
505
|
+
'Password must contain at least 2 lowercase characters, 0 found.',
|
|
506
|
+
'Password must contain at least 2 special characters, 0 found.',
|
|
507
|
+
'Password must contain at least 2 digit characters, 0 found.'
|
|
508
|
+
])
|
|
509
|
+
|
|
510
|
+
with self.raises(s_exc.BadArg) as exc:
|
|
511
|
+
await core.setUserPasswd(user.iden, 'aaaa')
|
|
512
|
+
self.eq(exc.exception.get('failures'), [
|
|
513
|
+
'Password must be at least 12 characters.',
|
|
514
|
+
'Password must contain at least 2 uppercase characters, 0 found.',
|
|
515
|
+
'Password must contain at least 2 special characters, 0 found.',
|
|
516
|
+
'Password must contain at least 2 digit characters, 0 found.'
|
|
517
|
+
])
|
|
518
|
+
|
|
519
|
+
with self.raises(s_exc.BadArg) as exc:
|
|
520
|
+
await core.setUserPasswd(user.iden, None)
|
|
521
|
+
self.isin(
|
|
522
|
+
'Password must be at least 12 characters.',
|
|
523
|
+
exc.exception.get('failures')
|
|
524
|
+
)
|
|
525
|
+
|
|
526
|
+
# Attempting to add a user with a bad passwd will add the user and fail to set the password
|
|
527
|
+
with self.raises(s_exc.BadArg):
|
|
528
|
+
await core.addUser('bob.grey', email='bob.grey@vertex.link', passwd='noncompliant')
|
|
529
|
+
user = await core.auth.getUserByName('bob.grey')
|
|
530
|
+
self.eq('bob.grey@vertex.link', user.info.get('email'))
|
|
531
|
+
self.len(1, user.info.get('roles')) # User has the default all role
|
|
532
|
+
# Password was not set
|
|
533
|
+
self.false(await user.tryPasswd('noncompliant'))
|
|
534
|
+
|
|
535
|
+
policy = {
|
|
536
|
+
'complexity': {
|
|
537
|
+
'length': None,
|
|
538
|
+
},
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
conf = {'auth:passwd:policy': policy}
|
|
542
|
+
async with self.getTestCore(conf=conf) as core:
|
|
543
|
+
auth = core.auth
|
|
544
|
+
|
|
545
|
+
user = await auth.addUser('blackout@vertex.link')
|
|
546
|
+
|
|
547
|
+
await core.setUserPasswd(user.iden, None)
|
|
548
|
+
|
|
549
|
+
with self.raises(s_exc.BadArg) as exc:
|
|
550
|
+
await core.setUserPasswd(user.iden, 'αβγA')
|
|
551
|
+
self.isin(
|
|
552
|
+
"Password contains invalid characters: ['α', 'β', 'γ']",
|
|
553
|
+
exc.exception.get('failures')
|
|
554
|
+
)
|
|
555
|
+
|
|
556
|
+
policy = {
|
|
557
|
+
'complexity': None,
|
|
558
|
+
'previous': 3,
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
conf = {'auth:passwd:policy': policy}
|
|
562
|
+
async with self.getTestCore(conf=conf) as core:
|
|
563
|
+
auth = core.auth
|
|
564
|
+
|
|
565
|
+
user = await auth.addUser('blackout@vertex.link')
|
|
566
|
+
await core.setUserPasswd(user.iden, pass1)
|
|
567
|
+
await core.setUserPasswd(user.iden, pass2)
|
|
568
|
+
await core.setUserPasswd(user.iden, pass3)
|
|
569
|
+
|
|
570
|
+
with self.raises(s_exc.BadArg) as exc:
|
|
571
|
+
await core.setUserPasswd(user.iden, pass1)
|
|
572
|
+
self.eq(exc.exception.get('failures'), [
|
|
573
|
+
'Password cannot be the same as previous 3 password(s).'
|
|
574
|
+
])
|
|
575
|
+
|
|
576
|
+
# Single complexity rule, uses default character lists
|
|
577
|
+
policy = {'complexity': {'length': 3}}
|
|
578
|
+
conf = {'auth:passwd:policy': policy}
|
|
579
|
+
async with self.getTestCore(conf=conf) as core:
|
|
580
|
+
auth = core.auth
|
|
581
|
+
user = await auth.addUser('blackout@vertex.link')
|
|
582
|
+
with self.raises(s_exc.BadArg):
|
|
583
|
+
await core.setUserPasswd(user.iden, 'no')
|
|
584
|
+
await core.setUserPasswd(user.iden, 'hehe')
|
|
585
|
+
await core.setUserPasswd(user.iden, 'heh')
|
|
586
|
+
with self.raises(s_exc.BadArg) as cm:
|
|
587
|
+
await core.setUserPasswd(user.iden, 'hehαβγ')
|
|
588
|
+
self.isin('Password contains invalid characters', cm.exception.get('mesg'))
|
|
589
|
+
|
|
590
|
+
# Complexity disables the *:valid groups so they will not be checked
|
|
591
|
+
policy = {'complexity': {'length': 3,
|
|
592
|
+
'upper:valid': None,
|
|
593
|
+
'upper:count': 20,
|
|
594
|
+
'lower:valid': None,
|
|
595
|
+
'lower:count': 20,
|
|
596
|
+
'special:valid': None,
|
|
597
|
+
'special:count': 20,
|
|
598
|
+
'number:valid': None,
|
|
599
|
+
'number:count': 20,
|
|
600
|
+
}}
|
|
601
|
+
conf = {'auth:passwd:policy': policy}
|
|
602
|
+
async with self.getTestCore(conf=conf) as core:
|
|
603
|
+
auth = core.auth
|
|
604
|
+
user = await auth.addUser('blackout@vertex.link')
|
|
605
|
+
with self.raises(s_exc.BadArg):
|
|
606
|
+
await core.setUserPasswd(user.iden, 'no')
|
|
607
|
+
await core.setUserPasswd(user.iden, 'heh')
|
|
608
|
+
await core.setUserPasswd(user.iden, 'hehαβγ1234!!@!@!')
|
|
609
|
+
|
|
610
|
+
# Policy only allows lowercase and specials...
|
|
611
|
+
policy = {'complexity': {'length': 2,
|
|
612
|
+
'upper:valid': None,
|
|
613
|
+
'number:valid': None,
|
|
614
|
+
'lower:count': 1,
|
|
615
|
+
'special:count': 1,
|
|
616
|
+
}}
|
|
617
|
+
conf = {'auth:passwd:policy': policy}
|
|
618
|
+
async with self.getTestCore(conf=conf) as core:
|
|
619
|
+
auth = core.auth
|
|
620
|
+
user = await auth.addUser('blackout@vertex.link')
|
|
621
|
+
with self.raises(s_exc.BadArg):
|
|
622
|
+
await core.setUserPasswd(user.iden, 'No')
|
|
623
|
+
with self.raises(s_exc.BadArg):
|
|
624
|
+
await core.setUserPasswd(user.iden, '1o')
|
|
625
|
+
await core.setUserPasswd(user.iden, 'y#s')
|
|
626
|
+
|
|
627
|
+
# Policy enforces character sets but doesn't care about minimum entries
|
|
628
|
+
policy = {'complexity': {'length': 3,
|
|
629
|
+
'upper:count': None,
|
|
630
|
+
'lower:count': None,
|
|
631
|
+
'special:count': None,
|
|
632
|
+
'number:count': None,
|
|
633
|
+
}}
|
|
634
|
+
conf = {'auth:passwd:policy': policy}
|
|
635
|
+
async with self.getTestCore(conf=conf) as core:
|
|
636
|
+
auth = core.auth
|
|
637
|
+
user = await auth.addUser('blackout@vertex.link')
|
|
638
|
+
await core.setUserPasswd(user.iden, 'yup')
|
|
639
|
+
await core.setUserPasswd(user.iden, 'Y!0')
|
|
640
|
+
with self.raises(s_exc.BadArg) as cm:
|
|
641
|
+
await core.setUserPasswd(user.iden, 'sadαβγ')
|
|
642
|
+
self.isin('Password contains invalid characters', cm.exception.get('mesg'))
|
|
643
|
+
|
|
644
|
+
# No complexity rules
|
|
645
|
+
policy = {'attempts': 1}
|
|
646
|
+
conf = {'auth:passwd:policy': policy, 'auth:passwd': 'secret'}
|
|
647
|
+
async with self.getTestCore(conf=conf) as core:
|
|
648
|
+
auth = core.auth
|
|
649
|
+
user = await auth.addUser('blackout@vertex.link')
|
|
650
|
+
await core.setUserPasswd(user.iden, 'hehe')
|
|
651
|
+
self.true(await user.tryPasswd('hehe'))
|
|
652
|
+
self.false(await user.tryPasswd('newp'))
|
|
653
|
+
self.true(user.isLocked())
|
|
654
|
+
# Root user may track policy lockouts but will not be locked out by failures.
|
|
655
|
+
root = auth.rootuser
|
|
656
|
+
self.false(await root.tryPasswd('newp'))
|
|
657
|
+
self.false(await root.tryPasswd('newpx'))
|
|
658
|
+
self.eq(root.info.get('policy:attempts'), 2)
|
|
659
|
+
self.false(root.isLocked())
|
|
660
|
+
# valid passwod auth resets root atttempt counter.
|
|
661
|
+
self.true(await root.tryPasswd('secret'))
|
|
662
|
+
self.eq(root.info.get('policy:attempts'), 0)
|
|
663
|
+
|
|
664
|
+
# auth:passwd does not interact with auth:passwd:policy
|
|
665
|
+
with self.getTestDir() as dirn:
|
|
666
|
+
policy = {'complexity': {'length': 5}}
|
|
667
|
+
conf = {'auth:passwd': 'newp', 'auth:passwd:policy': policy}
|
|
668
|
+
async with self.getTestCore(conf=conf, dirn=dirn) as core:
|
|
669
|
+
user = core.auth.rootuser
|
|
670
|
+
self.false(await user.tryPasswd('hehe'))
|
|
671
|
+
self.true(await user.tryPasswd('newp'))
|
|
672
|
+
|
|
673
|
+
conf = {'auth:passwd': 'yupp!!', 'auth:passwd:policy': policy}
|
|
674
|
+
async with self.getTestCore(conf=conf, dirn=dirn) as core:
|
|
675
|
+
user = core.auth.rootuser
|
|
676
|
+
self.false(await user.tryPasswd('newp'))
|
|
677
|
+
self.true(await user.tryPasswd('yupp!!'))
|
|
678
|
+
|
|
376
679
|
async def test_hive_auth_deepdeny(self):
|
|
377
680
|
async with self.getTestCore() as core:
|
|
378
681
|
|
synapse/tests/test_lib_base.py
CHANGED
|
@@ -60,6 +60,21 @@ class BaseTest(s_t_utils.SynTest):
|
|
|
60
60
|
event = await base.fire('woot', x=3, y=5, ret=[])
|
|
61
61
|
self.eq(event[1]['ret'], 8)
|
|
62
62
|
|
|
63
|
+
base00 = await s_base.Base.anit()
|
|
64
|
+
base01 = await s_base.Base.anit()
|
|
65
|
+
data = {}
|
|
66
|
+
async def onfini():
|
|
67
|
+
data['woot'] = True
|
|
68
|
+
|
|
69
|
+
await base00.fini()
|
|
70
|
+
base00.onfini(onfini)
|
|
71
|
+
await asyncio.sleep(0)
|
|
72
|
+
self.true(data.get('woot'))
|
|
73
|
+
|
|
74
|
+
base00.onfini(base01)
|
|
75
|
+
await asyncio.sleep(0)
|
|
76
|
+
self.true(base01.isfini)
|
|
77
|
+
|
|
63
78
|
async def test_base_anit(self):
|
|
64
79
|
|
|
65
80
|
afoo = await Hehe.anit(20)
|
|
@@ -201,6 +216,7 @@ class BaseTest(s_t_utils.SynTest):
|
|
|
201
216
|
self.eq(data['count'], 1)
|
|
202
217
|
|
|
203
218
|
async def test_base_waiter(self):
|
|
219
|
+
|
|
204
220
|
base0 = await s_base.Base.anit()
|
|
205
221
|
|
|
206
222
|
wait0 = base0.waiter(3, 'foo:bar')
|
|
@@ -224,6 +240,10 @@ class BaseTest(s_t_utils.SynTest):
|
|
|
224
240
|
evts = await wait2.wait(1)
|
|
225
241
|
self.len(2, evts)
|
|
226
242
|
|
|
243
|
+
with self.raises(s_exc.TimeOut):
|
|
244
|
+
async with base0.waiter(1, 'newp', 'nuuh', timeout=0.01):
|
|
245
|
+
pass
|
|
246
|
+
|
|
227
247
|
async def test_baseref(self):
|
|
228
248
|
|
|
229
249
|
bref = await s_base.BaseRef.anit()
|