dr29bart opened a new issue, #44541:
URL: https://github.com/apache/superset/issues/44541

   ### Bug description
   
   `#35237` (`abc2d46fed`, in 6.1.0) removed the only consumer of Flask's flash 
queue but left the
   producers in place. `get_flashed_messages()` is what *pops* `_flashes` out 
of the session; it used to
   run on every SPA render:
   
   
   ```diff
   --- a/superset/views/base.py
   +++ b/superset/views/base.py
    def common_bootstrap_payload() -> dict[str, Any]:
   -    return {
   -        **cached_common_bootstrap_data(utils.get_user_id(), get_locale()),
   -        "flash_messages": get_flashed_messages(with_categories=True),
   -    }
   +    return cached_common_bootstrap_data(utils.get_user_id(), get_locale())
   ```
   
   It now appears nowhere in `superset/`, `superset/templates/` or 
`superset-frontend/src`, and the same
   commit deleted the frontend `FlashProvider` that displayed the messages. 
Flask-AppBuilder's auth
   views still flash on every failed login, as do
   `superset/security/session_invalidation.py:132` and 
`superset/security/password_change.py:176`.
   
   So `_flashes` grows for the life of the session and nothing ever renders it. 
Two consequences:
   
   1. **The default client-side session cookie grows without bound** 
(`SESSION_SERVER_SIDE = False`),
      about 57 bytes per failed login attempt, carried on every request.
   2. **Login failures are invisible.** 
`superset-frontend/src/pages/Login/index.tsx` papers over the
      DB-credentials path by fabricating a message from `sessionStorage`, 
behind a TODO admitting the
      gap. There is no equivalent for OAuth, session invalidation, or forced 
password change.
   
   ### Minimal reproduction
   
   Default config, `AUTH_TYPE = AUTH_DB`, `SESSION_SERVER_SIDE = False`:
   
   1. Go to `/login/` and submit wrong credentials three times.
   2. Decode the `session` cookie — Flask signs but does not encrypt it, so no 
secret is needed:
   
      ```python
      import base64, json, zlib
   
      cookie = "<value of the session cookie>"
      raw = cookie.split(".")[1] if cookie.startswith(".") else 
cookie.split(".")[0]
      data = base64.urlsafe_b64decode(raw + "=" * (-len(raw) % 4))
      print(json.loads(zlib.decompress(data) if cookie.startswith(".") else 
data)["_flashes"])
      ```
   
   **Observed:** three copies of `["warning", "Invalid login. Please try 
again."]`, retained for the life
   of the session, none of them ever shown.
   **Expected:** the queue is drained when the login page renders, as it was 
before 6.1.0.
   
   ### Why it matters beyond cookie size
   
   Under `AUTH_TYPE = AUTH_OAUTH` the same accumulation stacks with Authlib's 
stale `_state_*` handshake
   entries (an Authlib/FAB issue, not this one). On the fourth consecutive 
refusal by the IdP, the 302
   carrying `Set-Cookie` + `Location` + CSP exceeded ingress-nginx's default 4k 
`proxy_buffer_size` and
   the user got **HTTP 502** instead of a login page — having never been told 
why any attempt failed.
   Past roughly six entries the cookie also crosses the browser's 4096-byte cap 
and the whole session,
   `csrf_token` included, is silently dropped.
   
   ### Suggested fix
   
   Drain and display at the login view, which addresses both consequences at 
once.
   `superset/views/auth.py`:
   
   ```python
   from flask import g, get_flashed_messages, redirect
   
       @expose("/")
       @no_cache
       def login(self, provider: Optional[str] = None) -> WerkzeugResponse:
           if g.user is not None and g.user.is_authenticated:
               return redirect(self.appbuilder.get_url_for_index)
   
           return super().render_app_template(
               {"auth_messages": get_flashed_messages(with_categories=True)}
           )
   ```
   
   `render_app_template`'s first argument is `extra_bootstrap_data`, which 
`get_spa_payload` merges per
   request. It must go there and **not** back into 
`common_bootstrap_payload()`, whose
   `cached_common_bootstrap_data` is `@cache_manager.cache.memoize(timeout=60)` 
— per-user messages
   there would bleed between users, which is presumably why #35237 deleted 
rather than relocated them.
   
   Then render `bootstrapData.auth_messages` in 
`superset-frontend/src/pages/Login/index.tsx` (replacing
   the `sessionStorage` hack) and add `auth_messages?: [string, string][]` to 
`BootstrapData` in
   `superset-frontend/src/types/bootstrapTypes.ts`.
   
   The alternative — removing the remaining `flash()` calls instead — bounds 
the cookie but leaves users
   with no feedback on a failed login.
   
   
   ### Screenshots/recordings
   
   _No response_
   
   ### Superset version
   
   master / latest-dev
   
   ### Python version
   
   3.11
   
   ### Node version
   
   18 or greater
   
   ### Browser
   
   Chrome
   
   ### Additional context
   
   k8s ingress controller logs:
   [error] 1103#1103: *10079930 upstream sent too big header while reading 
response header from upstream
   
    
   - No feature flags involved. `SESSION_SERVER_SIDE = False` is what puts the 
growth in the cookie
     rather than a server-side store; enabling server-side sessions hides the 
symptom but the queue
     still grows in the store.
   - No Python stacktrace: nothing raises. FAB logs the auth error and 
redirects; the 502 in the OAuth
     case comes from ingress-nginx.
   - Separate docs nit, if useful: `docs/admin_docs/security/security.mdx` says 
the session cookie "is
     encrypted with the application `SECRET_KEY` and cannot be read by the 
client". It is signed, not
     encrypted — the snippet above needs no secret.
   
   related?
   https://github.com/apache/superset/discussions/30302
   
   ### Checklist
   
   - [x] I have searched Superset docs and Slack and didn't find a solution to 
my problem.
   - [x] I have searched the GitHub issue tracker and didn't find a similar bug 
report.
   - [x] I have checked Superset's logs for errors and if I found a relevant 
Python stacktrace, I included it here as text in the "additional context" 
section.


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