Implement scoped P06 authentication policy and guarded optional onboarding
Assistant: codex Assistant-Model: gpt-6-astra Assistant-Session: 01a09cbb-87c6-7900-a145-4ce53ba9f1a6
This commit is contained in:
parent
aa709fb854
commit
e0b3c25f06
12 changed files with 1085 additions and 2 deletions
53
scripts/provider-browser-fixture.py
Normal file
53
scripts/provider-browser-fixture.py
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
"""Isolated provider contract test. Never loads production config or credentials."""
|
||||
import contextlib,io,json,logging,os,tempfile,time,base64,hmac,hashlib,struct,urllib.parse
|
||||
from pathlib import Path
|
||||
result={"success":False};phase="isolation"
|
||||
def check(name,condition):
|
||||
result[name]=bool(condition)
|
||||
if not condition:raise ValueError(name)
|
||||
def run():
|
||||
global phase
|
||||
for k in list(os.environ):
|
||||
if k.startswith("PRIVACYIDEA_"):del os.environ[k]
|
||||
logging.disable(logging.CRITICAL)
|
||||
with tempfile.TemporaryDirectory(prefix="provider-contract-") as d:
|
||||
root=Path(d);(root/'enckey').write_bytes(os.urandom(96))
|
||||
cfg=root/'fixture.cfg';cfg.write_text("SQLALCHEMY_DATABASE_URI='sqlite:///PLACEHOLDER_DB'\nSECRET_KEY='isolated-fixture-only'\nPI_PEPPER='isolated-fixture-only'\nPI_NO_RESPONSE_SIGN=True\nPI_AUDIT_NO_SIGN=True\nPI_LOGFILE="+repr(str(root/'log'))+"\nPI_ENCFILE="+repr(str(root/'enckey'))+"\nPI_TRUSTED_JWT=[]\n")
|
||||
cfg.write_text(cfg.read_text().replace('PLACEHOLDER_DB', str(root/'fixture.sqlite')))
|
||||
with cfg.open('a') as f:f.write('PI_AUDIT_SQL_URI='+repr('sqlite:///'+str(root/'audit.sqlite'))+'\n')
|
||||
from privacyidea.app import create_app
|
||||
from privacyidea.models import db
|
||||
from privacyidea.lib.policy import set_policy,enable_policy
|
||||
from privacyidea.lib.resolver import save_resolver
|
||||
from privacyidea.lib.realm import set_realm
|
||||
from privacyidea.lib.auth import create_db_admin
|
||||
from privacyidea.lib.resolvers.PasswdIdResolver import crypt_ctx
|
||||
app=create_app(config_name="testing",config_file=str(cfg),silent=True)
|
||||
app.config["PI_INIT_CHECK_HOOK"]="keycape_onboarding_guard.check"
|
||||
phase="fixture_database"
|
||||
with app.app_context():
|
||||
check('database_isolated',str(db.engine.url)=='sqlite:///'+str(root/'fixture.sqlite'));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)
|
||||
passwd=root/'users';passwd.write_text('alice:'+crypt_ctx.hash('fixture-password',scheme='sha512_crypt')+':1001:1001:Fixture:/tmp:/bin/false\n')
|
||||
with passwd.open('a') as f:f.write('native-alice:'+crypt_ctx.hash('fixture-password',scheme='sha512_crypt')+':1002:1002:Native fixture:/tmp:/bin/false\n')
|
||||
save_resolver({'resolver':'fixture-users','type':'passwdresolver','fileName':str(passwd)})
|
||||
set_realm('fixture',[{'name':'fixture-users'}])
|
||||
create_db_admin('fixture-reader',password='fixture-service-password')
|
||||
set_policy(name='fixture-admin-baseline',scope='admin',action='*',adminuser=['*','!fixture-reader'])
|
||||
set_policy(name='fixture-reader',scope='admin',action='tokenlist',adminuser='fixture-reader',realm='fixture')
|
||||
set_policy(name='fixture-user',scope='user',action='enrollTOTP',realm='fixture')
|
||||
set_policy(name='fixture-pending-cancel',scope='user',action='delete',realm='fixture',conditions=[('token','rollout_state','equals','verify',True)])
|
||||
set_policy(name='fixture-confirmation',scope='enrollment',action='verify_enrollment=totp',realm='fixture')
|
||||
set_policy(name='fixture-passthru',scope='authentication',action='passthru',realm='fixture')
|
||||
from privacyidea.lib.token import init_token
|
||||
probe=init_token({'serial':'P06SCOPEPROBE','type':'hotp','genkey':1,'realm':'fixture'})
|
||||
probe.token.active=False;probe.token.save()
|
||||
print(json.dumps({"fixture_ready":True,"production_database":False}),flush=True)
|
||||
app.run(host="0.0.0.0",port=8088,debug=False,use_reloader=False)
|
||||
if __name__=="__main__":
|
||||
try:run()
|
||||
except Exception as error:
|
||||
print(json.dumps({"fixture_failure":type(error).__name__,"phase":phase}),flush=True)
|
||||
raise SystemExit(1)
|
||||
Loading…
Add table
Add a link
Reference in a new issue