This is an automated email from the ASF dual-hosted git repository. shuwenwei pushed a commit to branch sync-generic-changes in repository https://gitbox.apache.org/repos/asf/iotdb.git
commit b59462d40e0cbf67d84e60e9f284847eab096c47 Author: shuwenwei <[email protected]> AuthorDate: Thu Sep 17 15:26:49 2026 +0800 [Auth] Persist user/role profiles with a versioned extra segment region --- .../schema/CNPhysicalPlanGenerator.java | 33 ++++++++++- .../commons/auth/role/LocalFileRoleAccessor.java | 69 +++++++++++++++++++++- .../commons/auth/user/LocalFileUserAccessor.java | 6 +- 3 files changed, 103 insertions(+), 5 deletions(-) diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/schema/CNPhysicalPlanGenerator.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/schema/CNPhysicalPlanGenerator.java index e4366c45fc4..c2e0e08fe21 100644 --- a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/schema/CNPhysicalPlanGenerator.java +++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/schema/CNPhysicalPlanGenerator.java @@ -21,6 +21,7 @@ package org.apache.iotdb.confignode.persistence.schema; import org.apache.iotdb.commons.auth.entity.PrivilegeModelType; import org.apache.iotdb.commons.auth.entity.PrivilegeType; +import org.apache.iotdb.commons.auth.role.LocalFileRoleAccessor.ExtraSegmentType; import org.apache.iotdb.commons.exception.IllegalPathException; import org.apache.iotdb.commons.path.PartialPath; import org.apache.iotdb.commons.schema.SchemaConstant; @@ -224,7 +225,7 @@ public class CNPhysicalPlanGenerator createUser.setPermissions(new HashSet<>()); createUser.setNodeNameList(new ArrayList<>()); planDeque.add(createUser); - if (tag == 2) { + if (tag >= 2) { final AuthorTreePlan updateUserMaxSession = new AuthorTreePlan(ConfigPhysicalPlanType.UpdateUserMaxSession); updateUserMaxSession.setMaxSessionPerUser(dataInputStream.readInt()); @@ -296,6 +297,10 @@ public class CNPhysicalPlanGenerator } } } + + if (tag >= 3) { + generateExtraSegmentPhysicalPlans(dataInputStream, user, isUser); + } } catch (IOException ioException) { logger.error( ManagerMessages.LOG_GOT_IOEXCEPTION_DESERIALIZE_USE_ROLE_FILE_TYPE_ARG_1B548759, @@ -307,6 +312,32 @@ public class CNPhysicalPlanGenerator } } + /** + * Reads the extra segment region appended after the RBAC privileges of a user/role profile file. + * Each segment is encoded as {@code [type: int32][length: int32][payload: bytes]} and dispatched + * by its type. No extra segment types are handled in this branch, so every payload is ignored, + * while segments of unknown types written by newer versions stay forward compatible. + */ + private void generateExtraSegmentPhysicalPlans( + final DataInputStream dataInputStream, final String granteeName, final boolean isUser) + throws IOException { + final int extraSegmentCount = dataInputStream.readInt(); + for (int i = 0; i < extraSegmentCount; i++) { + final ExtraSegmentType segmentType = ExtraSegmentType.fromType(dataInputStream.readInt()); + final int length = dataInputStream.readInt(); + final byte[] segmentData = new byte[length]; + dataInputStream.readFully(segmentData); + if (segmentType == null) { + continue; + } + switch (segmentType) { + default: + // No extra segment types are handled in this branch. + break; + } + } + } + private void generateGrantRolePhysicalPlan() { try (final DataInputStream roleInputStream = new DataInputStream(new BufferedInputStream((inputStream)))) { diff --git a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/auth/role/LocalFileRoleAccessor.java b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/auth/role/LocalFileRoleAccessor.java index df7d7f28427..4f57760183d 100644 --- a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/auth/role/LocalFileRoleAccessor.java +++ b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/auth/role/LocalFileRoleAccessor.java @@ -85,8 +85,34 @@ public class LocalFileRoleAccessor implements IEntityAccessor { protected final String entityDirPath; // It might be a good idea to use a Version number to control upgrade compatibility. - // Now it's version 1 - protected static final int VERSION = 2; + // Version 3 appends an extra segment region after the RBAC privileges. + protected static final int VERSION = 3; + + /** Types of the extra segments appended after the RBAC privileges in a profile file. */ + public enum ExtraSegmentType { + /** The subject's LBAC label grants and rule exemptions. */ + LBAC_GRANT_INFO(1); + + private final int type; + + ExtraSegmentType(final int type) { + this.type = type; + } + + public int getType() { + return type; + } + + /** Returns the segment type matching the given value, or {@code null} if unknown. */ + public static ExtraSegmentType fromType(final int type) { + for (final ExtraSegmentType segmentType : values()) { + if (segmentType.type == type) { + return segmentType; + } + } + return null; + } + } /** * Reused buffer for primitive types encoding/decoding, which aim to reduce memory fragments. Use @@ -151,6 +177,38 @@ public class LocalFileRoleAccessor implements IEntityAccessor { role.setObjectPrivilegeMap(objectPrivilegeMap); } + /** + * Writes the extra segment region appended after the RBAC privileges. The region starts with the + * segment count. No extra segments are written by this branch, so the region is empty. + */ + protected void saveExtraSegments(BufferedOutputStream outputStream, Role role) + throws IOException { + IOUtils.writeInt(outputStream, 0, encodingBufferLocal); + } + + /** + * Reads the extra segment region appended after the RBAC privileges. Each segment is encoded as + * [type: int32][length: int32][payload: bytes]. This branch handles no segment type, so every + * payload is ignored while profile files written by newer versions can still be loaded. + */ + protected void loadExtraSegments(DataInputStream dataInputStream, Role role) throws IOException { + final int extraSegmentCount = dataInputStream.readInt(); + for (int i = 0; i < extraSegmentCount; i++) { + final ExtraSegmentType segmentType = ExtraSegmentType.fromType(dataInputStream.readInt()); + final int length = dataInputStream.readInt(); + final byte[] segmentData = new byte[length]; + dataInputStream.readFully(segmentData); + if (segmentType == null) { + continue; + } + switch (segmentType) { + default: + // No extra segment types are handled in this branch. + break; + } + } + } + protected void saveSessionPerUser(BufferedOutputStream outputStream, Role role) throws IOException { // Just used in LocalFileUserAccessor.java. @@ -218,10 +276,14 @@ public class LocalFileRoleAccessor implements IEntityAccessor { loadPrivileges(dataInputStream, role); return role; } else { - assert tag == VERSION; + // tag >= 2: version 2 and version 3 share the same leading layout; version 3 additionally + // appends the extra segment region. entityName = IOUtils.readString(dataInputStream, STRING_ENCODING, strBufferLocal); Role role = new Role(entityName); loadPrivileges(dataInputStream, role); + if (tag >= 3) { + loadExtraSegments(dataInputStream, role); + } return role; } @@ -276,6 +338,7 @@ public class LocalFileRoleAccessor implements IEntityAccessor { saveEntityName(outputStream, entity); saveSessionPerUser(outputStream, entity); savePrivileges(outputStream, entity); + saveExtraSegments(outputStream, entity); outputStream.flush(); fileOutputStream.getFD().sync(); } catch (Exception e) { diff --git a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/auth/user/LocalFileUserAccessor.java b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/auth/user/LocalFileUserAccessor.java index 5ad0d08fc42..bac866a5291 100644 --- a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/auth/user/LocalFileUserAccessor.java +++ b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/auth/user/LocalFileUserAccessor.java @@ -172,13 +172,17 @@ public class LocalFileUserAccessor extends LocalFileRoleAccessor { user.setPassword(IOUtils.readString(dataInputStream, STRING_ENCODING, strBufferLocal)); loadPrivileges(dataInputStream, user); } else { - assert (tag == VERSION); + // tag >= 2: version 2 and version 3 share the same leading layout; version 3 additionally + // appends the extra segment region. user.setUserId(dataInputStream.readLong()); user.setName(IOUtils.readString(dataInputStream, STRING_ENCODING, strBufferLocal)); user.setPassword(IOUtils.readString(dataInputStream, STRING_ENCODING, strBufferLocal)); user.setMaxSessionPerUser(dataInputStream.readInt()); user.setMinSessionPerUser(dataInputStream.readInt()); loadPrivileges(dataInputStream, user); + if (tag >= 3) { + loadExtraSegments(dataInputStream, user); + } } File roleOfUser = checkFileAvailable(entityName, "_role");
