FIX: mandant wird erstellt wenn sich ein user mit microsoft oder google das erste mal registriert, damit er die app tatsächlich nutzen kann

This commit is contained in:
Ida 2026-06-12 09:28:11 +02:00
parent 66b44e5c78
commit 0438177934
5 changed files with 94 additions and 45 deletions

View file

@ -0,0 +1,55 @@
# Copyright (c) 2026 PowerOn AG
# All rights reserved.
"""Ensure new users receive a Home mandate on first login."""
import logging
logger = logging.getLogger(__name__)
def ensureHomeMandate(rootInterface, user) -> None:
"""Ensure user has a Home mandate, but only if they have no mandate memberships
AND no pending invitations.
Invited users should NOT get a Home mandate they join existing mandates via
invitation acceptance and can create their own later via onboarding.
"""
userId = str(user.id)
userMandates = rootInterface.getUserMandates(userId)
if userMandates:
for um in userMandates:
mandate = rootInterface.getMandate(um.mandateId)
if mandate and (mandate.name or "").startswith("Home ") and not mandate.isSystem:
return
logger.debug(
f"User {user.username} has {len(userMandates)} mandate(s) but no Home — skipping auto-creation"
)
return
try:
normalizedEmail = (user.email or "").strip().lower() if user.email else None
pendingByUsername = rootInterface.getInvitationsByTargetUsername(user.username)
pendingByEmail = (
rootInterface.getInvitationsByEmail(normalizedEmail) if normalizedEmail else []
)
seenIds = set()
for inv in pendingByUsername + pendingByEmail:
if inv.id in seenIds:
continue
seenIds.add(inv.id)
if not inv.revokedAt and (inv.currentUses or 0) < (inv.maxUses or 1):
logger.info(
f"User {user.username} has pending invitation(s) — skipping Home mandate creation"
)
return
except Exception as e:
logger.warning(f"Could not check pending invitations for {user.username}: {e}")
homeMandateLabel = f"Home {user.username}"
rootInterface._provisionMandateForUser(
userId=userId,
mandateLabel=homeMandateLabel,
planKey="TRIAL_14D",
)
logger.info(f"Created Home mandate '{homeMandateLabel}' for user {user.username}")

View file

@ -26,6 +26,7 @@ from modules.auth import (
setAccessTokenCookie, setAccessTokenCookie,
setRefreshTokenCookie, setRefreshTokenCookie,
) )
from modules.auth.homeMandateService import ensureHomeMandate
from modules.auth.mfaService import ( from modules.auth.mfaService import (
generateSetup, generateSetup,
confirmSetup, confirmSetup,
@ -229,6 +230,20 @@ def mfaVerify(
) )
userInterface.saveAccessToken(dbToken) userInterface.saveAccessToken(dbToken)
try:
ensureHomeMandate(rootInterface, user)
except Exception as homeErr:
logger.error(f"Error ensuring Home mandate for user {username}: {homeErr}")
try:
activatedCount = rootInterface._activatePendingSubscriptions(userId)
if activatedCount > 0:
logger.info(
f"Activated {activatedCount} pending subscription(s) for user {username} after MFA"
)
except Exception as subErr:
logger.error(f"Error activating subscriptions after MFA verify: {subErr}")
logger.info("MFA verify successful for user %s", username) logger.info("MFA verify successful for user %s", username)
# Mark device as trusted so MFA is skipped on next login from this device # Mark device as trusted so MFA is skipped on next login from this device

View file

@ -34,6 +34,7 @@ from modules.auth import (
) )
from modules.auth.tokenManager import TokenManager from modules.auth.tokenManager import TokenManager
from modules.auth.oauthProviderConfig import googleAuthScopes, googleDataScopes from modules.auth.oauthProviderConfig import googleAuthScopes, googleDataScopes
from modules.auth.homeMandateService import ensureHomeMandate
from modules.shared.timeUtils import createExpirationTimestamp, getUtcTimestamp, parseTimestamp from modules.shared.timeUtils import createExpirationTimestamp, getUtcTimestamp, parseTimestamp
from modules.shared.i18nRegistry import apiRouteContext from modules.shared.i18nRegistry import apiRouteContext
routeApiMsg = apiRouteContext("routeSecurityGoogle") routeApiMsg = apiRouteContext("routeSecurityGoogle")
@ -278,6 +279,11 @@ async def auth_login_callback(
) )
# --- end MFA gate ----------------------------------------------------- # --- end MFA gate -----------------------------------------------------
try:
ensureHomeMandate(rootInterface, user)
except Exception as homeErr:
logger.error(f"Error ensuring Home mandate for user {user.username}: {homeErr}")
jwt_token_data = { jwt_token_data = {
"sub": user.username, "sub": user.username,
"userId": str(user.id), "userId": str(user.id),

View file

@ -16,12 +16,13 @@ from jose import jwt
# Import auth modules # Import auth modules
from modules.auth import getCurrentUser, limiter, SECRET_KEY, ALGORITHM, getRequestContext, RequestContext from modules.auth import getCurrentUser, limiter, SECRET_KEY, ALGORITHM, getRequestContext, RequestContext
from modules.auth import createAccessToken, createRefreshToken, setAccessTokenCookie, setRefreshTokenCookie, clearAccessTokenCookie, clearRefreshTokenCookie from modules.auth import createAccessToken, createRefreshToken, setAccessTokenCookie, setRefreshTokenCookie, clearAccessTokenCookie, clearRefreshTokenCookie
from modules.interfaces.interfaceDbApp import getInterface, getRootInterface, getRootInterface as _getRootIf from modules.interfaces.interfaceDbApp import getInterface, getRootInterface
from modules.datamodels.datamodelUam import User, UserInDB, AuthAuthority, Mandate from modules.datamodels.datamodelUam import User, UserInDB, AuthAuthority, Mandate
from modules.datamodels.datamodelSecurity import Token, TokenPurpose from modules.datamodels.datamodelSecurity import Token, TokenPurpose
from modules.shared.configuration import APP_CONFIG from modules.shared.configuration import APP_CONFIG
from modules.shared.timeUtils import getUtcTimestamp from modules.shared.timeUtils import getUtcTimestamp
from modules.shared.i18nRegistry import apiRouteContext from modules.shared.i18nRegistry import apiRouteContext
from modules.auth.homeMandateService import ensureHomeMandate
routeApiMsg = apiRouteContext("routeSecurityLocal") routeApiMsg = apiRouteContext("routeSecurityLocal")
# Configure logger # Configure logger
@ -174,49 +175,6 @@ router = APIRouter(
} }
) )
def _ensureHomeMandate(rootInterface, user) -> None:
"""Ensure user has a Home mandate, but only if they have no mandate memberships
AND no pending invitations.
Invited users should NOT get a Home mandate they join existing mandates via
invitation acceptance and can create their own later via onboarding.
"""
userId = str(user.id)
userMandates = rootInterface.getUserMandates(userId)
if userMandates:
for um in userMandates:
mandate = rootInterface.getMandate(um.mandateId)
if mandate and (mandate.name or "").startswith("Home ") and not mandate.isSystem:
return
logger.debug(f"User {user.username} has {len(userMandates)} mandate(s) but no Home — skipping auto-creation")
return
try:
appIf = _getRootIf()
normalizedEmail = (user.email or "").strip().lower() if user.email else None
pendingByUsername = appIf.getInvitationsByTargetUsername(user.username)
pendingByEmail = appIf.getInvitationsByEmail(normalizedEmail) if normalizedEmail else []
seenIds = set()
for inv in pendingByUsername + pendingByEmail:
if inv.id in seenIds:
continue
seenIds.add(inv.id)
if not inv.revokedAt and (inv.currentUses or 0) < (inv.maxUses or 1):
logger.info(f"User {user.username} has pending invitation(s) — skipping Home mandate creation")
return
except Exception as e:
logger.warning(f"Could not check pending invitations for {user.username}: {e}")
homeMandateLabel = f"Home {user.username}"
rootInterface._provisionMandateForUser(
userId=userId,
mandateLabel=homeMandateLabel,
planKey="TRIAL_14D",
)
logger.info(f"Created Home mandate '{homeMandateLabel}' for user {user.username}")
@router.post("/login") @router.post("/login")
@limiter.limit("30/minute") @limiter.limit("30/minute")
def login( def login(
@ -364,7 +322,7 @@ def login(
# Ensure user has a Home mandate (created on first login if missing) # Ensure user has a Home mandate (created on first login if missing)
try: try:
_ensureHomeMandate(rootInterface, user) ensureHomeMandate(rootInterface, user)
except Exception as homeErr: except Exception as homeErr:
logger.error(f"Error ensuring Home mandate for user {user.username}: {homeErr}") logger.error(f"Error ensuring Home mandate for user {user.username}: {homeErr}")

View file

@ -35,6 +35,7 @@ from modules.auth import (
) )
from modules.auth.tokenManager import TokenManager from modules.auth.tokenManager import TokenManager
from modules.auth.oauthProviderConfig import msftAuthScopes, msftDataScopes, msftDataScopesForRefresh from modules.auth.oauthProviderConfig import msftAuthScopes, msftDataScopes, msftDataScopesForRefresh
from modules.auth.homeMandateService import ensureHomeMandate
from modules.shared.timeUtils import createExpirationTimestamp, getUtcTimestamp, parseTimestamp from modules.shared.timeUtils import createExpirationTimestamp, getUtcTimestamp, parseTimestamp
from modules.shared.i18nRegistry import apiRouteContext from modules.shared.i18nRegistry import apiRouteContext
routeApiMsg = apiRouteContext("routeSecurityMsft") routeApiMsg = apiRouteContext("routeSecurityMsft")
@ -251,6 +252,20 @@ async def auth_login_callback(
) )
# --- end MFA gate ----------------------------------------------------- # --- end MFA gate -----------------------------------------------------
try:
ensureHomeMandate(rootInterface, user)
except Exception as homeErr:
logger.error(f"Error ensuring Home mandate for user {user.username}: {homeErr}")
try:
activatedCount = rootInterface._activatePendingSubscriptions(str(user.id))
if activatedCount > 0:
logger.info(
f"Activated {activatedCount} pending subscription(s) for user {user.username}"
)
except Exception as subErr:
logger.error(f"Error activating subscriptions on Microsoft login: {subErr}")
jwt_token_data = { jwt_token_data = {
"sub": user.username, "sub": user.username,
"userId": str(user.id), "userId": str(user.id),