uam update

This commit is contained in:
ValueOn AG 2025-05-16 17:14:34 +02:00
parent bf986b4d71
commit 1261e54509
3 changed files with 104 additions and 130 deletions

View file

@ -154,14 +154,40 @@ class DatabaseConnector:
path = self._getTablePath(table) path = self._getTablePath(table)
try: try:
# Log the path and data being saved
logger.debug(f"Attempting to save table {table} to {path}")
logger.debug(f"Data to save: {json.dumps(data, indent=2)}")
# Check if directory exists and is writable
dir_path = os.path.dirname(path)
if not os.path.exists(dir_path):
logger.error(f"Directory does not exist: {dir_path}")
return False
if not os.access(dir_path, os.W_OK):
logger.error(f"Directory is not writable: {dir_path}")
return False
# Check if file exists and is writable
if os.path.exists(path) and not os.access(path, os.W_OK):
logger.error(f"File exists but is not writable: {path}")
return False
with open(path, 'w', encoding='utf-8') as f: with open(path, 'w', encoding='utf-8') as f:
json.dump(data, f, indent=2, ensure_ascii=False) json.dump(data, f, indent=2, ensure_ascii=False)
# Verify the file was written correctly
if not os.path.exists(path):
logger.error(f"File was not created after write: {path}")
return False
# Update the cache # Update the cache
self._tablesCache[table] = data self._tablesCache[table] = data
logger.debug(f"Successfully saved table {table}")
return True return True
except Exception as e: except Exception as e:
logger.error(f"Error saving table {table}: {e}") logger.error(f"Error saving table {table}: {str(e)}")
logger.error(f"Error type: {type(e).__name__}")
logger.error(f"Error details: {e.__dict__ if hasattr(e, '__dict__') else 'No details available'}")
return False return False
def _applyRecordFilter(self, records: List[Dict[str, Any]], recordFilter: Dict[str, Any] = None) -> List[Dict[str, Any]]: def _applyRecordFilter(self, records: List[Dict[str, Any]], recordFilter: Dict[str, Any] = None) -> List[Dict[str, Any]]:

View file

@ -279,8 +279,10 @@ class GatewayInterface:
users = self.db.getRecordset("users") users = self.db.getRecordset("users")
for user in users: for user in users:
if user.get("username") == username: if user.get("username") == username:
# Return a copy of the user with all fields, including hashedPassword # Log the fields present in the user record
return user.copy() logger.debug(f"Found user {username} with fields: {list(user.keys())}")
# Return a complete copy of the user record with all fields
return {**user} # Use dict unpacking to ensure we get a complete copy with all fields
logger.debug(f"No user found with username {username}") logger.debug(f"No user found with username {username}")
return None return None
@ -341,10 +343,7 @@ class GatewayInterface:
createdUser = self.db.recordCreate("users", userData) createdUser = self.db.recordCreate("users", userData)
# Remove password hash from the response # Return the complete user record
if "hashedPassword" in createdUser:
del createdUser["hashedPassword"]
return createdUser return createdUser
def authenticateUser(self, username: str, password: str) -> Optional[Dict[str, Any]]: def authenticateUser(self, username: str, password: str) -> Optional[Dict[str, Any]]:

View file

@ -1,8 +1,11 @@
from fastapi import APIRouter, HTTPException, Depends, Body, Path from fastapi import APIRouter, HTTPException, Depends, Body, Path, Request
from typing import List, Dict, Any, Optional from typing import List, Dict, Any, Optional
from fastapi import status from fastapi import status
from datetime import datetime from datetime import datetime
from dataclasses import dataclass from dataclasses import dataclass
import logging
import time
import traceback
# Import auth module # Import auth module
from modules.auth import getCurrentActiveUser, getUserContext from modules.auth import getCurrentActiveUser, getUserContext
@ -11,6 +14,9 @@ from modules.auth import getCurrentActiveUser, getUserContext
from modules.gatewayInterface import getGatewayInterface from modules.gatewayInterface import getGatewayInterface
from modules.gatewayModel import User from modules.gatewayModel import User
# Set up logger
logger = logging.getLogger(__name__)
# Determine all attributes of the model # Determine all attributes of the model
def getModelAttributes(modelClass): def getModelAttributes(modelClass):
return [attr for attr in dir(modelClass) return [attr for attr in dir(modelClass)
@ -66,145 +72,88 @@ async def getUsers(currentUser: Dict[str, Any] = Depends(getCurrentActiveUser)):
@router.post("/register", response_model=Dict[str, Any]) @router.post("/register", response_model=Dict[str, Any])
async def registerUser(userData: dict = Body(...)): async def registerUser(request: Request):
"""Register a new user""" """Register a new user."""
# Add debug logging to see what's coming in
import logging
logger = logging.getLogger(__name__)
logger.info(f"Registration request data: {userData}")
# Get the initial IDs for mandate and admin user
adminGateway = getGatewayInterface()
# Get ID of the root mandate - we'll use this for new users
rootMandateId = adminGateway.getInitialId("mandates")
adminUserId = adminGateway.getInitialId("users")
logger.info(f"Root mandate ID: {rootMandateId}, Admin user ID: {adminUserId}")
if not rootMandateId or not adminUserId:
logger.error("System initialization error: Missing root mandate or admin user")
raise HTTPException(
status_code=500,
detail="System is not properly initialized with root mandate and admin user"
)
# Use a gateway with admin context for user creation
gateway = getGatewayInterface(rootMandateId, adminUserId)
if "username" not in userData or "password" not in userData:
logger.error("Missing required fields in registration data")
raise HTTPException(status_code=400, detail="Username and password required")
try: try:
# Create user data - explicitly set fields # Get request data
userCreateData = { data = await request.json()
"username": userData["username"], logger.info(f"Registration request data: {data}")
"password": userData["password"],
"mandateId": rootMandateId, # Use the Root mandate # Get root mandate and admin user IDs
rootMandateId = 1 # Root mandate is always ID 1
adminUserId = 1 # Admin user is always ID 1
# Create a new gateway interface instance with admin context
adminGateway = getGatewayInterface(rootMandateId, adminUserId)
# Check required fields
if not data.get("username") or not data.get("password"):
logger.error("Missing required fields in registration request")
raise HTTPException(status_code=400, detail="Username and password are required")
# Create user data
userData = {
"username": data["username"],
"password": data["password"],
"email": data.get("email"),
"fullName": data.get("fullName"),
"language": data.get("language", "de"),
"mandateId": rootMandateId,
"disabled": False, "disabled": False,
"privilege": "user", "privilege": "user"
"language": userData.get("language", "de")
} }
# Explicitly add optional fields - only if they exist and are not empty
if "email" in userData and userData["email"]:
userCreateData["email"] = userData["email"]
if "fullName" in userData and userData["fullName"]:
userCreateData["fullName"] = userData["fullName"]
logger.info(f"Attempting to create user with data: {userCreateData}")
# First check if user already exists
existingUser = gateway.getUserByUsername(userData["username"])
if existingUser:
logger.error(f"User {userData['username']} already exists")
raise HTTPException(
status_code=400,
detail=f"User {userData['username']} already exists"
)
# Create the user # Create the user
newUser = gateway.createUser(**userCreateData) logger.info(f"Attempting to create user with data: {userData}")
logger.info(f"User created successfully: {newUser}") createdUser = adminGateway.createUser(**userData)
logger.info(f"User created successfully: {createdUser}")
# Wait a short moment to ensure database consistency # Add a small delay to ensure database consistency
import time
time.sleep(0.5) time.sleep(0.5)
# Verify that the password was properly stored # Verify the user was created and password was stored
createdUser = gateway.getUserByUsername(userData["username"])
logger.info(f"Retrieved created user: {createdUser}")
if not createdUser:
logger.error("User creation verification failed: User not found after creation")
raise HTTPException(
status_code=500,
detail="Failed to verify user creation. Please try again."
)
if "hashedPassword" not in createdUser: if "hashedPassword" not in createdUser:
logger.error("User creation verification failed: Password not stored") logger.error("Password not stored in user record")
# If password wasn't stored, delete the user and raise an error # Try to delete the user
if createdUser: try:
logger.info(f"Attempting to delete user {createdUser['id']} due to missing password") adminGateway.deleteUser(createdUser["id"])
try: logger.info("Successfully deleted user after password storage failure")
gateway.deleteUser(createdUser["id"]) except Exception as e:
logger.info(f"Successfully deleted user {createdUser['id']} after password storage failure") logger.error(f"Failed to delete user after password storage failure: {str(e)}")
except Exception as deleteError: raise HTTPException(status_code=500, detail="Password storage failed")
logger.error(f"Failed to delete user after password storage failure: {str(deleteError)}")
raise HTTPException(
status_code=500,
detail="Failed to store password securely. Please try again."
)
# Final verification - try to authenticate the user logger.info("User verification successful")
try:
authResult = gateway.authenticateUser(userData["username"], userData["password"]) # Test authentication
if not authResult: authResult = adminGateway.authenticateUser(userData["username"], userData["password"])
logger.error("Final verification failed: Could not authenticate newly created user") if not authResult:
# Delete the user if authentication fails logger.error("Authentication test failed after user creation")
if createdUser: # Try to delete the user
try: try:
gateway.deleteUser(createdUser["id"]) # adminGateway.deleteUser(createdUser["id"])
logger.info(f"Successfully deleted user {createdUser['id']} after authentication failure") logger.info("Successfully NOT deleted user after authentication test failure")
except Exception as deleteError: except Exception as e:
logger.error(f"Failed to delete user after authentication failure: {str(deleteError)}") logger.error(f"Failed to delete user after authentication test failure: {str(e)}")
raise HTTPException( raise HTTPException(status_code=500, detail="Authentication test failed")
status_code=500,
detail="Failed to verify user authentication. Please try again." logger.info("Authentication test successful")
)
except Exception as authError: # Return success response
logger.error(f"Authentication verification failed: {str(authError)}") return {
# Delete the user if authentication fails "message": "User registered successfully",
if createdUser: "userId": createdUser["id"]
try: }
gateway.deleteUser(createdUser["id"])
logger.info(f"Successfully deleted user {createdUser['id']} after authentication error")
except Exception as deleteError:
logger.error(f"Failed to delete user after authentication error: {str(deleteError)}")
raise HTTPException(
status_code=500,
detail="Failed to verify user authentication. Please try again."
)
logger.info("User registration completed successfully")
return newUser
except ValueError as e: except ValueError as e:
logger.error(f"ValueError in registration: {str(e)}") logger.error(f"Validation error during registration: {str(e)}")
raise HTTPException(status_code=400, detail=str(e)) raise HTTPException(status_code=400, detail=str(e))
except PermissionError as e: except PermissionError as e:
logger.error(f"PermissionError in registration: {str(e)}") logger.error(f"Permission error during registration: {str(e)}")
raise HTTPException(status_code=403, detail=str(e)) raise HTTPException(status_code=403, detail=str(e))
except Exception as e: except Exception as e:
import traceback logger.error(f"Unexpected error during registration: {str(e)}")
logger.error(f"Unexpected error in registration: {str(e)}")
logger.error("Full traceback:")
logger.error(traceback.format_exc()) logger.error(traceback.format_exc())
logger.error(f"Error type: {type(e).__name__}") raise HTTPException(status_code=500, detail="Internal server error")
logger.error(f"Error args: {e.args}")
raise HTTPException(status_code=500, detail=f"Registration failed: {str(e)}")
@router.post("/register-with-msal", response_model=Dict[str, Any]) @router.post("/register-with-msal", response_model=Dict[str, Any])
async def registerUserWithMsal(userData: dict = Body(...)): async def registerUserWithMsal(userData: dict = Body(...)):