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