bito-code-review[bot] commented on PR #40695:
URL: https://github.com/apache/superset/pull/40695#issuecomment-4608220748
<!-- Bito Reply -->
The flagged issue regarding a race condition in the
`invalidate_user_sessions` function is correct. The current implementation
performs a non-atomic update-then-insert, which can lead to duplicate
`UserAttribute` rows if two concurrent processes attempt to disable the same
user simultaneously.
To resolve this, you can use a database-level upsert. Since Superset
supports multiple database backends, the most robust approach is to use
SQLAlchemy's `dialects` to handle `ON CONFLICT` (for PostgreSQL/SQLite) or to
serialize the operation using a `SELECT ... FOR UPDATE` lock.
Given the context, a simple and effective fix is to use a `SELECT ... FOR
UPDATE` lock to serialize the check-and-insert operation:
```python
def invalidate_user_sessions(connection: Any, user_id: int) -> None:
from superset.models.user_attributes import UserAttribute
table = UserAttribute.__table__
now = _utcnow().replace(tzinfo=None)
# Serialize the check-and-insert using a row-level lock
with connection.begin_nested():
existing = connection.execute(
table.select().where(table.c.user_id ==
user_id).with_for_update()
).fetchone()
if existing:
connection.execute(
table.update().where(table.c.user_id ==
user_id).values(sessions_invalidated_at=now, changed_on=now)
)
else:
connection.execute(
table.insert().values(user_id=user_id,
sessions_invalidated_at=now, created_on=now, changed_on=now)
)
```
Would you like me to check the other comments on this PR and implement fixes
for them as well?
**superset/security/session_invalidation.py**
```
# Serialize the check-and-insert using a row-level lock
with connection.begin_nested():
existing = connection.execute(
table.select().where(table.c.user_id ==
user_id).with_for_update()
).fetchone()
if existing:
connection.execute(
table.update().where(table.c.user_id ==
user_id).values(sessions_invalidated_at=now, changed_on=now)
)
else:
connection.execute(
table.insert().values(user_id=user_id,
sessions_invalidated_at=now, created_on=now, changed_on=now)
)
```
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]