1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.hadoop.hbase.security.visibility;
20
21 import java.io.IOException;
22 import java.util.ArrayList;
23 import java.util.Collections;
24 import java.util.List;
25
26 import org.apache.commons.logging.Log;
27 import org.apache.commons.logging.LogFactory;
28 import org.apache.hadoop.hbase.classification.InterfaceAudience;
29 import org.apache.hadoop.hbase.Cell;
30 import org.apache.hadoop.hbase.KeyValue;
31 import org.apache.hadoop.hbase.KeyValue.Type;
32 import org.apache.hadoop.hbase.Tag;
33 import org.apache.hadoop.hbase.regionserver.ScanDeleteTracker;
34 import org.apache.hadoop.hbase.util.Bytes;
35 import org.apache.hadoop.hbase.util.Pair;
36 import org.apache.hadoop.hbase.util.Triple;
37
38
39
40
41
42 @InterfaceAudience.Private
43 public class VisibilityScanDeleteTracker extends ScanDeleteTracker {
44
45 private static final Log LOG = LogFactory.getLog(VisibilityScanDeleteTracker.class);
46
47
48
49
50 private static final List<Tag> EMPTY_TAG = Collections.EMPTY_LIST;
51
52
53
54
55
56
57
58
59 private List<Triple<List<Tag>, Byte, Long>> visibilityTagsDeleteFamily =
60 new ArrayList<Triple<List<Tag>, Byte, Long>>();
61
62
63 private List<Triple<List<Tag>, Byte, Long>> visibilityTagsDeleteFamilyVersion =
64 new ArrayList<Triple<List<Tag>, Byte, Long>>();
65 private List<Pair<List<Tag>, Byte>> visibilityTagsDeleteColumns;
66
67
68 private List<Pair<List<Tag>, Byte>> visiblityTagsDeleteColumnVersion =
69 new ArrayList<Pair<List<Tag>, Byte>>();
70
71 public VisibilityScanDeleteTracker() {
72 super();
73 }
74
75 @Override
76 public void add(Cell delCell) {
77
78 long timestamp = delCell.getTimestamp();
79 int qualifierOffset = delCell.getQualifierOffset();
80 int qualifierLength = delCell.getQualifierLength();
81 byte type = delCell.getTypeByte();
82 if (type == KeyValue.Type.DeleteFamily.getCode()) {
83 hasFamilyStamp = true;
84 boolean hasVisTag = extractDeleteCellVisTags(delCell, KeyValue.Type.DeleteFamily);
85 if (!hasVisTag && timestamp > familyStamp) {
86 familyStamp = timestamp;
87 }
88 return;
89 } else if (type == KeyValue.Type.DeleteFamilyVersion.getCode()) {
90 familyVersionStamps.add(timestamp);
91 extractDeleteCellVisTags(delCell, KeyValue.Type.DeleteFamilyVersion);
92 return;
93 }
94
95 if (deleteBuffer != null) {
96 if (Bytes.compareTo(deleteBuffer, deleteOffset, deleteLength, delCell.getQualifierArray(),
97 qualifierOffset, qualifierLength) != 0) {
98
99
100 visibilityTagsDeleteColumns = null;
101 visiblityTagsDeleteColumnVersion = null;
102 } else if (type == KeyValue.Type.Delete.getCode() && (deleteTimestamp != timestamp)) {
103
104
105
106
107
108
109
110 visiblityTagsDeleteColumnVersion = null;
111 }
112 }
113 deleteBuffer = delCell.getQualifierArray();
114 deleteOffset = qualifierOffset;
115 deleteLength = qualifierLength;
116 deleteType = type;
117 deleteTimestamp = timestamp;
118 extractDeleteCellVisTags(delCell, KeyValue.Type.codeToType(type));
119 }
120
121 private boolean extractDeleteCellVisTags(Cell delCell, Type type) {
122
123 boolean hasVisTag = false;
124 Byte deleteCellVisTagsFormat = null;
125 switch (type) {
126 case DeleteFamily:
127 List<Tag> delTags = new ArrayList<Tag>();
128 if (visibilityTagsDeleteFamily == null) {
129 visibilityTagsDeleteFamily = new ArrayList<Triple<List<Tag>, Byte, Long>>();
130 }
131 deleteCellVisTagsFormat = VisibilityUtils.extractVisibilityTags(delCell, delTags);
132 if (!delTags.isEmpty()) {
133 visibilityTagsDeleteFamily.add(new Triple<List<Tag>, Byte, Long>(delTags,
134 deleteCellVisTagsFormat, delCell.getTimestamp()));
135 hasVisTag = true;
136 } else {
137 visibilityTagsDeleteFamily.add(new Triple<>(EMPTY_TAG, deleteCellVisTagsFormat, delCell.getTimestamp()));
138 }
139 break;
140 case DeleteFamilyVersion:
141 if(visibilityTagsDeleteFamilyVersion == null) {
142 visibilityTagsDeleteFamilyVersion = new ArrayList<Triple<List<Tag>, Byte, Long>>();
143 }
144 delTags = new ArrayList<Tag>();
145 deleteCellVisTagsFormat = VisibilityUtils.extractVisibilityTags(delCell, delTags);
146 if (!delTags.isEmpty()) {
147 visibilityTagsDeleteFamilyVersion.add(new Triple<List<Tag>, Byte, Long>(delTags,
148 deleteCellVisTagsFormat, delCell.getTimestamp()));
149 hasVisTag = true;
150 } else {
151 visibilityTagsDeleteFamilyVersion.add(new Triple<>(EMPTY_TAG, deleteCellVisTagsFormat, delCell.getTimestamp()));
152 }
153 break;
154 case DeleteColumn:
155 if (visibilityTagsDeleteColumns == null) {
156 visibilityTagsDeleteColumns = new ArrayList<Pair<List<Tag>, Byte>>();
157 }
158 delTags = new ArrayList<Tag>();
159 deleteCellVisTagsFormat = VisibilityUtils.extractVisibilityTags(delCell, delTags);
160 if (!delTags.isEmpty()) {
161 visibilityTagsDeleteColumns.add(new Pair<List<Tag>, Byte>(delTags,
162 deleteCellVisTagsFormat));
163 hasVisTag = true;
164 } else {
165 visibilityTagsDeleteColumns.add(new Pair<>(EMPTY_TAG, deleteCellVisTagsFormat));
166 }
167 break;
168 case Delete:
169 if (visiblityTagsDeleteColumnVersion == null) {
170 visiblityTagsDeleteColumnVersion = new ArrayList<Pair<List<Tag>, Byte>>();
171 }
172 delTags = new ArrayList<Tag>();
173 deleteCellVisTagsFormat = VisibilityUtils.extractVisibilityTags(delCell, delTags);
174 if (!delTags.isEmpty()) {
175 visiblityTagsDeleteColumnVersion.add(new Pair<List<Tag>, Byte>(delTags,
176 deleteCellVisTagsFormat));
177 hasVisTag = true;
178 } else {
179 visiblityTagsDeleteColumnVersion.add(new Pair<>(EMPTY_TAG, deleteCellVisTagsFormat));
180 }
181 break;
182 default:
183 throw new IllegalArgumentException("Invalid delete type");
184 }
185 return hasVisTag;
186 }
187
188 @Override
189 public DeleteResult isDeleted(Cell cell) {
190 long timestamp = cell.getTimestamp();
191 int qualifierOffset = cell.getQualifierOffset();
192 int qualifierLength = cell.getQualifierLength();
193 try {
194 if (hasFamilyStamp) {
195 if (visibilityTagsDeleteFamily != null) {
196 if (!visibilityTagsDeleteFamily.isEmpty()) {
197 for (int i = 0; i < visibilityTagsDeleteFamily.size(); i++) {
198
199 Triple<List<Tag>, Byte, Long> triple = visibilityTagsDeleteFamily.get(i);
200 if (timestamp <= triple.getThird()) {
201 List<Tag> putVisTags = new ArrayList<Tag>();
202 Byte putCellVisTagsFormat = VisibilityUtils.extractVisibilityTags(cell, putVisTags);
203 boolean matchFound = VisibilityLabelServiceManager.getInstance()
204 .getVisibilityLabelService().matchVisibility(putVisTags, putCellVisTagsFormat,
205 triple.getFirst(), triple.getSecond());
206 if (matchFound) {
207
208
209
210
211
212
213 return DeleteResult.FAMILY_VERSION_DELETED;
214 }
215 }
216 }
217 } else {
218 if (!VisibilityUtils.isVisibilityTagsPresent(cell) && timestamp <= familyStamp) {
219
220 return DeleteResult.FAMILY_VERSION_DELETED;
221 }
222 }
223 } else {
224 if (!VisibilityUtils.isVisibilityTagsPresent(cell) && timestamp <= familyStamp) {
225
226 return DeleteResult.FAMILY_VERSION_DELETED;
227 }
228 }
229 }
230 if (familyVersionStamps.contains(Long.valueOf(timestamp))) {
231 if (visibilityTagsDeleteFamilyVersion != null) {
232 if (!visibilityTagsDeleteFamilyVersion.isEmpty()) {
233 for (int i = 0; i < visibilityTagsDeleteFamilyVersion.size(); i++) {
234
235 Triple<List<Tag>, Byte, Long> triple = visibilityTagsDeleteFamilyVersion.get(i);
236 if (timestamp == triple.getThird()) {
237 List<Tag> putVisTags = new ArrayList<Tag>();
238 Byte putCellVisTagsFormat = VisibilityUtils.extractVisibilityTags(cell, putVisTags);
239 boolean matchFound = VisibilityLabelServiceManager.getInstance()
240 .getVisibilityLabelService().matchVisibility(putVisTags, putCellVisTagsFormat,
241 triple.getFirst(), triple.getSecond());
242 if (matchFound) {
243 return DeleteResult.FAMILY_VERSION_DELETED;
244 }
245 }
246 }
247 } else {
248 if (!VisibilityUtils.isVisibilityTagsPresent(cell)) {
249
250 return DeleteResult.FAMILY_VERSION_DELETED;
251 }
252 }
253 } else {
254 if (!VisibilityUtils.isVisibilityTagsPresent(cell)) {
255
256 return DeleteResult.FAMILY_VERSION_DELETED;
257 }
258 }
259 }
260 if (deleteBuffer != null) {
261 int ret = Bytes.compareTo(deleteBuffer, deleteOffset, deleteLength,
262 cell.getQualifierArray(), qualifierOffset, qualifierLength);
263
264 if (ret == 0) {
265 if (deleteType == KeyValue.Type.DeleteColumn.getCode()) {
266 if (visibilityTagsDeleteColumns != null) {
267 if (!visibilityTagsDeleteColumns.isEmpty()) {
268 for (Pair<List<Tag>, Byte> tags : visibilityTagsDeleteColumns) {
269 List<Tag> putVisTags = new ArrayList<Tag>();
270 Byte putCellVisTagsFormat =
271 VisibilityUtils.extractVisibilityTags(cell, putVisTags);
272 boolean matchFound = VisibilityLabelServiceManager.getInstance()
273 .getVisibilityLabelService().matchVisibility(putVisTags, putCellVisTagsFormat,
274 tags.getFirst(), tags.getSecond());
275 if (matchFound) {
276 return DeleteResult.VERSION_DELETED;
277 }
278 }
279 } else {
280 if (!VisibilityUtils.isVisibilityTagsPresent(cell)) {
281
282 return DeleteResult.VERSION_DELETED;
283 }
284 }
285 } else {
286 if (!VisibilityUtils.isVisibilityTagsPresent(cell)) {
287
288 return DeleteResult.VERSION_DELETED;
289 }
290 }
291 }
292
293
294 if (timestamp == deleteTimestamp) {
295 if (visiblityTagsDeleteColumnVersion != null) {
296 if (!visiblityTagsDeleteColumnVersion.isEmpty()) {
297 for (Pair<List<Tag>, Byte> tags : visiblityTagsDeleteColumnVersion) {
298 List<Tag> putVisTags = new ArrayList<Tag>();
299 Byte putCellVisTagsFormat =
300 VisibilityUtils.extractVisibilityTags(cell, putVisTags);
301 boolean matchFound = VisibilityLabelServiceManager.getInstance()
302 .getVisibilityLabelService().matchVisibility(putVisTags, putCellVisTagsFormat,
303 tags.getFirst(), tags.getSecond());
304 if (matchFound) {
305 return DeleteResult.VERSION_DELETED;
306 }
307 }
308 } else {
309 if (!VisibilityUtils.isVisibilityTagsPresent(cell)) {
310
311 return DeleteResult.VERSION_DELETED;
312 }
313 }
314 } else {
315 if (!VisibilityUtils.isVisibilityTagsPresent(cell)) {
316
317 return DeleteResult.VERSION_DELETED;
318 }
319 }
320 }
321 } else if (ret < 0) {
322
323 deleteBuffer = null;
324
325 visibilityTagsDeleteColumns = null;
326 visiblityTagsDeleteColumnVersion = null;
327 } else {
328 throw new IllegalStateException("isDeleted failed: deleteBuffer="
329 + Bytes.toStringBinary(deleteBuffer, deleteOffset, deleteLength) + ", qualifier="
330 + Bytes.toStringBinary(cell.getQualifierArray(), qualifierOffset, qualifierLength)
331 + ", timestamp=" + timestamp + ", comparison result: " + ret);
332 }
333 }
334 } catch (IOException e) {
335 LOG.error("Error in isDeleted() check! Will treat cell as not deleted", e);
336 }
337 return DeleteResult.NOT_DELETED;
338 }
339
340 @Override
341 public void reset() {
342 super.reset();
343
344 visibilityTagsDeleteColumns = null;
345 visibilityTagsDeleteFamily = null;
346 visibilityTagsDeleteFamilyVersion = null;
347 visiblityTagsDeleteColumnVersion = null;
348 }
349 }