Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 0 additions & 7 deletions conf/db/upgrade/V5.5.18__schema.sql
Original file line number Diff line number Diff line change
Expand Up @@ -173,13 +173,6 @@ CREATE TABLE IF NOT EXISTS `PhysicalServerHardwareInfoVO` (
`cpuCores` INT DEFAULT NULL,
`cpuArchitecture` VARCHAR(255) DEFAULT NULL,
`totalMemoryBytes` BIGINT DEFAULT NULL,
`memoryModuleCount` INT DEFAULT NULL,
`totalDiskBytes` BIGINT DEFAULT NULL,
`diskCount` INT DEFAULT NULL,
`nicCount` INT DEFAULT NULL,
`gpuCount` INT DEFAULT NULL,
`healthStatus` VARCHAR(255) DEFAULT NULL,
`discoverSource` VARCHAR(255) DEFAULT NULL,
`lastDiscoverDate` TIMESTAMP NULL DEFAULT NULL,
`lastOpDate` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`createDate` TIMESTAMP NOT NULL DEFAULT '2000-01-01 00:00:00',
Expand Down
14 changes: 14 additions & 0 deletions conf/springConfigXml/PhysicalServerManager.xml
Original file line number Diff line number Diff line change
Expand Up @@ -133,4 +133,18 @@

<bean id="physicalServerPathTwoOrchestrator"
class="org.zstack.server.PhysicalServerPathTwoOrchestrator" />

<!--
QA gap (Confluence pageId=208903964 #2) / PRD §2.5.1: backfill
PhysicalServerVO.serialNumber / manufacturer / model from HostSystemTags
in the call-after-add-host-extension hook (chain tail), after connect has
written the tags. InitPhysicalServerCapacityFlow runs at chain head per
ADR-012 fail-loud ordering, too early to read SystemTag.
-->
<bean id="PhysicalServerKvmIdentityBackfillExtension"
class="org.zstack.server.PhysicalServerKvmIdentityBackfillExtension">
<zstack:plugin>
<zstack:extension interface="org.zstack.header.host.HostAddExtensionPoint" />
</zstack:plugin>
</bean>
</beans>
2 changes: 1 addition & 1 deletion conf/springConfigXml/encrypt.xml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,6 @@
</zstack:plugin>
</bean>

<bean id="PasswordConvert" class="org.zstack.core.convert.PasswordConverter" />
<bean id="PasswordConvert" class="org.zstack.header.core.convert.PasswordConverter" />
<bean id="SpecialDataConverter" class="org.zstack.core.convert.SpecialDataConverter" />
</beans>
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.stereotype.Component;
import org.zstack.core.encrypt.EncryptFacade;
import org.zstack.header.core.convert.EncryptFacade;
import org.zstack.core.encrypt.EncryptGlobalConfig;
import org.zstack.header.core.encrypt.PasswordEncryptType;
import org.zstack.utils.Utils;
Expand Down
26 changes: 0 additions & 26 deletions core/src/main/java/org/zstack/core/encrypt/EncryptFacade.java

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,15 @@
import org.zstack.core.Platform;
import org.zstack.core.componentloader.PluginRegistry;
import org.zstack.core.config.*;
import org.zstack.core.convert.PasswordConverter;
import org.zstack.header.core.convert.PasswordConverter;
import org.zstack.core.convert.SpecialDataConverter;
import org.zstack.core.db.DatabaseFacade;
import org.zstack.core.db.Q;
import org.zstack.core.db.SQL;
import org.zstack.core.db.SQLBatch;
import org.zstack.header.Component;
import org.zstack.header.core.encrypt.*;
import org.zstack.header.core.convert.EncryptFacade;
import org.zstack.header.errorcode.ErrorableValue;
import org.zstack.header.errorcode.OperationFailureException;
import org.zstack.header.exception.CloudRuntimeException;
Expand Down Expand Up @@ -76,6 +77,12 @@ public ErrorableValue<String> decrypt(String data, String algType) {
return encryptDriver.decrypt(data, algType);
}

@Override
public boolean isEncryptionDisabled() {
return PasswordEncryptType.None.toString()
.equals(EncryptGlobalConfig.ENABLE_PASSWORD_ENCRYPT.value(String.class));
}

private String getQuerySql(List<CovertSubClass> covertSubClasses, String className, String fieldName, String uuid) {
List<String> whereSqlList = covertSubClasses.stream()
.filter(subClass -> subClass.classSimpleName().equals(className) && !subClass.columnName().isEmpty())
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package org.zstack.header.core.convert;

import org.zstack.header.core.encrypt.EncryptEntityState;
import org.zstack.header.core.encrypt.EncryptedFieldBundle;
import org.zstack.header.errorcode.ErrorableValue;

import java.util.List;

/**
* Header-resident interface so header-bound entities (e.g.
* {@code PhysicalServerAO}) can reference the JPA
* {@link org.zstack.header.core.convert.PasswordConverter} without pulling in
* the {@code core} module (header is the upstream of core).
*
* <p>Originally lived in {@code org.zstack.core.encrypt}; moved with the
* {@code PasswordConverter} relocation in ZSTAC-85182.</p>
*/
public interface EncryptFacade {
String encrypt(String decryptString);

String decrypt(String encryptString);

ErrorableValue<String> encrypt(String data, String algType);

ErrorableValue<String> decrypt(String data, String algType);

void updateEncryptDataStateIfExists(String entity, String column, EncryptEntityState state);

List<EncryptedFieldBundle> getIntegrityEncryptionBundle();

List<EncryptedFieldBundle> getConfidentialityEncryptionBundle();

/**
* @return {@code true} when the global password-encrypt toggle is set to
* {@code None}; the {@link PasswordConverter} treats this as pass-through
* so legacy unencrypted columns stay readable. Centralised here so the
* converter does not need to depend on {@code core.EncryptGlobalConfig}.
*/
boolean isEncryptionDisabled();
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
package org.zstack.core.convert;
package org.zstack.header.core.convert;

import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowire;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.stereotype.Component;
import org.zstack.core.encrypt.EncryptFacade;
import org.zstack.core.encrypt.EncryptGlobalConfig;
import org.zstack.header.core.encrypt.PasswordEncryptType;
import org.zstack.utils.Utils;
import org.zstack.utils.logging.CLogger;

Expand All @@ -16,6 +13,13 @@

/**
* Created by kayo on 2018/9/7.
*
* <p>Relocated from {@code org.zstack.core.convert} to header in ZSTAC-85182 so
* header-resident entities (e.g. {@code PhysicalServerAO.oobPassword}) can
* apply {@code @Convert(converter = PasswordConverter.class)} directly. The
* gating against the global {@code enable.password.encrypt} toggle moved to
* {@link EncryptFacade#isEncryptionDisabled()} to keep this class free of any
* {@code core} import.</p>
*/
@Component
@Converter
Expand All @@ -32,7 +36,7 @@ public void initEncryptFacade(EncryptFacade encryptFacade){

@Override
public String convertToDatabaseColumn(String attribute) {
if (PasswordEncryptType.None.toString().equals(EncryptGlobalConfig.ENABLE_PASSWORD_ENCRYPT.value(String.class))) {
if (encryptFacade == null || encryptFacade.isEncryptionDisabled()) {
return attribute;
Comment on lines +39 to 40
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

encryptFacade == null 不应降级为明文透传

Line 39 和 Line 50 把 encryptFacade == null 视为“直接返回原值”,会在注入异常/初始化异常时静默写入明文密码,属于 fail-open。建议仅在 isEncryptionDisabled() 时透传,encryptFacade == null 应显式失败(或至少告警并阻断写入)。

🔧 建议修复
 `@Override`
 public String convertToDatabaseColumn(String attribute) {
-    if (encryptFacade == null || encryptFacade.isEncryptionDisabled()) {
+    if (encryptFacade == null) {
+        throw new IllegalStateException("EncryptFacade is not initialized");
+    }
+    if (encryptFacade.isEncryptionDisabled()) {
         return attribute;
     }
     if (StringUtils.isEmpty(attribute)) {
         return attribute;
     }
     return encryptFacade.encrypt(attribute);
 }

 `@Override`
 public String convertToEntityAttribute(String dbData) {
-    if (encryptFacade == null || encryptFacade.isEncryptionDisabled()) {
+    if (encryptFacade == null) {
+        throw new IllegalStateException("EncryptFacade is not initialized");
+    }
+    if (encryptFacade.isEncryptionDisabled()) {
         return dbData;
     }

     if (StringUtils.isEmpty(dbData)) {
         return dbData ;
     }

     return encryptFacade.decrypt(dbData);
 }

Also applies to: 50-51

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@header/src/main/java/org/zstack/header/core/encrypt/PasswordConverter.java`
around lines 39 - 40, In PasswordConverter, do not treat encryptFacade == null
as a permissive passthrough; update both convertToEntityAttribute and
convertToDatabaseColumn so they only return the raw attribute/value when
encryptFacade.isEncryptionDisabled() is true, and if encryptFacade is null then
throw an explicit runtime exception (e.g., IllegalStateException) or otherwise
fail-fast (with a clear error message) to block writing cleartext passwords;
reference the class PasswordConverter and its methods
convertToEntityAttribute/convertToDatabaseColumn and the
encryptFacade/isEncryptionDisabled symbols when making this change.

}
if (StringUtils.isEmpty(attribute)) {
Expand All @@ -43,7 +47,7 @@ public String convertToDatabaseColumn(String attribute) {

@Override
public String convertToEntityAttribute(String dbData) {
if (PasswordEncryptType.None.toString().equals(EncryptGlobalConfig.ENABLE_PASSWORD_ENCRYPT.value(String.class))) {
if (encryptFacade == null || encryptFacade.isEncryptionDisabled()) {
return dbData;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.zstack.header.server;

import org.zstack.header.core.convert.PasswordConverter;
import org.zstack.header.vo.ForeignKey;
import org.zstack.header.vo.ForeignKey.ReferenceOption;
import org.zstack.header.vo.ResourceVO;
Expand Down Expand Up @@ -70,6 +71,7 @@ public class PhysicalServerAO extends ResourceVO {

@EncryptColumn
@NoLogging
@Convert(converter = PasswordConverter.class)
@Column
private String oobPassword;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,11 +80,5 @@ interface HardwareInfoCarrier {
void setCpuCores(Integer v);
void setCpuArchitecture(String v);
void setTotalMemoryBytes(Long v);
void setMemoryModuleCount(Integer v);
void setTotalDiskBytes(Long v);
void setDiskCount(Integer v);
void setNicCount(Integer v);
void setGpuCount(Integer v);
void setHealthStatus(String v);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -53,36 +53,6 @@ public class PhysicalServerHardwareInfoVO {
@Column
private Long totalMemoryBytes;

@Column
private Integer memoryModuleCount;

@Column
private Long totalDiskBytes;

@Column
private Integer diskCount;

@Column
private Integer nicCount;

@Column
private Integer gpuCount;

@Column
private String healthStatus;

/**
* P1-3: first-writer-wins. The first {@code discoverHardware} pass that produced any
* non-null carrier field writes its winning source here (per the in-pass ordering
* IPMI_FRU &gt; KVM_AGENT &gt; K8S_NODEINFO). Subsequent passes refresh data columns
* and {@link #lastDiscoverDate} but do NOT overwrite this value — it is a stable
* "who first identified this host" tag, not a churning "currently primary contributor"
* signal. Operators wanting per-field provenance should look at lastDiscoverDate +
* field-level audit (out of scope for v5.5.18).
*/
@Column
private String discoverSource;

@Column
private Timestamp lastDiscoverDate;

Expand Down Expand Up @@ -172,62 +142,6 @@ public void setTotalMemoryBytes(Long totalMemoryBytes) {
this.totalMemoryBytes = totalMemoryBytes;
}

public Integer getMemoryModuleCount() {
return memoryModuleCount;
}

public void setMemoryModuleCount(Integer memoryModuleCount) {
this.memoryModuleCount = memoryModuleCount;
}

public Long getTotalDiskBytes() {
return totalDiskBytes;
}

public void setTotalDiskBytes(Long totalDiskBytes) {
this.totalDiskBytes = totalDiskBytes;
}

public Integer getDiskCount() {
return diskCount;
}

public void setDiskCount(Integer diskCount) {
this.diskCount = diskCount;
}

public Integer getNicCount() {
return nicCount;
}

public void setNicCount(Integer nicCount) {
this.nicCount = nicCount;
}

public Integer getGpuCount() {
return gpuCount;
}

public void setGpuCount(Integer gpuCount) {
this.gpuCount = gpuCount;
}

public String getHealthStatus() {
return healthStatus;
}

public void setHealthStatus(String healthStatus) {
this.healthStatus = healthStatus;
}

public String getDiscoverSource() {
return discoverSource;
}

public void setDiscoverSource(String discoverSource) {
this.discoverSource = discoverSource;
}

public Timestamp getLastDiscoverDate() {
return lastDiscoverDate;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package org.zstack.storage.ceph;

import org.zstack.core.convert.PasswordConverter;
import org.zstack.header.core.convert.PasswordConverter;
import org.zstack.header.core.encrypt.EncryptColumn;
import org.zstack.header.vo.ResourceVO;

Expand Down
2 changes: 1 addition & 1 deletion plugin/kvm/src/main/java/org/zstack/kvm/KVMHostVO.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package org.zstack.kvm;

import org.zstack.core.convert.PasswordConverter;
import org.zstack.header.core.convert.PasswordConverter;
import org.zstack.header.core.encrypt.EncryptColumn;
import org.zstack.header.host.HostEO;
import org.zstack.header.host.HostVO;
Expand Down
Loading