Fix bug with saml validation (#4522)

* fix bug with saml validation

* k
This commit is contained in:
pablonyx 2025-04-16 12:35:58 -07:00 committed by GitHub
parent 7e7b6e08ff
commit 0d12e96362
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -1,5 +1,6 @@
import contextlib
import secrets
import string
from typing import Any
from fastapi import APIRouter
@ -9,7 +10,6 @@ from fastapi import Request
from fastapi import Response
from fastapi import status
from fastapi_users import exceptions
from fastapi_users.password import PasswordHelper
from onelogin.saml2.auth import OneLogin_Saml2_Auth # type: ignore
from pydantic import BaseModel
from sqlalchemy.ext.asyncio import AsyncSession
@ -38,6 +38,16 @@ router = APIRouter(prefix="/auth/saml")
async def upsert_saml_user(email: str) -> User:
"""
Creates or updates a user account for SAML authentication.
For new users or users with non-web-login roles:
1. Generates a secure random password that meets validation criteria
2. Creates the user with appropriate role and verified status
SAML users never use this password directly as they authenticate via their
Identity Provider, but we need a valid password to satisfy system requirements.
"""
logger.debug(f"Attempting to upsert SAML user with email: {email}")
get_async_session_context = contextlib.asynccontextmanager(
get_async_session
@ -60,15 +70,41 @@ async def upsert_saml_user(email: str) -> User:
user_count = await get_user_count()
role = UserRole.ADMIN if user_count == 0 else UserRole.BASIC
fastapi_users_pw_helper = PasswordHelper()
password = fastapi_users_pw_helper.generate()
hashed_pass = fastapi_users_pw_helper.hash(password)
# Generate a secure random password meeting validation requirements
# We use a secure random password since we never need to know what it is
# (SAML users authenticate via their IdP)
secure_random_password = "".join(
[
# Ensure minimum requirements are met
secrets.choice(
string.ascii_uppercase
), # at least one uppercase
secrets.choice(
string.ascii_lowercase
), # at least one lowercase
secrets.choice(string.digits), # at least one digit
secrets.choice(
"!@#$%^&*()-_=+[]{}|;:,.<>?"
), # at least one special
# Fill remaining length with random chars (mix of all types)
"".join(
secrets.choice(
string.ascii_letters
+ string.digits
+ "!@#$%^&*()-_=+[]{}|;:,.<>?"
)
for _ in range(12)
),
]
)
# Create the user with SAML-appropriate settings
user = await user_manager.create(
UserCreate(
email=email,
password=hashed_pass,
password=secure_random_password, # Pass raw password, not hash
role=role,
is_verified=True, # SAML users are pre-verified by their IdP
)
)