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 static org.apache.hadoop.hbase.HConstants.OperationStatusCode.SANITY_CHECK_FAILURE;
22 import static org.apache.hadoop.hbase.HConstants.OperationStatusCode.SUCCESS;
23 import static org.apache.hadoop.hbase.security.visibility.VisibilityConstants.LABELS_TABLE_FAMILY;
24 import static org.apache.hadoop.hbase.security.visibility.VisibilityConstants.LABELS_TABLE_NAME;
25 import static org.apache.hadoop.hbase.security.visibility.VisibilityConstants.LABEL_QUALIFIER;
26 import static org.apache.hadoop.hbase.security.visibility.VisibilityUtils.SYSTEM_LABEL;
27
28 import java.io.ByteArrayOutputStream;
29 import java.io.DataOutputStream;
30 import java.io.IOException;
31 import java.util.ArrayList;
32 import java.util.BitSet;
33 import java.util.Collections;
34 import java.util.HashMap;
35 import java.util.Iterator;
36 import java.util.List;
37 import java.util.Map;
38
39 import org.apache.commons.logging.Log;
40 import org.apache.commons.logging.LogFactory;
41 import org.apache.hadoop.classification.InterfaceAudience;
42 import org.apache.hadoop.conf.Configuration;
43 import org.apache.hadoop.hbase.Cell;
44 import org.apache.hadoop.hbase.CellScanner;
45 import org.apache.hadoop.hbase.CellUtil;
46 import org.apache.hadoop.hbase.CoprocessorEnvironment;
47 import org.apache.hadoop.hbase.DoNotRetryIOException;
48 import org.apache.hadoop.hbase.HColumnDescriptor;
49 import org.apache.hadoop.hbase.HConstants;
50 import org.apache.hadoop.hbase.HRegionInfo;
51 import org.apache.hadoop.hbase.HTableDescriptor;
52 import org.apache.hadoop.hbase.KeyValue;
53 import org.apache.hadoop.hbase.KeyValue.Type;
54 import org.apache.hadoop.hbase.KeyValueUtil;
55 import org.apache.hadoop.hbase.NamespaceDescriptor;
56 import org.apache.hadoop.hbase.ServerName;
57 import org.apache.hadoop.hbase.TableName;
58 import org.apache.hadoop.hbase.Tag;
59 import org.apache.hadoop.hbase.catalog.MetaReader;
60 import org.apache.hadoop.hbase.client.Append;
61 import org.apache.hadoop.hbase.client.Delete;
62 import org.apache.hadoop.hbase.client.Get;
63 import org.apache.hadoop.hbase.client.Increment;
64 import org.apache.hadoop.hbase.client.Mutation;
65 import org.apache.hadoop.hbase.client.Put;
66 import org.apache.hadoop.hbase.client.Result;
67 import org.apache.hadoop.hbase.client.Scan;
68 import org.apache.hadoop.hbase.constraint.ConstraintException;
69 import org.apache.hadoop.hbase.coprocessor.BaseRegionObserver;
70 import org.apache.hadoop.hbase.coprocessor.CoprocessorException;
71 import org.apache.hadoop.hbase.coprocessor.CoprocessorHost;
72 import org.apache.hadoop.hbase.coprocessor.CoprocessorService;
73 import org.apache.hadoop.hbase.coprocessor.MasterCoprocessorEnvironment;
74 import org.apache.hadoop.hbase.coprocessor.MasterObserver;
75 import org.apache.hadoop.hbase.coprocessor.ObserverContext;
76 import org.apache.hadoop.hbase.coprocessor.RegionCoprocessorEnvironment;
77 import org.apache.hadoop.hbase.coprocessor.RegionObserver;
78 import org.apache.hadoop.hbase.coprocessor.RegionServerCoprocessorEnvironment;
79 import org.apache.hadoop.hbase.exceptions.DeserializationException;
80 import org.apache.hadoop.hbase.exceptions.FailedSanityCheckException;
81 import org.apache.hadoop.hbase.filter.Filter;
82 import org.apache.hadoop.hbase.filter.FilterBase;
83 import org.apache.hadoop.hbase.filter.FilterList;
84 import org.apache.hadoop.hbase.io.hfile.HFile;
85 import org.apache.hadoop.hbase.io.util.StreamUtils;
86 import org.apache.hadoop.hbase.ipc.RequestContext;
87 import org.apache.hadoop.hbase.master.MasterServices;
88 import org.apache.hadoop.hbase.master.RegionPlan;
89 import org.apache.hadoop.hbase.protobuf.ResponseConverter;
90 import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.RegionActionResult;
91 import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.SnapshotDescription;
92 import org.apache.hadoop.hbase.protobuf.generated.VisibilityLabelsProtos;
93 import org.apache.hadoop.hbase.protobuf.generated.VisibilityLabelsProtos.GetAuthsRequest;
94 import org.apache.hadoop.hbase.protobuf.generated.VisibilityLabelsProtos.GetAuthsResponse;
95 import org.apache.hadoop.hbase.protobuf.generated.VisibilityLabelsProtos.SetAuthsRequest;
96 import org.apache.hadoop.hbase.protobuf.generated.VisibilityLabelsProtos.VisibilityLabel;
97 import org.apache.hadoop.hbase.protobuf.generated.VisibilityLabelsProtos.VisibilityLabelsRequest;
98 import org.apache.hadoop.hbase.protobuf.generated.VisibilityLabelsProtos.VisibilityLabelsResponse;
99 import org.apache.hadoop.hbase.protobuf.generated.VisibilityLabelsProtos.VisibilityLabelsService;
100 import org.apache.hadoop.hbase.regionserver.BloomType;
101 import org.apache.hadoop.hbase.regionserver.DeleteTracker;
102 import org.apache.hadoop.hbase.regionserver.DisabledRegionSplitPolicy;
103 import org.apache.hadoop.hbase.regionserver.HRegion;
104 import org.apache.hadoop.hbase.regionserver.InternalScanner;
105 import org.apache.hadoop.hbase.regionserver.MiniBatchOperationInProgress;
106 import org.apache.hadoop.hbase.regionserver.OperationStatus;
107 import org.apache.hadoop.hbase.regionserver.RegionScanner;
108 import org.apache.hadoop.hbase.security.AccessDeniedException;
109 import org.apache.hadoop.hbase.security.User;
110 import org.apache.hadoop.hbase.security.access.AccessControlLists;
111 import org.apache.hadoop.hbase.security.access.AccessController;
112 import org.apache.hadoop.hbase.security.visibility.expression.ExpressionNode;
113 import org.apache.hadoop.hbase.security.visibility.expression.LeafExpressionNode;
114 import org.apache.hadoop.hbase.security.visibility.expression.NonLeafExpressionNode;
115 import org.apache.hadoop.hbase.security.visibility.expression.Operator;
116 import org.apache.hadoop.hbase.util.ByteRange;
117 import org.apache.hadoop.hbase.util.Bytes;
118 import org.apache.hadoop.hbase.util.Pair;
119 import org.apache.hadoop.hbase.util.SimpleByteRange;
120 import org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher;
121
122 import com.google.common.collect.Lists;
123 import com.google.common.collect.MapMaker;
124 import com.google.protobuf.ByteString;
125 import org.apache.hadoop.hbase.util.ByteStringer;
126 import com.google.protobuf.RpcCallback;
127 import com.google.protobuf.RpcController;
128 import com.google.protobuf.Service;
129
130
131
132
133
134 @InterfaceAudience.Private
135 public class VisibilityController extends BaseRegionObserver implements MasterObserver,
136 RegionObserver, VisibilityLabelsService.Interface, CoprocessorService {
137
138 private static final Log LOG = LogFactory.getLog(VisibilityController.class);
139 private static final byte[] DUMMY_VALUE = new byte[0];
140
141 private static final int SYSTEM_LABEL_ORDINAL = 1;
142 private static final Tag[] LABELS_TABLE_TAGS = new Tag[1];
143
144 private final ExpressionParser expressionParser = new ExpressionParser();
145 private final ExpressionExpander expressionExpander = new ExpressionExpander();
146 private VisibilityLabelsManager visibilityManager;
147
148 private RegionCoprocessorEnvironment regionEnv;
149 private List<ScanLabelGenerator> scanLabelGenerators;
150
151 private volatile int ordinalCounter = -1;
152
153 private boolean labelsRegion = false;
154
155 private boolean acOn = false;
156 private Configuration conf;
157 private volatile boolean initialized = false;
158
159 private Map<InternalScanner,String> scannerOwners =
160 new MapMaker().weakKeys().makeMap();
161
162 List<String> superUsers;
163
164 static {
165 ByteArrayOutputStream baos = new ByteArrayOutputStream();
166 DataOutputStream dos = new DataOutputStream(baos);
167 try {
168 StreamUtils.writeRawVInt32(dos, SYSTEM_LABEL_ORDINAL);
169 } catch (IOException e) {
170
171 }
172 LABELS_TABLE_TAGS[0] = new Tag(VisibilityUtils.VISIBILITY_TAG_TYPE, baos.toByteArray());
173 }
174
175
176 private static ArrayList<Byte> reservedVisTagTypes = new ArrayList<Byte>();
177 static {
178 reservedVisTagTypes.add(VisibilityUtils.VISIBILITY_TAG_TYPE);
179 reservedVisTagTypes.add(VisibilityUtils.VISIBILITY_EXP_SERIALIZATION_TAG_TYPE);
180 }
181
182 @Override
183 public void start(CoprocessorEnvironment env) throws IOException {
184 this.conf = env.getConfiguration();
185 if (HFile.getFormatVersion(conf) < HFile.MIN_FORMAT_VERSION_WITH_TAGS) {
186 throw new RuntimeException("A minimum HFile version of " + HFile.MIN_FORMAT_VERSION_WITH_TAGS
187 + " is required to persist visibility labels. Consider setting " + HFile.FORMAT_VERSION_KEY
188 + " accordingly.");
189 }
190 ZooKeeperWatcher zk = null;
191 if (env instanceof MasterCoprocessorEnvironment) {
192
193 MasterCoprocessorEnvironment mEnv = (MasterCoprocessorEnvironment) env;
194 zk = mEnv.getMasterServices().getZooKeeper();
195 } else if (env instanceof RegionCoprocessorEnvironment) {
196
197 regionEnv = (RegionCoprocessorEnvironment) env;
198 zk = regionEnv.getRegionServerServices().getZooKeeper();
199 } else if (env instanceof RegionServerCoprocessorEnvironment) {
200 throw new RuntimeException(
201 "Visibility controller should not be configured as " +
202 "'hbase.coprocessor.regionserver.classes'.");
203 }
204
205
206
207 if (zk == null) {
208 throw new RuntimeException("Error obtaining VisibilityLabelsManager, zk found null.");
209 }
210 try {
211 this.visibilityManager = VisibilityLabelsManager.get(zk, this.conf);
212 } catch (IOException ioe) {
213 throw new RuntimeException("Error obtaining VisibilityLabelsManager", ioe);
214 }
215 if (env instanceof RegionCoprocessorEnvironment) {
216
217 scanLabelGenerators = VisibilityUtils.getScanLabelGenerators(this.conf);
218 }
219 this.superUsers = getSystemAndSuperUsers();
220 }
221
222 @Override
223 public void stop(CoprocessorEnvironment env) throws IOException {
224
225 }
226
227
228
229 @Override
230 public void postStartMaster(ObserverContext<MasterCoprocessorEnvironment> ctx) throws IOException {
231
232 MasterServices master = ctx.getEnvironment().getMasterServices();
233 if (!MetaReader.tableExists(master.getCatalogTracker(), LABELS_TABLE_NAME)) {
234 HTableDescriptor labelsTable = new HTableDescriptor(LABELS_TABLE_NAME);
235 HColumnDescriptor labelsColumn = new HColumnDescriptor(LABELS_TABLE_FAMILY);
236 labelsColumn.setBloomFilterType(BloomType.NONE);
237 labelsColumn.setBlockCacheEnabled(false);
238
239 labelsTable.addFamily(labelsColumn);
240
241
242 labelsTable.setValue(HTableDescriptor.SPLIT_POLICY,
243 DisabledRegionSplitPolicy.class.getName());
244 labelsTable.setValue(Bytes.toBytes(HConstants.DISALLOW_WRITES_IN_RECOVERING),
245 Bytes.toBytes(true));
246 master.createTable(labelsTable, null);
247 }
248 }
249
250 @Override
251 public void preCreateTable(ObserverContext<MasterCoprocessorEnvironment> ctx,
252 HTableDescriptor desc, HRegionInfo[] regions) throws IOException {
253 }
254
255 @Override
256 public void postCreateTable(ObserverContext<MasterCoprocessorEnvironment> ctx,
257 HTableDescriptor desc, HRegionInfo[] regions) throws IOException {
258 }
259
260 @Override
261 public void preCreateTableHandler(ObserverContext<MasterCoprocessorEnvironment> ctx,
262 HTableDescriptor desc, HRegionInfo[] regions) throws IOException {
263 }
264
265 @Override
266 public void postCreateTableHandler(ObserverContext<MasterCoprocessorEnvironment> ctx,
267 HTableDescriptor desc, HRegionInfo[] regions) throws IOException {
268 }
269
270 @Override
271 public void preDeleteTable(ObserverContext<MasterCoprocessorEnvironment> ctx, TableName tableName)
272 throws IOException {
273 }
274
275 @Override
276 public void postDeleteTable(ObserverContext<MasterCoprocessorEnvironment> ctx, TableName tableName)
277 throws IOException {
278 }
279
280 @Override
281 public void preDeleteTableHandler(ObserverContext<MasterCoprocessorEnvironment> ctx,
282 TableName tableName) throws IOException {
283 }
284
285 @Override
286 public void postDeleteTableHandler(ObserverContext<MasterCoprocessorEnvironment> ctx,
287 TableName tableName) throws IOException {
288 }
289
290 @Override
291 public void preModifyTable(ObserverContext<MasterCoprocessorEnvironment> ctx,
292 TableName tableName, HTableDescriptor htd) throws IOException {
293 if (LABELS_TABLE_NAME.equals(tableName)) {
294 throw new ConstraintException("Cannot alter " + LABELS_TABLE_NAME);
295 }
296 }
297
298 @Override
299 public void postModifyTable(ObserverContext<MasterCoprocessorEnvironment> ctx,
300 TableName tableName, HTableDescriptor htd) throws IOException {
301 }
302
303 @Override
304 public void preModifyTableHandler(ObserverContext<MasterCoprocessorEnvironment> ctx,
305 TableName tableName, HTableDescriptor htd) throws IOException {
306 }
307
308 @Override
309 public void postModifyTableHandler(ObserverContext<MasterCoprocessorEnvironment> ctx,
310 TableName tableName, HTableDescriptor htd) throws IOException {
311 }
312
313 @Override
314 public void preAddColumn(ObserverContext<MasterCoprocessorEnvironment> ctx, TableName tableName,
315 HColumnDescriptor column) throws IOException {
316 if (LABELS_TABLE_NAME.equals(tableName)) {
317 throw new ConstraintException("Cannot alter " + LABELS_TABLE_NAME);
318 }
319 }
320
321 @Override
322 public void postAddColumn(ObserverContext<MasterCoprocessorEnvironment> ctx, TableName tableName,
323 HColumnDescriptor column) throws IOException {
324 }
325
326 @Override
327 public void preAddColumnHandler(ObserverContext<MasterCoprocessorEnvironment> ctx,
328 TableName tableName, HColumnDescriptor column) throws IOException {
329 }
330
331 @Override
332 public void postAddColumnHandler(ObserverContext<MasterCoprocessorEnvironment> ctx,
333 TableName tableName, HColumnDescriptor column) throws IOException {
334 }
335
336 @Override
337 public void preModifyColumn(ObserverContext<MasterCoprocessorEnvironment> ctx,
338 TableName tableName, HColumnDescriptor descriptor) throws IOException {
339 if (LABELS_TABLE_NAME.equals(tableName)) {
340 throw new ConstraintException("Cannot alter " + LABELS_TABLE_NAME);
341 }
342 }
343
344 @Override
345 public void postModifyColumn(ObserverContext<MasterCoprocessorEnvironment> ctx,
346 TableName tableName, HColumnDescriptor descriptor) throws IOException {
347 }
348
349 @Override
350 public void preModifyColumnHandler(ObserverContext<MasterCoprocessorEnvironment> ctx,
351 TableName tableName, HColumnDescriptor descriptor) throws IOException {
352 }
353
354 @Override
355 public void postModifyColumnHandler(ObserverContext<MasterCoprocessorEnvironment> ctx,
356 TableName tableName, HColumnDescriptor descriptor) throws IOException {
357 }
358
359 @Override
360 public void preDeleteColumn(ObserverContext<MasterCoprocessorEnvironment> ctx,
361 TableName tableName, byte[] c) throws IOException {
362 if (LABELS_TABLE_NAME.equals(tableName)) {
363 throw new ConstraintException("Cannot alter " + LABELS_TABLE_NAME);
364 }
365 }
366
367 @Override
368 public void postDeleteColumn(ObserverContext<MasterCoprocessorEnvironment> ctx,
369 TableName tableName, byte[] c) throws IOException {
370 }
371
372 @Override
373 public void preDeleteColumnHandler(ObserverContext<MasterCoprocessorEnvironment> ctx,
374 TableName tableName, byte[] c) throws IOException {
375 }
376
377 @Override
378 public void postDeleteColumnHandler(ObserverContext<MasterCoprocessorEnvironment> ctx,
379 TableName tableName, byte[] c) throws IOException {
380 }
381
382 @Override
383 public void preEnableTable(ObserverContext<MasterCoprocessorEnvironment> ctx, TableName tableName)
384 throws IOException {
385 }
386
387 @Override
388 public void postEnableTable(ObserverContext<MasterCoprocessorEnvironment> ctx, TableName tableName)
389 throws IOException {
390 }
391
392 @Override
393 public void preEnableTableHandler(ObserverContext<MasterCoprocessorEnvironment> ctx,
394 TableName tableName) throws IOException {
395 }
396
397 @Override
398 public void postEnableTableHandler(ObserverContext<MasterCoprocessorEnvironment> ctx,
399 TableName tableName) throws IOException {
400 }
401
402 @Override
403 public void preDisableTable(ObserverContext<MasterCoprocessorEnvironment> ctx, TableName tableName)
404 throws IOException {
405 if (LABELS_TABLE_NAME.equals(tableName)) {
406 throw new ConstraintException("Cannot disable " + LABELS_TABLE_NAME);
407 }
408 }
409
410 @Override
411 public void postDisableTable(ObserverContext<MasterCoprocessorEnvironment> ctx,
412 TableName tableName) throws IOException {
413 }
414
415 @Override
416 public void preDisableTableHandler(ObserverContext<MasterCoprocessorEnvironment> ctx,
417 TableName tableName) throws IOException {
418 }
419
420 @Override
421 public void postDisableTableHandler(ObserverContext<MasterCoprocessorEnvironment> ctx,
422 TableName tableName) throws IOException {
423 }
424
425 @Override
426 public void preMove(ObserverContext<MasterCoprocessorEnvironment> ctx, HRegionInfo region,
427 ServerName srcServer, ServerName destServer) throws IOException {
428 }
429
430 @Override
431 public void postMove(ObserverContext<MasterCoprocessorEnvironment> ctx, HRegionInfo region,
432 ServerName srcServer, ServerName destServer) throws IOException {
433 }
434
435 @Override
436 public void preAssign(ObserverContext<MasterCoprocessorEnvironment> ctx, HRegionInfo regionInfo)
437 throws IOException {
438 }
439
440 @Override
441 public void postAssign(ObserverContext<MasterCoprocessorEnvironment> ctx, HRegionInfo regionInfo)
442 throws IOException {
443 }
444
445 @Override
446 public void preUnassign(ObserverContext<MasterCoprocessorEnvironment> ctx,
447 HRegionInfo regionInfo, boolean force) throws IOException {
448 }
449
450 @Override
451 public void postUnassign(ObserverContext<MasterCoprocessorEnvironment> ctx,
452 HRegionInfo regionInfo, boolean force) throws IOException {
453 }
454
455 @Override
456 public void preRegionOffline(ObserverContext<MasterCoprocessorEnvironment> ctx,
457 HRegionInfo regionInfo) throws IOException {
458 }
459
460 @Override
461 public void postRegionOffline(ObserverContext<MasterCoprocessorEnvironment> ctx,
462 HRegionInfo regionInfo) throws IOException {
463 }
464
465 @Override
466 public void preBalance(ObserverContext<MasterCoprocessorEnvironment> ctx) throws IOException {
467 }
468
469 @Override
470 public void postBalance(ObserverContext<MasterCoprocessorEnvironment> ctx, List<RegionPlan> plans)
471 throws IOException {
472 }
473
474 @Override
475 public boolean preBalanceSwitch(ObserverContext<MasterCoprocessorEnvironment> ctx,
476 boolean newValue) throws IOException {
477 return false;
478 }
479
480 @Override
481 public void postBalanceSwitch(ObserverContext<MasterCoprocessorEnvironment> ctx,
482 boolean oldValue, boolean newValue) throws IOException {
483 }
484
485 @Override
486 public void preShutdown(ObserverContext<MasterCoprocessorEnvironment> ctx) throws IOException {
487 }
488
489 @Override
490 public void preStopMaster(ObserverContext<MasterCoprocessorEnvironment> ctx) throws IOException {
491 }
492
493 @Override
494 public void preSnapshot(ObserverContext<MasterCoprocessorEnvironment> ctx,
495 SnapshotDescription snapshot, HTableDescriptor hTableDescriptor) throws IOException {
496 }
497
498 @Override
499 public void postSnapshot(ObserverContext<MasterCoprocessorEnvironment> ctx,
500 SnapshotDescription snapshot, HTableDescriptor hTableDescriptor) throws IOException {
501 }
502
503 @Override
504 public void preCloneSnapshot(ObserverContext<MasterCoprocessorEnvironment> ctx,
505 SnapshotDescription snapshot, HTableDescriptor hTableDescriptor) throws IOException {
506 }
507
508 @Override
509 public void postCloneSnapshot(ObserverContext<MasterCoprocessorEnvironment> ctx,
510 SnapshotDescription snapshot, HTableDescriptor hTableDescriptor) throws IOException {
511 }
512
513 @Override
514 public void preRestoreSnapshot(ObserverContext<MasterCoprocessorEnvironment> ctx,
515 SnapshotDescription snapshot, HTableDescriptor hTableDescriptor) throws IOException {
516 }
517
518 @Override
519 public void postRestoreSnapshot(ObserverContext<MasterCoprocessorEnvironment> ctx,
520 SnapshotDescription snapshot, HTableDescriptor hTableDescriptor) throws IOException {
521 }
522
523 @Override
524 public void preDeleteSnapshot(ObserverContext<MasterCoprocessorEnvironment> ctx,
525 SnapshotDescription snapshot) throws IOException {
526 }
527
528 @Override
529 public void postDeleteSnapshot(ObserverContext<MasterCoprocessorEnvironment> ctx,
530 SnapshotDescription snapshot) throws IOException {
531 }
532
533 @Override
534 public void preGetTableDescriptors(ObserverContext<MasterCoprocessorEnvironment> ctx,
535 List<TableName> tableNamesList, List<HTableDescriptor> descriptors) throws IOException {
536 }
537
538 @Override
539 public void postGetTableDescriptors(ObserverContext<MasterCoprocessorEnvironment> ctx,
540 List<HTableDescriptor> descriptors) throws IOException {
541 }
542
543 @Override
544 public void preCreateNamespace(ObserverContext<MasterCoprocessorEnvironment> ctx,
545 NamespaceDescriptor ns) throws IOException {
546 }
547
548 @Override
549 public void postCreateNamespace(ObserverContext<MasterCoprocessorEnvironment> ctx,
550 NamespaceDescriptor ns) throws IOException {
551 }
552
553 @Override
554 public void preDeleteNamespace(ObserverContext<MasterCoprocessorEnvironment> ctx,
555 String namespace) throws IOException {
556 }
557
558 @Override
559 public void postDeleteNamespace(ObserverContext<MasterCoprocessorEnvironment> ctx,
560 String namespace) throws IOException {
561 }
562
563 @Override
564 public void preModifyNamespace(ObserverContext<MasterCoprocessorEnvironment> ctx,
565 NamespaceDescriptor ns) throws IOException {
566 }
567
568 @Override
569 public void postModifyNamespace(ObserverContext<MasterCoprocessorEnvironment> ctx,
570 NamespaceDescriptor ns) throws IOException {
571 }
572
573 @Override
574 public void preMasterInitialization(ObserverContext<MasterCoprocessorEnvironment> ctx)
575 throws IOException {
576
577 }
578
579
580
581 @Override
582 public void postOpen(ObserverContext<RegionCoprocessorEnvironment> e) {
583
584 if (e.getEnvironment().getRegion().getRegionInfo().getTable().equals(LABELS_TABLE_NAME)) {
585 this.labelsRegion = true;
586 this.acOn = CoprocessorHost.getLoadedCoprocessors().contains(AccessController.class.getName());
587 if (!e.getEnvironment().getRegion().isRecovering()) {
588 initialize(e);
589 }
590 } else {
591 this.initialized = true;
592 }
593 }
594
595 @Override
596 public void postLogReplay(ObserverContext<RegionCoprocessorEnvironment> e) {
597 if (this.labelsRegion) {
598 initialize(e);
599 }
600 }
601
602 private void initialize(ObserverContext<RegionCoprocessorEnvironment> e) {
603 try {
604 Pair<Map<String, Integer>, Map<String, List<Integer>>> labelsAndUserAuths =
605 extractLabelsAndAuths(getExistingLabelsWithAuths());
606 Map<String, Integer> labels = labelsAndUserAuths.getFirst();
607 Map<String, List<Integer>> userAuths = labelsAndUserAuths.getSecond();
608
609 addSystemLabel(e.getEnvironment().getRegion(), labels, userAuths);
610 int ordinal = 1;
611 for (Integer i : labels.values()) {
612 if (i > ordinal) {
613 ordinal = i;
614 }
615 }
616 this.ordinalCounter = ordinal + 1;
617 if (labels.size() > 0) {
618
619 byte[] serialized = VisibilityUtils.getDataToWriteToZooKeeper(labels);
620 this.visibilityManager.writeToZookeeper(serialized, true);
621 }
622 if (userAuths.size() > 0) {
623 byte[] serialized = VisibilityUtils.getUserAuthsDataToWriteToZooKeeper(userAuths);
624 this.visibilityManager.writeToZookeeper(serialized, false);
625 }
626 initialized = true;
627 } catch (IOException ioe) {
628 LOG.error("Error while updating the zk with the exisiting labels data", ioe);
629 }
630 }
631
632 private void addSystemLabel(HRegion region, Map<String, Integer> labels,
633 Map<String, List<Integer>> userAuths) throws IOException {
634 if (!labels.containsKey(SYSTEM_LABEL)) {
635 Put p = new Put(Bytes.toBytes(SYSTEM_LABEL_ORDINAL));
636 p.addImmutable(LABELS_TABLE_FAMILY, LABEL_QUALIFIER, Bytes.toBytes(SYSTEM_LABEL));
637
638 for (String superUser : this.superUsers) {
639 p.addImmutable(
640 LABELS_TABLE_FAMILY, Bytes.toBytes(superUser), DUMMY_VALUE, LABELS_TABLE_TAGS);
641 }
642 region.put(p);
643 labels.put(SYSTEM_LABEL, SYSTEM_LABEL_ORDINAL);
644 for (String superUser : superUsers) {
645 List<Integer> auths = userAuths.get(superUser);
646 if (auths == null) {
647 auths = new ArrayList<Integer>(1);
648 userAuths.put(superUser, auths);
649 }
650 auths.add(SYSTEM_LABEL_ORDINAL);
651 }
652 }
653 }
654
655 @Override
656 public void preBatchMutate(ObserverContext<RegionCoprocessorEnvironment> c,
657 MiniBatchOperationInProgress<Mutation> miniBatchOp) throws IOException {
658 if (c.getEnvironment().getRegion().getRegionInfo().getTable().isSystemTable()) {
659 return;
660 }
661
662 Map<String, List<Tag>> labelCache = new HashMap<String, List<Tag>>();
663 for (int i = 0; i < miniBatchOp.size(); i++) {
664 Mutation m = miniBatchOp.getOperation(i);
665 CellVisibility cellVisibility = null;
666 try {
667 cellVisibility = m.getCellVisibility();
668 } catch (DeserializationException de) {
669 miniBatchOp.setOperationStatus(i,
670 new OperationStatus(SANITY_CHECK_FAILURE, de.getMessage()));
671 continue;
672 }
673 boolean sanityFailure = false;
674 for (CellScanner cellScanner = m.cellScanner(); cellScanner.advance();) {
675 if (!checkForReservedVisibilityTagPresence(cellScanner.current())) {
676 miniBatchOp.setOperationStatus(i, new OperationStatus(SANITY_CHECK_FAILURE,
677 "Mutation contains cell with reserved type tag"));
678 sanityFailure = true;
679 break;
680 }
681 }
682 if (!sanityFailure) {
683 if (cellVisibility != null) {
684 String labelsExp = cellVisibility.getExpression();
685 List<Tag> visibilityTags = labelCache.get(labelsExp);
686 if (visibilityTags == null) {
687 try {
688 visibilityTags = createVisibilityTags(labelsExp, true);
689 } catch (ParseException e) {
690 miniBatchOp.setOperationStatus(i,
691 new OperationStatus(SANITY_CHECK_FAILURE, e.getMessage()));
692 } catch (InvalidLabelException e) {
693 miniBatchOp.setOperationStatus(i,
694 new OperationStatus(SANITY_CHECK_FAILURE, e.getMessage()));
695 }
696 }
697 if (visibilityTags != null) {
698 labelCache.put(labelsExp, visibilityTags);
699 List<Cell> updatedCells = new ArrayList<Cell>();
700 for (CellScanner cellScanner = m.cellScanner(); cellScanner.advance();) {
701 Cell cell = cellScanner.current();
702 List<Tag> tags = Tag.asList(cell.getTagsArray(), cell.getTagsOffset(),
703 cell.getTagsLengthUnsigned());
704 tags.addAll(visibilityTags);
705 Cell updatedCell = new KeyValue(cell.getRowArray(), cell.getRowOffset(),
706 cell.getRowLength(), cell.getFamilyArray(), cell.getFamilyOffset(),
707 cell.getFamilyLength(), cell.getQualifierArray(), cell.getQualifierOffset(),
708 cell.getQualifierLength(), cell.getTimestamp(), Type.codeToType(cell
709 .getTypeByte()), cell.getValueArray(), cell.getValueOffset(),
710 cell.getValueLength(), tags);
711 updatedCells.add(updatedCell);
712 }
713 m.getFamilyCellMap().clear();
714
715 for (Cell cell : updatedCells) {
716 if (m instanceof Put) {
717 Put p = (Put) m;
718 p.add(cell);
719 } else if (m instanceof Delete) {
720
721 Delete d = (Delete) m;
722 d.addDeleteMarker(cell);
723 }
724 }
725 }
726 }
727 }
728 }
729 }
730
731 @Override
732 public void prePrepareTimeStampForDeleteVersion(
733 ObserverContext<RegionCoprocessorEnvironment> ctx, Mutation delete, Cell cell,
734 byte[] byteNow, Get get) throws IOException {
735 KeyValue kv = KeyValueUtil.ensureKeyValue(cell);
736 CellVisibility cellVisibility = null;
737 try {
738 cellVisibility = delete.getCellVisibility();
739 } catch (DeserializationException de) {
740 throw new IOException("Invalid cell visibility specified " + delete, de);
741 }
742
743
744 List<Tag> visibilityTags = new ArrayList<Tag>();
745 if (cellVisibility != null) {
746 String labelsExp = cellVisibility.getExpression();
747 try {
748 visibilityTags = createVisibilityTags(labelsExp, false);
749 } catch (ParseException e) {
750 throw new IOException("Invalid cell visibility expression " + labelsExp, e);
751 } catch (InvalidLabelException e) {
752 throw new IOException("Invalid cell visibility specified " + labelsExp, e);
753 }
754 }
755 get.setFilter(new DeleteVersionVisibilityExpressionFilter(visibilityTags));
756 List<Cell> result = ctx.getEnvironment().getRegion().get(get, false);
757
758 if (result.size() < get.getMaxVersions()) {
759
760 kv.updateLatestStamp(Bytes.toBytes(Long.MIN_VALUE));
761 return;
762 }
763 if (result.size() > get.getMaxVersions()) {
764 throw new RuntimeException("Unexpected size: " + result.size()
765 + ". Results more than the max versions obtained.");
766 }
767 KeyValue getkv = KeyValueUtil.ensureKeyValue(result.get(get.getMaxVersions() - 1));
768 Bytes.putBytes(kv.getBuffer(), kv.getTimestampOffset(), getkv.getBuffer(),
769 getkv.getTimestampOffset(), Bytes.SIZEOF_LONG);
770
771
772
773
774
775 ctx.bypass();
776 }
777
778 @Override
779 public void postBatchMutate(ObserverContext<RegionCoprocessorEnvironment> c,
780 MiniBatchOperationInProgress<Mutation> miniBatchOp) throws IOException {
781 if (this.labelsRegion) {
782
783 Pair<Map<String, Integer>, Map<String, List<Integer>>> labelsAndUserAuths =
784 extractLabelsAndAuths(getExistingLabelsWithAuths());
785 Map<String, Integer> existingLabels = labelsAndUserAuths.getFirst();
786 Map<String, List<Integer>> userAuths = labelsAndUserAuths.getSecond();
787 boolean isNewLabels = false;
788 boolean isUserAuthsChange = false;
789 for (int i = 0; i < miniBatchOp.size(); i++) {
790 Mutation m = miniBatchOp.getOperation(i);
791 if (miniBatchOp.getOperationStatus(i).getOperationStatusCode() == SUCCESS) {
792 for (List<Cell> cells : m.getFamilyCellMap().values()) {
793 for (Cell cell : cells) {
794 int labelOrdinal = Bytes.toInt(cell.getRowArray(), cell.getRowOffset());
795 if (Bytes.equals(cell.getQualifierArray(), cell.getQualifierOffset(),
796 cell.getQualifierLength(), LABEL_QUALIFIER, 0,
797 LABEL_QUALIFIER.length)) {
798 if (m instanceof Put) {
799 existingLabels.put(
800 Bytes.toString(cell.getValueArray(), cell.getValueOffset(),
801 cell.getValueLength()), labelOrdinal);
802 isNewLabels = true;
803 }
804 } else {
805 String user = Bytes.toString(cell.getQualifierArray(),
806 cell.getQualifierOffset(), cell.getQualifierLength());
807 List<Integer> auths = userAuths.get(user);
808 if (auths == null) {
809 auths = new ArrayList<Integer>();
810 userAuths.put(user, auths);
811 }
812 if (m instanceof Delete) {
813 auths.remove(Integer.valueOf(labelOrdinal));
814 } else {
815 auths.add(labelOrdinal);
816 }
817 isUserAuthsChange = true;
818 }
819 }
820 }
821 }
822 }
823 if (isNewLabels) {
824 byte[] serialized = VisibilityUtils.getDataToWriteToZooKeeper(existingLabels);
825 this.visibilityManager.writeToZookeeper(serialized, true);
826 }
827 if (isUserAuthsChange) {
828 byte[] serialized = VisibilityUtils.getUserAuthsDataToWriteToZooKeeper(userAuths);
829 this.visibilityManager.writeToZookeeper(serialized, false);
830 }
831 }
832 }
833
834 private Pair<Map<String, Integer>, Map<String, List<Integer>>> extractLabelsAndAuths(
835 List<List<Cell>> labelDetails) {
836 Map<String, Integer> labels = new HashMap<String, Integer>();
837 Map<String, List<Integer>> userAuths = new HashMap<String, List<Integer>>();
838 for (List<Cell> cells : labelDetails) {
839 for (Cell cell : cells) {
840 if (Bytes.equals(cell.getQualifierArray(), cell.getQualifierOffset(),
841 cell.getQualifierLength(), LABEL_QUALIFIER, 0, LABEL_QUALIFIER.length)) {
842 labels.put(
843 Bytes.toString(cell.getValueArray(), cell.getValueOffset(), cell.getValueLength()),
844 Bytes.toInt(cell.getRowArray(), cell.getRowOffset()));
845 } else {
846
847 String user = Bytes.toString(cell.getQualifierArray(), cell.getQualifierOffset(),
848 cell.getQualifierLength());
849 List<Integer> auths = userAuths.get(user);
850 if (auths == null) {
851 auths = new ArrayList<Integer>();
852 userAuths.put(user, auths);
853 }
854 auths.add(Bytes.toInt(cell.getRowArray(), cell.getRowOffset()));
855 }
856 }
857 }
858 return new Pair<Map<String, Integer>, Map<String, List<Integer>>>(labels, userAuths);
859 }
860
861
862
863 private boolean checkForReservedVisibilityTagPresence(Cell cell) throws IOException {
864
865
866
867 if (isSystemOrSuperUser()) {
868 return true;
869 }
870 if (cell.getTagsLengthUnsigned() > 0) {
871 Iterator<Tag> tagsItr = CellUtil.tagsIterator(cell.getTagsArray(), cell.getTagsOffset(),
872 cell.getTagsLengthUnsigned());
873 while (tagsItr.hasNext()) {
874 if (reservedVisTagTypes.contains(tagsItr.next().getType())) {
875 return false;
876 }
877 }
878 }
879 return true;
880 }
881
882 private List<Tag> createVisibilityTags(String visibilityLabelsExp, boolean addSerializationTag)
883 throws IOException, ParseException, InvalidLabelException {
884 ExpressionNode node = null;
885 node = this.expressionParser.parse(visibilityLabelsExp);
886 node = this.expressionExpander.expand(node);
887 List<Tag> tags = new ArrayList<Tag>();
888 ByteArrayOutputStream baos = new ByteArrayOutputStream();
889 DataOutputStream dos = new DataOutputStream(baos);
890 List<Integer> labelOrdinals = new ArrayList<Integer>();
891
892
893 if (addSerializationTag) {
894 tags.add(VisibilityUtils.VIS_SERIALIZATION_TAG);
895 }
896 if (node.isSingleNode()) {
897 getLabelOrdinals(node, labelOrdinals);
898 writeLabelOrdinalsToStream(labelOrdinals, dos);
899 tags.add(new Tag(VisibilityUtils.VISIBILITY_TAG_TYPE, baos.toByteArray()));
900 baos.reset();
901 } else {
902 NonLeafExpressionNode nlNode = (NonLeafExpressionNode) node;
903 if (nlNode.getOperator() == Operator.OR) {
904 for (ExpressionNode child : nlNode.getChildExps()) {
905 getLabelOrdinals(child, labelOrdinals);
906 writeLabelOrdinalsToStream(labelOrdinals, dos);
907 tags.add(new Tag(VisibilityUtils.VISIBILITY_TAG_TYPE, baos.toByteArray()));
908 baos.reset();
909 labelOrdinals.clear();
910 }
911 } else {
912 getLabelOrdinals(nlNode, labelOrdinals);
913 writeLabelOrdinalsToStream(labelOrdinals, dos);
914 tags.add(new Tag(VisibilityUtils.VISIBILITY_TAG_TYPE, baos.toByteArray()));
915 baos.reset();
916 }
917 }
918 return tags;
919 }
920
921 private void writeLabelOrdinalsToStream(List<Integer> labelOrdinals, DataOutputStream dos)
922 throws IOException {
923 Collections.sort(labelOrdinals);
924 for (Integer labelOrdinal : labelOrdinals) {
925 StreamUtils.writeRawVInt32(dos, labelOrdinal);
926 }
927 }
928
929 private void getLabelOrdinals(ExpressionNode node, List<Integer> labelOrdinals)
930 throws IOException, InvalidLabelException {
931 if (node.isSingleNode()) {
932 String identifier = null;
933 int labelOrdinal = 0;
934 if (node instanceof LeafExpressionNode) {
935 identifier = ((LeafExpressionNode) node)
936 .getIdentifier();
937 if (LOG.isTraceEnabled()) {
938 LOG.trace("The identifier is "+identifier);
939 }
940 labelOrdinal = this.visibilityManager.getLabelOrdinal(identifier);
941 } else {
942
943 LeafExpressionNode lNode = (LeafExpressionNode) ((NonLeafExpressionNode) node)
944 .getChildExps().get(0);
945 identifier = lNode.getIdentifier();
946 labelOrdinal = this.visibilityManager.getLabelOrdinal(identifier);
947 labelOrdinal = -1 * labelOrdinal;
948 }
949 if (labelOrdinal == 0) {
950 throw new InvalidLabelException("Invalid visibility label " + identifier);
951 }
952 labelOrdinals.add(labelOrdinal);
953 } else {
954 List<ExpressionNode> childExps = ((NonLeafExpressionNode) node).getChildExps();
955 for (ExpressionNode child : childExps) {
956 getLabelOrdinals(child, labelOrdinals);
957 }
958 }
959 }
960
961 @Override
962 public RegionScanner preScannerOpen(ObserverContext<RegionCoprocessorEnvironment> e, Scan scan,
963 RegionScanner s) throws IOException {
964 HRegion region = e.getEnvironment().getRegion();
965 Authorizations authorizations = null;
966
967
968 if (checkIfScanOrGetFromSuperUser()) {
969 return s;
970 }
971 try {
972 authorizations = scan.getAuthorizations();
973 } catch (DeserializationException de) {
974 throw new IOException(de);
975 }
976 Filter visibilityLabelFilter = createVisibilityLabelFilter(region, authorizations);
977 if (visibilityLabelFilter != null) {
978 Filter filter = scan.getFilter();
979 if (filter != null) {
980 scan.setFilter(new FilterList(filter, visibilityLabelFilter));
981 } else {
982 scan.setFilter(visibilityLabelFilter);
983 }
984 }
985 return s;
986 }
987
988 private boolean checkIfScanOrGetFromSuperUser() throws IOException {
989 User user = getActiveUser();
990 if (user != null && user.getShortName() != null) {
991 List<String> auths = this.visibilityManager.getAuths(user.getShortName());
992 return (auths.contains(SYSTEM_LABEL));
993 }
994 return false;
995 }
996
997 @Override
998 public DeleteTracker postInstantiateDeleteTracker(
999 ObserverContext<RegionCoprocessorEnvironment> ctx, DeleteTracker delTracker)
1000 throws IOException {
1001 HRegion region = ctx.getEnvironment().getRegion();
1002 TableName table = region.getRegionInfo().getTable();
1003 if (table.isSystemTable()) {
1004 return delTracker;
1005 }
1006
1007
1008
1009
1010
1011 return new VisibilityScanDeleteTracker();
1012 }
1013 @Override
1014 public RegionScanner postScannerOpen(final ObserverContext<RegionCoprocessorEnvironment> c,
1015 final Scan scan, final RegionScanner s) throws IOException {
1016 User user = getActiveUser();
1017 if (user != null && user.getShortName() != null) {
1018 scannerOwners.put(s, user.getShortName());
1019 }
1020 return s;
1021 }
1022
1023 @Override
1024 public boolean preScannerNext(final ObserverContext<RegionCoprocessorEnvironment> c,
1025 final InternalScanner s, final List<Result> result, final int limit, final boolean hasNext)
1026 throws IOException {
1027 requireScannerOwner(s);
1028 return hasNext;
1029 }
1030
1031 @Override
1032 public void preScannerClose(final ObserverContext<RegionCoprocessorEnvironment> c,
1033 final InternalScanner s) throws IOException {
1034 requireScannerOwner(s);
1035 }
1036
1037 @Override
1038 public void postScannerClose(final ObserverContext<RegionCoprocessorEnvironment> c,
1039 final InternalScanner s) throws IOException {
1040
1041 scannerOwners.remove(s);
1042 }
1043
1044
1045
1046
1047
1048 private void requireScannerOwner(InternalScanner s) throws AccessDeniedException {
1049 if (RequestContext.isInRequestContext()) {
1050 String requestUName = RequestContext.getRequestUserName();
1051 String owner = scannerOwners.get(s);
1052 if (owner != null && !owner.equals(requestUName)) {
1053 throw new AccessDeniedException("User '" + requestUName + "' is not the scanner owner!");
1054 }
1055 }
1056 }
1057
1058 @Override
1059 public void preGetOp(ObserverContext<RegionCoprocessorEnvironment> e, Get get, List<Cell> results)
1060 throws IOException {
1061 Authorizations authorizations = null;
1062
1063
1064 if (checkIfScanOrGetFromSuperUser()) {
1065 return;
1066 }
1067 try {
1068 authorizations = get.getAuthorizations();
1069 } catch (DeserializationException de) {
1070 throw new IOException(de);
1071 }
1072 Filter visibilityLabelFilter = createVisibilityLabelFilter(e.getEnvironment().getRegion(),
1073 authorizations);
1074 if (visibilityLabelFilter != null) {
1075 Filter filter = get.getFilter();
1076 if (filter != null) {
1077 get.setFilter(new FilterList(filter, visibilityLabelFilter));
1078 } else {
1079 get.setFilter(visibilityLabelFilter);
1080 }
1081 }
1082 }
1083
1084 private Filter createVisibilityLabelFilter(HRegion region, Authorizations authorizations)
1085 throws IOException {
1086 Map<ByteRange, Integer> cfVsMaxVersions = new HashMap<ByteRange, Integer>();
1087 for (HColumnDescriptor hcd : region.getTableDesc().getFamilies()) {
1088 cfVsMaxVersions.put(new SimpleByteRange(hcd.getName()), hcd.getMaxVersions());
1089 }
1090 if (authorizations == null) {
1091
1092
1093
1094 TableName table = region.getRegionInfo().getTable();
1095 if (table.isSystemTable() && !table.equals(LABELS_TABLE_NAME)) {
1096 return null;
1097 }
1098 } else {
1099 for (String label : authorizations.getLabels()) {
1100 if (!VisibilityLabelsValidator.isValidLabel(label)) {
1101 throw new IllegalArgumentException("Invalid authorization label : " + label
1102 + ". Authorizations cannot contain '(', ')' ,'&' ,'|', '!'" + " and cannot be empty");
1103 }
1104 }
1105 }
1106 Filter visibilityLabelFilter = null;
1107 if (this.scanLabelGenerators != null) {
1108 List<String> labels = null;
1109 for (ScanLabelGenerator scanLabelGenerator : this.scanLabelGenerators) {
1110 try {
1111
1112 labels = scanLabelGenerator.getLabels(getActiveUser(), authorizations);
1113 labels = (labels == null) ? new ArrayList<String>() : labels;
1114 authorizations = new Authorizations(labels);
1115 } catch (Throwable t) {
1116 LOG.error(t);
1117 throw new IOException(t);
1118 }
1119 }
1120 int labelsCount = this.visibilityManager.getLabelsCount();
1121 BitSet bs = new BitSet(labelsCount + 1);
1122 if (labels != null) {
1123 for (String label : labels) {
1124 int labelOrdinal = this.visibilityManager.getLabelOrdinal(label);
1125 if (labelOrdinal != 0) {
1126 bs.set(labelOrdinal);
1127 }
1128 }
1129 }
1130 visibilityLabelFilter = new VisibilityLabelFilter(bs, cfVsMaxVersions);
1131 }
1132 return visibilityLabelFilter;
1133 }
1134
1135 private User getActiveUser() throws IOException {
1136 User user = RequestContext.getRequestUser();
1137 if (!RequestContext.isInRequestContext()) {
1138
1139 user = User.getCurrent();
1140 }
1141 if (LOG.isTraceEnabled()) {
1142 LOG.trace("Current active user name is "+user.getShortName());
1143 }
1144 return user;
1145 }
1146
1147 private List<String> getSystemAndSuperUsers() throws IOException {
1148 User user = User.getCurrent();
1149 if (user == null) {
1150 throw new IOException("Unable to obtain the current user, "
1151 + "authorization checks for internal operations will not work correctly!");
1152 }
1153 if (LOG.isTraceEnabled()) {
1154 LOG.trace("Current user name is "+user.getShortName());
1155 }
1156 String currentUser = user.getShortName();
1157 List<String> superUsers = Lists.asList(currentUser,
1158 this.conf.getStrings(AccessControlLists.SUPERUSER_CONF_KEY, new String[0]));
1159 return superUsers;
1160 }
1161
1162 private boolean isSystemOrSuperUser() throws IOException {
1163 User activeUser = getActiveUser();
1164 return this.superUsers.contains(activeUser.getShortName());
1165 }
1166
1167 @Override
1168 public Result preAppend(ObserverContext<RegionCoprocessorEnvironment> e, Append append)
1169 throws IOException {
1170 for (CellScanner cellScanner = append.cellScanner(); cellScanner.advance();) {
1171 if (!checkForReservedVisibilityTagPresence(cellScanner.current())) {
1172 throw new FailedSanityCheckException("Append contains cell with reserved type tag");
1173 }
1174 }
1175 return null;
1176 }
1177
1178 @Override
1179 public Result preIncrement(ObserverContext<RegionCoprocessorEnvironment> e, Increment increment)
1180 throws IOException {
1181 for (CellScanner cellScanner = increment.cellScanner(); cellScanner.advance();) {
1182 if (!checkForReservedVisibilityTagPresence(cellScanner.current())) {
1183 throw new FailedSanityCheckException("Increment contains cell with reserved type tag");
1184 }
1185 }
1186 return null;
1187 }
1188
1189 @Override
1190 public Cell postMutationBeforeWAL(ObserverContext<RegionCoprocessorEnvironment> ctx,
1191 MutationType opType, Mutation mutation, Cell oldCell, Cell newCell) throws IOException {
1192 List<Tag> tags = Lists.newArrayList();
1193 CellVisibility cellVisibility = null;
1194 try {
1195 cellVisibility = mutation.getCellVisibility();
1196 } catch (DeserializationException e) {
1197 throw new IOException(e);
1198 }
1199 if (cellVisibility == null) {
1200 return newCell;
1201 }
1202
1203 Iterator<Tag> tagsItr = CellUtil.tagsIterator(newCell.getTagsArray(), newCell.getTagsOffset(),
1204 newCell.getTagsLengthUnsigned());
1205 while (tagsItr.hasNext()) {
1206 Tag tag = tagsItr.next();
1207 if (tag.getType() != VisibilityUtils.VISIBILITY_TAG_TYPE
1208 && tag.getType() != VisibilityUtils.VISIBILITY_EXP_SERIALIZATION_TAG_TYPE) {
1209 tags.add(tag);
1210 }
1211 }
1212 try {
1213 tags.addAll(createVisibilityTags(cellVisibility.getExpression(), true));
1214 } catch (ParseException e) {
1215 throw new IOException(e);
1216 }
1217
1218
1219
1220 KeyValue newKv = KeyValueUtil.ensureKeyValue(newCell);
1221 byte[] bytes = newKv.getBuffer();
1222 KeyValue rewriteKv = new KeyValue(bytes, newKv.getRowOffset(), newKv.getRowLength(), bytes,
1223 newKv.getFamilyOffset(), newKv.getFamilyLength(), bytes, newKv.getQualifierOffset(),
1224 newKv.getQualifierLength(), newKv.getTimestamp(), KeyValue.Type.codeToType(newKv
1225 .getTypeByte()), bytes, newKv.getValueOffset(), newKv.getValueLength(), tags);
1226
1227 rewriteKv.setMvccVersion(newKv.getMvccVersion());
1228 return rewriteKv;
1229 }
1230
1231 @Override
1232 public Service getService() {
1233 return VisibilityLabelsProtos.VisibilityLabelsService.newReflectiveService(this);
1234 }
1235
1236
1237 @Override
1238 public synchronized void addLabels(RpcController controller, VisibilityLabelsRequest request,
1239 RpcCallback<VisibilityLabelsResponse> done) {
1240 VisibilityLabelsResponse.Builder response = VisibilityLabelsResponse.newBuilder();
1241 List<VisibilityLabel> labels = request.getVisLabelList();
1242 if (!initialized) {
1243 setExceptionResults(labels.size(), new CoprocessorException(
1244 "VisibilityController not yet initialized"), response);
1245 }
1246 try {
1247 checkCallingUserAuth();
1248 List<Mutation> puts = new ArrayList<Mutation>(labels.size());
1249 RegionActionResult successResult = RegionActionResult.newBuilder().build();
1250 for (VisibilityLabel visLabel : labels) {
1251 byte[] label = visLabel.getLabel().toByteArray();
1252 String labelStr = Bytes.toString(label);
1253 if (VisibilityLabelsValidator.isValidLabel(label)) {
1254 if (this.visibilityManager.getLabelOrdinal(labelStr) > 0) {
1255 RegionActionResult.Builder failureResultBuilder = RegionActionResult.newBuilder();
1256 failureResultBuilder.setException(ResponseConverter
1257 .buildException(new LabelAlreadyExistsException("Label '" + labelStr
1258 + "' already exists")));
1259 response.addResult(failureResultBuilder.build());
1260 } else {
1261 Put p = new Put(Bytes.toBytes(ordinalCounter));
1262 p.addImmutable(
1263 LABELS_TABLE_FAMILY, LABEL_QUALIFIER, label, LABELS_TABLE_TAGS);
1264 if (LOG.isDebugEnabled()) {
1265 LOG.debug("Adding the label "+labelStr);
1266 }
1267 puts.add(p);
1268 ordinalCounter++;
1269 response.addResult(successResult);
1270 }
1271 } else {
1272 RegionActionResult.Builder failureResultBuilder = RegionActionResult.newBuilder();
1273 failureResultBuilder.setException(ResponseConverter
1274 .buildException(new InvalidLabelException("Invalid visibility label '" + labelStr
1275 + "'")));
1276 response.addResult(failureResultBuilder.build());
1277 }
1278 }
1279 OperationStatus[] opStatus = this.regionEnv.getRegion().batchMutate(
1280 puts.toArray(new Mutation[puts.size()]));
1281 int i = 0;
1282 for (OperationStatus status : opStatus) {
1283 if (status.getOperationStatusCode() != SUCCESS) {
1284 while (response.getResult(i) != successResult)
1285 i++;
1286 RegionActionResult.Builder failureResultBuilder = RegionActionResult.newBuilder();
1287 failureResultBuilder.setException(ResponseConverter
1288 .buildException(new DoNotRetryIOException(status.getExceptionMsg())));
1289 response.setResult(i, failureResultBuilder.build());
1290 }
1291 i++;
1292 }
1293 } catch (IOException e) {
1294 LOG.error(e);
1295 setExceptionResults(labels.size(), e, response);
1296 }
1297 done.run(response.build());
1298 }
1299
1300 private void setExceptionResults(int size, IOException e,
1301 VisibilityLabelsResponse.Builder response) {
1302 RegionActionResult.Builder failureResultBuilder = RegionActionResult.newBuilder();
1303 failureResultBuilder.setException(ResponseConverter.buildException(e));
1304 RegionActionResult failureResult = failureResultBuilder.build();
1305 for (int i = 0; i < size; i++) {
1306 response.addResult(i, failureResult);
1307 }
1308 }
1309
1310 private void performACLCheck() throws IOException {
1311
1312 if (this.acOn && !isSystemOrSuperUser()) {
1313 User user = getActiveUser();
1314 throw new AccessDeniedException("User '" + (user != null ? user.getShortName() : "null")
1315 + " is not authorized to perform this action.");
1316 }
1317 }
1318
1319 private List<List<Cell>> getExistingLabelsWithAuths() throws IOException {
1320 Scan scan = new Scan();
1321 RegionScanner scanner = this.regionEnv.getRegion().getScanner(scan);
1322 List<List<Cell>> existingLabels = new ArrayList<List<Cell>>();
1323 try {
1324 while (true) {
1325 List<Cell> cells = new ArrayList<Cell>();
1326 scanner.next(cells);
1327 if (cells.isEmpty()) {
1328 break;
1329 }
1330 existingLabels.add(cells);
1331 }
1332 } finally {
1333 scanner.close();
1334 }
1335 return existingLabels;
1336 }
1337
1338 @Override
1339 public synchronized void setAuths(RpcController controller, SetAuthsRequest request,
1340 RpcCallback<VisibilityLabelsResponse> done) {
1341 VisibilityLabelsResponse.Builder response = VisibilityLabelsResponse.newBuilder();
1342 List<ByteString> auths = request.getAuthList();
1343 if (!initialized) {
1344 setExceptionResults(auths.size(), new CoprocessorException(
1345 "VisibilityController not yet initialized"), response);
1346 }
1347 byte[] user = request.getUser().toByteArray();
1348 try {
1349 checkCallingUserAuth();
1350 List<Mutation> puts = new ArrayList<Mutation>(auths.size());
1351 RegionActionResult successResult = RegionActionResult.newBuilder().build();
1352 for (ByteString authBS : auths) {
1353 byte[] auth = authBS.toByteArray();
1354 String authStr = Bytes.toString(auth);
1355 int labelOrdinal = this.visibilityManager.getLabelOrdinal(authStr);
1356 if (labelOrdinal == 0) {
1357
1358 RegionActionResult.Builder failureResultBuilder = RegionActionResult.newBuilder();
1359 failureResultBuilder.setException(ResponseConverter
1360 .buildException(new InvalidLabelException("Label '" + authStr + "' doesn't exist")));
1361 response.addResult(failureResultBuilder.build());
1362 } else {
1363 Put p = new Put(Bytes.toBytes(labelOrdinal));
1364 p.addImmutable(
1365 LABELS_TABLE_FAMILY, user, DUMMY_VALUE, LABELS_TABLE_TAGS);
1366 puts.add(p);
1367 response.addResult(successResult);
1368 }
1369 }
1370 OperationStatus[] opStatus = this.regionEnv.getRegion().batchMutate(
1371 puts.toArray(new Mutation[puts.size()]));
1372 int i = 0;
1373 for (OperationStatus status : opStatus) {
1374 if (status.getOperationStatusCode() != SUCCESS) {
1375 while (response.getResult(i) != successResult) i++;
1376 RegionActionResult.Builder failureResultBuilder = RegionActionResult.newBuilder();
1377 failureResultBuilder.setException(ResponseConverter
1378 .buildException(new DoNotRetryIOException(status.getExceptionMsg())));
1379 response.setResult(i, failureResultBuilder.build());
1380 }
1381 i++;
1382 }
1383 } catch (IOException e) {
1384 LOG.error(e);
1385 setExceptionResults(auths.size(), e, response);
1386 }
1387 done.run(response.build());
1388 }
1389
1390 @Override
1391 public synchronized void getAuths(RpcController controller, GetAuthsRequest request,
1392 RpcCallback<GetAuthsResponse> done) {
1393 byte[] user = request.getUser().toByteArray();
1394 GetAuthsResponse.Builder response = GetAuthsResponse.newBuilder();
1395 response.setUser(request.getUser());
1396 try {
1397 List<String> labels = getUserAuthsFromLabelsTable(user);
1398 for (String label : labels) {
1399 response.addAuth(ByteStringer.wrap(Bytes.toBytes(label)));
1400 }
1401 } catch (IOException e) {
1402 ResponseConverter.setControllerException(controller, e);
1403 }
1404 done.run(response.build());
1405 }
1406
1407 private List<String> getUserAuthsFromLabelsTable(byte[] user) throws IOException {
1408 Scan s = new Scan();
1409 s.addColumn(LABELS_TABLE_FAMILY, user);
1410 Filter filter = createVisibilityLabelFilter(this.regionEnv.getRegion(), new Authorizations(
1411 SYSTEM_LABEL));
1412 s.setFilter(filter);
1413 List<String> auths = new ArrayList<String>();
1414
1415
1416 performACLCheck();
1417 RegionScanner scanner = this.regionEnv.getRegion().getScanner(s);
1418 List<Cell> results = new ArrayList<Cell>(1);
1419 while (true) {
1420 scanner.next(results);
1421 if (results.isEmpty()) break;
1422 Cell cell = results.get(0);
1423 int ordinal = Bytes.toInt(cell.getRowArray(), cell.getRowOffset(), cell.getRowLength());
1424 String label = this.visibilityManager.getLabel(ordinal);
1425 if (label != null) {
1426 auths.add(label);
1427 }
1428 results.clear();
1429 }
1430 return auths;
1431 }
1432
1433 @Override
1434 public synchronized void clearAuths(RpcController controller, SetAuthsRequest request,
1435 RpcCallback<VisibilityLabelsResponse> done) {
1436 VisibilityLabelsResponse.Builder response = VisibilityLabelsResponse.newBuilder();
1437 List<ByteString> auths = request.getAuthList();
1438 if (!initialized) {
1439 setExceptionResults(auths.size(), new CoprocessorException(
1440 "VisibilityController not yet initialized"), response);
1441 }
1442 byte[] user = request.getUser().toByteArray();
1443 try {
1444 checkCallingUserAuth();
1445 List<String> currentAuths = this.getUserAuthsFromLabelsTable(user);
1446 List<Mutation> deletes = new ArrayList<Mutation>(auths.size());
1447 RegionActionResult successResult = RegionActionResult.newBuilder().build();
1448 for (ByteString authBS : auths) {
1449 byte[] auth = authBS.toByteArray();
1450 String authStr = Bytes.toString(auth);
1451 if (currentAuths.contains(authStr)) {
1452 int labelOrdinal = this.visibilityManager.getLabelOrdinal(authStr);
1453 assert labelOrdinal > 0;
1454 Delete d = new Delete(Bytes.toBytes(labelOrdinal));
1455 d.deleteColumns(LABELS_TABLE_FAMILY, user);
1456 deletes.add(d);
1457 response.addResult(successResult);
1458 } else {
1459
1460 RegionActionResult.Builder failureResultBuilder = RegionActionResult.newBuilder();
1461 failureResultBuilder.setException(ResponseConverter
1462 .buildException(new InvalidLabelException("Label '" + authStr
1463 + "' is not set for the user " + Bytes.toString(user))));
1464 response.addResult(failureResultBuilder.build());
1465 }
1466 }
1467 OperationStatus[] opStatus = this.regionEnv.getRegion().batchMutate(
1468 deletes.toArray(new Mutation[deletes.size()]));
1469 int i = 0;
1470 for (OperationStatus status : opStatus) {
1471 if (status.getOperationStatusCode() != SUCCESS) {
1472 while (response.getResult(i) != successResult) i++;
1473 RegionActionResult.Builder failureResultBuilder = RegionActionResult.newBuilder();
1474 failureResultBuilder.setException(ResponseConverter
1475 .buildException(new DoNotRetryIOException(status.getExceptionMsg())));
1476 response.setResult(i, failureResultBuilder.build());
1477 }
1478 i++;
1479 }
1480 } catch (IOException e) {
1481 LOG.error(e);
1482 setExceptionResults(auths.size(), e, response);
1483 }
1484 done.run(response.build());
1485 }
1486
1487 private void checkCallingUserAuth() throws IOException {
1488 if (!this.acOn) {
1489 User user = getActiveUser();
1490 if (user == null) {
1491 throw new IOException("Unable to retrieve calling user");
1492 }
1493 List<String> auths = this.visibilityManager.getAuths(user.getShortName());
1494 if (LOG.isTraceEnabled()) {
1495 LOG.trace("The list of auths are "+auths);
1496 }
1497 if (!auths.contains(SYSTEM_LABEL)) {
1498 throw new AccessDeniedException("User '" + user.getShortName()
1499 + "' is not authorized to perform this action.");
1500 }
1501 }
1502 }
1503
1504 static class DeleteVersionVisibilityExpressionFilter extends FilterBase {
1505 private List<Tag> visibilityTags;
1506
1507 public DeleteVersionVisibilityExpressionFilter(List<Tag> visibilityTags) {
1508 this.visibilityTags = visibilityTags;
1509 }
1510
1511 @Override
1512 public ReturnCode filterKeyValue(Cell kv) throws IOException {
1513 boolean matchFound = VisibilityUtils.checkForMatchingVisibilityTags(kv, visibilityTags);
1514 if (matchFound) {
1515 return ReturnCode.INCLUDE;
1516 } else {
1517 return ReturnCode.SKIP;
1518 }
1519 }
1520 }
1521 }