rusackas commented on code in PR #42934:
URL: https://github.com/apache/superset/pull/42934#discussion_r3744945353


##########
superset/views/users/api.py:
##########
@@ -49,12 +50,36 @@ class CurrentUserRestApi(BaseSupersetApi):
     def pre_update(self, item: User, data: Dict[str, Any]) -> None:
         item.changed_on = datetime.now()
         item.changed_by_fk = g.user.id
+        # Pop unconditionally: this key is only meaningful for verifying a
+        # password change below, and it isn't a real column on the user
+        # model -- it must never reach ``UserDAO.update``'s ``setattr`` loop.
+        current_password = data.pop("current_password", None)
         if "password" in data and data["password"]:
+            # An account with no password set yet (e.g. provisioned via an
+            # external auth backend) has nothing to prove knowledge of; for
+            # every other account, the caller must confirm the existing
+            # password before it can be replaced.
+            proof_ok = current_password and check_password_hash(
+                item.password, current_password
+            )

Review Comment:
   Right, `check_password_hash` was reached with `item.password is None` 
whenever `current_password` was truthy, before the `item.password` guard. Fixed 
by short-circuiting on `item.password` first.



##########
superset/security/session_invalidation.py:
##########
@@ -187,6 +187,23 @@ def _stamp_existing() -> int:
         _stamp_existing()
 
 
+def invalidate_sessions_for_user(user_id: int) -> None:
+    """Stamp the invalidation epoch for ``user_id`` from ordinary application 
code.
+
+    Convenience wrapper around ``invalidate_user_sessions`` for callers that
+    don't have the raw ``Connection`` the ``after_update`` event listener
+    receives -- e.g. a password-change flow. The stamp is written through the
+    current session's own connection, so it participates in whatever
+    transaction the caller's other pending changes belong to; it is not
+    committed here, so the caller's own commit (or the next flush that
+    triggers one) is what makes it durable.
+    """
+    # pylint: disable=import-outside-toplevel
+    from superset.extensions import db
+
+    invalidate_user_sessions(db.session.connection(), user_id)

Review Comment:
   Fair, the blind UPDATE could let a slower transaction with an older 
timestamp overwrite a newer committed epoch. Guarded the write to only apply 
when it advances (or initializes) the stored value.



-- 
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]

Reply via email to