• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

apache / iotdb / #10030

08 Sep 2023 01:34AM UTC coverage: 47.698%. First build
#10030

push

travis_ci

web-flow
[auth].fix cache info

37 of 37 new or added lines in 8 files covered. (100.0%)

80772 of 169340 relevant lines covered (47.7%)

0.48 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

86.36
/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/auth/role/LocalFileRoleAccessor.java
1
/*
2
 * Licensed to the Apache Software Foundation (ASF) under one
3
 * or more contributor license agreements.  See the NOTICE file
4
 * distributed with this work for additional information
5
 * regarding copyright ownership.  The ASF licenses this file
6
 * to you under the Apache License, Version 2.0 (the
7
 * "License"); you may not use this file except in compliance
8
 * with the License.  You may obtain a copy of the License at
9
 *
10
 *     http://www.apache.org/licenses/LICENSE-2.0
11
 *
12
 * Unless required by applicable law or agreed to in writing,
13
 * software distributed under the License is distributed on an
14
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15
 * KIND, either express or implied.  See the License for the
16
 * specific language governing permissions and limitations
17
 * under the License.
18
 */
19
package org.apache.iotdb.commons.auth.role;
20

21
import org.apache.iotdb.commons.auth.entity.PathPrivilege;
22
import org.apache.iotdb.commons.auth.entity.Role;
23
import org.apache.iotdb.commons.conf.IoTDBConstant;
24
import org.apache.iotdb.commons.file.SystemFileFactory;
25
import org.apache.iotdb.commons.utils.FileUtils;
26
import org.apache.iotdb.commons.utils.IOUtils;
27

28
import org.apache.thrift.TException;
29
import org.slf4j.Logger;
30
import org.slf4j.LoggerFactory;
31

32
import java.io.BufferedInputStream;
33
import java.io.BufferedOutputStream;
34
import java.io.DataInputStream;
35
import java.io.File;
36
import java.io.FileInputStream;
37
import java.io.IOException;
38
import java.nio.ByteBuffer;
39
import java.nio.file.Files;
40
import java.util.ArrayList;
41
import java.util.HashSet;
42
import java.util.List;
43
import java.util.Set;
44
import java.util.UUID;
45

46
/**
47
 * This class store role info in a separate sequential file and every role will have one role file.
48
 * Role file schema: rolename-length int32| rolename-bytes-utf8| system-perivileges int32|
49
 * path[1]-length int32| path[1]-bytes-utf8 | privilege-int32| path[2]-length int32|
50
 * path[2]-bytes-utf8 | privilege-int32| path[3]-length int32| path[3]-bytes-utf8 | privilege-int32|
51
 * .....
52
 *
53
 * <p>system-privileges is a int32 mask code. Low 16 bits for privileges and high 16 bits mark that
54
 * whether the corresponding position 's privilege has grant option.So we can use a int32 to mark 16
55
 * kinds of privileges. Here are the permissions corresponding to the bit location identifier:
56
 * Manage_database : 0 MANAGE_USER : 1 MANAGE_ROLE : 2 USE_TRIGGER : 3 USE_UDF : 4 USE_CQ : 5
57
 * USE_PIPE : 6 EXTEDN_TEMPLATE : 7 AUDIT : 8 MAINTAIN : 9 |0000-0000-0000-0001|0000-0000-0000-0001|
58
 * means this role has Manage_database's privilege and be able to grant it to others.
59
 *
60
 * <p>path-privileges is a pair contains paths and privileges mask. Path privilege is a int32 mask
61
 * code which has the same structure as system-privileges. For path privilege, the low 16 bits stand
62
 * for four privileges, they are: READ_DATA : 0 WRITE_DATA : 1 READ_SCHEMA : 2 WRITE_SCHEMA : 3 And
63
 * the high 16 bits stand for grant option.
64
 *
65
 * <p>Role files is appendable.
66
 */
67

68
/**
69
 * All user/role file store in config node's user/role folder. when we need someone's privilege
70
 * info, we load it form folder. If we did some alter query, we just store raft log.
71
 */
72
public class LocalFileRoleAccessor implements IRoleAccessor {
73
  private static final Logger logger = LoggerFactory.getLogger(LocalFileRoleAccessor.class);
1✔
74
  private static final String TEMP_SUFFIX = ".temp";
75
  private static final String STRING_ENCODING = "utf-8";
76
  private static final String roleSnapshotFileName = "system" + File.separator + "roles";
1✔
77

78
  private final String roleDirPath;
79

80
  /**
81
   * Reused buffer for primitive types encoding/decoding, which aim to reduce memory fragments. Use
82
   * ThreadLocal for thread safety.
83
   */
84
  private final ThreadLocal<ByteBuffer> encodingBufferLocal = new ThreadLocal<>();
1✔
85

86
  private final ThreadLocal<byte[]> strBufferLocal = new ThreadLocal<>();
1✔
87

88
  public LocalFileRoleAccessor(String roleDirPath) {
1✔
89
    this.roleDirPath = roleDirPath;
1✔
90
  }
1✔
91

92
  /**
93
   * @return role struct
94
   * @throws IOException
95
   */
96
  @Override
97
  public Role loadRole(String rolename) throws IOException {
98
    File roleProfile =
1✔
99
        SystemFileFactory.INSTANCE.getFile(
1✔
100
            roleDirPath + File.separator + rolename + IoTDBConstant.PROFILE_SUFFIX);
101
    if (!roleProfile.exists() || !roleProfile.isFile()) {
1✔
102
      // System may crush before a newer file is written, so search for back-up file.
103
      File backProfile =
1✔
104
          SystemFileFactory.INSTANCE.getFile(
1✔
105
              roleDirPath + File.separator + rolename + IoTDBConstant.PROFILE_SUFFIX + TEMP_SUFFIX);
106
      if (backProfile.exists() && backProfile.isFile()) {
1✔
107
        roleProfile = backProfile;
×
108
      } else {
109
        return null;
1✔
110
      }
111
    }
112
    FileInputStream inputStream = new FileInputStream(roleProfile);
1✔
113
    try (DataInputStream dataInputStream =
1✔
114
        new DataInputStream(new BufferedInputStream(inputStream))) {
115
      Role role = new Role();
1✔
116
      role.setName(IOUtils.readString(dataInputStream, STRING_ENCODING, strBufferLocal));
1✔
117
      role.setSysPrivilegeSet(dataInputStream.readInt());
1✔
118

119
      List<PathPrivilege> pathPrivilegeList = new ArrayList<>();
1✔
120
      for (int i = 0; dataInputStream.available() != 0; i++) {
1✔
121
        pathPrivilegeList.add(
1✔
122
            IOUtils.readPathPrivilege(dataInputStream, STRING_ENCODING, strBufferLocal));
1✔
123
      }
124
      role.setPrivilegeList(pathPrivilegeList);
1✔
125
      return role;
1✔
126
    } catch (Exception e) {
×
127
      throw new IOException(e);
×
128
    } finally {
129
      strBufferLocal.remove();
1✔
130
    }
131
  }
132

133
  @Override
134
  public void saveRole(Role role) throws IOException {
135
    File roleProfile =
1✔
136
        SystemFileFactory.INSTANCE.getFile(
1✔
137
            roleDirPath
138
                + File.separator
139
                + role.getName()
1✔
140
                + IoTDBConstant.PROFILE_SUFFIX
141
                + TEMP_SUFFIX);
142
    File roleDir = new File(roleDirPath);
1✔
143
    if (!roleDir.exists()) {
1✔
144
      if (!roleDir.mkdirs()) {
×
145
        logger.error("Failed to create role dir {}", roleDirPath);
×
146
      }
147
    }
148
    try (BufferedOutputStream outputStream =
1✔
149
        new BufferedOutputStream(Files.newOutputStream(roleProfile.toPath()))) {
1✔
150
      try {
151
        IOUtils.writeString(outputStream, role.getName(), STRING_ENCODING, encodingBufferLocal);
1✔
152
        IOUtils.writeInt(outputStream, role.getAllSysPrivileges(), encodingBufferLocal);
1✔
153
        int privilegeNum = role.getPathPrivilegeList().size();
1✔
154
        for (int i = 0; i < privilegeNum; i++) {
1✔
155
          PathPrivilege pathPrivilege = role.getPathPrivilegeList().get(i);
1✔
156
          IOUtils.writePathPrivilege(
1✔
157
              outputStream, pathPrivilege, STRING_ENCODING, encodingBufferLocal);
158
        }
159
        outputStream.flush();
1✔
160
      } catch (Exception e) {
×
161
        throw new IOException(e);
×
162
      }
1✔
163
    } finally {
164
      encodingBufferLocal.remove();
1✔
165
    }
166

167
    File oldFile =
1✔
168
        SystemFileFactory.INSTANCE.getFile(
1✔
169
            roleDirPath + File.separator + role.getName() + IoTDBConstant.PROFILE_SUFFIX);
1✔
170
    IOUtils.replaceFile(roleProfile, oldFile);
1✔
171
  }
1✔
172

173
  @Override
174
  public boolean deleteRole(String rolename) throws IOException {
175
    File roleProfile =
1✔
176
        SystemFileFactory.INSTANCE.getFile(
1✔
177
            roleDirPath + File.separator + rolename + IoTDBConstant.PROFILE_SUFFIX);
178
    File backFile =
1✔
179
        SystemFileFactory.INSTANCE.getFile(
1✔
180
            roleDirPath + File.separator + rolename + IoTDBConstant.PROFILE_SUFFIX + TEMP_SUFFIX);
181
    if (!roleProfile.exists() && !backFile.exists()) {
1✔
182
      return false;
1✔
183
    }
184
    if ((roleProfile.exists() && !roleProfile.delete())
1✔
185
        || (backFile.exists() && !backFile.delete())) {
1✔
186
      throw new IOException(String.format("Cannot delete role file of %s", rolename));
×
187
    }
188
    return true;
1✔
189
  }
190

191
  @Override
192
  public List<String> listAllRoles() {
193
    File roleDir = SystemFileFactory.INSTANCE.getFile(roleDirPath);
1✔
194
    String[] names =
1✔
195
        roleDir.list(
1✔
196
            (dir, name) ->
197
                name.endsWith(IoTDBConstant.PROFILE_SUFFIX) || name.endsWith(TEMP_SUFFIX));
1✔
198
    List<String> retList = new ArrayList<>();
1✔
199
    if (names != null) {
1✔
200
      // in very rare situations, normal file and backup file may exist at the same time
201
      // so a set is used to deduplicate
202
      Set<String> set = new HashSet<>();
1✔
203
      for (String fileName : names) {
1✔
204
        set.add(fileName.replace(IoTDBConstant.PROFILE_SUFFIX, "").replace(TEMP_SUFFIX, ""));
1✔
205
      }
206
      retList.addAll(set);
1✔
207
    }
208
    return retList;
1✔
209
  }
210

211
  @Override
212
  public boolean processTakeSnapshot(File snapshotDir) throws TException, IOException {
213
    SystemFileFactory systemFileFactory = SystemFileFactory.INSTANCE;
1✔
214
    File roleFolder = systemFileFactory.getFile(roleDirPath);
1✔
215
    File roleSnapshotDir = systemFileFactory.getFile(snapshotDir, roleSnapshotFileName);
1✔
216
    File roleTmpSnapshotDir =
1✔
217
        systemFileFactory.getFile(roleSnapshotDir.getAbsolutePath() + "-" + UUID.randomUUID());
1✔
218

219
    boolean result = true;
1✔
220
    try {
221
      result = FileUtils.copyDir(roleFolder, roleTmpSnapshotDir);
1✔
222
      result &= roleTmpSnapshotDir.renameTo(roleSnapshotDir);
1✔
223
    } finally {
224
      if (roleTmpSnapshotDir.exists() && !roleTmpSnapshotDir.delete()) {
1✔
225
        FileUtils.deleteDirectory(roleTmpSnapshotDir);
×
226
      }
227
    }
228
    return result;
1✔
229
  }
230

231
  @Override
232
  public void processLoadSnapshot(File snapshotDir) throws TException, IOException {
233
    SystemFileFactory systemFileFactory = SystemFileFactory.INSTANCE;
1✔
234
    File roleFolder = systemFileFactory.getFile(roleDirPath);
1✔
235
    File roleTmpFolder =
1✔
236
        systemFileFactory.getFile(roleFolder.getAbsolutePath() + "-" + UUID.randomUUID());
1✔
237
    File roleSnapshotDir = systemFileFactory.getFile(snapshotDir, roleSnapshotFileName);
1✔
238
    if (roleSnapshotDir.exists()) {
1✔
239
      try {
240
        org.apache.commons.io.FileUtils.moveDirectory(roleFolder, roleTmpFolder);
1✔
241
        if (!FileUtils.copyDir(roleSnapshotDir, roleFolder)) {
1✔
242
          logger.error("Failed to load role folder snapshot and rollback.");
×
243
          // rollback if failed to copy
244
          FileUtils.deleteDirectory(roleFolder);
×
245
          org.apache.commons.io.FileUtils.moveDirectory(roleTmpFolder, roleFolder);
×
246
        }
247
      } finally {
248
        FileUtils.deleteDirectory(roleTmpFolder);
1✔
249
      }
1✔
250
    } else {
251
      logger.info("There are no roles to load.");
×
252
    }
253
  }
1✔
254

255
  @Override
256
  public void reset() {
257
    if (SystemFileFactory.INSTANCE.getFile(roleDirPath).mkdirs()) {
1✔
258
      logger.info("role info dir {} is created", roleDirPath);
1✔
259
    } else if (!SystemFileFactory.INSTANCE.getFile(roleDirPath).exists()) {
1✔
260
      logger.error("role info dir {} can not be created", roleDirPath);
×
261
    }
262
  }
1✔
263

264
  @Override
265
  public void cleanRoleFolder() {
266
    File[] files = SystemFileFactory.INSTANCE.getFile(roleDirPath).listFiles();
1✔
267
    for (File file : files) {
1✔
268
      FileUtils.deleteFileIfExist(file);
×
269
    }
270
  }
1✔
271
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc