fix:登录流程改造1

This commit is contained in:
waner 2026-05-26 11:30:07 +08:00
parent 0f1c24caf9
commit 02328d1760
5 changed files with 297 additions and 0 deletions

View File

@ -0,0 +1,40 @@
package com.cisd.tms.modules.auth.dto;
import io.swagger.v3.oas.annotations.media.Schema;
@Schema(description = "修改口令准备响应")
public class PasswordChangePrepareResponse {
@Schema(description = "改密确认令牌")
private String changeToken;
@Schema(description = "旧口令动态摘要挑战随机数")
private String oldServerRandom;
@Schema(description = "新口令盐值,前端写入 UKey")
private String newPasswordSalt;
public String getChangeToken() {
return changeToken;
}
public void setChangeToken(String changeToken) {
this.changeToken = changeToken;
}
public String getOldServerRandom() {
return oldServerRandom;
}
public void setOldServerRandom(String oldServerRandom) {
this.oldServerRandom = oldServerRandom;
}
public String getNewPasswordSalt() {
return newPasswordSalt;
}
public void setNewPasswordSalt(String newPasswordSalt) {
this.newPasswordSalt = newPasswordSalt;
}
}

View File

@ -0,0 +1,152 @@
package com.cisd.tms.modules.log.controller;
import com.cisd.tms.modules.auth.controller.AuthAdminController;
import com.cisd.tms.modules.auth.controller.AuthController;
import com.cisd.tms.modules.device.controller.DeviceController;
import com.cisd.tms.modules.device.controller.IpWhitelistController;
import com.cisd.tms.modules.device.controller.NetworkConfigController;
import com.cisd.tms.modules.device.controller.TimeConfigController;
import com.cisd.tms.modules.log.annotation.AuditedOperation;
import com.cisd.tms.modules.log.enums.ActionType;
import com.cisd.tms.modules.log.enums.ModuleCode;
import com.cisd.tms.modules.mk.controller.LmkController;
import com.cisd.tms.modules.openapi.service.controller.OpenApiController;
import com.cisd.tms.modules.upgrade.controller.UpgradeController;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.core.annotation.AnnotatedElementUtils;
import java.lang.reflect.Method;
class AuditedOperationEndpointsTest {
@Test
void shouldAuditAuthStateChanges() throws Exception {
assertAudit(AuthController.class, "passwordLogin", ModuleCode.AUTH, ActionType.LOGIN,
com.cisd.tms.modules.auth.dto.PasswordLoginRequest.class);
assertAudit(AuthController.class, "ukeyLogin", ModuleCode.AUTH, ActionType.LOGIN,
com.cisd.tms.modules.auth.dto.UkeyLoginRequest.class);
assertAudit(AuthController.class, "logout", ModuleCode.AUTH, ActionType.LOGOUT,
jakarta.servlet.http.HttpServletRequest.class);
assertAudit(AuthController.class, "changeAccountPassword", ModuleCode.AUTH, ActionType.UPDATE,
Integer.class, com.cisd.tms.modules.auth.dto.ChangePasswordRequest.class, jakarta.servlet.http.HttpServletRequest.class);
assertAudit(AuthAdminController.class, "resetPassword", ModuleCode.AUTH, ActionType.RESET,
String.class, jakarta.servlet.http.HttpServletRequest.class);
assertAudit(AuthAdminController.class, "changeAccountPassword", ModuleCode.AUTH, ActionType.UPDATE,
String.class, Integer.class, com.cisd.tms.modules.auth.dto.AdminChangePasswordRequest.class,
jakarta.servlet.http.HttpServletRequest.class);
assertAudit(AuthAdminController.class, "issueSuperAdminUkeyBindingSign", ModuleCode.AUTH, ActionType.BIND,
com.cisd.tms.modules.mk.dto.UKeySignDTO.class);
assertAudit(AuthAdminController.class, "issueUkeyBindingSign", ModuleCode.AUTH, ActionType.BIND,
String.class, com.cisd.tms.modules.mk.dto.UKeySignDTO.class, jakarta.servlet.http.HttpServletRequest.class);
}
@Test
void shouldAuditDeviceNetworkAndMasterKeyMutations() throws Exception {
assertAudit(DeviceController.class, "restart", ModuleCode.DEVICE, ActionType.RESTART,
jakarta.servlet.http.HttpServletRequest.class);
assertAudit(TimeConfigController.class, "configureTime", ModuleCode.DEVICE, ActionType.UPDATE,
com.cisd.tms.modules.device.dto.TimeConfigRequest.class);
assertAudit(NetworkConfigController.class, "configureNetworkCard", ModuleCode.NETWORK, ActionType.UPDATE,
com.cisd.tms.modules.device.dto.network.NetworkConfigureRequest.class);
assertAudit(NetworkConfigController.class, "addNetworkCard", ModuleCode.NETWORK, ActionType.CREATE,
com.cisd.tms.modules.device.dto.network.NetworkConfigureRequest.class);
assertAudit(NetworkConfigController.class, "deleteNetworkCardRecord", ModuleCode.NETWORK, ActionType.DELETE,
com.cisd.tms.modules.device.dto.network.NetworkDeleteRequest.class);
assertAudit(NetworkConfigController.class, "deleteBond", ModuleCode.NETWORK, ActionType.DELETE, String.class);
assertAudit(NetworkConfigController.class, "createBond", ModuleCode.NETWORK, ActionType.CREATE,
com.cisd.tms.modules.device.dto.network.BondCreateRequest.class);
assertAudit(NetworkConfigController.class, "configBond", ModuleCode.NETWORK, ActionType.UPDATE,
com.cisd.tms.modules.device.dto.network.BondConfigRequest.class);
assertAudit(NetworkConfigController.class, "routeAdd", ModuleCode.NETWORK, ActionType.CREATE,
com.cisd.tms.modules.device.dto.network.RouteCreateRequest.class);
assertAudit(NetworkConfigController.class, "routeUpdate", ModuleCode.NETWORK, ActionType.UPDATE,
com.cisd.tms.modules.device.dto.network.RouteUpdateRequest.class);
assertAudit(NetworkConfigController.class, "routeDelete", ModuleCode.NETWORK, ActionType.DELETE,
com.cisd.tms.modules.device.dto.network.RouteDeleteRequest.class);
assertAudit(IpWhitelistController.class, "addWhitelist", ModuleCode.DEVICE, ActionType.CREATE,
com.cisd.tms.modules.device.dto.network.IpWhitelistRequest.class);
assertAudit(IpWhitelistController.class, "updateWhitelist", ModuleCode.DEVICE, ActionType.UPDATE,
com.cisd.tms.modules.device.dto.network.IpWhitelistRequest.class);
assertAudit(IpWhitelistController.class, "deleteWhitelist", ModuleCode.DEVICE, ActionType.DELETE, Long.class);
assertAudit(LmkController.class, "initMasterKey", ModuleCode.KEY, ActionType.CREATE);
assertAudit(LmkController.class, "destroyMasterKey", ModuleCode.KEY, ActionType.DELETE);
assertAudit(LmkController.class, "recoverLmkEx", ModuleCode.KEY, ActionType.RECOVER,
com.cisd.tms.modules.mk.dto.MasterKeyRecoverPacketsRequest.class);
assertAudit(LmkController.class, "Activate", ModuleCode.DEVICE, ActionType.ENABLE,
com.cisd.tms.modules.mk.dto.MasterKeyActivateRequest.class);
}
@Test
void shouldAuditFileUpgradeBackupLogAndOpenApiMutations() throws Exception {
assertAudit(com.cisd.tms.modules.file.controller.FileController.class, "upload", ModuleCode.SYSTEM, ActionType.IMPORT,
org.springframework.web.multipart.MultipartFile.class);
assertAudit(UpgradeController.class, "uploadPackage", ModuleCode.UPGRADE, ActionType.IMPORT,
org.springframework.web.multipart.MultipartFile.class);
assertAudit(UpgradeController.class, "create", ModuleCode.UPGRADE, ActionType.CREATE,
com.cisd.tms.modules.upgrade.dto.UpgradeCreateTaskRequest.class);
assertAudit(UpgradeController.class, "execute", ModuleCode.UPGRADE, ActionType.EXECUTE, String.class);
assertAudit(UpgradeController.class, "rollback", ModuleCode.UPGRADE, ActionType.ROLLBACK, String.class);
assertAudit(BackupController.class, "backup", ModuleCode.LOG, ActionType.BACKUP);
assertAudit(BackupController.class, "downloadBackupFile", ModuleCode.LOG, ActionType.EXPORT, String.class);
assertAudit(BackupConfigController.class, "saveOrUpdateConfig", ModuleCode.LOG, ActionType.UPDATE,
com.cisd.tms.modules.log.dto.BackupConfigRequest.class);
assertAudit(OperationAuditController.class, "reviewLog", ModuleCode.LOG, ActionType.UPDATE,
String.class, com.cisd.tms.modules.log.dto.AuditLogReviewRequest.class);
assertAudit(AuditLogRestoreController.class, "restoreFromZip", ModuleCode.LOG, ActionType.RECOVER,
org.springframework.web.multipart.MultipartFile.class);
assertAudit(OpenApiController.class, "rawSign", ModuleCode.KEY, ActionType.EXECUTE,
com.cisd.tms.modules.openapi.service.dto.RawSignRequest.class);
assertAudit(OpenApiController.class, "dettachedSign", ModuleCode.KEY, ActionType.EXECUTE,
com.cisd.tms.modules.openapi.service.dto.DettachedSignRequest.class);
assertAudit(OpenApiController.class, "uploadCert", ModuleCode.KEY, ActionType.IMPORT,
com.cisd.tms.modules.openapi.service.dto.UploadCertRequest.class);
}
@Test
void shouldNotAuditReadOnlyPreviewAndVerifyEndpoints() throws Exception {
assertNoAudit(UpgradeController.class, "preview", com.cisd.tms.modules.upgrade.dto.UpgradePreviewRequest.class);
assertNoAudit(OperationAuditController.class, "queryPage",
com.cisd.tms.modules.log.dto.OperationAuditLogPageRequest.class);
assertNoAudit(OpenApiController.class, "rawVerify", com.cisd.tms.modules.openapi.service.dto.RawVerifyRequest.class);
assertNoAudit(OpenApiController.class, "dettachedVerify",
com.cisd.tms.modules.openapi.service.dto.DettachedVerifyRequest.class);
assertNoAudit(OpenApiController.class, "dettachedVerifySimple",
com.cisd.tms.modules.openapi.service.dto.DettachedVerifyRequest.class);
}
private static void assertAudit(
Class<?> controller,
String methodName,
ModuleCode moduleCode,
ActionType actionType,
Class<?>... parameterTypes
) throws Exception {
AuditedOperation annotation = auditedOperation(controller, methodName, parameterTypes);
Assertions.assertNotNull(annotation, controller.getSimpleName() + "#" + methodName);
Assertions.assertEquals(moduleCode, annotation.module(), controller.getSimpleName() + "#" + methodName);
Assertions.assertEquals(actionType, annotation.action(), controller.getSimpleName() + "#" + methodName);
}
private static void assertNoAudit(Class<?> controller, String methodName, Class<?>... parameterTypes) throws Exception {
Assertions.assertNull(auditedOperation(controller, methodName, parameterTypes),
controller.getSimpleName() + "#" + methodName);
}
private static AuditedOperation auditedOperation(Class<?> controller, String methodName, Class<?>... parameterTypes)
throws Exception {
Method method = controller.getMethod(methodName, parameterTypes);
AuditedOperation methodAnnotation = AnnotatedElementUtils.findMergedAnnotation(method, AuditedOperation.class);
if (methodAnnotation != null) {
return methodAnnotation;
}
return AnnotatedElementUtils.findMergedAnnotation(controller, AuditedOperation.class);
}
}

View File

@ -0,0 +1,23 @@
package com.cisd.tms.modules.log.repository;
import java.nio.charset.StandardCharsets;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.core.io.ClassPathResource;
class OperationAuditSchemaContractTest {
@Test
void shouldAllowAnonymousBootstrapAuditLogRole() throws Exception {
String fullSql = readClasspathResource("db/migration/V2__tms_schema_full.sql");
Assertions.assertTrue(fullSql.contains("operator_role_code VARCHAR(64) NULL"));
Assertions.assertFalse(fullSql.contains("operator_role_code VARCHAR(64) NOT NULL"));
}
private static String readClasspathResource(String path) throws Exception {
ClassPathResource resource = new ClassPathResource(path);
Assertions.assertTrue(resource.exists(), "Missing classpath resource: " + path);
return new String(resource.getInputStream().readAllBytes(), StandardCharsets.UTF_8);
}
}

View File

@ -0,0 +1,34 @@
package com.cisd.tms.schema;
import java.nio.charset.StandardCharsets;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.core.io.ClassPathResource;
class FullSchemaVersionContractTest {
@Test
void shouldRetainV1MigrationAndExposeCurrentV2FullSchema() throws Exception {
String v1Sql = readClasspathResource("db/migration/V1__tms_schema_full.sql");
String v2Sql = readClasspathResource("db/migration/V2__tms_schema_full.sql");
Assertions.assertTrue(v1Sql.contains("ALTER TABLE tms_auth_full_account"));
Assertions.assertTrue(v1Sql.contains("AFTER password_hash"));
Assertions.assertFalse(v1Sql.contains("CREATE TABLE IF NOT EXISTS tms_auth_full_account"));
Assertions.assertTrue(v2Sql.contains("CREATE TABLE IF NOT EXISTS tms_operation_audit_log"));
}
@Test
void currentV2FullSchemaShouldNotDependOnPatchStatements() throws Exception {
String v2Sql = readClasspathResource("db/migration/V2__tms_schema_full.sql");
Assertions.assertFalse(v2Sql.contains("ALTER TABLE"));
Assertions.assertFalse(v2Sql.lines().anyMatch(line -> line.stripLeading().startsWith("UPDATE ")));
}
private static String readClasspathResource(String path) throws Exception {
ClassPathResource resource = new ClassPathResource(path);
Assertions.assertTrue(resource.exists(), "Missing classpath resource: " + path);
return new String(resource.getInputStream().readAllBytes(), StandardCharsets.UTF_8);
}
}

View File

@ -0,0 +1,48 @@
package com.cisd.tms.security.internal;
import com.cisd.tms.modules.auth.enums.AuthLevel;
import com.cisd.tms.modules.auth.enums.RoleCode;
import com.cisd.tms.modules.auth.security.RequireInternalAuth;
import com.cisd.tms.modules.device.controller.NetworkConfigController;
import com.cisd.tms.modules.device.controller.TimeConfigController;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.core.annotation.AnnotatedElementUtils;
class InternalBootstrapAuthContractTest {
@Test
void shouldRequireOpsFullAfterBootstrapForNetworkAndTimeConfig() throws Exception {
RequireInternalAuth networkAuth =
AnnotatedElementUtils.findMergedAnnotation(NetworkConfigController.class, RequireInternalAuth.class);
RequireInternalAuth timeAuth = AnnotatedElementUtils.findMergedAnnotation(
TimeConfigController.class.getMethod("configureTime",
com.cisd.tms.modules.device.dto.TimeConfigRequest.class),
RequireInternalAuth.class
);
assertBootstrapOpsFull(networkAuth);
assertBootstrapOpsFull(timeAuth);
}
@Test
void shouldNotStaticallyExcludeBootstrapConfigEndpointsFromInternalAuth() throws Exception {
String source = Files.readString(
Path.of("src/main/java/com/cisd/tms/common/config/WebMvcConfig.java"),
StandardCharsets.UTF_8
);
Assertions.assertFalse(source.contains("\"/api/v1/device/time-config\""));
Assertions.assertFalse(source.contains("\"/api/v1/device/network/**\""));
}
private static void assertBootstrapOpsFull(RequireInternalAuth auth) {
Assertions.assertNotNull(auth);
Assertions.assertEquals(RoleCode.OPS_ADMIN, auth.role());
Assertions.assertEquals(AuthLevel.FULL, auth.authLevel());
Assertions.assertTrue(auth.allowBeforeMasterKeyInitialized());
}
}