feat: per-host WinRM/SSH credentials override (0.5.17)
Allow host-level login/password for home/workgroup PCs while keeping global domain admins in Settings.
This commit is contained in:
+109
-16
@@ -46,8 +46,12 @@ from app.services.host_sessions import (
|
||||
terminate_windows_session,
|
||||
)
|
||||
from app.services.host_delete import delete_host_and_related
|
||||
from app.services.linux_admin_settings import get_effective_linux_admin_config
|
||||
from app.services.win_admin_settings import get_effective_win_admin_config
|
||||
from app.services.host_mgmt_credentials import (
|
||||
get_host_mgmt_access_view,
|
||||
upsert_host_mgmt_credentials,
|
||||
)
|
||||
from app.services.linux_admin_settings import get_effective_linux_admin_for_host
|
||||
from app.services.win_admin_settings import get_effective_win_admin_for_host
|
||||
from app.services.winrm_connect import (
|
||||
HostNotWindowsError,
|
||||
HostTargetMissingError,
|
||||
@@ -299,6 +303,23 @@ class HostAgentConfigResponse(BaseModel):
|
||||
settings: dict[str, object]
|
||||
|
||||
|
||||
class HostMgmtAccessResponse(BaseModel):
|
||||
host_id: int
|
||||
has_override: bool
|
||||
user: str | None = None
|
||||
password_set: bool = False
|
||||
password_hint: str | None = None
|
||||
effective_source: str
|
||||
effective_configured: bool
|
||||
effective_user: str | None = None
|
||||
|
||||
|
||||
class HostMgmtAccessUpdate(BaseModel):
|
||||
user: str | None = None
|
||||
password: str | None = None
|
||||
clear: bool = False
|
||||
|
||||
|
||||
class HostRemoteActionStartResponse(BaseModel):
|
||||
status: str
|
||||
host_id: int
|
||||
@@ -469,9 +490,12 @@ def test_host_winrm(
|
||||
if host is None:
|
||||
raise HTTPException(status_code=404, detail="Host not found")
|
||||
|
||||
cfg = get_effective_win_admin_config(db)
|
||||
cfg = get_effective_win_admin_for_host(db, host)
|
||||
if not cfg.configured:
|
||||
raise HTTPException(status_code=400, detail="Windows domain admin is not configured")
|
||||
raise HTTPException(
|
||||
status_code=400,
|
||||
detail="Windows admin is not configured (host override or Settings → Windows)",
|
||||
)
|
||||
|
||||
try:
|
||||
targets = iter_winrm_targets(host)
|
||||
@@ -532,9 +556,12 @@ def test_host_ssh(
|
||||
if host is None:
|
||||
raise HTTPException(status_code=404, detail="Host not found")
|
||||
|
||||
cfg = get_effective_linux_admin_config(db)
|
||||
cfg = get_effective_linux_admin_for_host(db, host)
|
||||
if not cfg.configured:
|
||||
raise HTTPException(status_code=400, detail="Linux SSH admin is not configured")
|
||||
raise HTTPException(
|
||||
status_code=400,
|
||||
detail="Linux SSH admin is not configured (host override or Settings → Linux)",
|
||||
)
|
||||
|
||||
response = _run_ssh_action_on_host(host, cfg, action=test_ssh_connection)
|
||||
_set_ssh_admin_status(host, response.ok)
|
||||
@@ -556,9 +583,12 @@ def update_host_agent_via_ssh(
|
||||
if host is None:
|
||||
raise HTTPException(status_code=404, detail="Host not found")
|
||||
|
||||
cfg = get_effective_linux_admin_config(db)
|
||||
cfg = get_effective_linux_admin_for_host(db, host)
|
||||
if not cfg.configured:
|
||||
raise HTTPException(status_code=400, detail="Linux SSH admin is not configured")
|
||||
raise HTTPException(
|
||||
status_code=400,
|
||||
detail="Linux SSH admin is not configured (host override or Settings → Linux)",
|
||||
)
|
||||
|
||||
title = "Обновление ssh-monitor (SSH)"
|
||||
try:
|
||||
@@ -686,9 +716,12 @@ def list_host_sessions(
|
||||
from app.services.winrm_connect import is_windows_host
|
||||
|
||||
if is_linux_host(host):
|
||||
cfg = get_effective_linux_admin_config(db)
|
||||
cfg = get_effective_linux_admin_for_host(db, host)
|
||||
if not cfg.configured:
|
||||
raise HTTPException(status_code=400, detail="Linux SSH admin is not configured")
|
||||
raise HTTPException(
|
||||
status_code=400,
|
||||
detail="Linux SSH admin is not configured (host override or Settings → Linux)",
|
||||
)
|
||||
try:
|
||||
sessions, result = list_linux_sessions(host, cfg)
|
||||
except SshHostNotLinuxError as exc:
|
||||
@@ -703,9 +736,12 @@ def list_host_sessions(
|
||||
)
|
||||
|
||||
if is_windows_host(host):
|
||||
cfg = get_effective_win_admin_config(db)
|
||||
cfg = get_effective_win_admin_for_host(db, host)
|
||||
if not cfg.configured:
|
||||
raise HTTPException(status_code=400, detail="Windows domain admin is not configured")
|
||||
raise HTTPException(
|
||||
status_code=400,
|
||||
detail="Windows admin is not configured (host override or Settings → Windows)",
|
||||
)
|
||||
try:
|
||||
sessions, result = list_windows_sessions(host, cfg)
|
||||
except HostNotWindowsError as exc:
|
||||
@@ -743,9 +779,12 @@ def terminate_host_session(
|
||||
raise HTTPException(status_code=422, detail="session_id is required")
|
||||
|
||||
if is_linux_host(host):
|
||||
cfg = get_effective_linux_admin_config(db)
|
||||
cfg = get_effective_linux_admin_for_host(db, host)
|
||||
if not cfg.configured:
|
||||
raise HTTPException(status_code=400, detail="Linux SSH admin is not configured")
|
||||
raise HTTPException(
|
||||
status_code=400,
|
||||
detail="Linux SSH admin is not configured (host override or Settings → Linux)",
|
||||
)
|
||||
try:
|
||||
result = terminate_linux_session(host, cfg, sid)
|
||||
except SshHostNotLinuxError as exc:
|
||||
@@ -761,9 +800,12 @@ def terminate_host_session(
|
||||
)
|
||||
|
||||
if is_windows_host(host):
|
||||
cfg = get_effective_win_admin_config(db)
|
||||
cfg = get_effective_win_admin_for_host(db, host)
|
||||
if not cfg.configured:
|
||||
raise HTTPException(status_code=400, detail="Windows domain admin is not configured")
|
||||
raise HTTPException(
|
||||
status_code=400,
|
||||
detail="Windows admin is not configured (host override or Settings → Windows)",
|
||||
)
|
||||
try:
|
||||
result = terminate_windows_session(host, cfg, sid)
|
||||
except HostNotWindowsError as exc:
|
||||
@@ -803,6 +845,57 @@ def patch_host_agent_config(
|
||||
)
|
||||
|
||||
|
||||
@router.get("/{host_id}/access", response_model=HostMgmtAccessResponse)
|
||||
def get_host_access(
|
||||
host_id: int,
|
||||
db: Session = Depends(get_db),
|
||||
_user=Depends(require_admin),
|
||||
) -> HostMgmtAccessResponse:
|
||||
host = db.get(Host, host_id)
|
||||
if host is None:
|
||||
raise HTTPException(status_code=404, detail="Host not found")
|
||||
view = get_host_mgmt_access_view(db, host)
|
||||
return HostMgmtAccessResponse(
|
||||
host_id=view.host_id,
|
||||
has_override=view.has_override,
|
||||
user=view.user,
|
||||
password_set=view.password_set,
|
||||
password_hint=view.password_hint,
|
||||
effective_source=view.effective_source,
|
||||
effective_configured=view.effective_configured,
|
||||
effective_user=view.effective_user,
|
||||
)
|
||||
|
||||
|
||||
@router.put("/{host_id}/access", response_model=HostMgmtAccessResponse)
|
||||
def put_host_access(
|
||||
host_id: int,
|
||||
body: HostMgmtAccessUpdate,
|
||||
db: Session = Depends(get_db),
|
||||
_user=Depends(require_admin),
|
||||
) -> HostMgmtAccessResponse:
|
||||
host = db.get(Host, host_id)
|
||||
if host is None:
|
||||
raise HTTPException(status_code=404, detail="Host not found")
|
||||
view = upsert_host_mgmt_credentials(
|
||||
db,
|
||||
host,
|
||||
user=body.user,
|
||||
password=body.password,
|
||||
clear=body.clear,
|
||||
)
|
||||
return HostMgmtAccessResponse(
|
||||
host_id=view.host_id,
|
||||
has_override=view.has_override,
|
||||
user=view.user,
|
||||
password_set=view.password_set,
|
||||
password_hint=view.password_hint,
|
||||
effective_source=view.effective_source,
|
||||
effective_configured=view.effective_configured,
|
||||
effective_user=view.effective_user,
|
||||
)
|
||||
|
||||
|
||||
@router.get("/{host_id}/agent-config", response_model=HostAgentConfigResponse)
|
||||
def get_host_agent_config(
|
||||
host_id: int,
|
||||
|
||||
Reference in New Issue
Block a user