login: honour next on both exits, same-origin only
The console's 401 redirect carries next=/leaders/ and /login dropped it, so a leader arriving cold landed on /account. next now rides the form as a hidden field and is applied after a successful POST and when an already-signed-in person hits /login. identity.safe_next() admits only a relative path with a single leading slash - no scheme, no //, no backslash, no control characters - so the login page cannot become an open redirect. Ten checks added to tests/smoke_identity.py; the suite is 59 + 24 + 53, all green.
This commit is contained in:
@@ -168,5 +168,17 @@ con.close()
|
||||
for k in ("invite.created", "invite.consumed", "login.ok", "login.failed", "login.throttled"):
|
||||
check("auth_events records %s" % k, k in kinds)
|
||||
|
||||
print("\nsafe_next")
|
||||
check("relative path passes", I.safe_next("/leaders/") == "/leaders/")
|
||||
check("query string kept", I.safe_next("/leaders/nearby?x=1") == "/leaders/nearby?x=1")
|
||||
check("empty falls back", I.safe_next("") == "/account")
|
||||
check("None falls back", I.safe_next(None) == "/account")
|
||||
check("absolute URL rejected", I.safe_next("https://evil.example/") == "/account")
|
||||
check("protocol-relative rejected", I.safe_next("//evil.example/") == "/account")
|
||||
check("backslash form rejected", I.safe_next("/\\evil.example") == "/account")
|
||||
check("control char rejected", I.safe_next("/leaders\r\nX: y") == "/account")
|
||||
check("no leading slash rejected", I.safe_next("leaders/") == "/account")
|
||||
check("custom default honoured", I.safe_next("nope", default="/") == "/")
|
||||
|
||||
print("\n%d passed, %d failed" % (PASS, FAIL))
|
||||
sys.exit(1 if FAIL else 0)
|
||||
|
||||
Reference in New Issue
Block a user