This is an automated email from the ASF dual-hosted git repository.
yongzao pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/iotdb.git
The following commit(s) were added to refs/heads/master by this push:
new 4ebfe9eab86 Append user index field for User (#16432)
4ebfe9eab86 is described below
commit 4ebfe9eab86d8dc56d7534bf3b24346e3692bd08
Author: wenyanshi-123 <[email protected]>
AuthorDate: Sat Sep 20 22:07:58 2025 +0800
Append user index field for User (#16432)
---
.../org/apache/iotdb/db/it/IoTDBRestServiceIT.java | 6 +-
.../org/apache/iotdb/db/it/auth/IoTDBAuthIT.java | 93 ++++++++++++----------
.../iotdb/db/it/auth/IoTDBRelationalAuthIT.java | 15 ++--
.../manual/IoTDBPipeMetaHistoricalIT.java | 4 +-
.../treemodel/manual/IoTDBPipePermissionIT.java | 4 +-
.../response/auth/PermissionInfoResp.java | 11 +++
.../confignode/manager/PermissionManager.java | 4 +
.../pipe/event/PipeConfigRegionSnapshotEvent.java | 35 +++++---
.../receiver/protocol/IoTDBConfigNodeReceiver.java | 3 +-
.../payload/PipeTransferConfigSnapshotSealReq.java | 8 +-
.../sink/protocol/IoTDBConfigRegionAirGapSink.java | 3 +-
.../pipe/sink/protocol/IoTDBConfigRegionSink.java | 3 +-
.../pipe/source/ConfigRegionListeningQueue.java | 25 ++++--
.../pipe/source/IoTDBConfigRegionSource.java | 3 +-
.../iotdb/confignode/persistence/AuthorInfo.java | 24 +++++-
.../schema/CNPhysicalPlanGenerator.java | 14 +++-
.../schema/ConfigNodeSnapshotParser.java | 5 +-
.../thrift/ConfigNodeRPCServiceProcessor.java | 2 +
.../pipe/sink/PipeConfigNodeThriftRequestTest.java | 3 +-
.../persistence/CNPhysicalPlanGeneratorTest.java | 15 ++--
.../org/apache/iotdb/db/auth/AuthorityChecker.java | 25 +++++-
.../org/apache/iotdb/db/auth/entity/UserTest.java | 4 +-
.../db/auth/user/LocalFileUserAccessorTest.java | 19 +++--
.../commons/auth/authorizer/BasicAuthorizer.java | 11 +++
.../iotdb/commons/auth/authorizer/IAuthorizer.java | 17 ++++
.../iotdb/commons/auth/entity/IEntityAccessor.java | 15 ++++
.../org/apache/iotdb/commons/auth/entity/Role.java | 18 +++++
.../org/apache/iotdb/commons/auth/entity/User.java | 36 ++++++++-
.../iotdb/commons/auth/role/BasicRoleManager.java | 22 +++++
.../iotdb/commons/auth/role/IEntityManager.java | 9 +++
.../commons/auth/role/LocalFileRoleAccessor.java | 64 ++++++++++++++-
.../iotdb/commons/auth/user/BasicUserManager.java | 60 +++++++++++++-
.../commons/auth/user/LocalFileUserAccessor.java | 47 +++++++++--
.../commons/auth/user/LocalFileUserManager.java | 1 +
.../schema/column/ColumnHeaderConstant.java | 7 ++
.../org/apache/iotdb/commons/utils/IOUtils.java | 30 +++++++
.../src/main/thrift/confignode.thrift | 8 ++
37 files changed, 555 insertions(+), 118 deletions(-)
diff --git
a/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBRestServiceIT.java
b/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBRestServiceIT.java
index 99d4b1560f0..7d6d8774385 100644
---
a/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBRestServiceIT.java
+++
b/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBRestServiceIT.java
@@ -1399,6 +1399,7 @@ public class IoTDBRestServiceIT {
List<Object> columnNames =
new ArrayList<Object>() {
{
+ add(ColumnHeaderConstant.USER_ID);
add(ColumnHeaderConstant.USER);
}
};
@@ -1409,7 +1410,7 @@ public class IoTDBRestServiceIT {
}
};
Assert.assertEquals(columnNames, columnNamesResult);
- Assert.assertEquals(values1, valuesResult.get(0));
+ Assert.assertEquals(values1, valuesResult.get(1));
}
public void selectCount(CloseableHttpClient httpClient) {
@@ -2062,6 +2063,7 @@ public class IoTDBRestServiceIT {
List<Object> columnNames =
new ArrayList<Object>() {
{
+ add(ColumnHeaderConstant.USER_ID);
add(ColumnHeaderConstant.USER);
}
};
@@ -2072,7 +2074,7 @@ public class IoTDBRestServiceIT {
}
};
Assert.assertEquals(columnNames, columnNamesResult);
- Assert.assertEquals(values1, valuesResult.get(0));
+ Assert.assertEquals(values1, valuesResult.get(1));
}
public void selectCountV2(CloseableHttpClient httpClient) {
diff --git
a/integration-test/src/test/java/org/apache/iotdb/db/it/auth/IoTDBAuthIT.java
b/integration-test/src/test/java/org/apache/iotdb/db/it/auth/IoTDBAuthIT.java
index e9425aa9444..c06658c1481 100644
---
a/integration-test/src/test/java/org/apache/iotdb/db/it/auth/IoTDBAuthIT.java
+++
b/integration-test/src/test/java/org/apache/iotdb/db/it/auth/IoTDBAuthIT.java
@@ -99,7 +99,8 @@ public class IoTDBAuthIT {
ResultSet resultSet = userStmt.executeQuery("LIST USER");
Assert.assertTrue(resultSet.next());
- Assert.assertEquals("tempuser", resultSet.getString(1));
+ Assert.assertEquals("10000", resultSet.getString(1));
+ Assert.assertEquals("tempuser", resultSet.getString(2));
Assert.assertFalse(resultSet.next());
resultSet = userStmt.executeQuery("LIST PRIVILEGES OF USER tempuser");
@@ -469,7 +470,7 @@ public class IoTDBAuthIT {
try {
ResultSet resultSet = adminStmt.executeQuery("LIST USER");
- String ans = "root,\n";
+ String ans = "0,root,\n";
try {
validateResultSet(resultSet, ans);
@@ -478,17 +479,17 @@ public class IoTDBAuthIT {
}
resultSet = adminStmt.executeQuery("LIST USER");
ans =
- "root,\n"
- + "user0,\n"
- + "user1,\n"
- + "user2,\n"
- + "user3,\n"
- + "user4,\n"
- + "user5,\n"
- + "user6,\n"
- + "user7,\n"
- + "user8,\n"
- + "user9,\n";
+ "0,root,\n"
+ + "10000,user0,\n"
+ + "10001,user1,\n"
+ + "10002,user2,\n"
+ + "10003,user3,\n"
+ + "10004,user4,\n"
+ + "10005,user5,\n"
+ + "10006,user6,\n"
+ + "10007,user7,\n"
+ + "10008,user8,\n"
+ + "10009,user9,\n";
validateResultSet(resultSet, ans);
for (int i = 0; i < 10; i++) {
@@ -497,7 +498,13 @@ public class IoTDBAuthIT {
}
}
resultSet = adminStmt.executeQuery("LIST USER");
- ans = "root,\n" + "user1,\n" + "user3,\n" + "user5,\n" + "user7,\n" +
"user9,\n";
+ ans =
+ "0,root,\n"
+ + "10001,user1,\n"
+ + "10003,user3,\n"
+ + "10005,user5,\n"
+ + "10007,user7,\n"
+ + "10009,user9,\n";
validateResultSet(resultSet, ans);
} finally {
resultSet.close();
@@ -581,7 +588,7 @@ public class IoTDBAuthIT {
ans = "role1,\nrole2,\n";
validateResultSet(resultSet, ans);
resultSet = userStmt.executeQuery("LIST USER OF ROLE role1");
- ans = "user1,\nuser2,\n";
+ ans = "10000,user1,\n10001,user2,\n";
validateResultSet(resultSet, ans);
} finally {
userStmt.close();
@@ -764,25 +771,25 @@ public class IoTDBAuthIT {
ResultSet resultSet = adminStmt.executeQuery("LIST USER OF ROLE dalao");
String ans =
- "DailySecurity,\n"
- + "DoubleLight,\n"
- + "East,\n"
- + "Eastwards,\n"
- + "GoldLuck,\n"
- + "GoodWoods,\n"
- + "HealthHonor,\n"
- + "HighFly,\n"
- + "Moon,\n"
- + "Persistence,\n"
- + "RayBud,\n"
- + "ScentEffusion,\n"
- + "Smart,\n"
- + "SunComparison,\n";
+ "10011,DailySecurity,\n"
+ + "10006,DoubleLight,\n"
+ + "10010,East,\n"
+ + "10007,Eastwards,\n"
+ + "10005,GoldLuck,\n"
+ + "10003,GoodWoods,\n"
+ + "10004,HealthHonor,\n"
+ + "10000,HighFly,\n"
+ + "10012,Moon,\n"
+ + "10002,Persistence,\n"
+ + "10013,RayBud,\n"
+ + "10008,ScentEffusion,\n"
+ + "10009,Smart,\n"
+ + "10001,SunComparison,\n";
try {
validateResultSet(resultSet, ans);
resultSet = adminStmt.executeQuery("LIST USER OF ROLE zhazha");
- ans = "RiverSky,\n";
+ ans = "10014,RiverSky,\n";
validateResultSet(resultSet, ans);
adminStmt.execute("REVOKE ROLE zhazha from RiverSky");
@@ -837,25 +844,25 @@ public class IoTDBAuthIT {
try (Connection userCon = EnvFactory.getEnv().getConnection("tempuser",
"temppw123456");
Statement userStmt = userCon.createStatement()) {
try {
- String ans = "tempuser,\n";
+ String ans = "10010,tempuser,\n";
ResultSet resultSet = userStmt.executeQuery("LIST USER");
validateResultSet(resultSet, ans);
// with list user privilege
adminStmt.execute("GRANT SECURITY on root.** TO USER tempuser");
resultSet = userStmt.executeQuery("LIST USER");
ans =
- "root,\n"
- + "tempuser,\n"
- + "user0,\n"
- + "user1,\n"
- + "user2,\n"
- + "user3,\n"
- + "user4,\n"
- + "user5,\n"
- + "user6,\n"
- + "user7,\n"
- + "user8,\n"
- + "user9,\n";
+ "0,root,\n"
+ + "10010,tempuser,\n"
+ + "10000,user0,\n"
+ + "10001,user1,\n"
+ + "10002,user2,\n"
+ + "10003,user3,\n"
+ + "10004,user4,\n"
+ + "10005,user5,\n"
+ + "10006,user6,\n"
+ + "10007,user7,\n"
+ + "10008,user8,\n"
+ + "10009,user9,\n";
validateResultSet(resultSet, ans);
} finally {
userStmt.close();
diff --git
a/integration-test/src/test/java/org/apache/iotdb/db/it/auth/IoTDBRelationalAuthIT.java
b/integration-test/src/test/java/org/apache/iotdb/db/it/auth/IoTDBRelationalAuthIT.java
index 073d05599ce..d3e05027cc1 100644
---
a/integration-test/src/test/java/org/apache/iotdb/db/it/auth/IoTDBRelationalAuthIT.java
+++
b/integration-test/src/test/java/org/apache/iotdb/db/it/auth/IoTDBRelationalAuthIT.java
@@ -72,7 +72,8 @@ public class IoTDBRelationalAuthIT {
Statement userStmt = userCon.createStatement()) {
ResultSet resultSet = userStmt.executeQuery("LIST USER");
Assert.assertTrue(resultSet.next());
- Assert.assertEquals("testuser", resultSet.getString(1));
+ Assert.assertEquals("10000", resultSet.getString(1));
+ Assert.assertEquals("testuser", resultSet.getString(2));
Assert.assertFalse(resultSet.next());
}
adminStmt.execute("create database testdb");
@@ -136,7 +137,7 @@ public class IoTDBRelationalAuthIT {
adminStmt.execute("create role testrole");
adminStmt.execute("GRANT ROLE testrole to testuser");
rs = adminStmt.executeQuery("LIST USER OF ROLE testrole");
- TestUtils.assertResultSetEqual(rs, "User,",
Collections.singleton("testuser,"));
+ TestUtils.assertResultSetEqual(rs, "UserId,User,",
Collections.singleton("10000,testuser,"));
rs = adminStmt.executeQuery("LIST ROLE OF USER testuser");
TestUtils.assertResultSetEqual(rs, "Role,",
Collections.singleton("testrole,"));
}
@@ -533,11 +534,11 @@ public class IoTDBRelationalAuthIT {
ResultSet resultSet = adminStmt.executeQuery("List user");
Set<String> resultSetList = new HashSet<>();
- resultSetList.add("root,");
- resultSetList.add("testuser,");
- resultSetList.add("!@#$%^*()_+-=1,");
- resultSetList.add("!@#$%^*()_+-=2,");
- TestUtils.assertResultSetEqual(resultSet, "User,", resultSetList);
+ resultSetList.add("0,root,");
+ resultSetList.add("10000,testuser,");
+ resultSetList.add("10001,!@#$%^*()_+-=1,");
+ resultSetList.add("10002,!@#$%^*()_+-=2,");
+ TestUtils.assertResultSetEqual(resultSet, "UserId,User,", resultSetList);
resultSet = adminStmt.executeQuery("List role");
TestUtils.assertResultSetEqual(resultSet, "Role,",
Collections.singleton("!@#$%^*()_+-=3,"));
adminStmt.execute("GRANT role \"!@#$%^*()_+-=3\" to
\"!@#$%^*()_+-=1\"");
diff --git
a/integration-test/src/test/java/org/apache/iotdb/pipe/it/dual/treemodel/manual/IoTDBPipeMetaHistoricalIT.java
b/integration-test/src/test/java/org/apache/iotdb/pipe/it/dual/treemodel/manual/IoTDBPipeMetaHistoricalIT.java
index 6d38f7f95bb..2daa6cda9e6 100644
---
a/integration-test/src/test/java/org/apache/iotdb/pipe/it/dual/treemodel/manual/IoTDBPipeMetaHistoricalIT.java
+++
b/integration-test/src/test/java/org/apache/iotdb/pipe/it/dual/treemodel/manual/IoTDBPipeMetaHistoricalIT.java
@@ -230,8 +230,8 @@ public class IoTDBPipeMetaHistoricalIT extends
AbstractPipeDualTreeModelManualIT
TestUtils.assertDataEventuallyOnEnv(
receiverEnv,
"list user of role `admin`",
- ColumnHeaderConstant.USER + ",",
- Collections.singleton("thulab,"));
+ ColumnHeaderConstant.USER_ID + "," + ColumnHeaderConstant.USER + ",",
+ Collections.singleton("10000,thulab,"));
TestUtils.assertDataEventuallyOnEnv(
receiverEnv,
"list privileges of role `admin`",
diff --git
a/integration-test/src/test/java/org/apache/iotdb/pipe/it/dual/treemodel/manual/IoTDBPipePermissionIT.java
b/integration-test/src/test/java/org/apache/iotdb/pipe/it/dual/treemodel/manual/IoTDBPipePermissionIT.java
index 320dd7db749..085ed30e7f3 100644
---
a/integration-test/src/test/java/org/apache/iotdb/pipe/it/dual/treemodel/manual/IoTDBPipePermissionIT.java
+++
b/integration-test/src/test/java/org/apache/iotdb/pipe/it/dual/treemodel/manual/IoTDBPipePermissionIT.java
@@ -147,8 +147,8 @@ public class IoTDBPipePermissionIT extends
AbstractPipeDualTreeModelManualIT {
TestUtils.assertDataEventuallyOnEnv(
receiverEnv,
"list user",
- "User,",
- new HashSet<>(Arrays.asList("root,", "user,", "thulab,")));
+ "UserId,User,",
+ new HashSet<>(Arrays.asList("0,root,", "10001,user,",
"10000,thulab,")));
final Set<String> expectedResSet = new HashSet<>();
expectedResSet.add(
"root.ln.wf02.wt01.temperature,null,root.ln,INT64,PLAIN,LZ4,null,null,null,null,BASE,");
diff --git
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/consensus/response/auth/PermissionInfoResp.java
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/consensus/response/auth/PermissionInfoResp.java
index 70413d552db..de440336753 100644
---
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/consensus/response/auth/PermissionInfoResp.java
+++
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/consensus/response/auth/PermissionInfoResp.java
@@ -20,6 +20,7 @@
package org.apache.iotdb.confignode.consensus.response.auth;
import org.apache.iotdb.common.rpc.thrift.TSStatus;
+import org.apache.iotdb.confignode.rpc.thrift.TListUserInfo;
import org.apache.iotdb.confignode.rpc.thrift.TPermissionInfoResp;
import org.apache.iotdb.consensus.common.DataSet;
@@ -32,6 +33,8 @@ public class PermissionInfoResp implements DataSet {
private String tag;
private List<String> memberList;
+ private List<TListUserInfo> usersInfo;
+
private TPermissionInfoResp permissionInfoResp;
public PermissionInfoResp() {}
@@ -62,6 +65,14 @@ public class PermissionInfoResp implements DataSet {
return memberList;
}
+ public void setUsersInfo(List<TListUserInfo> usersInfo) {
+ this.usersInfo = usersInfo;
+ }
+
+ public List<TListUserInfo> getUsersInfo() {
+ return usersInfo;
+ }
+
public TPermissionInfoResp getPermissionInfoResp() {
return permissionInfoResp;
}
diff --git
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/PermissionManager.java
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/PermissionManager.java
index 46549c67449..605e5785e9e 100644
---
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/PermissionManager.java
+++
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/PermissionManager.java
@@ -141,4 +141,8 @@ public class PermissionManager {
public TPermissionInfoResp getUser(String username) throws AuthException {
return authorInfo.getUser(username);
}
+
+ public String getUserName(long userId) throws AuthException {
+ return authorInfo.getUserName(userId);
+ }
}
diff --git
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/pipe/event/PipeConfigRegionSnapshotEvent.java
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/pipe/event/PipeConfigRegionSnapshotEvent.java
index df76f4fe7df..5a8465e99d5 100644
---
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/pipe/event/PipeConfigRegionSnapshotEvent.java
+++
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/pipe/event/PipeConfigRegionSnapshotEvent.java
@@ -60,6 +60,8 @@ public class PipeConfigRegionSnapshotEvent extends
PipeSnapshotEvent
SNAPSHOT_FILE_TYPE_2_CONFIG_PHYSICAL_PLAN_TYPE_MAP = new
EnumMap<>(CNSnapshotFileType.class);
private CNSnapshotFileType fileType;
+ private String authUserName = "";
+
static {
SNAPSHOT_FILE_TYPE_2_CONFIG_PHYSICAL_PLAN_TYPE_MAP.put(
CNSnapshotFileType.ROLE,
@@ -136,6 +138,14 @@ public class PipeConfigRegionSnapshotEvent extends
PipeSnapshotEvent
this.fileType = type;
}
+ public String getAuthUserName() {
+ return authUserName;
+ }
+
+ public void setAuthUserName(String authUserName) {
+ this.authUserName = authUserName;
+ }
+
public File getSnapshotFile() {
return new File(snapshotPath);
}
@@ -195,17 +205,20 @@ public class PipeConfigRegionSnapshotEvent extends
PipeSnapshotEvent
final boolean skipIfNoPrivileges,
final long startTime,
final long endTime) {
- return new PipeConfigRegionSnapshotEvent(
- snapshotPath,
- templateFilePath,
- fileType,
- pipeName,
- creationTime,
- pipeTaskMeta,
- treePattern,
- tablePattern,
- userName,
- skipIfNoPrivileges);
+ PipeConfigRegionSnapshotEvent pipeConfigRegionSnapshotEvent =
+ new PipeConfigRegionSnapshotEvent(
+ snapshotPath,
+ templateFilePath,
+ fileType,
+ pipeName,
+ creationTime,
+ pipeTaskMeta,
+ treePattern,
+ tablePattern,
+ userName,
+ skipIfNoPrivileges);
+ pipeConfigRegionSnapshotEvent.setAuthUserName(authUserName);
+ return pipeConfigRegionSnapshotEvent;
}
@Override
diff --git
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/pipe/receiver/protocol/IoTDBConfigNodeReceiver.java
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/pipe/receiver/protocol/IoTDBConfigNodeReceiver.java
index 5d00996ec61..d52ad5cd7e8 100644
---
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/pipe/receiver/protocol/IoTDBConfigNodeReceiver.java
+++
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/pipe/receiver/protocol/IoTDBConfigNodeReceiver.java
@@ -1033,7 +1033,8 @@ public class IoTDBConfigNodeReceiver extends
IoTDBFileReceiver {
Paths.get(fileAbsolutePaths.get(0)),
fileAbsolutePaths.size() > 1 ? Paths.get(fileAbsolutePaths.get(1))
: null,
CNSnapshotFileType.deserialize(
-
Byte.parseByte(parameters.get(PipeTransferConfigSnapshotSealReq.FILE_TYPE))));
+
Byte.parseByte(parameters.get(PipeTransferConfigSnapshotSealReq.FILE_TYPE))),
+ parameters.getOrDefault("authUserName", ""));
if (Objects.isNull(generator)) {
throw new IOException(
String.format("The config region snapshots %s cannot be parsed.",
fileAbsolutePaths));
diff --git
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/pipe/sink/payload/PipeTransferConfigSnapshotSealReq.java
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/pipe/sink/payload/PipeTransferConfigSnapshotSealReq.java
index 1162e8ade94..90a13f32e49 100644
---
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/pipe/sink/payload/PipeTransferConfigSnapshotSealReq.java
+++
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/pipe/sink/payload/PipeTransferConfigSnapshotSealReq.java
@@ -58,7 +58,8 @@ public class PipeTransferConfigSnapshotSealReq extends
PipeTransferFileSealReqV2
final String templateFileName,
final long templateFileLength,
final CNSnapshotFileType fileType,
- final String typeString)
+ final String typeString,
+ final String authUserName)
throws IOException {
final Map<String, String> parameters = new HashMap<>();
parameters.put(ColumnHeaderConstant.PATH_PATTERN, treePattern);
@@ -72,6 +73,7 @@ public class PipeTransferConfigSnapshotSealReq extends
PipeTransferFileSealReqV2
}
parameters.put(FILE_TYPE, Byte.toString(fileType.getType()));
parameters.put(ColumnHeaderConstant.TYPE, typeString);
+ parameters.put("authUserName", authUserName);
return (PipeTransferConfigSnapshotSealReq)
new PipeTransferConfigSnapshotSealReq()
@@ -103,7 +105,8 @@ public class PipeTransferConfigSnapshotSealReq extends
PipeTransferFileSealReqV2
final String templateFileName,
final long templateFileLength,
final CNSnapshotFileType fileType,
- final String typeString)
+ final String typeString,
+ final String authUserName)
throws IOException {
final Map<String, String> parameters = new HashMap<>();
parameters.put(ColumnHeaderConstant.PATH_PATTERN, treePattern);
@@ -117,6 +120,7 @@ public class PipeTransferConfigSnapshotSealReq extends
PipeTransferFileSealReqV2
}
parameters.put(FILE_TYPE, Byte.toString(fileType.getType()));
parameters.put(ColumnHeaderConstant.TYPE, typeString);
+ parameters.put("authUserName", authUserName);
return new PipeTransferConfigSnapshotSealReq()
.convertToTPipeTransferSnapshotSealBytes(
Objects.nonNull(templateFileName)
diff --git
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/pipe/sink/protocol/IoTDBConfigRegionAirGapSink.java
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/pipe/sink/protocol/IoTDBConfigRegionAirGapSink.java
index 5f32bae8c27..1c577e4adb9 100644
---
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/pipe/sink/protocol/IoTDBConfigRegionAirGapSink.java
+++
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/pipe/sink/protocol/IoTDBConfigRegionAirGapSink.java
@@ -237,7 +237,8 @@ public class IoTDBConfigRegionAirGapSink extends
IoTDBAirGapSink {
Objects.nonNull(templateFile) ? templateFile.getName() : null,
Objects.nonNull(templateFile) ? templateFile.length() : 0,
pipeConfigRegionSnapshotEvent.getFileType(),
- pipeConfigRegionSnapshotEvent.toSealTypeString()))) {
+ pipeConfigRegionSnapshotEvent.toSealTypeString(),
+ pipeConfigRegionSnapshotEvent.getAuthUserName()))) {
final String errorMessage =
String.format("Seal config region snapshot %s error. Socket %s.",
snapshot, socket);
// Send handshake because we don't know whether the receiver side
configNode
diff --git
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/pipe/sink/protocol/IoTDBConfigRegionSink.java
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/pipe/sink/protocol/IoTDBConfigRegionSink.java
index e846410b5e7..b93a0b92be8 100644
---
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/pipe/sink/protocol/IoTDBConfigRegionSink.java
+++
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/pipe/sink/protocol/IoTDBConfigRegionSink.java
@@ -246,7 +246,8 @@ public class IoTDBConfigRegionSink extends IoTDBSslSyncSink
{
Objects.nonNull(templateFile) ? templateFile.getName() :
null,
Objects.nonNull(templateFile) ? templateFile.length() : 0,
snapshotEvent.getFileType(),
- snapshotEvent.toSealTypeString()));
+ snapshotEvent.toSealTypeString(),
+ snapshotEvent.getAuthUserName()));
rateLimitIfNeeded(
snapshotEvent.getPipeName(),
snapshotEvent.getCreationTime(),
diff --git
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/pipe/source/ConfigRegionListeningQueue.java
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/pipe/source/ConfigRegionListeningQueue.java
index 94ea7a54dde..b70a039da44 100644
---
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/pipe/source/ConfigRegionListeningQueue.java
+++
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/pipe/source/ConfigRegionListeningQueue.java
@@ -19,6 +19,7 @@
package org.apache.iotdb.confignode.manager.pipe.source;
+import org.apache.iotdb.commons.auth.AuthException;
import org.apache.iotdb.commons.auth.user.LocalFileUserAccessor;
import org.apache.iotdb.commons.conf.IoTDBConstant;
import org.apache.iotdb.commons.exception.MetadataException;
@@ -135,25 +136,39 @@ public class ConfigRegionListeningQueue extends
AbstractPipeListeningQueue
&& snapshotPath
.toFile()
.getName()
- .equals(AuthorityChecker.SUPER_USER +
IoTDBConstant.PROFILE_SUFFIX)
+ .equals(AuthorityChecker.SUPER_USER_ID_IN_STR +
IoTDBConstant.PROFILE_SUFFIX)
|| type == CNSnapshotFileType.USER_ROLE
&& snapshotPath
.toFile()
.getName()
.equals(
- AuthorityChecker.SUPER_USER
+ AuthorityChecker.SUPER_USER_ID_IN_STR
+ LocalFileUserAccessor.ROLE_SUFFIX
- + IoTDBConstant.PROFILE_SUFFIX)) {
+ + IoTDBConstant.PROFILE_SUFFIX)
+ || snapshotPath.toFile().getName().equals("user_id.profile")) {
continue;
}
final Path templateFilePath = snapshotPathInfo.getLeft().getRight();
- events.add(
+ PipeConfigRegionSnapshotEvent curEvent =
new PipeConfigRegionSnapshotEvent(
snapshotPath.toString(),
Objects.nonNull(templateFilePath) &&
templateFilePath.toFile().length() > 0
? templateFilePath.toString()
: null,
- snapshotPathInfo.getRight()));
+ snapshotPathInfo.getRight());
+ if (type == CNSnapshotFileType.USER_ROLE) {
+ long userId =
Long.parseLong(snapshotPath.toFile().getName().split("_")[0]);
+ try {
+ curEvent.setAuthUserName(
+ ConfigNode.getInstance()
+ .getConfigManager()
+ .getPermissionManager()
+ .getUserName(userId));
+ } catch (AuthException e) {
+ LOGGER.warn("Failed to collect user name for user id {}", userId, e);
+ }
+ }
+ events.add(curEvent);
}
tryListen(events);
}
diff --git
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/pipe/source/IoTDBConfigRegionSource.java
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/pipe/source/IoTDBConfigRegionSource.java
index ef1e08f8536..fc965624c1d 100644
---
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/pipe/source/IoTDBConfigRegionSource.java
+++
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/pipe/source/IoTDBConfigRegionSource.java
@@ -203,7 +203,8 @@ public class IoTDBConfigRegionSource extends
IoTDBNonDataRegionSource {
Objects.nonNull(snapshotEvent.getTemplateFile())
? Paths.get(snapshotEvent.getTemplateFile().getPath())
: null,
- snapshotEvent.getFileType());
+ snapshotEvent.getFileType(),
+ snapshotEvent.getAuthUserName());
}
@Override
diff --git
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/AuthorInfo.java
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/AuthorInfo.java
index e4d2c17bfac..efcbd894360 100644
---
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/AuthorInfo.java
+++
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/AuthorInfo.java
@@ -46,6 +46,7 @@ import
org.apache.iotdb.confignode.consensus.request.write.auth.AuthorTreePlan;
import org.apache.iotdb.confignode.consensus.response.auth.PermissionInfoResp;
import org.apache.iotdb.confignode.manager.ConfigManager;
import org.apache.iotdb.confignode.rpc.thrift.TAuthizedPatternTreeResp;
+import org.apache.iotdb.confignode.rpc.thrift.TListUserInfo;
import org.apache.iotdb.confignode.rpc.thrift.TPermissionInfoResp;
import org.apache.iotdb.confignode.rpc.thrift.TRoleResp;
import org.apache.iotdb.confignode.rpc.thrift.TUserResp;
@@ -62,6 +63,7 @@ import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
@@ -510,13 +512,17 @@ public class AuthorInfo implements SnapshotProcessor {
public PermissionInfoResp executeListUsers(final AuthorPlan plan) throws
AuthException {
final PermissionInfoResp result = new PermissionInfoResp();
final List<String> userList;
+ final List<TListUserInfo> userInfoList;
boolean hasPermissionToListOtherUsers = plan.getUserName().isEmpty();
if (!hasPermissionToListOtherUsers) {
// userList may be modified later
userList = new ArrayList<>(1);
userList.add(plan.getUserName());
+ User user = authorizer.getUser(plan.getUserName());
+ userInfoList = Collections.singletonList(user.convertToListUserInfo());
} else {
userList = authorizer.listAllUsers();
+ userInfoList = authorizer.listAllUsersInfo();
}
if (!plan.getRoleName().isEmpty()) {
final Role role = authorizer.getRole(plan.getRoleName());
@@ -527,8 +533,19 @@ public class AuthorInfo implements SnapshotProcessor {
return result;
}
final Iterator<String> itr = userList.iterator();
+ Set<String> toRemove = new HashSet<>();
while (itr.hasNext()) {
- User userObj = authorizer.getUser(itr.next());
+ String userName = itr.next();
+ User userObj = authorizer.getUser(userName);
+ if (userObj == null || !userObj.hasRole(plan.getRoleName())) {
+ itr.remove();
+ toRemove.add(userName);
+ }
+ }
+ userInfoList.removeIf(info -> toRemove.contains(info.username));
+ final Iterator<TListUserInfo> userInfoitr = userInfoList.iterator();
+ while (itr.hasNext()) {
+ User userObj = authorizer.getUser(userInfoitr.next().getUsername());
if (userObj == null || !userObj.hasRole(plan.getRoleName())) {
itr.remove();
}
@@ -536,6 +553,7 @@ public class AuthorInfo implements SnapshotProcessor {
}
result.setTag(ColumnHeaderConstant.USER);
result.setMemberInfo(userList);
+ result.setUsersInfo(userInfoList);
result.setStatus(RpcUtils.getStatus(TSStatusCode.SUCCESS_STATUS));
return result;
}
@@ -674,6 +692,10 @@ public class AuthorInfo implements SnapshotProcessor {
return result;
}
+ public String getUserName(long userId) throws AuthException {
+ return authorizer.getUser(userId).getName();
+ }
+
@Override
public boolean processTakeSnapshot(File snapshotDir) throws TException,
IOException {
return authorizer.processTakeSnapshot(snapshotDir);
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 33fb4b4ed6d..b81b14ef504 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
@@ -103,14 +103,15 @@ public class CNPhysicalPlanGenerator
private Exception latestException = null;
private String userName;
- public CNPhysicalPlanGenerator(final Path snapshotFilePath, final
CNSnapshotFileType fileType)
+ public CNPhysicalPlanGenerator(
+ final Path snapshotFilePath, final CNSnapshotFileType fileType, final
String userName)
throws IOException {
if (fileType == CNSnapshotFileType.SCHEMA) {
logger.warn("schema_template need two files");
return;
}
if (fileType == CNSnapshotFileType.USER_ROLE) {
- userName =
snapshotFilePath.getFileName().toString().split("_role.profile")[0];
+ this.userName = userName;
}
snapshotFileType = fileType;
inputStream = Files.newInputStream(snapshotFilePath);
@@ -200,9 +201,14 @@ public class CNPhysicalPlanGenerator
int tag = dataInputStream.readInt();
boolean fromOldVersion = tag < 0;
String user;
- if (fromOldVersion) {
+ if (tag < 0) {
user = readString(dataInputStream, STRING_ENCODING, strBufferLocal, -1
* tag);
+ } else if (tag == 1) {
+ user = readString(dataInputStream, STRING_ENCODING, strBufferLocal);
} else {
+ if (isUser) {
+ dataInputStream.readLong(); // skip userId since authorPlan do not
demand it.
+ }
user = readString(dataInputStream, STRING_ENCODING, strBufferLocal);
}
@@ -226,7 +232,7 @@ public class CNPhysicalPlanGenerator
final int privilegeMask = dataInputStream.readInt();
generateGrantSysPlan(user, isUser, privilegeMask);
- if (fromOldVersion) {
+ if (tag < 0) {
while (dataInputStream.available() != 0) {
final String path = readString(dataInputStream, STRING_ENCODING,
strBufferLocal);
final PartialPath priPath;
diff --git
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/schema/ConfigNodeSnapshotParser.java
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/schema/ConfigNodeSnapshotParser.java
index 31b1cd56519..84126441694 100644
---
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/schema/ConfigNodeSnapshotParser.java
+++
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/schema/ConfigNodeSnapshotParser.java
@@ -166,7 +166,8 @@ public class ConfigNodeSnapshotParser {
}
public static CNPhysicalPlanGenerator translate2PhysicalPlan(
- final Path path1, final Path path2, final CNSnapshotFileType type)
throws IOException {
+ final Path path1, final Path path2, final CNSnapshotFileType type, final
String userName)
+ throws IOException {
if (path1 == null) {
LOGGER.warn("Path1 should not be null");
return null;
@@ -180,7 +181,7 @@ public class ConfigNodeSnapshotParser {
if (type == CNSnapshotFileType.SCHEMA) {
return new CNPhysicalPlanGenerator(path1, path2);
} else {
- return new CNPhysicalPlanGenerator(path1, type);
+ return new CNPhysicalPlanGenerator(path1, type, userName);
}
}
}
diff --git
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/service/thrift/ConfigNodeRPCServiceProcessor.java
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/service/thrift/ConfigNodeRPCServiceProcessor.java
index 97c9c18d52a..fbb9d69fea6 100644
---
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/service/thrift/ConfigNodeRPCServiceProcessor.java
+++
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/service/thrift/ConfigNodeRPCServiceProcessor.java
@@ -670,6 +670,7 @@ public class ConfigNodeRPCServiceProcessor implements
IConfigNodeRPCService.Ifac
resp.setMemberInfo(dataSet.getMemberList());
resp.setPermissionInfo(dataSet.getPermissionInfoResp());
resp.setTag(dataSet.getTag());
+ resp.setUsersInfo(dataSet.getUsersInfo());
return resp;
}
@@ -712,6 +713,7 @@ public class ConfigNodeRPCServiceProcessor implements
IConfigNodeRPCService.Ifac
final TAuthorizerResp resp = new TAuthorizerResp(dataSet.getStatus());
resp.setMemberInfo(dataSet.getMemberList());
resp.setPermissionInfo(dataSet.getPermissionInfoResp());
+ resp.setUsersInfo(dataSet.getUsersInfo());
resp.setTag(dataSet.getTag());
return resp;
}
diff --git
a/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/manager/pipe/sink/PipeConfigNodeThriftRequestTest.java
b/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/manager/pipe/sink/PipeConfigNodeThriftRequestTest.java
index 0f729c7b4b0..5c578ebead8 100644
---
a/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/manager/pipe/sink/PipeConfigNodeThriftRequestTest.java
+++
b/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/manager/pipe/sink/PipeConfigNodeThriftRequestTest.java
@@ -96,7 +96,8 @@ public class PipeConfigNodeThriftRequestTest {
templateInfoName,
10,
fileType,
- typeString);
+ typeString,
+ "");
PipeTransferConfigSnapshotSealReq deserializeReq =
PipeTransferConfigSnapshotSealReq.fromTPipeTransferReq(req);
diff --git
a/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/persistence/CNPhysicalPlanGeneratorTest.java
b/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/persistence/CNPhysicalPlanGeneratorTest.java
index 647b50fdcf5..19622c80906 100644
---
a/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/persistence/CNPhysicalPlanGeneratorTest.java
+++
b/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/persistence/CNPhysicalPlanGeneratorTest.java
@@ -178,7 +178,7 @@ public class CNPhysicalPlanGeneratorTest {
+ ".profile");
final CNPhysicalPlanGenerator planGenerator =
- new CNPhysicalPlanGenerator(roleProfile.toPath(),
CNSnapshotFileType.ROLE);
+ new CNPhysicalPlanGenerator(roleProfile.toPath(),
CNSnapshotFileType.ROLE, "");
int count = 0;
for (ConfigPhysicalPlan authPlan : planGenerator) {
Assert.assertTrue(answerSet.contains(authPlan.hashCode()));
@@ -260,11 +260,11 @@ public class CNPhysicalPlanGeneratorTest {
+ File.separator
+ USER_SNAPSHOT_FILE_NAME
+ File.separator
- + userName
+ + 10000
+ ".profile");
CNPhysicalPlanGenerator planGenerator =
- new CNPhysicalPlanGenerator(userProfile.toPath(),
CNSnapshotFileType.USER);
+ new CNPhysicalPlanGenerator(userProfile.toPath(),
CNSnapshotFileType.USER, userName);
int count = 0;
// plan 1-4
for (ConfigPhysicalPlan authPlan : planGenerator) {
@@ -278,10 +278,11 @@ public class CNPhysicalPlanGeneratorTest {
+ File.separator
+ USER_SNAPSHOT_FILE_NAME
+ File.separator
- + userName
+ + 10000
+ "_role.profile");
planGenerator =
- new CNPhysicalPlanGenerator(roleListProfile.toPath(),
CNSnapshotFileType.USER_ROLE);
+ new CNPhysicalPlanGenerator(
+ roleListProfile.toPath(), CNSnapshotFileType.USER_ROLE, userName);
count = 0;
// plan 5
for (ConfigPhysicalPlan authPlan : planGenerator) {
@@ -345,7 +346,7 @@ public class CNPhysicalPlanGeneratorTest {
}
planGenerator.checkException();
Assert.assertEquals(5, count);
- planGenerator = new CNPhysicalPlanGenerator(ttlInfo.toPath(),
CNSnapshotFileType.TTL);
+ planGenerator = new CNPhysicalPlanGenerator(ttlInfo.toPath(),
CNSnapshotFileType.TTL, "");
for (ConfigPhysicalPlan plan : planGenerator) {
if (plan.getType() == ConfigPhysicalPlanType.SetTTL) {
if (!new PartialPath(((SetTTLPlan) plan).getPathPattern())
@@ -510,7 +511,7 @@ public class CNPhysicalPlanGeneratorTest {
}
Assert.assertEquals(8, count);
- planGenerator = new CNPhysicalPlanGenerator(ttlInfo.toPath(),
CNSnapshotFileType.TTL);
+ planGenerator = new CNPhysicalPlanGenerator(ttlInfo.toPath(),
CNSnapshotFileType.TTL, "");
for (ConfigPhysicalPlan plan : planGenerator) {
if (plan.getType() == ConfigPhysicalPlanType.SetTTL) {
if (!new PartialPath(((SetTTLPlan) plan).getPathPattern())
diff --git
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/auth/AuthorityChecker.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/auth/AuthorityChecker.java
index b67987159b7..17f21627264 100644
---
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/auth/AuthorityChecker.java
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/auth/AuthorityChecker.java
@@ -30,6 +30,7 @@ import
org.apache.iotdb.commons.schema.column.ColumnHeaderConstant;
import org.apache.iotdb.commons.service.metric.PerformanceOverviewMetrics;
import org.apache.iotdb.confignode.rpc.thrift.TAuthorizerResp;
import org.apache.iotdb.confignode.rpc.thrift.TDBPrivilege;
+import org.apache.iotdb.confignode.rpc.thrift.TListUserInfo;
import org.apache.iotdb.confignode.rpc.thrift.TPathPrivilege;
import org.apache.iotdb.confignode.rpc.thrift.TRoleResp;
import org.apache.iotdb.confignode.rpc.thrift.TTablePrivilege;
@@ -44,7 +45,6 @@ import
org.apache.iotdb.db.queryengine.plan.relational.security.TreeAccessCheckV
import
org.apache.iotdb.db.queryengine.plan.relational.sql.ast.RelationalAuthorStatement;
import org.apache.iotdb.db.queryengine.plan.statement.Statement;
import org.apache.iotdb.db.queryengine.plan.statement.sys.AuthorStatement;
-import org.apache.iotdb.rpc.RpcUtils;
import org.apache.iotdb.rpc.TSStatusCode;
import com.google.common.util.concurrent.SettableFuture;
@@ -63,6 +63,7 @@ import java.util.Set;
import java.util.StringJoiner;
import java.util.stream.Collectors;
+import static
org.apache.iotdb.commons.schema.column.ColumnHeaderConstant.LIST_USER_COLUMN_HEADERS;
import static
org.apache.iotdb.commons.schema.column.ColumnHeaderConstant.LIST_USER_OR_ROLE_PRIVILEGES_COLUMN_HEADERS;
// Authority checker is SingleTon working at datanode.
@@ -71,7 +72,9 @@ public class AuthorityChecker {
public static String SUPER_USER =
CommonDescriptor.getInstance().getConfig().getAdminName();
- public static final TSStatus SUCCEED = RpcUtils.SUCCESS_STATUS;
+ public static String SUPER_USER_ID_IN_STR = "0";
+
+ public static final TSStatus SUCCEED = new
TSStatus(TSStatusCode.SUCCESS_STATUS.getStatusCode());
public static final String ONLY_ADMIN_ALLOWED =
"No permissions for this operation, only root user is allowed";
@@ -383,7 +386,7 @@ public class AuthorityChecker {
List<ColumnHeader> headerList = new ArrayList<>();
TsBlockBuilder builder;
- if (listRoleUser) {
+ if (authResp.tag.equals(ColumnHeaderConstant.ROLE)) {
headerList.add(new ColumnHeader(authResp.getTag(), TSDataType.TEXT));
types.add(TSDataType.TEXT);
builder = new TsBlockBuilder(types);
@@ -392,6 +395,22 @@ public class AuthorityChecker {
builder.getColumnBuilder(0).writeBinary(new Binary(name,
TSFileConfig.STRING_CHARSET));
builder.declarePosition();
}
+ } else if (authResp.tag.equals(ColumnHeaderConstant.USER)) {
+ headerList = LIST_USER_COLUMN_HEADERS;
+ types =
+ LIST_USER_COLUMN_HEADERS.stream()
+ .map(ColumnHeader::getColumnType)
+ .collect(Collectors.toList());
+ builder = new TsBlockBuilder(types);
+ for (TListUserInfo userinfo : authResp.getUsersInfo()) {
+ builder.getTimeColumnBuilder().writeLong(0L);
+ builder.getColumnBuilder(0).writeLong(userinfo.getUserId());
+ builder
+ .getColumnBuilder(1)
+ .writeBinary(new Binary(userinfo.getUsername(),
TSFileConfig.STRING_CHARSET));
+ builder.declarePosition();
+ }
+
} else {
headerList = LIST_USER_OR_ROLE_PRIVILEGES_COLUMN_HEADERS;
types =
diff --git
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/auth/entity/UserTest.java
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/auth/entity/UserTest.java
index eee3be0bc73..82e7d8f15b1 100644
---
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/auth/entity/UserTest.java
+++
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/auth/entity/UserTest.java
@@ -39,13 +39,13 @@ public class UserTest {
user.setPathPrivileges(
new PartialPath("root.ln"),
Collections.singleton(PrivilegeType.WRITE_DATA));
Assert.assertEquals(
- "User{name='user', pathPrivilegeList=[root.ln : WRITE_DATA], "
+ "User{id=-1, name='user', pathPrivilegeList=[root.ln : WRITE_DATA], "
+ "sysPrivilegeSet=[], AnyScopePrivilegeMap=[],
objectPrivilegeMap={}, roleList=[], isOpenIdUser=false}",
user.toString());
User user1 = new User("user1", "password1");
user1.deserialize(user.serialize());
Assert.assertEquals(
- "User{name='user', pathPrivilegeList=[root.ln : WRITE_DATA], "
+ "User{id=-1, name='user', pathPrivilegeList=[root.ln : WRITE_DATA], "
+ "sysPrivilegeSet=[], AnyScopePrivilegeMap=[],
objectPrivilegeMap={}, roleList=[], isOpenIdUser=false}",
user1.toString());
Assert.assertEquals(user1, user);
diff --git
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/auth/user/LocalFileUserAccessorTest.java
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/auth/user/LocalFileUserAccessorTest.java
index 54442238891..eafb95b0824 100644
---
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/auth/user/LocalFileUserAccessorTest.java
+++
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/auth/user/LocalFileUserAccessorTest.java
@@ -66,6 +66,7 @@ public class LocalFileUserAccessorTest {
@Test
public void test() throws IOException, IllegalPathException {
User user = new User("test", "password123456");
+ user.setUserId(5);
user.grantSysPrivilege(PrivilegeType.EXTEND_TEMPLATE, false);
user.grantSysPrivilege(PrivilegeType.MANAGE_USER, false);
PathPrivilege pathPrivilege = new PathPrivilege(new
PartialPath("root.test"));
@@ -80,23 +81,24 @@ public class LocalFileUserAccessorTest {
user.addRole("testRole2");
accessor.saveEntity(user);
accessor.reset();
- User loadUser = accessor.loadEntity("test");
+ User loadUser = accessor.loadEntity("5");
assertEquals(user, loadUser);
user.setName("test1");
+ user.setUserId(6);
accessor.saveEntity(user);
// list
List<String> usernames = accessor.listAllEntities();
usernames.sort(null);
- assertTrue(usernames.contains("test"));
- assertTrue(usernames.contains("test1"));
+ assertTrue(usernames.contains("5"));
+ assertTrue(usernames.contains("6"));
// delete
assertFalse(accessor.deleteEntity("not a user"));
- assertTrue(accessor.deleteEntity(user.getName()));
+ assertTrue(accessor.deleteEntity(String.valueOf(user.getUserId())));
usernames = accessor.listAllEntities();
assertEquals(1, usernames.size());
- assertTrue(usernames.contains("test"));
+ assertTrue(usernames.contains("5"));
User nullUser = accessor.loadEntity(user.getName());
assertNull(nullUser);
}
@@ -127,9 +129,14 @@ public class LocalFileUserAccessorTest {
accessor.saveUserOldVersion(role);
User newRole = accessor.loadEntity("root");
assertEquals(role, newRole);
+ newRole.setName("root1");
+ accessor.saveUserOldVersion1(newRole);
+ User newRole1 = accessor.loadEntity("root1");
+ assertEquals(newRole, newRole1);
newRole.setName("root2");
+ newRole.setUserId(10000);
accessor.saveEntity(newRole);
- User newRole2 = accessor.loadEntity("root2");
+ User newRole2 = accessor.loadEntity("10000");
assertEquals(newRole, newRole2);
}
}
diff --git
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/auth/authorizer/BasicAuthorizer.java
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/auth/authorizer/BasicAuthorizer.java
index 77a211de5d2..de800b2be56 100644
---
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/auth/authorizer/BasicAuthorizer.java
+++
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/auth/authorizer/BasicAuthorizer.java
@@ -32,6 +32,7 @@ import
org.apache.iotdb.commons.security.encrypt.AsymmetricEncrypt;
import org.apache.iotdb.commons.service.IService;
import org.apache.iotdb.commons.service.ServiceType;
import org.apache.iotdb.commons.utils.AuthUtils;
+import org.apache.iotdb.confignode.rpc.thrift.TListUserInfo;
import org.apache.iotdb.rpc.TSStatusCode;
import org.apache.thrift.TException;
@@ -450,6 +451,11 @@ public abstract class BasicAuthorizer implements
IAuthorizer, IService {
return userManager.listAllEntities();
}
+ @Override
+ public List<TListUserInfo> listAllUsersInfo() {
+ return userManager.listAllEntitiesInfo();
+ }
+
@Override
public List<String> listAllRoles() {
return roleManager.listAllEntities();
@@ -465,6 +471,11 @@ public abstract class BasicAuthorizer implements
IAuthorizer, IService {
return userManager.getEntity(username);
}
+ @Override
+ public User getUser(long userId) throws AuthException {
+ return userManager.getEntity(userId);
+ }
+
@Override
public boolean processTakeSnapshot(File snapshotDir) throws TException,
IOException {
return userManager.processTakeSnapshot(snapshotDir)
diff --git
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/auth/authorizer/IAuthorizer.java
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/auth/authorizer/IAuthorizer.java
index e98474a8f2a..52b8ad4e0f4 100644
---
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/auth/authorizer/IAuthorizer.java
+++
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/auth/authorizer/IAuthorizer.java
@@ -26,6 +26,7 @@ import org.apache.iotdb.commons.auth.entity.Role;
import org.apache.iotdb.commons.auth.entity.User;
import org.apache.iotdb.commons.path.PartialPath;
import org.apache.iotdb.commons.snapshot.SnapshotProcessor;
+import org.apache.iotdb.confignode.rpc.thrift.TListUserInfo;
import java.util.List;
import java.util.Map;
@@ -186,6 +187,14 @@ public interface IAuthorizer extends SnapshotProcessor {
*/
List<String> listAllUsers();
+ /**
+ * List existing users info in the database.
+ *
+ * @return A list contains all users' baisc info including userid,
username,maxSessionPerUser and
+ * minSessionPerUser.
+ */
+ List<TListUserInfo> listAllUsersInfo();
+
/**
* List existing roles in the database.
*
@@ -209,6 +218,14 @@ public interface IAuthorizer extends SnapshotProcessor {
*/
User getUser(String username) throws AuthException;
+ /**
+ * Find a user by its userId.
+ *
+ * @param userId the index of the user.
+ * @return A user whose id is userId or null if such user does not exist.
+ */
+ User getUser(long userId) throws AuthException;
+
/**
* get all user
*
diff --git
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/auth/entity/IEntityAccessor.java
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/auth/entity/IEntityAccessor.java
index 3c42d1a1dec..972106467e2 100644
---
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/auth/entity/IEntityAccessor.java
+++
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/auth/entity/IEntityAccessor.java
@@ -35,6 +35,21 @@ public interface IEntityAccessor extends SnapshotProcessor {
*/
Role loadEntity(String entityName) throws IOException;
+ /**
+ * Deserialize userid from lower storage.
+ *
+ * @return The max userid.
+ * @throws IOException if an exception is raised when interacting with the
lower storage.
+ */
+ long loadUserId() throws IOException;
+
+ /**
+ * save maxUserId to lower storage when snapshot.
+ *
+ * @throws IOException if an exception is raised when interacting with the
lower storage.
+ */
+ void saveUserId(long nextUserId) throws IOException;
+
/**
* Serialize the entity object to lower storage.
*
diff --git
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/auth/entity/Role.java
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/auth/entity/Role.java
index 2443ef38a17..e5296dca60c 100644
---
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/auth/entity/Role.java
+++
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/auth/entity/Role.java
@@ -44,6 +44,8 @@ import java.util.Set;
public class Role {
protected String name;
+ protected int maxSessionPerUser = -1;
+ protected int minSessionPerUser = -1;
protected List<PathPrivilege> pathPrivilegeList;
protected Map<String, DatabasePrivilege> objectPrivilegeMap;
@@ -81,6 +83,14 @@ public class Role {
return name;
}
+ public int getMaxSessionPerUser() {
+ return maxSessionPerUser;
+ }
+
+ public int getMinSessionPerUser() {
+ return minSessionPerUser;
+ }
+
public List<PathPrivilege> getPathPrivilegeList() {
return pathPrivilegeList;
}
@@ -250,6 +260,14 @@ public class Role {
this.name = name;
}
+ public void setMaxSessionPerUser(int maxSessionPerUser) {
+ this.maxSessionPerUser = maxSessionPerUser;
+ }
+
+ public void setMinSessionPerUser(int minSessionPerUser) {
+ this.minSessionPerUser = minSessionPerUser;
+ }
+
public void setPrivilegeList(List<PathPrivilege> privilegeList) {
this.pathPrivilegeList = privilegeList;
}
diff --git
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/auth/entity/User.java
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/auth/entity/User.java
index c0098cf0d51..d7963bc3d77 100644
---
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/auth/entity/User.java
+++
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/auth/entity/User.java
@@ -19,6 +19,8 @@
package org.apache.iotdb.commons.auth.entity;
import org.apache.iotdb.commons.utils.SerializeUtils;
+import org.apache.iotdb.commons.utils.TestOnly;
+import org.apache.iotdb.confignode.rpc.thrift.TListUserInfo;
import org.apache.iotdb.confignode.rpc.thrift.TUserResp;
import java.io.ByteArrayOutputStream;
@@ -34,6 +36,8 @@ import java.util.Set;
/** This class contains all information of a User. */
public class User extends Role {
+ private long userId = -1;
+
private String password;
private Set<String> roleSet;
@@ -44,15 +48,24 @@ public class User extends Role {
// empty constructor
}
+ @TestOnly
+ public User(String name, String password) {
+ super(name);
+ this.password = password;
+ this.roleSet = new HashSet<>();
+ }
+
/**
* construct function for User.
*
* @param name -user name
* @param password -user password
+ * @param userId -user index
*/
- public User(String name, String password) {
+ public User(String name, String password, long userId) {
super(name);
this.password = password;
+ this.userId = userId;
this.roleSet = new HashSet<>();
}
@@ -73,7 +86,15 @@ public class User extends Role {
roleSet.add(roleName);
}
+ public void setUserId(long userId) {
+ this.userId = userId;
+ }
+
/** ------------ get func ----------------* */
+ public long getUserId() {
+ return userId;
+ }
+
public String getPassword() {
return password;
}
@@ -99,6 +120,15 @@ public class User extends Role {
return resp;
}
+ public TListUserInfo convertToListUserInfo() {
+ TListUserInfo userInfo = new TListUserInfo();
+ userInfo.setUserId(userId);
+ userInfo.setUsername(name);
+ userInfo.setMaxSessionPerUser(maxSessionPerUser);
+ userInfo.setMinSessionPerUser(minSessionPerUser);
+ return userInfo;
+ }
+
/** -------------- misc ----------------* */
@Override
public boolean equals(Object o) {
@@ -196,7 +226,9 @@ public class User extends Role {
@Override
public String toString() {
return "User{"
- + "name='"
+ + "id="
+ + userId
+ + ", name='"
+ super.getName()
+ '\''
+ ", pathPrivilegeList="
diff --git
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/auth/role/BasicRoleManager.java
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/auth/role/BasicRoleManager.java
index 17cda526d34..f6804d3055c 100644
---
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/auth/role/BasicRoleManager.java
+++
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/auth/role/BasicRoleManager.java
@@ -23,9 +23,11 @@ import org.apache.iotdb.commons.auth.entity.IEntityAccessor;
import org.apache.iotdb.commons.auth.entity.PrivilegeType;
import org.apache.iotdb.commons.auth.entity.PrivilegeUnion;
import org.apache.iotdb.commons.auth.entity.Role;
+import org.apache.iotdb.commons.auth.entity.User;
import org.apache.iotdb.commons.concurrent.HashLock;
import org.apache.iotdb.commons.snapshot.SnapshotProcessor;
import org.apache.iotdb.commons.utils.AuthUtils;
+import org.apache.iotdb.confignode.rpc.thrift.TListUserInfo;
import org.apache.iotdb.rpc.TSStatusCode;
import org.slf4j.Logger;
@@ -33,6 +35,7 @@ import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.ArrayList;
+import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -78,6 +81,10 @@ public abstract class BasicRoleManager implements
IEntityManager, SnapshotProces
return role;
}
+ public Role getEntity(long entityId) {
+ return null;
+ }
+
public boolean createRole(String entityName) {
Role role = getEntity(entityName);
if (role != null) {
@@ -229,4 +236,19 @@ public abstract class BasicRoleManager implements
IEntityManager, SnapshotProces
rtlist.sort(null);
return rtlist;
}
+
+ public List<TListUserInfo> listAllEntitiesInfo() {
+
+ List<TListUserInfo> rtlist = new ArrayList<>();
+ for (Role r : entityMap.values()) {
+ TListUserInfo userInfo = new TListUserInfo();
+ userInfo.userId = ((User) r).getUserId();
+ userInfo.username = r.getName();
+ userInfo.maxSessionPerUser = r.getMaxSessionPerUser();
+ userInfo.minSessionPerUser = r.getMinSessionPerUser();
+ rtlist.add(userInfo);
+ }
+ rtlist.sort(Comparator.comparingLong(TListUserInfo::getUserId));
+ return rtlist;
+ }
}
diff --git
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/auth/role/IEntityManager.java
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/auth/role/IEntityManager.java
index d70c18273f0..c1331fa8483 100644
---
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/auth/role/IEntityManager.java
+++
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/auth/role/IEntityManager.java
@@ -37,6 +37,15 @@ public interface IEntityManager extends SnapshotProcessor {
*/
Role getEntity(String entityName) throws AuthException;
+ /**
+ * Get an entity object.
+ *
+ * @param entityId The id of the entity.
+ * @return An entity object whose index is entityId or null if such entity
does not exist.
+ * @throws AuthException if exception is raised while getting the entity.
+ */
+ Role getEntity(long entityId) throws AuthException;
+
/**
* Delete an entity.
*
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 809d2397f3b..07bb08ca7de 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
@@ -22,6 +22,7 @@ import org.apache.iotdb.commons.auth.entity.DatabasePrivilege;
import org.apache.iotdb.commons.auth.entity.IEntityAccessor;
import org.apache.iotdb.commons.auth.entity.PathPrivilege;
import org.apache.iotdb.commons.auth.entity.Role;
+import org.apache.iotdb.commons.auth.entity.User;
import org.apache.iotdb.commons.conf.CommonDescriptor;
import org.apache.iotdb.commons.conf.IoTDBConstant;
import org.apache.iotdb.commons.exception.IllegalPathException;
@@ -84,7 +85,7 @@ public class LocalFileRoleAccessor implements IEntityAccessor
{
// 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 = 1;
+ protected static final int VERSION = 2;
/**
* Reused buffer for primitive types encoding/decoding, which aim to reduce
memory fragments. Use
@@ -223,13 +224,37 @@ public class LocalFileRoleAccessor implements
IEntityAccessor {
}
}
+ @Override
+ public long loadUserId() throws IOException {
+ File userIdFile = checkFileAvailable("user_id", "");
+ if (userIdFile == null) {
+ return -1;
+ }
+ FileInputStream inputStream = new FileInputStream(userIdFile);
+ try (DataInputStream dataInputStream =
+ new DataInputStream(new BufferedInputStream(inputStream))) {
+ dataInputStream.readInt(); // read version
+ return dataInputStream.readLong();
+ } catch (Exception e) {
+ throw new IOException(e);
+ } finally {
+ strBufferLocal.remove();
+ }
+ }
+
@Override
public void saveEntity(Role entity) throws IOException {
+ String prefixName = "";
+ if (entity instanceof User) {
+ prefixName = String.valueOf(((User) entity).getUserId());
+ } else {
+ prefixName = entity.getName();
+ }
File roleProfile =
SystemFileFactory.INSTANCE.getFile(
entityDirPath
+ File.separator
- + entity.getName()
+ + prefixName
+ IoTDBConstant.PROFILE_SUFFIX
+ TEMP_SUFFIX);
File roleDir = new File(entityDirPath);
@@ -253,7 +278,7 @@ public class LocalFileRoleAccessor implements
IEntityAccessor {
File oldFile =
SystemFileFactory.INSTANCE.getFile(
- entityDirPath + File.separator + entity.getName() +
IoTDBConstant.PROFILE_SUFFIX);
+ entityDirPath + File.separator + prefixName +
IoTDBConstant.PROFILE_SUFFIX);
IOUtils.replaceFile(roleProfile, oldFile);
saveRoles(entity);
}
@@ -301,6 +326,7 @@ public class LocalFileRoleAccessor implements
IEntityAccessor {
}
retList.addAll(set);
}
+ retList.remove("user_id"); // skip user_id.profile
return retList;
}
@@ -378,4 +404,36 @@ public class LocalFileRoleAccessor implements
IEntityAccessor {
LOGGER.warn("Role folder not exists");
}
}
+
+ @Override
+ public void saveUserId(long nextUserId) throws IOException {
+ File userInfoProfile =
+ SystemFileFactory.INSTANCE.getFile(
+ entityDirPath
+ + File.separator
+ + "user_id"
+ + IoTDBConstant.PROFILE_SUFFIX
+ + TEMP_SUFFIX);
+ File userDir = new File(entityDirPath);
+ if (!userDir.exists() && !userDir.mkdirs()) {
+ LOGGER.error("Failed to create user dir {}", entityDirPath);
+ }
+
+ try (FileOutputStream fileOutputStream = new
FileOutputStream(userInfoProfile);
+ BufferedOutputStream outputStream = new
BufferedOutputStream(fileOutputStream)) {
+ IOUtils.writeInt(outputStream, VERSION, encodingBufferLocal);
+ IOUtils.writeLong(outputStream, nextUserId, encodingBufferLocal);
+ outputStream.flush();
+ fileOutputStream.getFD().sync();
+ } catch (Exception e) {
+ LOGGER.warn("meet error when save userId: {}", nextUserId);
+ throw new IOException(e);
+ } finally {
+ encodingBufferLocal.remove();
+ }
+ File oldFile =
+ SystemFileFactory.INSTANCE.getFile(
+ entityDirPath + File.separator + "user_id" +
IoTDBConstant.PROFILE_SUFFIX);
+ IOUtils.replaceFile(userInfoProfile, oldFile);
+ }
}
diff --git
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/auth/user/BasicUserManager.java
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/auth/user/BasicUserManager.java
index 86e4f46d235..3387796b632 100644
---
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/auth/user/BasicUserManager.java
+++
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/auth/user/BasicUserManager.java
@@ -22,6 +22,7 @@ import org.apache.iotdb.commons.auth.AuthException;
import org.apache.iotdb.commons.auth.entity.IEntityAccessor;
import org.apache.iotdb.commons.auth.entity.PathPrivilege;
import org.apache.iotdb.commons.auth.entity.PrivilegeType;
+import org.apache.iotdb.commons.auth.entity.Role;
import org.apache.iotdb.commons.auth.entity.User;
import org.apache.iotdb.commons.auth.role.BasicRoleManager;
import org.apache.iotdb.commons.conf.CommonDescriptor;
@@ -35,6 +36,9 @@ import org.apache.iotdb.rpc.TSStatusCode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import java.io.IOException;
+import java.util.Map;
+
/** This class stores information of each user. */
public abstract class BasicUserManager extends BasicRoleManager {
@@ -50,6 +54,8 @@ public abstract class BasicUserManager extends
BasicRoleManager {
return "No such user %s";
}
+ protected long nextUserId = 9999;
+
/**
* BasicUserManager Constructor.
*
@@ -102,11 +108,42 @@ public abstract class BasicUserManager extends
BasicRoleManager {
LOGGER.info("Admin initialized");
}
+ private void initUserId() {
+ try {
+ long maxUserId = this.accessor.loadUserId();
+ if (maxUserId < 9999) {
+ nextUserId = 9999;
+ } else {
+ nextUserId = maxUserId;
+ }
+
+ for (Map.Entry<String, Role> userEntry : entityMap.entrySet()) {
+ User user = (User) userEntry.getValue();
+ if (user.getUserId() == -1) {
+ user.setUserId(++nextUserId);
+ }
+ }
+ } catch (IOException e) {
+ LOGGER.warn("meet error in load max userId.", e);
+ throw new RuntimeException(e);
+ }
+ }
+
@Override
public User getEntity(String entityName) {
return (User) super.getEntity(entityName);
}
+ @Override
+ public User getEntity(long entityId) {
+ for (Map.Entry<String, Role> roleEntry : entityMap.entrySet()) {
+ if (((User) roleEntry.getValue()).getUserId() == entityId) {
+ return (User) roleEntry.getValue();
+ }
+ }
+ return null;
+ }
+
public boolean createUser(
String username, String password, boolean validCheck, boolean
enableEncrypt)
throws AuthException {
@@ -128,7 +165,15 @@ public abstract class BasicUserManager extends
BasicRoleManager {
}
lock.writeLock(username);
try {
- user = new User(username, enableEncrypt ?
AuthUtils.encryptPassword(password) : password);
+ long userid;
+ if
(username.equals(CommonDescriptor.getInstance().getConfig().getAdminName())) {
+ userid = 0;
+ } else {
+ userid = ++nextUserId;
+ }
+ user =
+ new User(
+ username, enableEncrypt ? AuthUtils.encryptPassword(password) :
password, userid);
entityMap.put(username, user);
return true;
} finally {
@@ -196,7 +241,18 @@ public abstract class BasicUserManager extends
BasicRoleManager {
@Override
public void reset() throws AuthException {
- super.reset();
+ accessor.reset();
+ entityMap.clear();
+ for (String userId : accessor.listAllEntities()) {
+ try {
+ User user = (User) accessor.loadEntity(userId);
+ entityMap.put(user.getName(), user);
+ } catch (IOException e) {
+ LOGGER.warn("Get exception when load user {}", userId);
+ throw new AuthException(TSStatusCode.AUTH_IO_EXCEPTION, e);
+ }
+ }
+ initUserId();
initAdmin();
}
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 8a50a87ad96..11ff8c73e9a 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
@@ -89,6 +89,7 @@ public class LocalFileUserAccessor extends
LocalFileRoleAccessor {
@Override
protected void saveEntityName(BufferedOutputStream outputStream, Role role)
throws IOException {
+ IOUtils.writeLong(outputStream, ((User) role).getUserId(),
encodingBufferLocal);
super.saveEntityName(outputStream, role);
IOUtils.writeString(
outputStream, ((User) role).getPassword(), STRING_ENCODING,
encodingBufferLocal);
@@ -101,7 +102,7 @@ public class LocalFileUserAccessor extends
LocalFileRoleAccessor {
SystemFileFactory.INSTANCE.getFile(
entityDirPath
+ File.separator
- + user.getName()
+ + user.getUserId()
+ ROLE_SUFFIX
+ IoTDBConstant.PROFILE_SUFFIX
+ TEMP_SUFFIX);
@@ -123,7 +124,7 @@ public class LocalFileUserAccessor extends
LocalFileRoleAccessor {
SystemFileFactory.INSTANCE.getFile(
entityDirPath
+ File.separator
- + user.getName()
+ + user.getUserId()
+ ROLE_SUFFIX
+ IoTDBConstant.PROFILE_SUFFIX);
IOUtils.replaceFile(roleProfile, oldURoleFile);
@@ -144,14 +145,10 @@ public class LocalFileUserAccessor extends
LocalFileRoleAccessor {
FileInputStream inputStream = new FileInputStream(entityFile);
try (DataInputStream dataInputStream =
new DataInputStream(new BufferedInputStream(inputStream))) {
- boolean fromOldVersion = false;
int tag = dataInputStream.readInt();
- if (tag < 0) {
- fromOldVersion = true;
- }
User user = new User();
- if (fromOldVersion) {
+ if (tag < 0) {
String name =
IOUtils.readString(dataInputStream, STRING_ENCODING,
strBufferLocal, -1 * tag);
user.setName(name);
@@ -163,8 +160,13 @@ public class LocalFileUserAccessor extends
LocalFileRoleAccessor {
IOUtils.readPathPrivilege(dataInputStream, STRING_ENCODING,
strBufferLocal));
}
user.setPrivilegeList(pathPrivilegeList);
+ } else if (tag == 1) {
+ user.setName(IOUtils.readString(dataInputStream, STRING_ENCODING,
strBufferLocal));
+ user.setPassword(IOUtils.readString(dataInputStream, STRING_ENCODING,
strBufferLocal));
+ loadPrivileges(dataInputStream, user);
} else {
assert (tag == VERSION);
+ user.setUserId(dataInputStream.readLong());
user.setName(IOUtils.readString(dataInputStream, STRING_ENCODING,
strBufferLocal));
user.setPassword(IOUtils.readString(dataInputStream, STRING_ENCODING,
strBufferLocal));
loadPrivileges(dataInputStream, user);
@@ -300,4 +302,35 @@ public class LocalFileUserAccessor extends
LocalFileRoleAccessor {
entityDirPath + File.separator + user.getName() +
IoTDBConstant.PROFILE_SUFFIX);
IOUtils.replaceFile(userProfile, oldFile);
}
+
+ @TestOnly
+ public void saveUserOldVersion1(User user) throws IOException {
+ File userProfile =
+ SystemFileFactory.INSTANCE.getFile(
+ entityDirPath
+ + File.separator
+ + user.getName()
+ + IoTDBConstant.PROFILE_SUFFIX
+ + TEMP_SUFFIX);
+
+ try (FileOutputStream fileOutputStream = new FileOutputStream(userProfile);
+ BufferedOutputStream outputStream = new
BufferedOutputStream(fileOutputStream)) {
+ // test for version1
+ IOUtils.writeInt(outputStream, 1, encodingBufferLocal);
+ IOUtils.writeString(outputStream, user.getName(), STRING_ENCODING,
encodingBufferLocal);
+ IOUtils.writeString(outputStream, user.getPassword(), STRING_ENCODING,
encodingBufferLocal);
+ savePrivileges(outputStream, user);
+ outputStream.flush();
+ fileOutputStream.getFD().sync();
+ } catch (Exception e) {
+ throw new IOException(e);
+ } finally {
+ encodingBufferLocal.remove();
+ }
+
+ File oldFile =
+ SystemFileFactory.INSTANCE.getFile(
+ entityDirPath + File.separator + user.getName() +
IoTDBConstant.PROFILE_SUFFIX);
+ IOUtils.replaceFile(userProfile, oldFile);
+ }
}
diff --git
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/auth/user/LocalFileUserManager.java
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/auth/user/LocalFileUserManager.java
index e2c8a33fee0..5b061e16ba2 100644
---
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/auth/user/LocalFileUserManager.java
+++
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/auth/user/LocalFileUserManager.java
@@ -39,6 +39,7 @@ public class LocalFileUserManager extends BasicUserManager {
for (Map.Entry<String, Role> entry : entityMap.entrySet()) {
accessor.saveEntity(entry.getValue());
}
+ accessor.saveUserId(nextUserId);
return accessor.processTakeSnapshot(snapshotDir);
}
diff --git
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/column/ColumnHeaderConstant.java
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/column/ColumnHeaderConstant.java
index 7cdfd60f34b..6c7cf212da5 100644
---
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/column/ColumnHeaderConstant.java
+++
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/column/ColumnHeaderConstant.java
@@ -163,6 +163,8 @@ public class ColumnHeaderConstant {
public static final String COUNT_TIME_PARTITION = "count(timePartition)";
public static final String START_TIME = "StartTime";
public static final String ROLE = "Role";
+ public static final String MAX_SESSION_PER_USER = "MaxSessionPerUser";
+ public static final String MIN_SESSION_PER_USER = "MinSessionPerUser";
public static final String CREATE_TIME = "CreateTime";
public static final String TSFILE_SIZE = "TsFileSize";
public static final String COMPRESSION_RATIO = "CompressionRatio";
@@ -279,6 +281,7 @@ public class ColumnHeaderConstant {
// column names for show throttle quota
public static final String USER = "User";
+ public static final String USER_ID = "UserId";
public static final String READ_WRITE = "Read/Write";
// column names for show models/trials
@@ -689,6 +692,10 @@ public class ColumnHeaderConstant {
new ColumnHeader(TABLE, TSDataType.TEXT),
new ColumnHeader(CREATE_TABLE, TSDataType.TEXT));
+ public static final List<ColumnHeader> LIST_USER_COLUMN_HEADERS =
+ ImmutableList.of(
+ new ColumnHeader(USER_ID, TSDataType.INT64), new ColumnHeader(USER,
TSDataType.TEXT));
+
public static final List<ColumnHeader> showTablesColumnHeaders =
ImmutableList.of(
new ColumnHeader(TABLE_NAME, TSDataType.TEXT),
diff --git
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/utils/IOUtils.java
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/utils/IOUtils.java
index d1c049e86d7..8b63d29bd78 100644
---
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/utils/IOUtils.java
+++
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/utils/IOUtils.java
@@ -92,6 +92,36 @@ public class IOUtils {
outputStream.write(encodingBuffer.array(), 0, Integer.BYTES);
}
+ /**
+ * Write a long (8-byte) into the given stream.
+ *
+ * @param outputStream the destination to insert.
+ * @param i the long value to be written.
+ * @param encodingBufferLocal a ThreadLocal buffer may be passed to avoid
frequent memory
+ * allocations. A null may also be passed to use a local buffer.
+ * @throws IOException when an exception raised during operating the stream.
+ */
+ public static void writeLong(
+ OutputStream outputStream, long i, ThreadLocal<ByteBuffer>
encodingBufferLocal)
+ throws IOException {
+
+ ByteBuffer encodingBuffer;
+ if (encodingBufferLocal != null) {
+ encodingBuffer = encodingBufferLocal.get();
+ if (encodingBuffer == null) {
+ // 8 bytes is exactly what we need for a long
+ encodingBuffer = ByteBuffer.allocate(8);
+ encodingBufferLocal.set(encodingBuffer);
+ }
+ } else {
+ encodingBuffer = ByteBuffer.allocate(8);
+ }
+
+ encodingBuffer.clear();
+ encodingBuffer.putLong(i);
+ outputStream.write(encodingBuffer.array(), 0, Long.BYTES);
+ }
+
/**
* Read a string from the given stream.
*
diff --git a/iotdb-protocol/thrift-confignode/src/main/thrift/confignode.thrift
b/iotdb-protocol/thrift-confignode/src/main/thrift/confignode.thrift
index 02c051837ed..fef2aa63d26 100644
--- a/iotdb-protocol/thrift-confignode/src/main/thrift/confignode.thrift
+++ b/iotdb-protocol/thrift-confignode/src/main/thrift/confignode.thrift
@@ -362,6 +362,14 @@ struct TAuthorizerResp {
2: optional string tag
3: optional list<string> memberInfo
4: optional TPermissionInfoResp permissionInfo
+ 5: optional list<TListUserInfo> usersInfo
+}
+
+struct TListUserInfo{
+ 1: required i64 userId
+ 2: required string username
+ 3: required i32 maxSessionPerUser
+ 4: required i32 minSessionPerUser
}
struct TUserResp {