fix: address security review findings

This commit is contained in:
Marek Miklewicz
2026-06-30 11:41:40 +02:00
parent 3b096b67bb
commit 54b2e620ff
12 changed files with 188 additions and 31 deletions
+42 -1
View File
@@ -12,6 +12,7 @@ test('directadmin context derives server name from first host label', function (
$ctx = DirectAdminContext::fromServer([
'USERNAME' => 'mxtest',
'HTTP_HOST' => 'https://h4.domena.pl:2222',
'SERVER_NAME' => 'h4.domena.pl',
'REMOTE_ADDR' => '198.51.100.10',
'REQUEST_METHOD' => 'GET',
], $settings);
@@ -21,6 +22,34 @@ test('directadmin context derives server name from first host label', function (
assert_same('h4', $ctx->serverName());
});
test('directadmin context prefers trusted configured source server name over host header', function (): void {
$settings = Settings::fromArray(['MAIL_LOGIN_SOURCE_SERVER_NAME' => 'h4']);
$ctx = DirectAdminContext::fromServer([
'USERNAME' => 'mxtest',
'HTTP_HOST' => 'evil.example.net:2222',
'SERVER_NAME' => 'h4.domena.pl',
'REMOTE_ADDR' => '198.51.100.10',
'REQUEST_METHOD' => 'GET',
], $settings);
assert_same('h4.domena.pl', $ctx->sourceHost());
assert_same('h4', $ctx->serverName());
});
test('directadmin context fails closed without directadmin username', function (): void {
try {
DirectAdminContext::fromServer([
'USER' => 'root',
'HTTP_HOST' => 'h4.domena.pl:2222',
'REMOTE_ADDR' => '198.51.100.10',
'REQUEST_METHOD' => 'GET',
], Settings::fromArray([]));
throw new RuntimeException('Expected missing USERNAME to fail');
} catch (InvalidArgumentException $e) {
assert_contains('username', strtolower($e->getMessage()));
}
});
test('directadmin context rejects invalid usernames', function (): void {
try {
DirectAdminContext::fromServer([
@@ -58,6 +87,19 @@ test('client ip honors forwarded header only from trusted proxy', function (): v
assert_same('203.0.113.20', $ip);
});
test('client ip supports trusted proxy cidr ranges', function (): void {
$settings = Settings::fromArray([
'MAIL_LOGIN_CLIENT_IP_MODE' => 'trusted_proxy',
'MAIL_LOGIN_TRUSTED_PROXIES' => '10.0.0.0/24',
]);
$ip = ClientIp::resolve([
'REMOTE_ADDR' => '10.0.0.25',
'HTTP_X_FORWARDED_FOR' => '203.0.113.20',
], $settings);
assert_same('203.0.113.20', $ip);
});
test('source authorizer rejects hosts outside allowlist', function (): void {
$settings = Settings::fromArray(['MAIL_LOGIN_ALLOWED_SOURCE_HOSTS' => 'h4.domena.pl']);
@@ -79,4 +121,3 @@ test('key name uses requested format and truncates long values deterministically
assert_true(str_starts_with($long, 'autologin-'));
assert_true((bool)preg_match('/-[a-f0-9]{10}-1782810000$/', $long), 'Long key should contain hash suffix');
});