fix: WinRM try host.hostname first like Enter-PSSession (0.10.4)
This commit is contained in:
@@ -35,8 +35,28 @@ def resolve_windows_host_target(host: Host) -> str:
|
|||||||
return targets[0]
|
return targets[0]
|
||||||
|
|
||||||
|
|
||||||
|
def _netbios_name_variants(name: str | None) -> list[str]:
|
||||||
|
"""Короткое имя ПК (NetBIOS), как Enter-PSSession -ComputerName Andrisonova-PC."""
|
||||||
|
text = (name or "").strip()
|
||||||
|
if not text:
|
||||||
|
return []
|
||||||
|
short = text.split(".")[0].split("\\")[0].strip()
|
||||||
|
if not short:
|
||||||
|
return []
|
||||||
|
if short.casefold() == text.casefold():
|
||||||
|
return [short]
|
||||||
|
return [short, text]
|
||||||
|
|
||||||
|
|
||||||
|
def _looks_like_computer_name(value: str) -> bool:
|
||||||
|
text = value.strip()
|
||||||
|
if not text or " " in text:
|
||||||
|
return False
|
||||||
|
return len(text) <= 63
|
||||||
|
|
||||||
|
|
||||||
def iter_winrm_targets(host: Host) -> list[str]:
|
def iter_winrm_targets(host: Host) -> list[str]:
|
||||||
"""WinRM + NTLM: сначала имя машины (SPN), затем IPv4."""
|
"""WinRM + NTLM: сначала имя хоста (как Enter-PSSession -ComputerName), IP — последним."""
|
||||||
if not is_windows_host(host):
|
if not is_windows_host(host):
|
||||||
raise HostNotWindowsError("Host is not Windows")
|
raise HostNotWindowsError("Host is not Windows")
|
||||||
|
|
||||||
@@ -45,17 +65,24 @@ def iter_winrm_targets(host: Host) -> list[str]:
|
|||||||
|
|
||||||
def add(value: str | None) -> None:
|
def add(value: str | None) -> None:
|
||||||
text = (value or "").strip()
|
text = (value or "").strip()
|
||||||
if not text or text in seen:
|
if not text or text.casefold() in seen:
|
||||||
return
|
return
|
||||||
seen.add(text)
|
seen.add(text.casefold())
|
||||||
ordered.append(text)
|
ordered.append(text)
|
||||||
|
|
||||||
|
for variant in _netbios_name_variants(host.hostname):
|
||||||
|
add(variant)
|
||||||
|
|
||||||
inventory = host.inventory if isinstance(host.inventory, dict) else {}
|
inventory = host.inventory if isinstance(host.inventory, dict) else {}
|
||||||
computer_name = inventory.get("computer_name")
|
computer_name = inventory.get("computer_name")
|
||||||
if isinstance(computer_name, str):
|
if isinstance(computer_name, str):
|
||||||
add(computer_name)
|
for variant in _netbios_name_variants(computer_name):
|
||||||
add(host.hostname)
|
add(variant)
|
||||||
add(host.display_name)
|
|
||||||
|
if host.display_name and _looks_like_computer_name(host.display_name):
|
||||||
|
for variant in _netbios_name_variants(host.display_name):
|
||||||
|
add(variant)
|
||||||
|
|
||||||
add(host.ipv4)
|
add(host.ipv4)
|
||||||
return ordered
|
return ordered
|
||||||
|
|
||||||
@@ -104,8 +131,8 @@ def test_winrm_connection(
|
|||||||
hint = ""
|
hint = ""
|
||||||
if "credentials were rejected" in detail.lower():
|
if "credentials were rejected" in detail.lower():
|
||||||
hint = (
|
hint = (
|
||||||
" Проверьте логин (B26\\user), пароль и что учётка — admin на целевом ПК; "
|
" Проверьте логин (B26\\user), пароль и права admin на ПК; "
|
||||||
"при подключении по IP NTLM часто отклоняет creds — используйте имя хоста."
|
"подключайтесь по имени хоста (как Enter-PSSession -ComputerName), не по IP."
|
||||||
)
|
)
|
||||||
return WinRmTestResult(
|
return WinRmTestResult(
|
||||||
ok=False,
|
ok=False,
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
"""Единый источник версии SAC (API, health, логи, OpenAPI)."""
|
"""Единый источник версии SAC (API, health, логи, OpenAPI)."""
|
||||||
|
|
||||||
APP_NAME = "Security Alert Center"
|
APP_NAME = "Security Alert Center"
|
||||||
APP_VERSION = "0.10.3"
|
APP_VERSION = "0.10.4"
|
||||||
APP_VERSION_LABEL = f"{APP_NAME} v.{APP_VERSION}"
|
APP_VERSION_LABEL = f"{APP_NAME} v.{APP_VERSION}"
|
||||||
|
|||||||
@@ -4,6 +4,6 @@ from app.version import APP_NAME, APP_VERSION, APP_VERSION_LABEL
|
|||||||
|
|
||||||
|
|
||||||
def test_version_constants():
|
def test_version_constants():
|
||||||
assert APP_VERSION == "0.10.3"
|
assert APP_VERSION == "0.10.4"
|
||||||
assert APP_NAME == "Security Alert Center"
|
assert APP_NAME == "Security Alert Center"
|
||||||
assert APP_VERSION_LABEL == "Security Alert Center v.0.10.3"
|
assert APP_VERSION_LABEL == "Security Alert Center v.0.10.4"
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ from unittest.mock import patch
|
|||||||
|
|
||||||
from app.models.ui_settings import UI_SETTINGS_ROW_ID, UiSettings
|
from app.models.ui_settings import UI_SETTINGS_ROW_ID, UiSettings
|
||||||
from app.services.win_admin_settings import normalize_win_admin_user
|
from app.services.win_admin_settings import normalize_win_admin_user
|
||||||
|
from app.services.winrm_connect import iter_winrm_targets
|
||||||
|
|
||||||
|
|
||||||
def test_normalize_win_admin_user():
|
def test_normalize_win_admin_user():
|
||||||
@@ -11,6 +12,21 @@ def test_normalize_win_admin_user():
|
|||||||
assert normalize_win_admin_user(r"B26\papatramp") == r"B26\papatramp"
|
assert normalize_win_admin_user(r"B26\papatramp") == r"B26\papatramp"
|
||||||
|
|
||||||
|
|
||||||
|
def test_iter_winrm_targets_hostname_before_ip():
|
||||||
|
from app.models import Host
|
||||||
|
|
||||||
|
host = Host(
|
||||||
|
hostname="Andrisonova-PC",
|
||||||
|
os_family="windows",
|
||||||
|
product="rdp-login-monitor",
|
||||||
|
ipv4="192.168.1.50",
|
||||||
|
inventory={"computer_name": "Andrisonova-PC"},
|
||||||
|
)
|
||||||
|
targets = iter_winrm_targets(host)
|
||||||
|
assert targets[0] == "Andrisonova-PC"
|
||||||
|
assert targets[-1] == "192.168.1.50"
|
||||||
|
|
||||||
|
|
||||||
def test_get_win_admin_settings_env_default(jwt_headers, client, monkeypatch):
|
def test_get_win_admin_settings_env_default(jwt_headers, client, monkeypatch):
|
||||||
monkeypatch.setenv("SAC_WIN_ADMIN_USER", "")
|
monkeypatch.setenv("SAC_WIN_ADMIN_USER", "")
|
||||||
monkeypatch.setenv("SAC_WIN_ADMIN_PASSWORD", "")
|
monkeypatch.setenv("SAC_WIN_ADMIN_PASSWORD", "")
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "sac-ui",
|
"name": "sac-ui",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.10.3",
|
"version": "0.10.4",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
/** Fallback до загрузки /health; при релизе держите в sync с backend/app/version.py */
|
/** Fallback до загрузки /health; при релизе держите в sync с backend/app/version.py */
|
||||||
export const APP_NAME = "Security Alert Center";
|
export const APP_NAME = "Security Alert Center";
|
||||||
export const APP_VERSION = "0.10.3";
|
export const APP_VERSION = "0.10.4";
|
||||||
export const APP_VERSION_LABEL = `${APP_NAME} v.${APP_VERSION}`;
|
export const APP_VERSION_LABEL = `${APP_NAME} v.${APP_VERSION}`;
|
||||||
|
|||||||
Reference in New Issue
Block a user