diff --git a/backend/open_webui/migrations/versions/0bd252b206fb_add_missing_auth_rows.py b/backend/open_webui/migrations/versions/0bd252b206fb_add_missing_auth_rows.py new file mode 100644 index 0000000000..8e190dcb03 --- /dev/null +++ b/backend/open_webui/migrations/versions/0bd252b206fb_add_missing_auth_rows.py @@ -0,0 +1,34 @@ +"""add missing auth rows + +Revision ID: 0bd252b206fb +Revises: c92da83b017f +""" + +import sqlalchemy as sa +from alembic import op + +revision = '0bd252b206fb' +down_revision = 'c92da83b017f' +branch_labels = None +depends_on = None + +_user = sa.table('user', sa.column('id', sa.Text), sa.column('email', sa.Text)) +_auth = sa.table( + 'auth', + sa.column('id', sa.Text), + sa.column('email', sa.Text), + sa.column('password', sa.Text), + sa.column('active', sa.Boolean), +) + + +def upgrade() -> None: + # An empty password never verifies, so these accounts stay SSO-only. + users_without_auth = sa.select(_user.c.id, _user.c.email, sa.literal_column("''"), sa.true()).where( + ~sa.exists().where(_auth.c.id == _user.c.id) + ) + op.execute(_auth.insert().from_select(['id', 'email', 'password', 'active'], users_without_auth)) + + +def downgrade() -> None: + pass diff --git a/backend/open_webui/routers/scim.py b/backend/open_webui/routers/scim.py index 2f90ac1557..43acdf6859 100644 --- a/backend/open_webui/routers/scim.py +++ b/backend/open_webui/routers/scim.py @@ -20,12 +20,14 @@ from open_webui.constants import ERROR_MESSAGES from open_webui.events import EVENTS, publish_event from open_webui.env import SCIM_AUTH_PROVIDER from open_webui.internal.db import get_async_session +from open_webui.models.auths import Auths from open_webui.models.groups import GroupModel, Groups, GroupHierarchyError from open_webui.models.users import UserModel, Users from open_webui.utils.auth import ( decode_token, get_admin_user, get_current_user, + get_password_hash, get_verified_user, ) from pydantic import BaseModel, ConfigDict, Field @@ -620,9 +622,6 @@ async def create_user( detail=f'User with email {email} already exists', ) - # Create user - user_id = str(uuid.uuid4()) - # Parse name if provided name = user_data.displayName if user_data.name: @@ -636,10 +635,11 @@ async def create_user( if user_data.photos and len(user_data.photos) > 0: profile_image = user_data.photos[0].value - new_user = await Users.insert_new_user( - id=user_id, - name=name, + # Create user + new_user = await Auths.insert_new_auth( email=email, + password=await get_password_hash(str(uuid.uuid4())), + name=name, profile_image_url=profile_image, role='user' if user_data.active else 'pending', db=db, @@ -651,7 +651,7 @@ async def create_user( detail='Failed to create user', ) - new_user = await Users.update_user_scim_by_id(user_id, get_scim_provider(), user_data.externalId, db=db) + new_user = await Users.update_user_scim_by_id(new_user.id, get_scim_provider(), user_data.externalId, db=db) if not new_user: raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, @@ -721,6 +721,8 @@ async def update_user( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail='Failed to update user', ) + if 'email' in update_data: + await Auths.update_email_by_id(user_id, update_data['email'], db=db) # Update externalId in the scim field if user_data.externalId: @@ -830,6 +832,8 @@ async def patch_user( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail='Failed to update user', ) + if 'email' in update_data: + await Auths.update_email_by_id(user_id, update_data['email'], db=db) else: updated_user = user @@ -871,7 +875,7 @@ async def delete_user( detail=f'User {user_id} not found', ) - success = await Users.delete_user_by_id(user_id, db=db) + success = await Auths.delete_auth_by_id(user_id, db=db) if not success: raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,