"""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)