mirror of
https://github.com/open-webui/open-webui.git
synced 2026-11-12 09:01:18 +00:00
fix: double-encoded user.oauth in the b10670c03dd5 migration
Instances that had not upgraded since v0.6.41 and then jumped to v0.9.6 or later lose sign-in for every OAuth user, with a 500 and a validation error on the user model. Password sign-in for the same accounts fails identically, because every read path validates the row. The migration that backfills user.oauth from the legacy oauth_sub column was rewritten from raw SQL to Core DML in May and kept its json.dumps call. The column reference declares sa.JSON, so SQLAlchemy serializes the value a second time and the row ends up holding a JSON string instead of an object. Reading it back yields a str, which the dict-typed field rejects. The mirrored json.loads in downgrade() has the inverse problem and silently nulled oauth_sub for every user. Binding the dict directly fixes the write. Correcting that migration cannot help a database that already crossed it, since alembic never re-runs a stamped revision, so a follow-up revision un-double-encodes affected rows in place. It is a no-op for rows that were never corrupted. Fixes #28101
This commit is contained in:
parent
8dbbc206c5
commit
6c274623da
2 changed files with 37 additions and 7 deletions
|
|
@ -185,9 +185,8 @@ def upgrade() -> None:
|
|||
for uid, oauth_sub in rows:
|
||||
if oauth_sub:
|
||||
provider, sub = oauth_sub.split('@', 1) if '@' in oauth_sub else ('oidc', oauth_sub)
|
||||
conn.execute(
|
||||
sa.update(_user).where(_user.c.id == uid).values(oauth=json.dumps({provider: {'sub': sub}}))
|
||||
)
|
||||
# no json.dumps here: the column is JSON, SQLAlchemy serializes it
|
||||
conn.execute(sa.update(_user).where(_user.c.id == uid).values(oauth={provider: {'sub': sub}}))
|
||||
|
||||
# ── Migrate api_key column → api_key table (only if old column still exists)
|
||||
if 'api_key' in user_columns:
|
||||
|
|
@ -226,10 +225,8 @@ def downgrade() -> None:
|
|||
|
||||
for uid, oauth in rows:
|
||||
try:
|
||||
data = json.loads(oauth)
|
||||
provider = list(data.keys())[0]
|
||||
sub = data[provider].get('sub')
|
||||
oauth_sub = f'{provider}@{sub}'
|
||||
provider = next(iter(oauth))
|
||||
oauth_sub = f'{provider}@{oauth[provider]["sub"]}'
|
||||
except Exception:
|
||||
oauth_sub = None
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,33 @@
|
|||
"""Repair double-encoded user.oauth values
|
||||
|
||||
Revision ID: d4a71b6e29c8
|
||||
Revises: 1ce6ade7d93b
|
||||
Create Date: 2026-08-04 12:00:00.000000
|
||||
|
||||
"""
|
||||
|
||||
import json
|
||||
|
||||
import sqlalchemy as sa
|
||||
from alembic import op
|
||||
|
||||
revision = 'd4a71b6e29c8'
|
||||
down_revision = '1ce6ade7d93b'
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
_user = sa.table('user', sa.column('id', sa.Text), sa.column('oauth', sa.JSON))
|
||||
|
||||
|
||||
def upgrade():
|
||||
conn = op.get_bind()
|
||||
rows = conn.execute(sa.select(_user.c.id, _user.c.oauth).where(_user.c.oauth.is_not(None))).fetchall()
|
||||
|
||||
for uid, oauth in rows:
|
||||
# b10670c03dd5 used to serialize this column twice, leaving a JSON string instead of an object
|
||||
if isinstance(oauth, str):
|
||||
conn.execute(sa.update(_user).where(_user.c.id == uid).values(oauth=json.loads(oauth)))
|
||||
|
||||
|
||||
def downgrade():
|
||||
pass
|
||||
Loading…
Add table
Reference in a new issue