Skip to content

Conversation

@Caideyipi
Copy link
Collaborator

Description

As the title said.


This PR has:

  • been self-reviewed.
    • concurrent read
    • concurrent write
    • concurrent read and write
  • added documentation for new or modified features or behaviors.
  • added Javadocs for most classes and all non-trivial methods.
  • added or updated version, license, or notice information
  • added comments explaining the "why" and the intent of the code wherever would not be obvious
    for an unfamiliar reader.
  • added unit tests or modified existing tests to cover new code paths, ensuring the threshold
    for code coverage.
  • added integration tests.
  • been tested in a test IoTDB cluster.

Key changed/added classes (or packages if there are too many classes) in this PR

CRZbulabula and others added 30 commits September 24, 2025 09:38
* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* refactor

* fix

* fix

* partial

* grass

* Update PipeConfigTreePrivilegeParseVisitor.java

* Feature/client hide password (#16468)

* session hide password

* fix start-cli.sh

* fix start-cli.bat

* client hide password

* fix client warning

* echo cmd line

* fix

* Update PipeConfigTreePrivilegeParseVisitor.java

* partial

* partial

* fix

* fix

* partial

---------

Co-authored-by: Hongzhi Gao <[email protected]>
* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* refactor

* fix

* fix

* partial

* grass

* Update PipeConfigTreePrivilegeParseVisitor.java

* Feature/client hide password (#16468)

* session hide password

* fix start-cli.sh

* fix start-cli.bat

* client hide password

* fix client warning

* echo cmd line

* fix

* Update PipeConfigTreePrivilegeParseVisitor.java

* partial

* partial

* fix

* fix

* partial

---------

Co-authored-by: Hongzhi Gao <[email protected]>
# Conflicts:
#	integration-test/src/test/java/org/apache/iotdb/pipe/it/dual/treemodel/auto/basic/IoTDBTreePatternFormatIT.java
#	integration-test/src/test/java/org/apache/iotdb/pipe/it/dual/treemodel/manual/IoTDBPipeInclusionIT.java
#	iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/pipe/source/PipeConfigTreePatternParseVisitor.java
#	iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/auth/AuthorInfo.java
#	iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/schema/CNPhysicalPlanGenerator.java
#	iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/manager/pipe/source/PipeConfigTreePatternParseVisitorTest.java
#	iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/agent/task/connection/PipeEventCollector.java
#	iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/event/common/tsfile/parser/TsFileInsertionEventParser.java
#	iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/event/common/tsfile/parser/TsFileInsertionEventParserProvider.java
#	iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/event/common/tsfile/parser/query/TsFileInsertionEventQueryParser.java
#	iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/event/common/tsfile/parser/scan/TsFileInsertionEventScanParser.java
#	iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/event/common/tsfile/parser/table/TsFileInsertionEventTableParser.java
#	iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/receiver/visitor/PipeTableStatementDataTypeConvertExecutionVisitor.java
#	iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/executor/ClusterConfigTaskExecutor.java
#	iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/load/converter/LoadTableStatementDataTypeConvertExecutionVisitor.java
#	iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/datastructure/pattern/IoTDBTreePattern.java
# Conflicts:
#	iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/pipe/source/PipeConfigTreePatternParseVisitor.java
#	iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/agent/task/connection/PipeEventCollector.java
#	iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/datastructure/pattern/IoTDBTreePattern.java
Comment on lines +379 to +386
// A user shall only see its own pipe
try (final SyncConfigNodeIServiceClient client =
(SyncConfigNodeIServiceClient) senderEnv.getLeaderConfigNodeConnection()) {
Assert.assertEquals(
1, client.showPipe(new TShowPipeReq().setUserName("thulab")).pipeInfoList.size());
} catch (Exception e) {
fail(e.getMessage());
}
Copy link
Contributor

Choose a reason for hiding this comment

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

You can show another user's pipe simply by setting the request's username?

Copy link
Collaborator Author

@Caideyipi Caideyipi Dec 3, 2025

Choose a reason for hiding this comment

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

Yes, but if the config client can be initialized outside of IoTDB, a user can do everything without permission, because the permissions are checked on DataNode. So users shall not have the chance to directly "set" the request's username

Comment on lines +249 to +256
if (!Boolean.TRUE.equals(isTableDatabasePlan)) {
final Optional<ConfigPhysicalPlan> result = treePrivilegeParseVisitor.process(plan, userName);
if (result.isPresent()) {
return Optional.of(
new PipeConfigRegionWritePlanEvent(result.get(), event.isGeneratedByPipe()));
}
}

final Optional<ConfigPhysicalPlan> result =
TABLE_PRIVILEGE_PARSE_VISITOR.process(plan, userName);
if (result.isPresent()) {
return Optional.of(
new PipeConfigRegionWritePlanEvent(result.get(), event.isGeneratedByPipe()));
if (!Boolean.FALSE.equals(isTableDatabasePlan)) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Reverse the conditions to remove unnecessary !.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This cannot be done because other than table database, the planNodes are processed by both of the visitor but will only be filtered by one and pass directly through another. The ! is to tell 'null + FALSE' and 'TRUE + NULL'

Comment on lines +132 to +173
public boolean canShowSchemaTemplate(final String templateName, final String userName) {
try {
return ConfigNode.getInstance()
.getConfigManager()
.getPermissionManager()
.checkUserPrivileges(userName, new PrivilegeUnion(PrivilegeType.SYSTEM))
.getStatus()
.getCode()
== TSStatusCode.SUCCESS_STATUS.getStatusCode()
|| ConfigNode.getInstance()
.getConfigManager()
.getClusterSchemaManager()
.getPathsSetTemplate(templateName, ALL_MATCH_SCOPE)
.getPathList()
.stream()
.anyMatch(
path -> {
try {
return ConfigNode.getInstance()
.getConfigManager()
.getPermissionManager()
.checkUserPrivileges(
userName,
new PrivilegeUnion(
Collections.singletonList(
new PartialPath(path)
.concatNode(MULTI_LEVEL_PATH_WILDCARD)),
PrivilegeType.READ_SCHEMA))
.getStatus()
.getCode()
== TSStatusCode.SUCCESS_STATUS.getStatusCode();
} catch (final IllegalPathException e) {
throw new RuntimeException(e);
}
});
} catch (final Exception e) {
LOGGER.warn(
"Un-parse-able path name encountered during template privilege trimming, please check",
e);
return false;
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Add a test to cover this?

Comment on lines 509 to 531
final Set<IDeviceID> devices = getDeviceSet();
if (Objects.nonNull(devices)) {
final List<MeasurementPath> measurementList = new ArrayList<>();
for (final IDeviceID device : devices) {
measurementList.add(new MeasurementPath(device, IoTDBConstant.ONE_LEVEL_PATH_WILDCARD));
}
final TSStatus status =
AuthorityChecker.getAccessControl()
.checkSeriesPrivilege4Pipe(
new UserEntity(Long.parseLong(userId), userName, cliHostname),
measurementList,
PrivilegeType.READ_DATA);
if (TSStatusCode.SUCCESS_STATUS.getStatusCode() != status.getCode()) {
if (skipIfNoPrivileges) {
shouldParse4Privilege = true;
} else {
throw new AccessDeniedException(status.getMessage());
}
}
} else {
shouldParse4Privilege = true;
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

If the file only contains root.db1.d1.s1 (on which the user has privileges), but the user does not have privileges on root.db1.s2, and skipIfNoPrivileges = false, then the file will not be transferred?

Copy link
Collaborator Author

@Caideyipi Caideyipi Dec 3, 2025

Choose a reason for hiding this comment

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

Of course, "skipIf == false" means the pipe will stop for any data/schema without privilege.

Comment on lines -206 to +211
TABLE_PRIVILEGE_PARSE_VISITOR.process(
((PipeSchemaRegionWritePlanEvent) event).getPlanNode(), userEntity);
treePrivilegeParseVisitor
.process(((PipeSchemaRegionWritePlanEvent) event).getPlanNode(), userEntity)
.flatMap(planNode -> TABLE_PRIVILEGE_PARSE_VISITOR.process(planNode, userEntity));
Copy link
Contributor

Choose a reason for hiding this comment

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

The same node is processed by both treeVisitor and tableVisitor?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This is OK because one kind of node will only be parsed by one visitor. In the other one it just "pass by"

@sonarqubecloud
Copy link

sonarqubecloud bot commented Dec 4, 2025

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants