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