diff --git a/exec/bootstrap.php b/exec/bootstrap.php index 68e8ca1..1c2b75d 100644 --- a/exec/bootstrap.php +++ b/exec/bootstrap.php @@ -19,7 +19,6 @@ foreach ([ 'KeyName.php', 'RateLimiter.php', 'RemoteLoginUrlClient.php', - 'SourceAuthorizer.php', 'UrlValidator.php', ] as $file) { require_once PLUGIN_EXEC_DIR . '/lib/' . $file; diff --git a/exec/handlers/login.php b/exec/handlers/login.php index c5081ef..33c47f2 100644 --- a/exec/handlers/login.php +++ b/exec/handlers/login.php @@ -14,7 +14,6 @@ return static function (): void { Http::errorPage('Metoda logowania nie jest obsługiwana.', 500); } $ctx = DirectAdminContext::fromServer($_SERVER, $settings); - SourceAuthorizer::assertAllowed($ctx->sourceHost(), $settings); $auditBase = [ 'request_id' => bin2hex(random_bytes(8)), diff --git a/exec/lib/DirectAdminContext.php b/exec/lib/DirectAdminContext.php index 8c3baf0..6f43afa 100644 --- a/exec/lib/DirectAdminContext.php +++ b/exec/lib/DirectAdminContext.php @@ -20,7 +20,7 @@ final class DirectAdminContext if (!preg_match('/^[A-Za-z0-9][A-Za-z0-9._-]{0,31}$/', $username)) { throw new InvalidArgumentException('Invalid DirectAdmin username'); } - $host = self::trustedSourceHost($server, $settings); + $host = self::trustedSourceHost($server); if ($host === '') { throw new InvalidArgumentException('Missing source host'); } @@ -37,17 +37,8 @@ final class DirectAdminContext /** * @param array $server */ - private static function trustedSourceHost(array $server, Settings $settings): string + private static function trustedSourceHost(array $server): string { - $configuredName = $settings->sourceServerName(); - if ($configuredName !== '') { - foreach ($settings->allowedSourceHosts() as $allowedHost) { - $label = $settings->sanitizeServerName(explode('.', $allowedHost)[0] ?? ''); - if ($label === $configuredName) { - return $allowedHost; - } - } - } return Settings::normalizeHost((string)($server['SERVER_NAME'] ?? '')); } diff --git a/exec/lib/Settings.php b/exec/lib/Settings.php index 13c93f9..ae1ac15 100644 --- a/exec/lib/Settings.php +++ b/exec/lib/Settings.php @@ -64,7 +64,6 @@ final class Settings 'MAIL_LOGIN_REDIRECT_URL' => '/', 'LOGIN_KEY_TTL' => '30', 'USER_IP_BOUND' => '1', - 'MAIL_LOGIN_ALLOWED_SOURCE_HOSTS' => 's1.abc.pl,serwer.mojserwer.pl,serwer2.xxb.ovh', 'MAIL_LOGIN_SOURCE_SERVER_NAME' => '', 'MAIL_LOGIN_CLIENT_IP_MODE' => 'direct', 'MAIL_LOGIN_TRUSTED_PROXIES' => '', @@ -136,14 +135,6 @@ final class Settings return $this->getString('USER_IP_BOUND', '1') === '1'; } - /** - * @return list - */ - public function allowedSourceHosts(): array - { - return $this->csvHosts('MAIL_LOGIN_ALLOWED_SOURCE_HOSTS'); - } - public function sourceServerName(): string { return $this->sanitizeServerName($this->getString('MAIL_LOGIN_SOURCE_SERVER_NAME', '')); @@ -213,25 +204,6 @@ final class Settings return substr($name, 0, 32); } - /** - * @return list - */ - private function csvHosts(string $key): array - { - $raw = $this->getString($key, ''); - if ($raw === '') { - return []; - } - $out = []; - foreach (explode(',', $raw) as $item) { - $host = self::normalizeHost($item); - if ($host !== '') { - $out[] = $host; - } - } - return array_values(array_unique($out)); - } - /** * @return list */ diff --git a/exec/lib/SourceAuthorizer.php b/exec/lib/SourceAuthorizer.php deleted file mode 100644 index 1e7cd46..0000000 --- a/exec/lib/SourceAuthorizer.php +++ /dev/null @@ -1,16 +0,0 @@ -allowedSourceHosts(); - if ($allowed === []) { - throw new RuntimeException('No source host allowlist configured'); - } - if (!in_array(Settings::normalizeHost($sourceHost), $allowed, true)) { - throw new RuntimeException('Source host is not allowed'); - } - } -} diff --git a/plugin-settings.conf b/plugin-settings.conf index a7aaa8d..fdfbb54 100644 --- a/plugin-settings.conf +++ b/plugin-settings.conf @@ -20,10 +20,7 @@ LOGIN_KEY_TTL=30 # 1 = przypnij URL do IP przeglądarki użytkownika, 0 = nie przypinaj do IP. USER_IP_BOUND=1 -# Hosty DirectAdmin WWW, z których wolno inicjować autologowanie do MX. -MAIL_LOGIN_ALLOWED_SOURCE_HOSTS=s1.abc.pl,serwer.mojserwer.pl,serwer2.xxb.ovh - -# Opcjonalna jawna nazwa źródłowego serwera. Puste = pierwsza etykieta HTTP_HOST. +# Opcjonalna jawna nazwa źródłowego serwera. Puste = pierwsza etykieta SERVER_NAME. MAIL_LOGIN_SOURCE_SERVER_NAME= # direct = REMOTE_ADDR, trusted_proxy = pierwszy X-Forwarded-For tylko od zaufanego proxy. diff --git a/plugin.conf b/plugin.conf index 7218776..3e0567d 100644 --- a/plugin.conf +++ b/plugin.conf @@ -2,7 +2,7 @@ name=mail-login id=mail-login type=user author=HITME.PL -version=1.0.4 +version=1.0.5 active=no installed=no user_run_as=root diff --git a/tests/context_test.php b/tests/context_test.php index a2cb07a..d97a74b 100644 --- a/tests/context_test.php +++ b/tests/context_test.php @@ -5,7 +5,6 @@ require_once PLUGIN_ROOT . '/exec/lib/Settings.php'; require_once PLUGIN_ROOT . '/exec/lib/DirectAdminContext.php'; require_once PLUGIN_ROOT . '/exec/lib/ClientIp.php'; require_once PLUGIN_ROOT . '/exec/lib/KeyName.php'; -require_once PLUGIN_ROOT . '/exec/lib/SourceAuthorizer.php'; test('directadmin context derives server name from first host label', function (): void { $settings = Settings::fromArray(['MAIL_LOGIN_SOURCE_SERVER_NAME' => '']); @@ -22,7 +21,7 @@ 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 { +test('directadmin context uses configured source server name and trusts local server name host', function (): void { $settings = Settings::fromArray(['MAIL_LOGIN_SOURCE_SERVER_NAME' => 'h4']); $ctx = DirectAdminContext::fromServer([ 'USERNAME' => 'mxtest', @@ -100,19 +99,6 @@ test('client ip supports trusted proxy cidr ranges', function (): void { 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']); - - SourceAuthorizer::assertAllowed('h4.domena.pl', $settings); - - try { - SourceAuthorizer::assertAllowed('evil.example.net', $settings); - throw new RuntimeException('Expected disallowed source host to fail'); - } catch (RuntimeException $e) { - assert_contains('source host', strtolower($e->getMessage())); - } -}); - test('key name uses requested format and truncates long values deterministically', function (): void { assert_same('autologin-h4-mxtest-1782810000', KeyName::build('h4', 'mxtest', 1782810000)); diff --git a/tests/package_contents_test.php b/tests/package_contents_test.php index c41b5b7..0b67d23 100644 --- a/tests/package_contents_test.php +++ b/tests/package_contents_test.php @@ -8,7 +8,7 @@ test('plugin metadata and packaging docs match project rules', function (): void assert_contains('name=mail-login', $conf); assert_contains('id=mail-login', $conf); assert_contains('type=user', $conf); - assert_contains('version=1.0.4', $conf); + assert_contains('version=1.0.5', $conf); assert_contains('user_run_as=root', $conf); assert_contains('/Users/marek/GPT/ChatGPT/da_plugins/mail-login/src', $packing); assert_contains('/Users/marek/GPT/ChatGPT/da_plugins/mail-login/archives/X.Y.Z/mail-login.tar.gz', $packing); diff --git a/tests/settings_test.php b/tests/settings_test.php index 25a1823..301b286 100644 --- a/tests/settings_test.php +++ b/tests/settings_test.php @@ -49,12 +49,12 @@ test('settings reject unsupported mx login mode values', function (): void { } }); -test('settings parse allowed source hosts as normalized hostnames', function (): void { - $settings = Settings::fromArray([ - 'MAIL_LOGIN_ALLOWED_SOURCE_HOSTS' => 'https://h4.domena.pl:2222, serwer2.example.net:2222', - ]); +test('source plugin settings do not expose local source host allowlist', function (): void { + $defaults = Settings::defaults(); + $config = file_get_contents(PLUGIN_ROOT . '/plugin-settings.conf') ?: ''; - assert_same(['h4.domena.pl', 'serwer2.example.net'], $settings->allowedSourceHosts()); + assert_false(array_key_exists('MAIL_LOGIN_ALLOWED_SOURCE_HOSTS', $defaults)); + assert_not_contains('MAIL_LOGIN_ALLOWED_SOURCE_HOSTS', $config); }); test('settings reject disabled plugin and unsupported methods through access guard', function (): void {