Logout: perform full SSO logout via /user-logout
The /?logout=1 endpoint destroyed only the PWA's own PHP session and then redirected to the bare landing page — which has no session and immediately blocks access, so the user was never actually logged out of SSO. - public/index.php: after session_destroy(), redirect to https://lupmis4luspa.org/user-logout (the portal's full SSO logout) instead of the landing page. Crucially, no longer clear sso_auth_token here — /user-logout needs that cookie to identify which SSO session to terminate (and it clears the cookie itself). The production access-guard bounce to the landing page is unchanged. - main.js: drop the now-redundant best-effort client call to /sso/logout; the server redirect chain (/?logout=1 → /user-logout) owns the SSO logout. Offline guard and district-cache wipe unchanged. - sw.js: update the v12 changelog note (still v12; not yet deployed). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
d8ddbbc910
commit
c335a8987e
1
dist/assets/index-BTRQkY7z.js.map
vendored
1
dist/assets/index-BTRQkY7z.js.map
vendored
File diff suppressed because one or more lines are too long
@ -919,5 +919,5 @@ Other providers are not affected. The tiles will re-download as you browse onlin
|
||||
|
||||
Logging out needs a connection to the sign-in server, and you would not be able to sign back in until you are online again.
|
||||
|
||||
Please try again once you have a connection. You can keep working — the app stays signed in while offline.`);return}if(!confirm(`Log out, ${n?.full_name||n?.username||"user"}?`))return;const e=document.cookie.split(";").map(t=>t.trim()).find(t=>t.startsWith("sso_auth_token="))?.split("=")[1];if(e)try{await fetch("https://lupmis4luspa.org/sso/logout?token="+encodeURIComponent(e),{method:"GET",mode:"no-cors",credentials:"include",cache:"no-store"})}catch(t){console.warn("[Logout] Best-effort SSO logout call failed:",t)}try{await Io(),localStorage.removeItem(vo)}catch(t){console.warn("[Logout] Cache clear failed (continuing):",t)}window.location.href="/?logout=1"}document.readyState==="loading"?document.addEventListener("DOMContentLoaded",An):An();
|
||||
//# sourceMappingURL=index-BTRQkY7z.js.map
|
||||
Please try again once you have a connection. You can keep working — the app stays signed in while offline.`);return}if(confirm(`Log out, ${n?.full_name||n?.username||"user"}?`)){try{await Io(),localStorage.removeItem(vo)}catch(e){console.warn("[Logout] Cache clear failed (continuing):",e)}window.location.href="/?logout=1"}}document.readyState==="loading"?document.addEventListener("DOMContentLoaded",An):An();
|
||||
//# sourceMappingURL=index-Ko1mW_fQ.js.map
|
||||
1
dist/assets/index-Ko1mW_fQ.js.map
vendored
Normal file
1
dist/assets/index-Ko1mW_fQ.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
2
dist/index.html
vendored
2
dist/index.html
vendored
@ -1601,7 +1601,7 @@
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<script type="module" crossorigin src="/assets/index-BTRQkY7z.js"></script>
|
||||
<script type="module" crossorigin src="/assets/index-Ko1mW_fQ.js"></script>
|
||||
<link rel="modulepreload" crossorigin href="/assets/openlayers-D8ReJJOp.js">
|
||||
<link rel="modulepreload" crossorigin href="/assets/bootstrap-D1-uvFxm.js">
|
||||
<link rel="modulepreload" crossorigin href="/assets/ol-ext-P1ircg-B.js">
|
||||
|
||||
27
dist/index.php
vendored
27
dist/index.php
vendored
@ -24,26 +24,33 @@
|
||||
session_start();
|
||||
|
||||
// ────────────────────────────────────────────────────────────────────────────
|
||||
// Logout — end the PWA's OWN session
|
||||
// Logout — end the PWA's OWN session, then hand off to the central SSO logout
|
||||
// ────────────────────────────────────────────────────────────────────────────
|
||||
// The PWA keeps its own PHP session (PHPSESSID on this host), independent of
|
||||
// the central SSO portal. Logging out of the SSO portal clears `sso_auth_token`
|
||||
// but leaves this PHPSESSID session intact, so the previous user's fields
|
||||
// (incl. district_id) persist. This endpoint is what actually destroys the PWA
|
||||
// session. Triggered by `/?logout=1` from the in-app menu.
|
||||
// the central SSO portal, so the previous user's fields (incl. district_id)
|
||||
// persist until this session is destroyed. We do that here, then redirect to
|
||||
// the portal's `/user-logout`, which performs the FULL SSO logout (invalidates
|
||||
// the token server-side and clears the sso_auth_token cookie itself).
|
||||
//
|
||||
// Important: we deliberately do NOT clear `sso_auth_token` here. `/user-logout`
|
||||
// needs that cookie to identify which SSO session to terminate — expiring it
|
||||
// first would leave the SSO session alive on the server. Redirecting to the
|
||||
// bare landing page (the old behaviour) only dropped the user on a page that
|
||||
// then blocked them; it never logged them out of SSO.
|
||||
//
|
||||
// Triggered by `/?logout=1` from the in-app menu.
|
||||
if (isset($_GET['logout'])) {
|
||||
$_SESSION = [];
|
||||
// Expire the session cookie itself.
|
||||
// Expire the PWA's own session cookie (PHPSESSID).
|
||||
if (ini_get('session.use_cookies')) {
|
||||
$cp = session_get_cookie_params();
|
||||
setcookie(session_name(), '', time() - 42000,
|
||||
$cp['path'], $cp['domain'], $cp['secure'], $cp['httponly']);
|
||||
}
|
||||
session_destroy();
|
||||
// Clear the shared SSO cookie across all *.lupmis4luspa.org subdomains.
|
||||
setcookie('sso_auth_token', '', time() - 3600, '/', '.lupmis4luspa.org');
|
||||
// Bounce to the central LUSPA portal to complete SSO logout.
|
||||
header('Location: https://lupmis4luspa.org/', true, 302);
|
||||
// Hand off to the central SSO logout (full logout: invalidates the token
|
||||
// and clears sso_auth_token). Keep the cookie intact so it can do so.
|
||||
header('Location: https://lupmis4luspa.org/user-logout', true, 302);
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
8
dist/sw.js
vendored
8
dist/sw.js
vendored
@ -46,9 +46,11 @@
|
||||
// sample values + Unicode-bold field names in the mapping dropdown).
|
||||
// New hashed bundle + updated embed.php shell.
|
||||
// v12: Session/district correctness — a real /?logout=1 endpoint that destroys
|
||||
// the PWA's own PHP session (logout previously only cleared the SSO
|
||||
// cookie, leaving the district_id pinned). SSO is validated once per
|
||||
// session at login; a transfer is picked up on the next logout→login.
|
||||
// the PWA's own PHP session and then hands off to the portal's
|
||||
// /user-logout for a FULL SSO logout (token invalidated + sso_auth_token
|
||||
// cleared by the portal). Previously logout left the PHP session intact,
|
||||
// pinning a stale district_id. SSO is validated once per session at login;
|
||||
// a transfer is picked up on the next logout→login.
|
||||
// Client-side stale-district guard (wipes district-scoped caches when the
|
||||
// session district changes) + district-keyed boundary cache; GPS read-out
|
||||
// UTM coordinate-format setting; ol-ext touch-cursor gated to touch-only
|
||||
|
||||
42
main.js
42
main.js
@ -3993,17 +3993,16 @@ function initAccountCard() {
|
||||
|
||||
/**
|
||||
* Logout flow:
|
||||
* 1. Confirm with the user.
|
||||
* 2. Best-effort fire-and-forget call to the SSO logout endpoint so the
|
||||
* server-side token is invalidated (no-cors mode tolerates CORS issues).
|
||||
* 1. Refuse if offline (login needs the server — see guard below).
|
||||
* 2. Confirm with the user.
|
||||
* 3. Wipe district-scoped local caches so the next (possibly different) user
|
||||
* on this device can't briefly see the previous user's cached map data.
|
||||
* 4. Navigate to the PWA's OWN logout endpoint (/?logout=1). That endpoint
|
||||
* runs session_destroy() — clearing the PHPSESSID session that holds the
|
||||
* user's district_id — clears the sso_auth_token cookie server-side, and
|
||||
* redirects to the central LUSPA portal. Clearing only the cookie here
|
||||
* (as before) left the PHP session intact, which is what pinned users to
|
||||
* a stale district across logout/login.
|
||||
* user's district_id — and then redirects to the central portal's
|
||||
* /user-logout, which performs the full SSO logout (invalidates the token
|
||||
* and clears sso_auth_token). We let the server chain own the SSO side, so
|
||||
* there is no separate client-side token-invalidation call.
|
||||
*/
|
||||
async function handleSignOut(session) {
|
||||
// Guard: logging back in requires the SSO server (a session can only be
|
||||
@ -4029,28 +4028,8 @@ async function handleSignOut(session) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 1. Best-effort: invalidate the SSO token server-side
|
||||
const cookieToken = document.cookie
|
||||
.split(';')
|
||||
.map((c) => c.trim())
|
||||
.find((c) => c.startsWith('sso_auth_token='))
|
||||
?.split('=')[1];
|
||||
if (cookieToken) {
|
||||
try {
|
||||
// no-cors swallows CORS errors; we don't read the response
|
||||
await fetch('https://lupmis4luspa.org/sso/logout?token=' + encodeURIComponent(cookieToken), {
|
||||
method: 'GET',
|
||||
mode: 'no-cors',
|
||||
credentials: 'include',
|
||||
cache: 'no-store',
|
||||
});
|
||||
} catch (err) {
|
||||
console.warn('[Logout] Best-effort SSO logout call failed:', err);
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Drop locally-cached, district-scoped layers and the last-district
|
||||
// marker so a different next user starts clean.
|
||||
// Drop locally-cached, district-scoped layers and the last-district marker
|
||||
// so a different next user starts clean.
|
||||
try {
|
||||
await clearAllCachedLayers();
|
||||
localStorage.removeItem(LAST_DISTRICT_KEY);
|
||||
@ -4058,8 +4037,9 @@ async function handleSignOut(session) {
|
||||
console.warn('[Logout] Cache clear failed (continuing):', err);
|
||||
}
|
||||
|
||||
// 3. Hand off to the server logout endpoint — it destroys the PHP session,
|
||||
// clears the SSO cookie, and 302-redirects to the LUSPA portal.
|
||||
// Hand off to the server logout endpoint: it destroys the PWA's PHP session,
|
||||
// then redirects to https://lupmis4luspa.org/user-logout for the full SSO
|
||||
// logout (token invalidation + sso_auth_token cleared by the portal).
|
||||
window.location.href = '/?logout=1';
|
||||
}
|
||||
|
||||
|
||||
@ -24,26 +24,33 @@
|
||||
session_start();
|
||||
|
||||
// ────────────────────────────────────────────────────────────────────────────
|
||||
// Logout — end the PWA's OWN session
|
||||
// Logout — end the PWA's OWN session, then hand off to the central SSO logout
|
||||
// ────────────────────────────────────────────────────────────────────────────
|
||||
// The PWA keeps its own PHP session (PHPSESSID on this host), independent of
|
||||
// the central SSO portal. Logging out of the SSO portal clears `sso_auth_token`
|
||||
// but leaves this PHPSESSID session intact, so the previous user's fields
|
||||
// (incl. district_id) persist. This endpoint is what actually destroys the PWA
|
||||
// session. Triggered by `/?logout=1` from the in-app menu.
|
||||
// the central SSO portal, so the previous user's fields (incl. district_id)
|
||||
// persist until this session is destroyed. We do that here, then redirect to
|
||||
// the portal's `/user-logout`, which performs the FULL SSO logout (invalidates
|
||||
// the token server-side and clears the sso_auth_token cookie itself).
|
||||
//
|
||||
// Important: we deliberately do NOT clear `sso_auth_token` here. `/user-logout`
|
||||
// needs that cookie to identify which SSO session to terminate — expiring it
|
||||
// first would leave the SSO session alive on the server. Redirecting to the
|
||||
// bare landing page (the old behaviour) only dropped the user on a page that
|
||||
// then blocked them; it never logged them out of SSO.
|
||||
//
|
||||
// Triggered by `/?logout=1` from the in-app menu.
|
||||
if (isset($_GET['logout'])) {
|
||||
$_SESSION = [];
|
||||
// Expire the session cookie itself.
|
||||
// Expire the PWA's own session cookie (PHPSESSID).
|
||||
if (ini_get('session.use_cookies')) {
|
||||
$cp = session_get_cookie_params();
|
||||
setcookie(session_name(), '', time() - 42000,
|
||||
$cp['path'], $cp['domain'], $cp['secure'], $cp['httponly']);
|
||||
}
|
||||
session_destroy();
|
||||
// Clear the shared SSO cookie across all *.lupmis4luspa.org subdomains.
|
||||
setcookie('sso_auth_token', '', time() - 3600, '/', '.lupmis4luspa.org');
|
||||
// Bounce to the central LUSPA portal to complete SSO logout.
|
||||
header('Location: https://lupmis4luspa.org/', true, 302);
|
||||
// Hand off to the central SSO logout (full logout: invalidates the token
|
||||
// and clears sso_auth_token). Keep the cookie intact so it can do so.
|
||||
header('Location: https://lupmis4luspa.org/user-logout', true, 302);
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
@ -46,9 +46,11 @@
|
||||
// sample values + Unicode-bold field names in the mapping dropdown).
|
||||
// New hashed bundle + updated embed.php shell.
|
||||
// v12: Session/district correctness — a real /?logout=1 endpoint that destroys
|
||||
// the PWA's own PHP session (logout previously only cleared the SSO
|
||||
// cookie, leaving the district_id pinned). SSO is validated once per
|
||||
// session at login; a transfer is picked up on the next logout→login.
|
||||
// the PWA's own PHP session and then hands off to the portal's
|
||||
// /user-logout for a FULL SSO logout (token invalidated + sso_auth_token
|
||||
// cleared by the portal). Previously logout left the PHP session intact,
|
||||
// pinning a stale district_id. SSO is validated once per session at login;
|
||||
// a transfer is picked up on the next logout→login.
|
||||
// Client-side stale-district guard (wipes district-scoped caches when the
|
||||
// session district changes) + district-keyed boundary cache; GPS read-out
|
||||
// UTM coordinate-format setting; ol-ext touch-cursor gated to touch-only
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user