|
|
@@ -3,17 +3,16 @@ package com.cisd.tms.modules.log.service;
|
|
|
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
|
|
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
|
|
|
import com.cisd.tms.common.enums.ErrorCode;
|
|
|
|
import com.cisd.tms.common.enums.ErrorCode;
|
|
|
|
import com.cisd.tms.common.exception.BizException;
|
|
|
|
import com.cisd.tms.common.exception.BizException;
|
|
|
|
import com.cisd.tms.integration.crypto.pcie.service.PcieCryptoService;
|
|
|
|
import com.cisd.tms.modules.auth.entity.RoleUkeyBindingEntity;
|
|
|
|
|
|
|
|
import com.cisd.tms.modules.auth.repository.RoleUkeyBindingRepository;
|
|
|
|
import com.cisd.tms.modules.log.annotation.AuditedOperation;
|
|
|
|
import com.cisd.tms.modules.log.annotation.AuditedOperation;
|
|
|
|
import com.cisd.tms.modules.log.dto.*;
|
|
|
|
import com.cisd.tms.modules.log.dto.*;
|
|
|
|
import com.cisd.tms.modules.log.entity.OperationAuditLogEntity;
|
|
|
|
import com.cisd.tms.modules.log.entity.OperationAuditLogEntity;
|
|
|
|
import com.cisd.tms.modules.log.enums.AuditStatus;
|
|
|
|
import com.cisd.tms.modules.log.enums.*;
|
|
|
|
import com.cisd.tms.modules.log.enums.AuthLevel;
|
|
|
|
|
|
|
|
import com.cisd.tms.modules.log.enums.OperationResult;
|
|
|
|
|
|
|
|
import com.cisd.tms.modules.log.enums.OperatorRoleCode;
|
|
|
|
|
|
|
|
import com.cisd.tms.modules.log.repository.OperationAuditLogRepository;
|
|
|
|
import com.cisd.tms.modules.log.repository.OperationAuditLogRepository;
|
|
|
|
import jakarta.servlet.http.HttpServletRequest;
|
|
|
|
import jakarta.servlet.http.HttpServletRequest;
|
|
|
|
import lombok.RequiredArgsConstructor;
|
|
|
|
import lombok.RequiredArgsConstructor;
|
|
|
|
|
|
|
|
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
|
|
|
import org.bouncycastle.util.encoders.Hex;
|
|
|
|
import org.bouncycastle.util.encoders.Hex;
|
|
|
|
import org.slf4j.Logger;
|
|
|
|
import org.slf4j.Logger;
|
|
|
|
import org.slf4j.LoggerFactory;
|
|
|
|
import org.slf4j.LoggerFactory;
|
|
|
@@ -22,25 +21,37 @@ import org.springframework.core.annotation.AnnotatedElementUtils;
|
|
|
|
import org.springframework.stereotype.Service;
|
|
|
|
import org.springframework.stereotype.Service;
|
|
|
|
import org.springframework.web.method.HandlerMethod;
|
|
|
|
import org.springframework.web.method.HandlerMethod;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import java.nio.charset.StandardCharsets;
|
|
|
|
|
|
|
|
import java.security.PublicKey;
|
|
|
|
|
|
|
|
import java.security.Security;
|
|
|
|
|
|
|
|
import java.security.Signature;
|
|
|
|
|
|
|
|
import java.security.spec.X509EncodedKeySpec;
|
|
|
|
import java.time.LocalDateTime;
|
|
|
|
import java.time.LocalDateTime;
|
|
|
|
import java.util.Base64;
|
|
|
|
import java.util.Base64;
|
|
|
|
|
|
|
|
import java.util.List;
|
|
|
|
import java.util.UUID;
|
|
|
|
import java.util.UUID;
|
|
|
|
|
|
|
|
|
|
|
|
@Service
|
|
|
|
@Service
|
|
|
|
@RequiredArgsConstructor
|
|
|
|
@RequiredArgsConstructor
|
|
|
|
public class OperationAuditService {
|
|
|
|
public class OperationAuditService {
|
|
|
|
|
|
|
|
|
|
|
|
public static final String ATTR_ROLE_CODE = "CURRENT_ROLE_CODE";
|
|
|
|
private static final String PROVIDER = "BC";
|
|
|
|
public static final String ATTR_AUTH_LEVEL = "CURRENT_AUTH_LEVEL";
|
|
|
|
private static final String SIGNATURE_ALGO = "SM3withSM2";
|
|
|
|
|
|
|
|
private static final String ATTR_ROLE_CODE = "CURRENT_ROLE_CODE";
|
|
|
|
|
|
|
|
private static final String ATTR_AUTH_LEVEL = "CURRENT_AUTH_LEVEL";
|
|
|
|
|
|
|
|
|
|
|
|
private static final Logger log = LoggerFactory.getLogger(OperationAuditService.class);
|
|
|
|
private static final Logger log = LoggerFactory.getLogger(OperationAuditService.class);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private final OperationAuditLogRepository operationAuditLogRepository;
|
|
|
|
private final OperationAuditLogRepository operationAuditLogRepository;
|
|
|
|
|
|
|
|
private final RoleUkeyBindingRepository roleUkeyBindingRepository;
|
|
|
|
private final OperationAuditSigner auditSigner;
|
|
|
|
private final OperationAuditSigner auditSigner;
|
|
|
|
|
|
|
|
|
|
|
|
private final PcieCryptoService pcieCryptoService;
|
|
|
|
|
|
|
|
|
|
|
|
static {
|
|
|
|
|
|
|
|
if (Security.getProvider(PROVIDER) == null) {
|
|
|
|
|
|
|
|
Security.addProvider(new BouncyCastleProvider());
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public void record(OperationAuditCommand command, boolean isSensitive) {
|
|
|
|
public void record(OperationAuditCommand command, boolean isSensitive) {
|
|
|
|
try {
|
|
|
|
try {
|
|
|
@@ -183,31 +194,33 @@ public class OperationAuditService {
|
|
|
|
OperationAuditLogEntity existLog = operationAuditLogRepository.findByLogId(logId)
|
|
|
|
OperationAuditLogEntity existLog = operationAuditLogRepository.findByLogId(logId)
|
|
|
|
.orElseThrow(() -> new BizException(ErrorCode.VALIDATE_FAILED.getCode(), "未找到该logId"));
|
|
|
|
.orElseThrow(() -> new BizException(ErrorCode.VALIDATE_FAILED.getCode(), "未找到该logId"));
|
|
|
|
|
|
|
|
|
|
|
|
// String signValue = trim(req.getAuditSign());
|
|
|
|
|
|
|
|
// if (signValue.isEmpty()){
|
|
|
|
|
|
|
|
// throw new IllegalArgumentException("签名值不能为空");
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
// String payload = auditSigner.buildAuditPayload(existLog);
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
// UserKeyVerifyRequest userKeyVerifyRequest = new UserKeyVerifyRequest();
|
|
|
|
|
|
|
|
// userKeyVerifyRequest.setKeyIndex(1);
|
|
|
|
|
|
|
|
// userKeyVerifyRequest.setData(payload.getBytes(StandardCharsets.UTF_8));
|
|
|
|
|
|
|
|
// userKeyVerifyRequest.setSignature(decodeBlob(signValue, "signature is invalid"));
|
|
|
|
|
|
|
|
// try {
|
|
|
|
|
|
|
|
// pcieCryptoService.userKeyVerifyWithSm3(userKeyVerifyRequest);
|
|
|
|
|
|
|
|
// } catch (BizException ex) {
|
|
|
|
|
|
|
|
// throw ex;
|
|
|
|
|
|
|
|
// } catch (RuntimeException ex) {
|
|
|
|
|
|
|
|
// throw new BizException(ErrorCode.UNAUTHORIZED.getCode(), "signature verification 执行失败");
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!AuditStatus.PENDING.equals(existLog.getAuditStatus())) {
|
|
|
|
if (!AuditStatus.PENDING.equals(existLog.getAuditStatus())) {
|
|
|
|
throw new BizException(ErrorCode.BIZ_ERROR.getCode(), "该日志已审计,禁止重复操作");
|
|
|
|
throw new BizException(ErrorCode.BIZ_ERROR.getCode(), "该日志已审计,禁止重复操作");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
String auditSign = trim(req.getAuditSign());
|
|
|
|
|
|
|
|
if (auditSign.isEmpty()){
|
|
|
|
|
|
|
|
throw new IllegalArgumentException("签名值不能为空");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
String signValueSource = buildSignValueSource(existLog, req.getAuditResult());
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
List<RoleUkeyBindingEntity> list = roleUkeyBindingRepository.findActiveByRoleCode("AUDIT_ADMIN");
|
|
|
|
|
|
|
|
if (list.isEmpty()){
|
|
|
|
|
|
|
|
throw new BizException(ErrorCode.BIZ_ERROR.getCode(), "未找到审计管理员UKey");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
RoleUkeyBindingEntity roleUkeyBindingEntity = list.get(0);
|
|
|
|
|
|
|
|
String publicKey = roleUkeyBindingEntity.getUkeyPubkey();
|
|
|
|
|
|
|
|
try{
|
|
|
|
|
|
|
|
verifySm2Signature(signValueSource, auditSign, publicKey);
|
|
|
|
|
|
|
|
} catch (Exception e){
|
|
|
|
|
|
|
|
throw new BizException(ErrorCode.BIZ_ERROR.getCode(), e.getMessage());
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
try{
|
|
|
|
OperationAuditLogEntity updateEntity = new OperationAuditLogEntity();
|
|
|
|
OperationAuditLogEntity updateEntity = new OperationAuditLogEntity();
|
|
|
|
updateEntity.setLogId(existLog.getLogId());
|
|
|
|
updateEntity.setLogId(existLog.getLogId());
|
|
|
|
updateEntity.setAuditStatus(AuditStatus.REVIEWED);
|
|
|
|
updateEntity.setAuditStatus(AuditStatus.REVIEWED);
|
|
|
@@ -217,11 +230,51 @@ public class OperationAuditService {
|
|
|
|
updateEntity.setAuditedAt(LocalDateTime.now());
|
|
|
|
updateEntity.setAuditedAt(LocalDateTime.now());
|
|
|
|
|
|
|
|
|
|
|
|
operationAuditLogRepository.updateByLogId(updateEntity);
|
|
|
|
operationAuditLogRepository.updateByLogId(updateEntity);
|
|
|
|
|
|
|
|
} catch (Exception e){
|
|
|
|
|
|
|
|
throw new BizException(ErrorCode.BIZ_ERROR.getCode(), "日志审计更新失败");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
log.info("日志复核完成, logId: {}, 审计人: {}, 结果: {}, {}", logId, auditorUser, req.getAuditResult(), req.getAuditComment());
|
|
|
|
log.info("日志复核完成, logId: {}, 审计人: {}, 结果: {}, {}", logId, auditorUser, req.getAuditResult(), req.getAuditComment());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private static String buildSignValueSource(OperationAuditLogEntity existLog, AuditResult auditResult) {
|
|
|
|
|
|
|
|
String signValueSource = trim(existLog.getLogId()) +
|
|
|
|
|
|
|
|
existLog.getOperatorRoleCode() +
|
|
|
|
|
|
|
|
existLog.getOperatorAuthLevel() +
|
|
|
|
|
|
|
|
existLog.getModuleCode() +
|
|
|
|
|
|
|
|
existLog.getActionType() +
|
|
|
|
|
|
|
|
trim(existLog.getRemoteIp()) +
|
|
|
|
|
|
|
|
existLog.getOperationResult() +
|
|
|
|
|
|
|
|
trim(existLog.getSummary()) +
|
|
|
|
|
|
|
|
trim(existLog.getErrorMessage()) +
|
|
|
|
|
|
|
|
existLog.getAuditStatus() +
|
|
|
|
|
|
|
|
auditResult +
|
|
|
|
|
|
|
|
trim(existLog.getSignValue()) +
|
|
|
|
|
|
|
|
existLog.getOccurredAt();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return signValueSource;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public boolean verifySm2Signature(String data, String signatureBase64, String publicKeyBase64) {
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
|
|
byte[] keyBytes = Base64.getDecoder().decode(publicKeyBase64);
|
|
|
|
|
|
|
|
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
|
|
|
|
|
|
|
|
java.security.KeyFactory keyFactory = java.security.KeyFactory.getInstance("EC", PROVIDER);
|
|
|
|
|
|
|
|
PublicKey publicKey = keyFactory.generatePublic(keySpec);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Signature signature = Signature.getInstance(SIGNATURE_ALGO, PROVIDER);
|
|
|
|
|
|
|
|
signature.initVerify(publicKey);
|
|
|
|
|
|
|
|
signature.update(data.getBytes(StandardCharsets.UTF_8));
|
|
|
|
|
|
|
|
byte[] signatureBytes = Base64.getDecoder().decode(signatureBase64);
|
|
|
|
|
|
|
|
return signature.verify(signatureBytes);
|
|
|
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
|
|
|
throw new RuntimeException("SM2验签失败", e);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private byte[] decodeBlob(String value, String message) {
|
|
|
|
private byte[] decodeBlob(String value, String message) {
|
|
|
|
String normalized = value == null ? "" : value.trim();
|
|
|
|
String normalized = value == null ? "" : value.trim();
|
|
|
|
if (normalized.isEmpty()) {
|
|
|
|
if (normalized.isEmpty()) {
|
|
|
@@ -238,7 +291,7 @@ public class OperationAuditService {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private String trim(String s){
|
|
|
|
private static String trim(String s){
|
|
|
|
return s == null ? "" : s.trim();
|
|
|
|
return s == null ? "" : s.trim();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|