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
27
scripts/keycape_onboarding_guard.py
Normal file
27
scripts/keycape_onboarding_guard.py
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
"""Provider enrollment hook: password-only self-service cannot replace an active factor.
|
||||
|
||||
Loaded explicitly by provider configuration, so a missing module fails startup.
|
||||
Pending setup can be regenerated/confirmed; active-factor replacement goes through
|
||||
fresh-MFA audited recovery. Admin actions retain their existing provider policies.
|
||||
"""
|
||||
def check(request, action):
|
||||
from flask import g
|
||||
from privacyidea.lib.error import PolicyError
|
||||
from privacyidea.lib.user import User
|
||||
from privacyidea.lib.token import get_tokens
|
||||
|
||||
principal = g.logged_in_user
|
||||
if principal.get('role') != 'user':
|
||||
return True
|
||||
user = User(principal.get('username', ''), principal.get('realm', ''))
|
||||
if user.is_empty() or action != 'init':
|
||||
raise PolicyError('Use the account recovery process to replace an active authenticator.')
|
||||
tokens = get_tokens(user=user, active=True)
|
||||
if any(token.token.rollout_state not in {'verify', 'clientwait', 'pending'} for token in tokens):
|
||||
raise PolicyError('An active authenticator already exists. Use the account recovery process to replace it.')
|
||||
serial = request.all_data.get('serial')
|
||||
if serial:
|
||||
matches = [token for token in tokens if token.token.serial == serial]
|
||||
if len(matches) != 1 or matches[0].token.rollout_state != 'verify':
|
||||
raise PolicyError('Only your unfinished authenticator setup can be confirmed or regenerated.')
|
||||
return True
|
||||
Loading…
Add table
Add a link
Reference in a new issue