Issue 132 MFA Login Redirected To A Missing Page - edmozley/freeitsm GitHub Wiki
Signing in with an authenticator app landed on a page that does not exist (issue #132)
Reported by mbsouth ยท Fixed in #1463
1. What you saw
Sign in as an analyst with multi-factor authentication switched on. Enter your username and password, then the six-digit code from your authenticator app.
On the sixth digit the browser goes to /auth/index.php - a blank error page - instead of your inbox. You are actually signed in; you just have to type the address by hand to get anywhere.
The reporter had it exactly right in the title: the redirect went to the wrong URL.
2. What was actually wrong
api/myaccount/verify_login_otp.php finishes a successful code check by telling the browser where to go next:
$redirect = 'index.php';
That is a relative address. The page asking the question is /auth/login.php, and window.location.href resolves a relative address against the page it is on - so index.php does not mean the top of the site, it means next to the sign-in page. /auth/ is a folder of sign-in machinery with no home page in it, so the browser asks for a file that has never existed.
Why the other redirect in the same response looked fine
The identical mistake was in the same file twice more:
$redirect = 'force_password_change.php';
That one worked - and only by accident. auth/force_password_change.php really does live in /auth/, so resolving it against the sign-in page happens to land in the right place. One bare filename was wrong and one was right, for reasons that had nothing to do with either being written correctly.
The comparison that makes it plain
Ordinary sign-in - no code, no authenticator - never showed this, because auth/login.php builds the same two addresses properly a few lines away:
header('Location: ' . (defined('BASE_URL') ? BASE_URL : '/') . 'index.php');
header('Location: ' . (defined('BASE_URL') ? BASE_URL : '/') . 'auth/force_password_change.php');
So the two paths through the same screen disagreed. Switching on multi-factor authentication quietly changed where you ended up after signing in, which is not something anybody would think to check when enabling it.
The second bug hiding inside the first
A bare index.php is also wrong for a reason that has nothing to do with /auth/: it assumes FreeITSM is served from the root of a domain. On an install running in a subfolder, BASE_URL carries that prefix and the relative form drops it. Building the address from BASE_URL fixes both problems at once, which is why the non-MFA path was already written that way.
This is the same shape as #117, where a relative address in a Location header sent people somewhere that did not exist.
3. Why self-service is not affected
The portal has the same pattern - window.location.href = 'index.php' after its own code check - and it is fine. Its sign-in page is /self-service/login.php, so the relative address resolves to /self-service/index.php, which is the portal home. It also uses the same value on both its MFA and non-MFA paths, so the two do not disagree.
Checked rather than assumed. Left alone.
4. ๐ Files
| File | Change |
|---|---|
api/myaccount/verify_login_otp.php |
Builds a $base from BASE_URL and returns absolute addresses: $base . 'index.php' and $base . 'auth/force_password_change.php' |
No schema change, no change to the sign-in page itself, and no change to what the code check does - only to the address it hands back.
5. How it was verified
BASE_URL was read from a live install and the resulting addresses printed:
BASE_URL = '/'
was (MFA) : index.php -> resolves against /auth/ = /auth/index.php
now (MFA) : /index.php
now (pwd) : /auth/force_password_change.php
/index.php is the address the reporter said works. The forced-password-change address is unchanged, which matters - it was already landing correctly and a careless fix would have moved it.
The endpoint was then called directly to confirm it still runs and still refuses a request with no challenge pending:
{"success":false,"error":"No MFA challenge pending"}
What was not done
The full path was not driven end to end, because that needs a valid six-digit code for a real account with MFA enabled, and the secret is encrypted at rest. The change is one address string on a path that was otherwise working - the code check, the session promotion and the throttle counters are all untouched.
6. What this means for you
Nothing to do. After upgrading, signing in with an authenticator app takes you to the same place as signing in without one.
If you run FreeITSM in a subfolder rather than at the root of a domain, this also fixes the address for you properly rather than by luck.
7. Related
- #117 - OIDC sent people to a relative address - the same class of fault, in a
Locationheader - Security - how sign-in and multi-factor authentication work