api.py: Revise spiderpig login session handling
Issue #1
If SessionMiddleware receives an expired session cookie (and the
route function doesn't do anything further to set session state), it
responds with a Set-Cookie header that will cause the session cookie
to be deleted.
Issue #2
While a browser is navigating to a new URL (in this case, to the CAS
login URL), interval timers old the old page still run and network
requests that they might create will continue to run until navigation
has completed.
Problem
These two issues together have the potential to result in bad behavior
when a session cookie expires (or even when first visiting spiderpig).
When the spiderpig overview page is visited, multiple components start
interval timers to periodically retrieve information from the
apiserver. If any one of these requests fails with a 401 response,
the client code will redirect the browser to the CAS server to acquire
a login ticket. The CAS server will respond with a redirect to the
apiserver's /api/login route with a login ticket. /api/login will
establish a new session and return it in the session cookie. However,
if an old request completes after the /api/login call finishes, the
old request (which had an invalid session cookie) will respond by
deleting the session cookie. This blasts the recently-acquired good
cookie that was just returned by /api/login.
Resolution
Instead of using SessionMiddleware for session management, handle
the "session" cookie explicitly. This gives us full control over when
a cookie is set or deleted. Now we only set the cookie in
/api/login or /api/login2 and only delete it in /api/logout.
This prevents in-flight requests with an old/bad cookie from
disrupting an in-progress auth workflow.
Updated tests accordingly.
Bug: T397457