net-kingdom/tests/realm_bootstrap_native_fixture.py

85 lines
4.9 KiB
Python
Raw Normal View History

"""Disposable privacyIDEA 3.12.2 HTTP and database proof, no production config."""
import contextlib
import io
import json
import logging
import os
from pathlib import Path
import sys
import tempfile
import threading
def run():
for name in list(os.environ):
if name.startswith('PRIVACYIDEA_'):del os.environ[name]
logging.disable(logging.CRITICAL)
sys.path.insert(0,str(Path(__file__).resolve().parents[1]/'sso-mfa/k8s/privacyidea'))
import realm_bootstrap as r
from privacyidea.app import create_app
from privacyidea.models import db
from privacyidea.lib.auth import create_db_admin
from privacyidea.lib.policy import PolicyClass,set_policy
from privacyidea.lib.resolver import get_resolver_config,save_resolver
from privacyidea.lib.realm import set_realm,set_default_realm
from werkzeug.serving import make_server
with tempfile.TemporaryDirectory(prefix='realm-native-') as directory:
root=Path(directory);(root/'enckey').write_bytes(os.urandom(96))
cfg=root/'fixture.cfg'
config=dict(SQLALCHEMY_DATABASE_URI='sqlite:///'+str(root/'db.sqlite'),SECRET_KEY='fixture-secret-key',
PI_PEPPER='fixture-pepper',PI_ENCFILE=str(root/'enckey'),PI_NO_RESPONSE_SIGN=True,
PI_AUDIT_NO_SIGN=True,PI_LOGFILE=str(root/'log'),PI_TRUSTED_JWT=[],
PI_AUDIT_SQL_URI='sqlite:///'+str(root/'audit.sqlite'))
cfg.write_text('\n'.join(k+'='+repr(v) for k,v in config.items()))
app=create_app(config_name='testing',config_file=str(cfg),silent=True)
with app.app_context():
assert str(db.engine.url)==config['SQLALCHEMY_DATABASE_URI'];db.create_all()
from privacyidea.lib.audit import getAudit
from privacyidea.lib.auditmodules.sqlaudit import LogEntry
LogEntry.__table__.create(getAudit(app.config).engine,checkfirst=True)
create_db_admin('pi-admin',password='fixture-admin-password')
policies=PolicyClass().policies
server=make_server('127.0.0.1',0,app);thread=threading.Thread(target=server.serve_forever,daemon=True);thread.start()
try:
client=r.Client(f'http://127.0.0.1:{server.server_port}','fixture-admin-password')
preview=r.repair(client,lambda:None)
assert preview['configuration_writes']==0
result=r.repair(client,lambda:'fixture-bind-password',apply=True)
assert result['actions']==['create-resolver','create-realm','set-first-realm-default'],result
with app.app_context():
assert get_resolver_config(r.RESOLVER)['BINDPW']=='fixture-bind-password'
assert PolicyClass().policies==policies
set_policy(name='totp-self-enrollment',scope='user',action='enrollTOTP',realm='coulomb')
set_policy(name='keycape-pending-enrollment-cancel',scope='user',action='delete',realm='coulomb',conditions=[('token','rollout_state','equals','verify',True)])
set_policy(name='mfa-passthru-phase1',scope='authentication',action='passthru',realm='coulomb',active=False)
policies=PolicyClass().policies
save_resolver({'resolver':r.RESOLVER,'type':'ldapresolver','TIMEOUT':'','SIZELIMIT':'777','TLS_VERIFY':True,'CACHE_TIMEOUT':'333'})
set_realm('other',[]);set_default_realm('other')
before=client.snapshot()
result=r.repair(client,lambda:(_ for _ in ()).throw(AssertionError()),apply=True)
assert result['actions']==['fill-missing-tuning']
after=client.snapshot()
assert after['realms']==before['realms']
assert after['resolver']['data']['TIMEOUT']=='5'
for key,value in before['resolver']['data'].items():
if key!='TIMEOUT':assert after['resolver']['data'][key]==value
with app.app_context():
assert get_resolver_config(r.RESOLVER)['BINDPW']=='fixture-bind-password'
assert PolicyClass().policies==policies
assert r.repair(client,lambda:None,apply=True)['configuration_writes']==0
return {'native_create_and_readback':True,'native_minimal_update_preserves_omitted_fields':True,
'native_bind_password_preserved':True,'native_hardened_policies_preserved':True,
'native_existing_default_preserved':True,'native_repeat_is_noop':True}
finally:server.shutdown();thread.join();server.server_close()
if __name__=='__main__':
try:
with contextlib.redirect_stdout(io.StringIO()),contextlib.redirect_stderr(io.StringIO()):result=run()
print(json.dumps(result,sort_keys=True))
except Exception as exc:
import traceback
frame=traceback.extract_tb(exc.__traceback__)[-1]
print(json.dumps({'result':'failed','type':type(exc).__name__,'file':Path(frame.filename).name,'line':frame.lineno}))
raise SystemExit(1)