|
|
@@ -10,7 +10,7 @@ from urllib.parse import urlencode
|
|
|
import httpx
|
|
|
|
|
|
from gpustack.config.config import Config
|
|
|
-from gpustack.security import JWTManager
|
|
|
+from gpustack.security import JWTManager, get_secret_hash
|
|
|
from gpustack.server.services import create_user_with_principal
|
|
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
@@ -154,20 +154,22 @@ async def sync_user_from_sso(
|
|
|
logger.info(f"Updated SSO user: {username}")
|
|
|
return existing
|
|
|
else:
|
|
|
- # Create new user
|
|
|
- # SSO users don't have a local password; generate a random one
|
|
|
+ # Create new user — construct User object first, then persist
|
|
|
+ # with create_user_with_principal (session, user) signature.
|
|
|
import secrets
|
|
|
random_password = secrets.token_urlsafe(32)
|
|
|
|
|
|
- user = await create_user_with_principal(
|
|
|
- session=session,
|
|
|
+ user_info = User(
|
|
|
username=username,
|
|
|
- password=random_password,
|
|
|
- is_admin=is_admin,
|
|
|
full_name=full_name,
|
|
|
avatar_url=avatar_url,
|
|
|
+ hashed_password=get_secret_hash(random_password),
|
|
|
+ is_admin=is_admin,
|
|
|
+ is_active=True,
|
|
|
source=AuthProviderEnum.OIDC,
|
|
|
+ require_password_change=False,
|
|
|
)
|
|
|
+ user = await create_user_with_principal(session, user_info)
|
|
|
logger.info(f"Created SSO user: {username}")
|
|
|
return user
|
|
|
|
|
|
@@ -198,6 +200,7 @@ async def handle_sso_exchange_code(
|
|
|
|
|
|
# Step 5: Sync user
|
|
|
user = await sync_user_from_sso(session, config, userinfo)
|
|
|
+ await session.commit()
|
|
|
|
|
|
# Step 6: Issue local JWT
|
|
|
local_token = jwt_manager.create_jwt_token(username=user.username)
|