diff --git a/orion-ops-framework/orion-ops-spring-boot-starter-web/src/main/java/com/orion/ops/framework/web/core/handler/GlobalExceptionHandler.java b/orion-ops-framework/orion-ops-spring-boot-starter-web/src/main/java/com/orion/ops/framework/web/core/handler/GlobalExceptionHandler.java index 346c4048..2fff803a 100644 --- a/orion-ops-framework/orion-ops-spring-boot-starter-web/src/main/java/com/orion/ops/framework/web/core/handler/GlobalExceptionHandler.java +++ b/orion-ops-framework/orion-ops-spring-boot-starter-web/src/main/java/com/orion/ops/framework/web/core/handler/GlobalExceptionHandler.java @@ -50,7 +50,7 @@ public class GlobalExceptionHandler { @ExceptionHandler(value = Exception.class) public HttpWrapper defaultExceptionHandler(Exception ex) { log.error("defaultExceptionHandler", ex); - return ErrorCode.INTERNAL_SERVER_ERROR.wrapper(ex.getMessage()); + return ErrorCode.INTERNAL_SERVER_ERROR.wrapper(); } // -------------------- http 异常 -------------------- @@ -98,7 +98,7 @@ public class GlobalExceptionHandler { @ExceptionHandler(value = MaxUploadSizeExceededException.class) public HttpWrapper maxUploadSizeExceededExceptionHandler(MaxUploadSizeExceededException ex) { log.error("maxUploadSizeExceededExceptionHandler", ex); - return ErrorCode.PAYLOAD_TOO_LARGE.wrapper(ex.getMessage()); + return ErrorCode.PAYLOAD_TOO_LARGE.wrapper(); } // -------------------- 框架异常 -------------------- @@ -132,7 +132,7 @@ public class GlobalExceptionHandler { }) public HttpWrapper timeoutExceptionHandler(Exception ex) { log.error("timeoutExceptionHandler", ex); - return ErrorCode.REQUEST_TIMEOUT.wrapper(ex.getMessage()); + return ErrorCode.REQUEST_TIMEOUT.wrapper(); } @ExceptionHandler(value = { @@ -142,7 +142,7 @@ public class GlobalExceptionHandler { }) public HttpWrapper interruptExceptionHandler(Exception ex) { log.error("interruptExceptionHandler", ex); - return ErrorCode.INTERRUPT_ERROR.wrapper(ex.getMessage()); + return ErrorCode.INTERRUPT_ERROR.wrapper(); } @ExceptionHandler(value = { @@ -151,7 +151,7 @@ public class GlobalExceptionHandler { }) public HttpWrapper ioExceptionHandler(Exception ex) { log.error("ioExceptionHandler", ex); - return ErrorCode.IO_EXCEPTION.wrapper(ex.getMessage()); + return ErrorCode.IO_EXCEPTION.wrapper(); } @ExceptionHandler(value = SQLException.class) @@ -178,7 +178,7 @@ public class GlobalExceptionHandler { }) public HttpWrapper sftpExceptionHandler(Exception ex) { log.error("sftpExceptionHandler", ex); - return ErrorCode.SFTP_EXCEPTION.wrapper(ex.getMessage()); + return ErrorCode.SFTP_EXCEPTION.wrapper(); } @ExceptionHandler(value = ParseRuntimeException.class) @@ -186,22 +186,22 @@ public class GlobalExceptionHandler { log.error("parseExceptionHandler", ex); if (Exceptions.isCausedBy(ex, EncryptedDocumentException.class)) { // excel 密码错误 - return ErrorCode.EXCEL_PASSWORD_ERROR.wrapper(ex.getMessage()); + return ErrorCode.EXCEL_PASSWORD_ERROR.wrapper(); } else { - return ErrorCode.PASER_FAILED.wrapper(ex.getMessage()); + return ErrorCode.PASER_FAILED.wrapper(); } } @ExceptionHandler(value = EncryptException.class) public HttpWrapper encryptExceptionHandler(Exception ex) { log.error("encryptExceptionHandler", ex); - return ErrorCode.ENCRYPT_ERROR.wrapper(ex.getMessage()); + return ErrorCode.ENCRYPT_ERROR.wrapper(); } @ExceptionHandler(value = DecryptException.class) public HttpWrapper decryptExceptionHandler(Exception ex) { log.error("decryptExceptionHandler", ex); - return ErrorCode.DECRYPT_ERROR.wrapper(ex.getMessage()); + return ErrorCode.DECRYPT_ERROR.wrapper(); } @ExceptionHandler(value = {HttpRequestException.class}) @@ -213,7 +213,7 @@ public class GlobalExceptionHandler { @ExceptionHandler(value = VcsException.class) public HttpWrapper vcsExceptionHandler(Exception ex) { log.error("vcsExceptionHandler", ex); - return ErrorCode.VCS_OPETATOR_ERROR.wrapper(ex.getMessage()); + return ErrorCode.VCS_OPETATOR_ERROR.wrapper(); } @ExceptionHandler(value = { @@ -222,30 +222,31 @@ public class GlobalExceptionHandler { }) public HttpWrapper taskExceptionHandler(Exception ex) { log.error("taskExceptionHandler", ex); - return ErrorCode.TASK_EXECUTE_ERROR.wrapper(ex.getMessage()); + return ErrorCode.TASK_EXECUTE_ERROR.wrapper(); } @ExceptionHandler(value = ConnectionRuntimeException.class) public HttpWrapper connectionExceptionHandler(Exception ex) { log.error("connectionExceptionHandler", ex); - return ErrorCode.CONNECT_ERROR.wrapper(ex.getMessage()); + return ErrorCode.CONNECT_ERROR.wrapper(); } @ExceptionHandler(value = UnsafeException.class) public HttpWrapper unsafeExceptionHandler(Exception ex) { log.error("unsafeExceptionHandler", ex); - return ErrorCode.UNSAFE_OPERATOR.wrapper(ex.getMessage()); + return ErrorCode.UNSAFE_OPERATOR.wrapper(); } @ExceptionHandler(value = LogException.class) public HttpWrapper logExceptionHandler(LogException ex) { log.error("logExceptionHandler", ex); - return ErrorCode.INTERNAL_SERVER_ERROR.wrapper(ex.getMessage()); + return ErrorCode.INTERNAL_SERVER_ERROR.wrapper(); } @ExceptionHandler(value = ParseCronException.class) public HttpWrapper parseCronExceptionHandler(ParseCronException ex) { - return ErrorCode.EXPRESSION_ERROR.wrapper(ex.getMessage()); + log.error("parseCronExceptionHandler", ex); + return ErrorCode.EXPRESSION_ERROR.wrapper(); } @ExceptionHandler(value = CodeArgumentException.class) diff --git a/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/controller/HostTerminalController.http b/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/controller/HostTerminalController.http new file mode 100644 index 00000000..434d9f89 --- /dev/null +++ b/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/controller/HostTerminalController.http @@ -0,0 +1,11 @@ +### 获取主机终端连接 token +POST {{baseUrl}}/asset/host-terminal/access +Content-Type: application/json +Authorization: {{token}} + +{ + "hostId": 1 +} + + +### diff --git a/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/controller/HostTerminalController.java b/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/controller/HostTerminalController.java new file mode 100644 index 00000000..fd1e971b --- /dev/null +++ b/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/controller/HostTerminalController.java @@ -0,0 +1,49 @@ +package com.orion.ops.module.asset.controller; + +import com.orion.ops.framework.biz.operator.log.core.annotation.OperatorLog; +import com.orion.ops.framework.security.core.utils.SecurityUtils; +import com.orion.ops.framework.web.core.annotation.RestWrapper; +import com.orion.ops.module.asset.define.operator.HostTerminalOperatorType; +import com.orion.ops.module.asset.entity.request.host.HostTerminalConnectRequest; +import com.orion.ops.module.asset.service.HostTerminalService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.extern.slf4j.Slf4j; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; + +/** + * 主机终端 api + * + * @author Jiahang Li + * @version 1.0.0 + * @since 2023-9-20 11:55 + */ +@Tag(name = "asset - 主机终端服务") +@Slf4j +@Validated +@RestWrapper +@RestController +@RequestMapping("/asset/host-terminal") +@SuppressWarnings({"ELValidationInJSP", "SpringElInspection"}) +public class HostTerminalController { + + @Resource + private HostTerminalService hostTerminalService; + + @OperatorLog(HostTerminalOperatorType.ACCESS) + @PostMapping("/access") + @Operation(summary = "获取主机终端连接 token") + @PreAuthorize("@ss.hasPermission('asset:host-terminal:access')") + public String getHostAccessToken(@Validated @RequestBody HostTerminalConnectRequest request) { + return hostTerminalService.getHostAccessToken(request.getHostId(), SecurityUtils.getLoginUserId()); + } + +} + diff --git a/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/define/cache/HostTerminalCacheKeyDefine.java b/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/define/cache/HostTerminalCacheKeyDefine.java new file mode 100644 index 00000000..e0ec2389 --- /dev/null +++ b/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/define/cache/HostTerminalCacheKeyDefine.java @@ -0,0 +1,27 @@ +package com.orion.ops.module.asset.define.cache; + +import com.orion.lang.define.cache.key.CacheKeyBuilder; +import com.orion.lang.define.cache.key.CacheKeyDefine; +import com.orion.lang.define.cache.key.struct.RedisCacheStruct; +import com.orion.ops.module.asset.entity.dto.HostSshConnectDTO; + +import java.util.concurrent.TimeUnit; + +/** + * 主机终端服务缓存 key + * + * @author Jiahang Li + * @version 1.0.0 + * @since 2023/12/27 18:13 + */ +public interface HostTerminalCacheKeyDefine { + + CacheKeyDefine HOST_TERMINAL_CONNECT = new CacheKeyBuilder() + .key("host:terminal:connect:{}") + .desc("主机终端连接信息 ${token}") + .type(HostSshConnectDTO.class) + .struct(RedisCacheStruct.STRING) + .timeout(3, TimeUnit.MINUTES) + .build(); + +} diff --git a/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/define/operator/HostTerminalOperatorType.java b/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/define/operator/HostTerminalOperatorType.java new file mode 100644 index 00000000..47a286d5 --- /dev/null +++ b/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/define/operator/HostTerminalOperatorType.java @@ -0,0 +1,28 @@ +package com.orion.ops.module.asset.define.operator; + +import com.orion.ops.framework.biz.operator.log.core.annotation.Module; +import com.orion.ops.framework.biz.operator.log.core.factory.InitializingOperatorTypes; +import com.orion.ops.framework.biz.operator.log.core.model.OperatorType; + +import static com.orion.ops.framework.biz.operator.log.core.enums.OperatorRiskLevel.L; + +/** + * 主机终端 操作日志类型 + * + * @author Jiahang Li + * @version 1.0.0 + * @since 2023/10/10 17:30 + */ +@Module("asset:host-terminal") +public class HostTerminalOperatorType extends InitializingOperatorTypes { + + public static final String ACCESS = "host-terminal:access"; + + @Override + public OperatorType[] types() { + return new OperatorType[]{ + new OperatorType(L, ACCESS, "连接主机终端 ${hostName}"), + }; + } + +} diff --git a/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/entity/dto/HostSshConnectDTO.java b/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/entity/dto/HostSshConnectDTO.java index 18138da7..32fe90f4 100644 --- a/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/entity/dto/HostSshConnectDTO.java +++ b/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/entity/dto/HostSshConnectDTO.java @@ -1,7 +1,7 @@ package com.orion.ops.module.asset.entity.dto; -import com.orion.ops.module.asset.entity.domain.HostKeyDO; -import com.orion.ops.module.asset.enums.HostSshAuthTypeEnum; +import com.orion.ops.framework.desensitize.core.annotation.Desensitize; +import com.orion.ops.framework.desensitize.core.annotation.DesensitizeObject; import io.swagger.v3.oas.annotations.media.Schema; import lombok.AllArgsConstructor; import lombok.Builder; @@ -19,12 +19,22 @@ import lombok.NoArgsConstructor; @Builder @NoArgsConstructor @AllArgsConstructor +@DesensitizeObject @Schema(name = "HostSshConnectDTO", description = "主机连接参数") public class HostSshConnectDTO { + @Schema(description = "token") + private String token; + + @Schema(description = "userId") + private Long userId; + @Schema(description = "hostId") private Long hostId; + @Schema(description = "hostName") + private String hostName; + @Schema(description = "主机地址") private String address; @@ -34,19 +44,26 @@ public class HostSshConnectDTO { @Schema(description = "超时时间") private Integer timeout; - @Schema(description = "认证方式") - private HostSshAuthTypeEnum authType; - @Schema(description = "用户名") private String username; + @Desensitize(toEmpty = true) @Schema(description = "密码") private String password; - @Schema(description = "主机秘钥") - private HostKeyDO key; + @Schema(description = "秘钥id") + private Long keyId; - // @Schema(description = "") - // private ; + @Desensitize(toEmpty = true) + @Schema(description = "公钥文本") + private String publicKey; + + @Desensitize(toEmpty = true) + @Schema(description = "私钥文本") + private String privateKey; + + @Desensitize(toEmpty = true) + @Schema(description = "私钥密码") + private String privateKeyPassword; } diff --git a/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/entity/request/host/HostTerminalConnectRequest.java b/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/entity/request/host/HostTerminalConnectRequest.java new file mode 100644 index 00000000..52dc0a99 --- /dev/null +++ b/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/entity/request/host/HostTerminalConnectRequest.java @@ -0,0 +1,30 @@ +package com.orion.ops.module.asset.entity.request.host; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotNull; +import java.io.Serializable; + +/** + * 主机终端连接 请求对象 + * + * @author Jiahang Li + * @version 1.0.0 + * @since 2023-9-20 11:55 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Schema(name = "HostTerminalConnectRequest", description = "主机终端连接 请求对象") +public class HostTerminalConnectRequest implements Serializable { + + @NotNull + @Schema(description = "hostId") + private Long hostId; + +} diff --git a/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/service/HostConnectService.java b/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/service/HostConnectService.java deleted file mode 100644 index c39cc08e..00000000 --- a/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/service/HostConnectService.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.orion.ops.module.asset.service; - -import com.orion.net.host.SessionStore; - -/** - * 主机连接服务 - * - * @author Jiahang Li - * @version 1.0.0 - * @since 2023/12/26 14:22 - */ -public interface HostConnectService { - - /** - * 打开主机会话 - * 鉴权并且读取用户配置 - * - * @param hostId hostId - * @param userId userId - * @return session - */ - SessionStore openSessionStore(Long hostId, Long userId); - - /** - * 打开主机会话 - * 使用默认配置 不鉴权 - * - * @param hostId hostId - * @return session - */ - SessionStore openSessionStore(Long hostId); - -} diff --git a/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/service/HostTerminalService.java b/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/service/HostTerminalService.java new file mode 100644 index 00000000..99f43684 --- /dev/null +++ b/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/service/HostTerminalService.java @@ -0,0 +1,48 @@ +package com.orion.ops.module.asset.service; + +import com.orion.net.host.SessionStore; +import com.orion.ops.module.asset.entity.dto.HostSshConnectDTO; + +/** + * 主机终端服务 + * + * @author Jiahang Li + * @version 1.0.0 + * @since 2023/12/26 14:22 + */ +public interface HostTerminalService { + + /** + * 获取主机终端连接 token + * + * @param hostId hostId + * @param userId userId + * @return session + */ + String getHostAccessToken(Long hostId, Long userId); + + /** + * 通过 token 获取主机终端连接信息 + * + * @param token token + * @return config + */ + HostSshConnectDTO getConnectInfoByToken(String token); + + /** + * 使用默认配置打开主机会话 + * + * @param hostId hostId + * @return session + */ + SessionStore openSessionStore(Long hostId); + + /** + * 打开主机会话 + * + * @param conn conn + * @return session + */ + SessionStore openSessionStore(HostSshConnectDTO conn); + +} diff --git a/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/service/impl/HostConnectServiceImpl.java b/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/service/impl/HostTerminalServiceImpl.java similarity index 72% rename from orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/service/impl/HostConnectServiceImpl.java rename to orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/service/impl/HostTerminalServiceImpl.java index 198c4b65..b20c97ef 100644 --- a/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/service/impl/HostConnectServiceImpl.java +++ b/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/service/impl/HostTerminalServiceImpl.java @@ -1,17 +1,21 @@ package com.orion.ops.module.asset.service.impl; import com.orion.lang.exception.AuthenticationException; +import com.orion.lang.id.UUIds; import com.orion.lang.utils.Exceptions; import com.orion.lang.utils.Strings; import com.orion.net.host.SessionHolder; import com.orion.net.host.SessionStore; +import com.orion.ops.framework.biz.operator.log.core.uitls.OperatorLogs; import com.orion.ops.framework.common.constant.Const; import com.orion.ops.framework.common.constant.ErrorMessage; import com.orion.ops.framework.common.utils.CryptoUtils; import com.orion.ops.framework.common.utils.Valid; +import com.orion.ops.framework.redis.core.utils.RedisStrings; import com.orion.ops.module.asset.dao.HostDAO; import com.orion.ops.module.asset.dao.HostIdentityDAO; import com.orion.ops.module.asset.dao.HostKeyDAO; +import com.orion.ops.module.asset.define.cache.HostTerminalCacheKeyDefine; import com.orion.ops.module.asset.entity.domain.HostDO; import com.orion.ops.module.asset.entity.domain.HostIdentityDO; import com.orion.ops.module.asset.entity.domain.HostKeyDO; @@ -23,10 +27,12 @@ import com.orion.ops.module.asset.enums.HostSshAuthTypeEnum; import com.orion.ops.module.asset.handler.host.config.model.HostSshConfigModel; import com.orion.ops.module.asset.handler.host.extra.model.HostSshExtraModel; import com.orion.ops.module.asset.service.HostConfigService; -import com.orion.ops.module.asset.service.HostConnectService; +import com.orion.ops.module.asset.service.HostConnectLogService; import com.orion.ops.module.asset.service.HostExtraService; +import com.orion.ops.module.asset.service.HostTerminalService; import com.orion.ops.module.infra.api.DataPermissionApi; import com.orion.ops.module.infra.api.SystemUserApi; +import com.orion.ops.module.infra.entity.dto.user.SystemUserDTO; import com.orion.ops.module.infra.enums.DataPermissionTypeEnum; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; @@ -44,7 +50,7 @@ import java.util.Optional; */ @Slf4j @Service -public class HostConnectServiceImpl implements HostConnectService { +public class HostTerminalServiceImpl implements HostTerminalService { @Resource private HostConfigService hostConfigService; @@ -55,6 +61,9 @@ public class HostConnectServiceImpl implements HostConnectService { @Resource private AssetAuthorizedDataServiceImpl assetAuthorizedDataService; + @Resource + private HostConnectLogService hostConnectLogService; + @Resource private HostDAO hostDAO; @@ -71,11 +80,14 @@ public class HostConnectServiceImpl implements HostConnectService { private SystemUserApi systemUserApi; @Override - public SessionStore openSessionStore(Long hostId, Long userId) { - log.info("HostConnectService.openSessionStore-withUser hostId: {}, userId: {}", hostId, userId); + public String getHostAccessToken(Long hostId, Long userId) { + log.info("HostConnectService.getHostAccessToken hostId: {}, userId: {}", hostId, userId); // 查询主机 HostDO host = hostDAO.selectById(hostId); Valid.notNull(host, ErrorMessage.HOST_ABSENT); + // 查询用户 + SystemUserDTO user = systemUserApi.getUserById(userId); + Valid.notNull(user, ErrorMessage.USER_ABSENT); // 查询主机配置 HostSshConfigModel config = hostConfigService.getHostConfig(hostId, HostConfigTypeEnum.SSH); Valid.notNull(config, ErrorMessage.CONFIG_ABSENT); @@ -104,8 +116,24 @@ public class HostConnectServiceImpl implements HostConnectService { } } } - // 连接 - return this.openSessionStoreWithHost(host, config, extra); + String token = UUIds.random32(); + // 获取连接配置 + HostSshConnectDTO connect = this.getHostConnectInfo(host, config, extra); + connect.setUserId(userId); + connect.setUsername(user.getUsername()); + connect.setToken(token); + // 设置缓存 + String key = HostTerminalCacheKeyDefine.HOST_TERMINAL_CONNECT.format(token); + RedisStrings.setJson(key, HostTerminalCacheKeyDefine.HOST_TERMINAL_CONNECT, connect); + // 设置日志参数 + OperatorLogs.add(connect); + return token; + } + + @Override + public HostSshConnectDTO getConnectInfoByToken(String token) { + String key = HostTerminalCacheKeyDefine.HOST_TERMINAL_CONNECT.format(token); + return RedisStrings.getJson(key, HostTerminalCacheKeyDefine.HOST_TERMINAL_CONNECT); } @Override @@ -115,102 +143,36 @@ public class HostConnectServiceImpl implements HostConnectService { HostDO host = hostDAO.selectById(hostId); Valid.notNull(host, ErrorMessage.HOST_ABSENT); // 查询主机配置 - HostSshConfigModel config = hostConfigService.getHostConfig(hostId, HostConfigTypeEnum.SSH); - Valid.notNull(config, ErrorMessage.CONFIG_ABSENT); - // 连接 - return this.openSessionStoreWithHost(host, config, null); + HostSshConfigModel model = hostConfigService.getHostConfig(hostId, HostConfigTypeEnum.SSH); + Valid.notNull(model, ErrorMessage.CONFIG_ABSENT); + // 获取配置 + HostSshConnectDTO connect = this.getHostConnectInfo(host, model, null); + // 打开连接 + return this.openSessionStore(connect); } - /** - * 打开主机会话 - * - * @param host host - * @param config config - * @param extra extra - * @return session - */ - private SessionStore openSessionStoreWithHost(HostDO host, - HostSshConfigModel config, - HostSshExtraModel extra) { - // 获取认证方式 - HostSshAuthTypeEnum authType = HostSshAuthTypeEnum.of(config.getAuthType()); - HostExtraSshAuthTypeEnum extraAuthType = Optional.ofNullable(extra) - .map(HostSshExtraModel::getAuthType) - .map(HostExtraSshAuthTypeEnum::of) - .orElse(HostExtraSshAuthTypeEnum.DEFAULT); - if (HostExtraSshAuthTypeEnum.CUSTOM_KEY.equals(extraAuthType)) { - // 自定义秘钥 - authType = HostSshAuthTypeEnum.KEY; - config.setKeyId(extra.getKeyId()); - if (extra.getUsername() != null) { - config.setUsername(extra.getUsername()); - } - } else if (HostExtraSshAuthTypeEnum.CUSTOM_IDENTITY.equals(extraAuthType)) { - // 自定义身份 - authType = HostSshAuthTypeEnum.IDENTITY; - config.setIdentityId(extra.getIdentityId()); - } - // 填充认证信息 - HostSshConnectDTO conn = new HostSshConnectDTO(); - conn.setHostId(host.getId()); - conn.setAddress(host.getAddress()); - conn.setPort(config.getPort()); - conn.setTimeout(config.getConnectTimeout()); - conn.setAuthType(authType); - conn.setUsername(config.getUsername()); - // 填充身份信息 - if (HostSshAuthTypeEnum.PASSWORD.equals(authType)) { - conn.setPassword(config.getPassword()); - } else if (HostSshAuthTypeEnum.KEY.equals(authType)) { - // 秘钥认证 - HostKeyDO key = hostKeyDAO.selectById(config.getKeyId()); - Valid.notNull(key, ErrorMessage.KEY_ABSENT); - conn.setKey(key); - } else if (HostSshAuthTypeEnum.IDENTITY.equals(authType)) { - // 身份认证 - HostIdentityDO identity = hostIdentityDAO.selectById(config.getIdentityId()); - Valid.notNull(identity, ErrorMessage.IDENTITY_ABSENT); - if (identity.getKeyId() != null) { - // 秘钥认证 - HostKeyDO key = hostKeyDAO.selectById(config.getKeyId()); - Valid.notNull(key, ErrorMessage.KEY_ABSENT); - conn.setKey(key); - } - conn.setUsername(identity.getUsername()); - conn.setPassword(identity.getPassword()); - } - // 连接 - return this.openSessionStoreWithConfig(conn); - } - - /** - * 打开主机会话 - * - * @param conn conn - * @return session - */ - private SessionStore openSessionStoreWithConfig(HostSshConnectDTO conn) { + @Override + public SessionStore openSessionStore(HostSshConnectDTO conn) { Long hostId = conn.getHostId(); String address = conn.getAddress(); String username = conn.getUsername(); log.info("HostConnectService-openSessionStore-start hostId: {}, address: {}, username: {}", hostId, address, username); try { SessionHolder sessionHolder = new SessionHolder(); - HostKeyDO key = conn.getKey(); - final boolean useKey = key != null; + final boolean useKey = conn.getKeyId() != null; // 使用秘钥认证 if (useKey) { // 加载秘钥 - String publicKey = Optional.ofNullable(key.getPublicKey()) + String publicKey = Optional.ofNullable(conn.getPublicKey()) .map(CryptoUtils::decryptAsString) .orElse(null); - String privateKey = Optional.ofNullable(key.getPrivateKey()) + String privateKey = Optional.ofNullable(conn.getPrivateKey()) .map(CryptoUtils::decryptAsString) .orElse(null); - String password = Optional.ofNullable(key.getPassword()) + String password = Optional.ofNullable(conn.getPrivateKeyPassword()) .map(CryptoUtils::decryptAsString) .orElse(null); - sessionHolder.addIdentityValue(String.valueOf(key.getId()), + sessionHolder.addIdentityValue(String.valueOf(conn.getKeyId()), privateKey, publicKey, password); @@ -240,4 +202,68 @@ public class HostConnectServiceImpl implements HostConnectService { } } + /** + * 获取主机会话连接配置 + * + * @param host host + * @param config config + * @param extra extra + * @return session + */ + private HostSshConnectDTO getHostConnectInfo(HostDO host, + HostSshConfigModel config, + HostSshExtraModel extra) { + // 获取认证方式 + HostSshAuthTypeEnum authType = HostSshAuthTypeEnum.of(config.getAuthType()); + HostExtraSshAuthTypeEnum extraAuthType = Optional.ofNullable(extra) + .map(HostSshExtraModel::getAuthType) + .map(HostExtraSshAuthTypeEnum::of) + .orElse(HostExtraSshAuthTypeEnum.DEFAULT); + if (HostExtraSshAuthTypeEnum.CUSTOM_KEY.equals(extraAuthType)) { + // 自定义秘钥 + authType = HostSshAuthTypeEnum.KEY; + config.setKeyId(extra.getKeyId()); + if (extra.getUsername() != null) { + config.setUsername(extra.getUsername()); + } + } else if (HostExtraSshAuthTypeEnum.CUSTOM_IDENTITY.equals(extraAuthType)) { + // 自定义身份 + authType = HostSshAuthTypeEnum.IDENTITY; + config.setIdentityId(extra.getIdentityId()); + } + Long keyId = null; + // 填充认证信息 + HostSshConnectDTO conn = new HostSshConnectDTO(); + conn.setHostId(host.getId()); + conn.setHostName(host.getName()); + conn.setAddress(host.getAddress()); + conn.setPort(config.getPort()); + conn.setTimeout(config.getConnectTimeout()); + conn.setUsername(config.getUsername()); + // 填充身份信息 + if (HostSshAuthTypeEnum.PASSWORD.equals(authType)) { + conn.setPassword(config.getPassword()); + } else if (HostSshAuthTypeEnum.KEY.equals(authType)) { + // 秘钥认证 + keyId = config.getKeyId(); + } else if (HostSshAuthTypeEnum.IDENTITY.equals(authType)) { + // 身份认证 + HostIdentityDO identity = hostIdentityDAO.selectById(config.getIdentityId()); + Valid.notNull(identity, ErrorMessage.IDENTITY_ABSENT); + keyId = identity.getKeyId(); + conn.setUsername(identity.getUsername()); + conn.setPassword(identity.getPassword()); + } + // 设置秘钥信息 + if (keyId != null) { + HostKeyDO key = hostKeyDAO.selectById(keyId); + Valid.notNull(key, ErrorMessage.KEY_ABSENT); + conn.setPublicKey(key.getPublicKey()); + conn.setPrivateKey(key.getPrivateKey()); + conn.setPrivateKeyPassword(key.getPassword()); + } + // 连接 + return conn; + } + } diff --git a/sql/init-3-data.sql b/sql/init-3-data.sql index 09c154ff..48002dcc 100644 --- a/sql/init-3-data.sql +++ b/sql/init-3-data.sql @@ -65,7 +65,7 @@ INSERT INTO `system_menu` VALUES (106, 105, '查询字典配置值', 'infra:dict INSERT INTO `system_menu` VALUES (107, 105, '创建字典配置值', 'infra:dict-value:create', 3, 220, 1, 1, 1, 0, NULL, NULL, NULL, '2023-10-17 11:38:18', '2023-10-27 01:16:10', NULL, '1', 0); INSERT INTO `system_menu` VALUES (108, 105, '修改字典配置值', 'infra:dict-value:update', 3, 230, 1, 1, 1, 0, NULL, NULL, NULL, '2023-10-17 11:38:18', '2023-10-27 01:16:10', NULL, '1', 0); INSERT INTO `system_menu` VALUES (109, 105, '删除字典配置值', 'infra:dict-value:delete', 3, 240, 1, 1, 1, 0, NULL, NULL, NULL, '2023-10-17 11:38:18', '2023-10-27 01:16:10', NULL, '1', 0); -INSERT INTO `system_menu` VALUES (120, 97, '查询字典配置项', 'infra:dict-key:create', 3, 100, 1, 1, 1, 0, NULL, NULL, NULL, '2023-10-20 11:27:12', '2023-10-27 01:16:10', '1', '1', 0); +INSERT INTO `system_menu` VALUES (120, 97, '查询字典配置项', 'infra:dict-key:query', 3, 100, 1, 1, 1, 0, NULL, NULL, NULL, '2023-10-20 11:27:12', '2023-10-27 01:16:10', '1', '1', 0); INSERT INTO `system_menu` VALUES (121, 97, '刷新缓存', 'infra:dict-key:management:refresh-cache', 3, 140, 1, 1, 1, 0, NULL, NULL, NULL, '2023-10-27 15:50:04', '2023-12-27 12:40:12', '1', '1', 0); INSERT INTO `system_menu` VALUES (122, 5, '操作日志', NULL, 2, 30, 1, 1, 1, 0, 'IconCalendarClock', NULL, 'userOperatorLog', '2023-11-01 14:09:36', '2023-11-01 14:09:36', '1', '1', 0); INSERT INTO `system_menu` VALUES (123, 122, '查询操作日志', 'infra:operator-log:query', 3, 10, 1, 1, 1, 0, NULL, NULL, NULL, '2023-11-02 11:22:54', '2023-11-02 11:22:54', '1', '1', 0);