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:
parent
66b44e5c78
commit
0438177934
5 changed files with 94 additions and 45 deletions
55
modules/auth/homeMandateService.py
Normal file
55
modules/auth/homeMandateService.py
Normal 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}")
|
||||
|
|
@ -26,6 +26,7 @@ from modules.auth import (
|
|||
setAccessTokenCookie,
|
||||
setRefreshTokenCookie,
|
||||
)
|
||||
from modules.auth.homeMandateService import ensureHomeMandate
|
||||
from modules.auth.mfaService import (
|
||||
generateSetup,
|
||||
confirmSetup,
|
||||
|
|
@ -229,6 +230,20 @@ def mfaVerify(
|
|||
)
|
||||
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)
|
||||
|
||||
# Mark device as trusted so MFA is skipped on next login from this device
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ from modules.auth import (
|
|||
)
|
||||
from modules.auth.tokenManager import TokenManager
|
||||
from modules.auth.oauthProviderConfig import googleAuthScopes, googleDataScopes
|
||||
from modules.auth.homeMandateService import ensureHomeMandate
|
||||
from modules.shared.timeUtils import createExpirationTimestamp, getUtcTimestamp, parseTimestamp
|
||||
from modules.shared.i18nRegistry import apiRouteContext
|
||||
routeApiMsg = apiRouteContext("routeSecurityGoogle")
|
||||
|
|
@ -278,6 +279,11 @@ async def auth_login_callback(
|
|||
)
|
||||
# --- 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 = {
|
||||
"sub": user.username,
|
||||
"userId": str(user.id),
|
||||
|
|
|
|||
|
|
@ -16,12 +16,13 @@ from jose import jwt
|
|||
# Import auth modules
|
||||
from modules.auth import getCurrentUser, limiter, SECRET_KEY, ALGORITHM, getRequestContext, RequestContext
|
||||
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.datamodelSecurity import Token, TokenPurpose
|
||||
from modules.shared.configuration import APP_CONFIG
|
||||
from modules.shared.timeUtils import getUtcTimestamp
|
||||
from modules.shared.i18nRegistry import apiRouteContext
|
||||
from modules.auth.homeMandateService import ensureHomeMandate
|
||||
routeApiMsg = apiRouteContext("routeSecurityLocal")
|
||||
|
||||
# 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")
|
||||
@limiter.limit("30/minute")
|
||||
def login(
|
||||
|
|
@ -364,7 +322,7 @@ def login(
|
|||
|
||||
# Ensure user has a Home mandate (created on first login if missing)
|
||||
try:
|
||||
_ensureHomeMandate(rootInterface, user)
|
||||
ensureHomeMandate(rootInterface, user)
|
||||
except Exception as homeErr:
|
||||
logger.error(f"Error ensuring Home mandate for user {user.username}: {homeErr}")
|
||||
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ from modules.auth import (
|
|||
)
|
||||
from modules.auth.tokenManager import TokenManager
|
||||
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.i18nRegistry import apiRouteContext
|
||||
routeApiMsg = apiRouteContext("routeSecurityMsft")
|
||||
|
|
@ -251,6 +252,20 @@ async def auth_login_callback(
|
|||
)
|
||||
# --- 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 = {
|
||||
"sub": user.username,
|
||||
"userId": str(user.id),
|
||||
|
|
|
|||
Loading…
Reference in a new issue