1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.hadoop.hbase.security.visibility;
19
20 import static org.apache.hadoop.hbase.TagType.VISIBILITY_TAG_TYPE;
21
22 import java.io.ByteArrayOutputStream;
23 import java.io.DataOutputStream;
24 import java.io.IOException;
25 import java.util.ArrayList;
26 import java.util.Collections;
27 import java.util.HashMap;
28 import java.util.Iterator;
29 import java.util.List;
30 import java.util.Map;
31 import java.util.Map.Entry;
32 import java.util.Set;
33
34 import org.apache.commons.lang.StringUtils;
35 import org.apache.commons.logging.Log;
36 import org.apache.commons.logging.LogFactory;
37 import org.apache.hadoop.conf.Configuration;
38 import org.apache.hadoop.hbase.Cell;
39 import org.apache.hadoop.hbase.CellUtil;
40 import org.apache.hadoop.hbase.HColumnDescriptor;
41 import org.apache.hadoop.hbase.Tag;
42 import org.apache.hadoop.hbase.TagType;
43 import org.apache.hadoop.hbase.classification.InterfaceAudience;
44 import org.apache.hadoop.hbase.exceptions.DeserializationException;
45 import org.apache.hadoop.hbase.filter.Filter;
46 import org.apache.hadoop.hbase.io.util.StreamUtils;
47 import org.apache.hadoop.hbase.ipc.RpcServer;
48 import org.apache.hadoop.hbase.protobuf.ProtobufUtil;
49 import org.apache.hadoop.hbase.protobuf.generated.VisibilityLabelsProtos.MultiUserAuthorizations;
50 import org.apache.hadoop.hbase.protobuf.generated.VisibilityLabelsProtos.UserAuthorizations;
51 import org.apache.hadoop.hbase.protobuf.generated.VisibilityLabelsProtos.VisibilityLabel;
52 import org.apache.hadoop.hbase.protobuf.generated.VisibilityLabelsProtos.VisibilityLabelsRequest;
53 import org.apache.hadoop.hbase.regionserver.Region;
54 import org.apache.hadoop.hbase.security.AccessDeniedException;
55 import org.apache.hadoop.hbase.security.User;
56 import org.apache.hadoop.hbase.security.visibility.expression.ExpressionNode;
57 import org.apache.hadoop.hbase.security.visibility.expression.LeafExpressionNode;
58 import org.apache.hadoop.hbase.security.visibility.expression.NonLeafExpressionNode;
59 import org.apache.hadoop.hbase.security.visibility.expression.Operator;
60 import org.apache.hadoop.hbase.util.ByteRange;
61 import org.apache.hadoop.hbase.util.ByteStringer;
62 import org.apache.hadoop.hbase.util.Bytes;
63 import org.apache.hadoop.hbase.util.SimpleMutableByteRange;
64 import org.apache.hadoop.util.ReflectionUtils;
65
66
67
68
69 @InterfaceAudience.Private
70 public class VisibilityUtils {
71
72 private static final Log LOG = LogFactory.getLog(VisibilityUtils.class);
73
74 public static final String VISIBILITY_LABEL_GENERATOR_CLASS =
75 "hbase.regionserver.scan.visibility.label.generator.class";
76 public static final String SYSTEM_LABEL = "system";
77 public static final Tag SORTED_ORDINAL_SERIALIZATION_FORMAT_TAG = new Tag(
78 TagType.VISIBILITY_EXP_SERIALIZATION_FORMAT_TAG_TYPE,
79 VisibilityConstants.SORTED_ORDINAL_SERIALIZATION_FORMAT_TAG_VAL);
80 private static final String COMMA = ",";
81
82 private static final ExpressionParser EXP_PARSER = new ExpressionParser();
83 private static final ExpressionExpander EXP_EXPANDER = new ExpressionExpander();
84
85
86
87
88
89
90 public static byte[] getDataToWriteToZooKeeper(Map<String, Integer> existingLabels) {
91 VisibilityLabelsRequest.Builder visReqBuilder = VisibilityLabelsRequest.newBuilder();
92 for (Entry<String, Integer> entry : existingLabels.entrySet()) {
93 VisibilityLabel.Builder visLabBuilder = VisibilityLabel.newBuilder();
94 visLabBuilder.setLabel(ByteStringer.wrap(Bytes.toBytes(entry.getKey())));
95 visLabBuilder.setOrdinal(entry.getValue());
96 visReqBuilder.addVisLabel(visLabBuilder.build());
97 }
98 return ProtobufUtil.prependPBMagic(visReqBuilder.build().toByteArray());
99 }
100
101
102
103
104
105
106 public static byte[] getUserAuthsDataToWriteToZooKeeper(Map<String, List<Integer>> userAuths) {
107 MultiUserAuthorizations.Builder builder = MultiUserAuthorizations.newBuilder();
108 for (Entry<String, List<Integer>> entry : userAuths.entrySet()) {
109 UserAuthorizations.Builder userAuthsBuilder = UserAuthorizations.newBuilder();
110 userAuthsBuilder.setUser(ByteStringer.wrap(Bytes.toBytes(entry.getKey())));
111 for (Integer label : entry.getValue()) {
112 userAuthsBuilder.addAuth(label);
113 }
114 builder.addUserAuths(userAuthsBuilder.build());
115 }
116 return ProtobufUtil.prependPBMagic(builder.build().toByteArray());
117 }
118
119
120
121
122
123
124
125
126
127 public static List<VisibilityLabel> readLabelsFromZKData(byte[] data)
128 throws DeserializationException {
129 if (ProtobufUtil.isPBMagicPrefix(data)) {
130 int pblen = ProtobufUtil.lengthOfPBMagic();
131 try {
132 VisibilityLabelsRequest.Builder builder = VisibilityLabelsRequest.newBuilder();
133 ProtobufUtil.mergeFrom(builder, data, pblen, data.length - pblen);
134 return builder.getVisLabelList();
135 } catch (IOException e) {
136 throw new DeserializationException(e);
137 }
138 }
139 return null;
140 }
141
142
143
144
145
146
147
148 public static MultiUserAuthorizations readUserAuthsFromZKData(byte[] data)
149 throws DeserializationException {
150 if (ProtobufUtil.isPBMagicPrefix(data)) {
151 int pblen = ProtobufUtil.lengthOfPBMagic();
152 try {
153 MultiUserAuthorizations.Builder builder = MultiUserAuthorizations.newBuilder();
154 ProtobufUtil.mergeFrom(builder, data, pblen, data.length - pblen);
155 return builder.build();
156 } catch (IOException e) {
157 throw new DeserializationException(e);
158 }
159 }
160 return null;
161 }
162
163
164
165
166
167
168
169
170
171 public static List<ScanLabelGenerator> getScanLabelGenerators(Configuration conf) {
172
173 String slgClassesCommaSeparated = conf.get(VISIBILITY_LABEL_GENERATOR_CLASS);
174
175
176 List<ScanLabelGenerator> slgs = new ArrayList<ScanLabelGenerator>();
177 if (StringUtils.isNotEmpty(slgClassesCommaSeparated)) {
178 String[] slgClasses = slgClassesCommaSeparated.split(COMMA);
179 for (String slgClass : slgClasses) {
180 Class<? extends ScanLabelGenerator> slgKlass;
181 try {
182 slgKlass = (Class<? extends ScanLabelGenerator>) conf.getClassByName(slgClass.trim());
183 slgs.add(ReflectionUtils.newInstance(slgKlass, conf));
184 } catch (ClassNotFoundException e) {
185 throw new IllegalArgumentException("Unable to find " + slgClass, e);
186 }
187 }
188 }
189
190
191
192
193
194
195
196
197 if (slgs.isEmpty()) {
198 slgs.add(ReflectionUtils.newInstance(FeedUserAuthScanLabelGenerator.class, conf));
199 slgs.add(ReflectionUtils.newInstance(DefinedSetFilterScanLabelGenerator.class, conf));
200 }
201 return slgs;
202 }
203
204
205
206
207
208
209
210 public static Byte extractVisibilityTags(Cell cell, List<Tag> tags) {
211 Byte serializationFormat = null;
212 if (cell.getTagsLength() > 0) {
213 Iterator<Tag> tagsIterator = CellUtil.tagsIterator(cell.getTagsArray(), cell.getTagsOffset(),
214 cell.getTagsLength());
215 while (tagsIterator.hasNext()) {
216 Tag tag = tagsIterator.next();
217 if (tag.getType() == TagType.VISIBILITY_EXP_SERIALIZATION_FORMAT_TAG_TYPE) {
218 serializationFormat = tag.getBuffer()[tag.getTagOffset()];
219 } else if (tag.getType() == VISIBILITY_TAG_TYPE) {
220 tags.add(tag);
221 }
222 }
223 }
224 return serializationFormat;
225 }
226
227
228
229
230
231
232
233
234
235
236
237
238
239 public static Byte extractAndPartitionTags(Cell cell, List<Tag> visTags,
240 List<Tag> nonVisTags) {
241 Byte serializationFormat = null;
242 if (cell.getTagsLength() > 0) {
243 Iterator<Tag> tagsIterator = CellUtil.tagsIterator(cell.getTagsArray(), cell.getTagsOffset(),
244 cell.getTagsLength());
245 while (tagsIterator.hasNext()) {
246 Tag tag = tagsIterator.next();
247 if (tag.getType() == TagType.VISIBILITY_EXP_SERIALIZATION_FORMAT_TAG_TYPE) {
248 serializationFormat = tag.getBuffer()[tag.getTagOffset()];
249 } else if (tag.getType() == VISIBILITY_TAG_TYPE) {
250 visTags.add(tag);
251 } else {
252
253 nonVisTags.add(tag);
254 }
255 }
256 }
257 return serializationFormat;
258 }
259
260 public static boolean isVisibilityTagsPresent(Cell cell) {
261 if (cell.getTagsLength() == 0) {
262 return false;
263 }
264 Iterator<Tag> tagsIterator = CellUtil.tagsIterator(cell.getTagsArray(), cell.getTagsOffset(),
265 cell.getTagsLength());
266 while (tagsIterator.hasNext()) {
267 Tag tag = tagsIterator.next();
268 if (tag.getType() == VISIBILITY_TAG_TYPE) {
269 return true;
270 }
271 }
272 return false;
273 }
274
275 public static Filter createVisibilityLabelFilter(Region region, Authorizations authorizations)
276 throws IOException {
277 Map<ByteRange, Integer> cfVsMaxVersions = new HashMap<ByteRange, Integer>();
278 for (HColumnDescriptor hcd : region.getTableDesc().getFamilies()) {
279 cfVsMaxVersions.put(new SimpleMutableByteRange(hcd.getName()), hcd.getMaxVersions());
280 }
281 VisibilityLabelService vls = VisibilityLabelServiceManager.getInstance()
282 .getVisibilityLabelService();
283 Filter visibilityLabelFilter = new VisibilityLabelFilter(
284 vls.getVisibilityExpEvaluator(authorizations), cfVsMaxVersions);
285 return visibilityLabelFilter;
286 }
287
288
289
290
291
292 public static User getActiveUser() throws IOException {
293 User user = RpcServer.getRequestUser();
294 if (user == null) {
295 user = User.getCurrent();
296 }
297 if (LOG.isTraceEnabled()) {
298 LOG.trace("Current active user name is " + user.getShortName());
299 }
300 return user;
301 }
302
303 public static List<Tag> createVisibilityExpTags(String visExpression,
304 boolean withSerializationFormat, boolean checkAuths, Set<Integer> auths,
305 VisibilityLabelOrdinalProvider ordinalProvider) throws IOException {
306 ExpressionNode node = null;
307 try {
308 node = EXP_PARSER.parse(visExpression);
309 } catch (ParseException e) {
310 throw new IOException(e);
311 }
312 node = EXP_EXPANDER.expand(node);
313 List<Tag> tags = new ArrayList<Tag>();
314 ByteArrayOutputStream baos = new ByteArrayOutputStream();
315 DataOutputStream dos = new DataOutputStream(baos);
316 List<Integer> labelOrdinals = new ArrayList<Integer>();
317
318
319 if (withSerializationFormat) {
320 tags.add(VisibilityUtils.SORTED_ORDINAL_SERIALIZATION_FORMAT_TAG);
321 }
322 if (node.isSingleNode()) {
323 getLabelOrdinals(node, labelOrdinals, auths, checkAuths, ordinalProvider);
324 writeLabelOrdinalsToStream(labelOrdinals, dos);
325 tags.add(new Tag(VISIBILITY_TAG_TYPE, baos.toByteArray()));
326 baos.reset();
327 } else {
328 NonLeafExpressionNode nlNode = (NonLeafExpressionNode) node;
329 if (nlNode.getOperator() == Operator.OR) {
330 for (ExpressionNode child : nlNode.getChildExps()) {
331 getLabelOrdinals(child, labelOrdinals, auths, checkAuths, ordinalProvider);
332 writeLabelOrdinalsToStream(labelOrdinals, dos);
333 tags.add(new Tag(VISIBILITY_TAG_TYPE, baos.toByteArray()));
334 baos.reset();
335 labelOrdinals.clear();
336 }
337 } else {
338 getLabelOrdinals(nlNode, labelOrdinals, auths, checkAuths, ordinalProvider);
339 writeLabelOrdinalsToStream(labelOrdinals, dos);
340 tags.add(new Tag(VISIBILITY_TAG_TYPE, baos.toByteArray()));
341 baos.reset();
342 }
343 }
344 return tags;
345 }
346
347 private static void getLabelOrdinals(ExpressionNode node, List<Integer> labelOrdinals,
348 Set<Integer> auths, boolean checkAuths, VisibilityLabelOrdinalProvider ordinalProvider)
349 throws IOException, InvalidLabelException {
350 if (node.isSingleNode()) {
351 String identifier = null;
352 int labelOrdinal = 0;
353 if (node instanceof LeafExpressionNode) {
354 identifier = ((LeafExpressionNode) node).getIdentifier();
355 if (LOG.isTraceEnabled()) {
356 LOG.trace("The identifier is " + identifier);
357 }
358 labelOrdinal = ordinalProvider.getLabelOrdinal(identifier);
359 checkAuths(auths, labelOrdinal, identifier, checkAuths);
360 } else {
361
362 LeafExpressionNode lNode = (LeafExpressionNode) ((NonLeafExpressionNode) node)
363 .getChildExps().get(0);
364 identifier = lNode.getIdentifier();
365 labelOrdinal = ordinalProvider.getLabelOrdinal(identifier);
366 checkAuths(auths, labelOrdinal, identifier, checkAuths);
367 labelOrdinal = -1 * labelOrdinal;
368 }
369 if (labelOrdinal == 0) {
370 throw new InvalidLabelException("Invalid visibility label " + identifier);
371 }
372 labelOrdinals.add(labelOrdinal);
373 } else {
374 List<ExpressionNode> childExps = ((NonLeafExpressionNode) node).getChildExps();
375 for (ExpressionNode child : childExps) {
376 getLabelOrdinals(child, labelOrdinals, auths, checkAuths, ordinalProvider);
377 }
378 }
379 }
380
381
382
383
384
385
386
387
388
389
390
391 private static void writeLabelOrdinalsToStream(List<Integer> labelOrdinals, DataOutputStream dos)
392 throws IOException {
393 Collections.sort(labelOrdinals);
394 for (Integer labelOrdinal : labelOrdinals) {
395 StreamUtils.writeRawVInt32(dos, labelOrdinal);
396 }
397 }
398
399 private static void checkAuths(Set<Integer> auths, int labelOrdinal, String identifier,
400 boolean checkAuths) throws IOException {
401 if (checkAuths) {
402 if (auths == null || (!auths.contains(labelOrdinal))) {
403 throw new AccessDeniedException("Visibility label " + identifier
404 + " not authorized for the user " + VisibilityUtils.getActiveUser().getShortName());
405 }
406 }
407 }
408 }