fix: Prevent credential sharing errors for shared hosts
- Skip credential resolution for shared hosts with credential authentication to prevent decryption errors (credentials are encrypted per-user) - Add warning alert in sharing tab when host uses credential authentication - Inform users that shared users cannot connect to credential-based hosts - Add translations for credential sharing warning (EN/ZH) This prevents authentication failures when sharing hosts configured with credential authentication while maintaining security by keeping credentials isolated per user.
This commit is contained in:
@@ -1549,6 +1549,29 @@ async function resolveHostCredentials(
|
||||
host: Record<string, unknown>,
|
||||
): Promise<Record<string, unknown>> {
|
||||
try {
|
||||
// Skip credential resolution for shared hosts
|
||||
// Shared users cannot access the owner's encrypted credentials
|
||||
if (host.isShared && host.credentialId) {
|
||||
sshLogger.info(
|
||||
`Skipping credential resolution for shared host ${host.id} with credentialId ${host.credentialId}`,
|
||||
{
|
||||
operation: "resolve_host_credentials_shared",
|
||||
hostId: host.id as number,
|
||||
isShared: host.isShared,
|
||||
},
|
||||
);
|
||||
// Return host without resolving credentials
|
||||
// The frontend should handle credential auth for shared hosts differently
|
||||
const result = { ...host };
|
||||
if (host.key_password !== undefined) {
|
||||
if (result.keyPassword === undefined) {
|
||||
result.keyPassword = host.key_password;
|
||||
}
|
||||
delete result.key_password;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
if (host.credentialId && host.userId) {
|
||||
const credentialId = host.credentialId as number;
|
||||
const userId = host.userId as string;
|
||||
|
||||
@@ -1888,6 +1888,8 @@
|
||||
"cannotRemoveSystemRole": "Cannot remove system role",
|
||||
"cannotShareWithSelf": "Cannot share host with yourself",
|
||||
"noCustomRolesToAssign": "No custom roles available. System roles are auto-assigned.",
|
||||
"credentialSharingWarning": "Credential Authentication Not Supported for Sharing",
|
||||
"credentialSharingWarningDescription": "This host uses credential-based authentication. Shared users will not be able to connect because credentials are encrypted per-user and cannot be shared. Please use password or key-based authentication for hosts you intend to share.",
|
||||
"auditLogs": "Audit Logs",
|
||||
"viewAuditLogs": "View Audit Logs",
|
||||
"action": "Action",
|
||||
|
||||
@@ -1749,6 +1749,8 @@
|
||||
"cannotRemoveSystemRole": "无法移除系统角色",
|
||||
"cannotShareWithSelf": "不能与自己共享主机",
|
||||
"noCustomRolesToAssign": "没有可用的自定义角色。系统角色已自动分配。",
|
||||
"credentialSharingWarning": "不支持共享使用凭据认证的主机",
|
||||
"credentialSharingWarningDescription": "此主机使用凭据认证。由于凭据是按用户加密的无法共享,共享用户将无法连接。请为计划共享的主机使用密码或密钥认证。",
|
||||
"auditLogs": "审计日志",
|
||||
"viewAuditLogs": "查看审计日志",
|
||||
"action": "操作",
|
||||
|
||||
@@ -39,8 +39,10 @@ import {
|
||||
shareHost,
|
||||
getHostAccess,
|
||||
revokeHostAccess,
|
||||
getSSHHostById,
|
||||
type Role,
|
||||
type AccessRecord,
|
||||
type SSHHost,
|
||||
} from "@/ui/main-axios.ts";
|
||||
|
||||
interface HostSharingTabProps {
|
||||
@@ -79,6 +81,7 @@ export function HostSharingTab({
|
||||
const [accessList, setAccessList] = React.useState<AccessRecord[]>([]);
|
||||
const [loading, setLoading] = React.useState(false);
|
||||
const [currentUserId, setCurrentUserId] = React.useState<string>("");
|
||||
const [hostData, setHostData] = React.useState<SSHHost | null>(null);
|
||||
|
||||
// Load roles
|
||||
const loadRoles = React.useCallback(async () => {
|
||||
@@ -124,13 +127,27 @@ export function HostSharingTab({
|
||||
}
|
||||
}, [hostId]);
|
||||
|
||||
// Load host data
|
||||
const loadHostData = React.useCallback(async () => {
|
||||
if (!hostId) return;
|
||||
|
||||
try {
|
||||
const host = await getSSHHostById(hostId);
|
||||
setHostData(host);
|
||||
} catch (error) {
|
||||
console.error("Failed to load host data:", error);
|
||||
setHostData(null);
|
||||
}
|
||||
}, [hostId]);
|
||||
|
||||
React.useEffect(() => {
|
||||
loadRoles();
|
||||
loadUsers();
|
||||
if (!isNewHost) {
|
||||
loadAccessList();
|
||||
loadHostData();
|
||||
}
|
||||
}, [loadRoles, loadUsers, loadAccessList, isNewHost]);
|
||||
}, [loadRoles, loadUsers, loadAccessList, loadHostData, isNewHost]);
|
||||
|
||||
// Load current user ID
|
||||
React.useEffect(() => {
|
||||
@@ -235,6 +252,17 @@ export function HostSharingTab({
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
{/* Credential Authentication Warning */}
|
||||
{hostData?.authType === "Credential" && (
|
||||
<Alert variant="destructive">
|
||||
<AlertCircle className="h-4 w-4" />
|
||||
<AlertTitle>{t("rbac.credentialSharingWarning")}</AlertTitle>
|
||||
<AlertDescription>
|
||||
{t("rbac.credentialSharingWarningDescription")}
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
)}
|
||||
|
||||
{/* Share Form */}
|
||||
<div className="space-y-4 border rounded-lg p-4">
|
||||
<h3 className="text-lg font-semibold flex items-center gap-2">
|
||||
|
||||
Reference in New Issue
Block a user