Skip to content

Commit 59df6c4

Browse files
committed
Add tests
1 parent 0bcdb3b commit 59df6c4

2 files changed

Lines changed: 141 additions & 4 deletions

File tree

src/SimpleSAML/Utils/HTTP.php

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -265,7 +265,9 @@ private function redirect(string $url, array $parameters = []): void
265265
echo '</html>';
266266

267267
// end script execution
268-
exit;
268+
if (!defined('SIMPLESAMLPHP_TEST_NOEXIT')) {
269+
exit;
270+
}
269271
}
270272

271273

@@ -360,7 +362,8 @@ public function checkSessionCookie(?string $retryURL = null): void
360362
* Check if a URL is valid and is in our list of allowed URLs.
361363
*
362364
* @param string $url The URL to check.
363-
* @param string[]|null $trustedSites An optional white list of domains. If none specified, the 'trusted.url.domains'
365+
* @param string[]|null $trustedSites An optional white list of domains.
366+
* If none specified, the 'trusted.url.domains'
364367
* configuration directive will be used.
365368
*
366369
* @return string The normalized URL itself if it is allowed. An empty string if the $url parameter is empty as
@@ -1096,7 +1099,9 @@ public function setCookie(string $name, ?string $value, ?array $params = null, b
10961099
Error\CannotSetCookie::SECURE_COOKIE,
10971100
);
10981101
}
1099-
Logger::warning('Error setting cookie: setting secure cookie on plain HTTP (except on localhost) is not allowed.');
1102+
Logger::warning(
1103+
'Error setting cookie: setting secure cookie on plain HTTP (except on localhost) is not allowed.',
1104+
);
11001105
return;
11011106
}
11021107

@@ -1187,6 +1192,7 @@ public function submitPOSTData(string $destination, array $data): void
11871192
if ($allowed && preg_match("#^http:#", $destination) && $this->isHTTPS()) {
11881193
// we need to post the data to HTTP
11891194
$this->redirect($this->getSecurePOSTRedirectURL($destination, $data));
1195+
return;
11901196
}
11911197

11921198
$p = new Template($config, 'post.twig');
@@ -1201,6 +1207,8 @@ public function submitPOSTData(string $destination, array $data): void
12011207
$p->data['slow_post_delay_ms'] = $delay;
12021208

12031209
$p->send();
1204-
exit(0);
1210+
if (!defined('SIMPLESAMLPHP_TEST_NOEXIT')) {
1211+
exit(0);
1212+
}
12051213
}
12061214
}

tests/src/SimpleSAML/Utils/HTTPTest.php

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,17 @@
1818
#[CoversClass(Utils\HTTP::class)]
1919
class HTTPTest extends ClearStateTestCase
2020
{
21+
/**
22+
* Set up the test.
23+
*/
24+
protected function setUp(): void
25+
{
26+
parent::setUp();
27+
if (!defined('SIMPLESAMLPHP_TEST_NOEXIT')) {
28+
define('SIMPLESAMLPHP_TEST_NOEXIT', true);
29+
}
30+
}
31+
2132
/**
2233
* Set up the environment ($_SERVER) populating the typical variables from a given URL.
2334
*
@@ -620,4 +631,122 @@ public static function detectSameSiteProvider(): array
620631
];
621632
// @codingStandardsIgnoreEnd
622633
}
634+
635+
/**
636+
* submitPOSTData() should throw Error\Exception for an invalid destination URL.
637+
*/
638+
public function testSubmitPOSTDataThrowsOnInvalidURL(): void
639+
{
640+
$httpUtils = new Utils\HTTP();
641+
642+
// Minimal configuration to satisfy internals; won’t be used since we fail early.
643+
Configuration::loadFromArray([
644+
'baseurlpath' => 'https://example.com/simplesaml/',
645+
], '[ARRAY]', 'simplesaml');
646+
647+
$this->expectException(Error\Exception::class);
648+
$this->expectExceptionMessage('Invalid destination URL: not-a-url');
649+
650+
$httpUtils->submitPOSTData('not-a-url', ['a' => 'b']);
651+
}
652+
653+
654+
/**
655+
* When enable.http_post = true, destination is http:// and current request is HTTPS, we must redirect.
656+
* We assert a Location header is sent pointing to a postredirect URL.
657+
*/
658+
#[Depends('testXdebugMode')]
659+
#[RunInSeparateProcess]
660+
public function testSubmitPOSTDataRedirectsFromHttpsToHttp(): void
661+
{
662+
$httpUtils = new Utils\HTTP();
663+
664+
// Configure base URL and allow http post.
665+
Configuration::loadFromArray([
666+
'baseurlpath' => 'https://idp.example.org/simplesaml/',
667+
'enable.http_post' => true,
668+
'secretsalt' => 'abc',
669+
], '[ARRAY]', 'simplesaml');
670+
671+
// Simulate the current request being HTTPS
672+
$this->setupEnvFromURL('https://idp.example.org/simplesaml/module.php/core/someaction?x=1');
673+
674+
// Destination is explicitly http://
675+
$destination = 'http://sp.example.com/acs';
676+
$post = ['SAMLResponse' => 'abc', 'RelayState' => 'xyz'];
677+
678+
try {
679+
$httpUtils->submitPOSTData($destination, $post);
680+
} catch (\Throwable $e) {
681+
}
682+
683+
$headers = function_exists('xdebug_get_headers') ? xdebug_get_headers() : [];
684+
685+
// Find the Location header
686+
$locationHeader = null;
687+
foreach ($headers as $h) {
688+
if (stripos($h, 'Location: ') === 0) {
689+
$locationHeader = substr($h, 10);
690+
break;
691+
}
692+
}
693+
694+
$this->assertNotNull($locationHeader, 'Expected a Location header to be sent');
695+
$this->assertStringStartsWith('http://', $locationHeader, 'Location should be http://');
696+
$this->assertStringContainsString('/core/postredirect', $locationHeader);
697+
$this->assertTrue(
698+
(str_contains($locationHeader, 'RedirInfo=')),
699+
'Location should contain RedirInfo parameter',
700+
);
701+
}
702+
703+
704+
/**
705+
* submitPOSTData() should pass slow_post_delay_ms to the template:
706+
* - default 30000 when config key missing
707+
* - default 30000 when config value < 0
708+
* - exact value when config value is 10000
709+
*/
710+
#[DataProvider('slowPostDelayProvider')]
711+
#[RunInSeparateProcess]
712+
public function testSubmitPOSTDataSlowPostDelay(?int $configured, int $expected): void
713+
{
714+
$httpUtils = new Utils\HTTP();
715+
716+
// Base config
717+
$config = [
718+
'baseurlpath' => 'https://idp.example.org/simplesaml/',
719+
'enable.http_post' => false,
720+
];
721+
if ($configured !== null) {
722+
$config['slow_post_delay_ms'] = $configured;
723+
}
724+
Configuration::loadFromArray($config, '[ARRAY]', 'simplesaml');
725+
726+
// Use https destination to bypass the http-redirect branch entirely
727+
$destination = 'https://sp.example.com/acs';
728+
$post = ['k' => 'v'];
729+
730+
// Capture output
731+
ob_start();
732+
try {
733+
$httpUtils->submitPOSTData($destination, $post);
734+
} catch (\Throwable $e) {
735+
}
736+
$html = ob_get_clean();
737+
738+
// The template writes the delay into data-slow-post-delay attribute
739+
$needle = 'data-slow-post-delay="' . $expected . '"';
740+
$this->assertStringContainsString($needle, $html);
741+
}
742+
743+
public static function slowPostDelayProvider(): array
744+
{
745+
return [
746+
// [configured, expected]
747+
'missing config => default' => [null, 30000],
748+
'negative config => default' => [-5, 30000],
749+
'positive config 10000 => 10000' => [10000, 10000],
750+
];
751+
}
623752
}

0 commit comments

Comments
 (0)