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]