Bugfix Issue 1478 PrintDocument Invalid Apikey Deny - sebiboga/testlink-upgraded GitHub Wiki
Bugfix β Issue #1478: printDocument.php β bogus 64-char apikey renders doc + 3x basehref E_WARNING
Problem
A bogus/unknown 64-char object api key on lib/results/printDocument.php
was silently accepted: the document rendered (HTTP 200) with broken relative
CSS/logo URLs and emitted the same 3 E_WARNING Undefined array key "basehref"
events as #1416 (printDocument.php:175, printDocument.php:254,
print.inc.php:700), each polluting the events table (log_level=2).
setUpEnvForAnonymousAccess() returns false for an unknown key, but
printDocument.php::init_args() ignored the return and rendered anyway.
Reproduced on the CI box (fresh import, PHP 8.x, MySQL) with
tmp/fixtures_1415.php (tproject=1, tplan=12, builds 1/2, tc3/6/9):
curl "http://localhost:8082/lib/results/printDocument.php?apikey=0000β¦0βΆβ΄&tproject_id=1&tplan_id=12&type=testreport_onbuild&level=testproject&build_id=2&format=0&allOptionsOn=1"
β HTTP=200 size=7932 + 3 new log_level=2 rows (events ids 5/6/7); baseline 0
Root Cause
Chain (each hop backed by file:line, default branch ce26f778a):
lib/results/printDocument.php:334βinit_args(): 64-char apikey enters the anonymous branch and callssetUpEnvForAnonymousAccess($db,$apikey,$cerbero)as a bare statement; the returned boolean is discarded.lib/functions/common.php:1330-1353β the paranoic candidate list['testplan','testproject'](the #1416 shape) runsgetEntityByAPIKey()(common.php:1395-1435) againsttestplans.api_key+testprojects.api_key; a key owned by neither entity yields$item=NULL.common.php:1355-1379β the anonymous-session block (userID=-1, locale,setPaths()β$_SESSION['basehref']) only runs insideif(!is_null($item)); with$item=NULLit is skipped and the function returnsfalse.- Back in
init_args()thefalseis ignored β rendering proceeds with an uninitialized session βbasehrefis never set and the three legacy readers fireE_WARNING Undefined array key "basehref"(printDocument.php:175renderHTMLHeader,print.inc.php:700logo,printDocument.php:254env basehref). Each E_WARNING is logged as aneventsrow β Event Viewer pollution. Document returns HTTP 200 with relativehref="gui/themes/default/css/tl_documents.css".
Why it breaks now: not a fresh regression β the unchecked call predates
the modern work; #1415/#1416 merely exercised the plan-report link shapes.
#1416 deliberately did not touch the caller (its own doc: "the deny path at
common.php:1355-1379 stays unreachable for direct printDocument access").
Blast radius: setUpEnvForAnonymousAccess() is the shared anonymous
gateway used by 16+ screens, each with its own deny semantics
(lnl.php:278 flips light=red; displayMgr.php:65 throws later on
post-conditions; metricsDashboard.php:388 re-verifies via getByAPIKey).
Fixing inside the shared function would change all callers; the correct seam is
the per-caller check. printDocument.php is the only caller that follows the
gateway call with a raw document render β so this fix is a single-caller
change with zero blast radius.
Fix
Committed on branch fix/issue-1478 (a7c80b2d9):
} else {
$args->addOpAccess = false;
$cerbero->method = null;
// Refs #1478: an object api key that matches NO testproject/testplan
// entity must not render the document. setUpEnvForAnonymousAccess()
// returns false when the key is unknown, leaving the anonymous session
// (basehref included) uninitialized; rendering anyway produced a broken
// relative-URL document plus 3 basehref E_WARNING events per hit.
$status_ok = setUpEnvForAnonymousAccess($dbHandler,$args->apikey,$cerbero);
if (!$status_ok) {
renderGracefulExit(lang_get('error_print_doc_invalid_apikey'));
exit;
}
}
Reuses the existing renderGracefulExit() page already shipped in this exact
controller for missing id (Refs #683) and missing testplan (Refs #573).
New legacy i18n key error_print_doc_invalid_apikey added to
locale/en_US/strings.txt (:638) and locale/en_GB/strings.txt (:645) β
the only two bundles carrying the error_print_doc_* family; lang_get()
falls back to en_GB (lib/functions/lang_api.php:73-80) for every other
locale, so all locales resolve the message.
Why this method: the gateway return is the authoritative "does this key own
an entity?" signal; checking it at the one caller that renders raw output gives
the minimal, complete deny. Matches the modern BFF precedent
(api/reportsprint already answers HTTP 401 {"status":"error","message":"Unknown api key"}
for a bogus key).
Rejected alternatives: (a) guarding each $_SESSION['basehref'] reader
with isset()?: β hides the symptom but still renders a half-initialized
anonymous session (no userID/locale) and keeps the false accept; (b) turning
the shared setUpEnvForAnonymousAccess() failure into an exception β would
change 16 callers' error semantics; (c) doing nothing but the #1416 fallback β
the bogus key still misses every lookup so #1416 cannot help.
Files Changed
lib/results/printDocument.phpβ anonymous-branch deny: capturesetUpEnvForAnonymousAccess()return; onfalsegraceful exit +exit.locale/en_US/strings.txt,locale/en_GB/strings.txtβ new keyerror_print_doc_invalid_apikey.tmp/TLU_Test_Cases.mdβ regression suite "Regression β Issue #1478", 11/11 PASS.docs/Bugfix-Issue-1478-PrintDocument-Invalid-Apikey-Deny.mdβ this file.tmp/wiki-repo/Bugfix-Issue-1478-PrintDocument-Invalid-Apikey-Deny.mdβ wiki mirror.docs/screenshots/issue-1478-anonymous-invalid-apikey-denied.png,docs/screenshots/issue-1478-anonymous-valid-apikey-document.pngβ deny state and valid anonymous render after fix.CHANGELOGβ one-line entry under 2.0.1 key bugfix section.
Verification
All checks on branch fix/issue-1478, PHP 8.x, MySQL fresh-import schema,
fixture tmp/fixtures_1415.php:
- Pre-fix control: repro URL β HTTP 200 size=7932 + 3 new
log_level=2basehref E_WARNING events (ids 5/6/7) vs baseline 0. - Post-fix R1 (bogus key, exact repro URL): HTTP 200 size=422 = graceful error page ("Document generation error" + new apikey message), 0 new events.
- Post-fix R2 (valid
testprojects.api_key+ tplan_id): HTTP 200 size=7976 full document, absolute asset URLs, 0 new events β no #1416 regression. - Post-fix R3 (valid
testplans.api_key): HTTP 200 size=7976, 0 new events. - Post-fix R4 (session render, admin browser session): full Test Plan Design Report (title page, TOC, platform/suite tree, 3 TCs incl. Passed exec tc3), absolute logo URL, 0 new events.
- Post-fix R5 (
lnl.phpvalid key): HTTP 302 βreportPrint.html?β¦(green public link unchanged). - Post-fix R6 (
lnl.phpbogus key): HTTP 200, no redirect, 0 new events. - Post-fix R7 (modern BFF
api/reportsprintbogus key): HTTP 401{"status":"error","message":"Unknown api key"}β already denied; 0 events. - Browser console on the deny page and both anonymous/session documents:
<no console messages found>β clean. - Event Viewer:
SELECT COUNT(*) FROM events WHERE log_level=2final = 3 (the pre-fix reproduction rows); zero growth across the whole suite. php -l lib/results/printDocument.phpclean.
Regression suite: tmp/TLU_Test_Cases.md β "Regression β Issue #1478", 11/11 PASS.
Address: Fixes #1478.
Screenshots

