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