1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package org.apache.hadoop.hbase.security.access;
16
17 import java.io.IOException;
18 import java.net.InetAddress;
19 import java.util.Arrays;
20 import java.util.Collection;
21 import java.util.Collections;
22 import java.util.LinkedList;
23 import java.util.List;
24 import java.util.Map;
25 import java.util.Set;
26 import java.util.TreeSet;
27
28 import com.google.protobuf.RpcCallback;
29 import com.google.protobuf.RpcController;
30 import com.google.protobuf.Service;
31 import org.apache.commons.logging.Log;
32 import org.apache.commons.logging.LogFactory;
33 import org.apache.hadoop.conf.Configuration;
34 import org.apache.hadoop.hbase.Cell;
35 import org.apache.hadoop.hbase.CoprocessorEnvironment;
36 import org.apache.hadoop.hbase.HColumnDescriptor;
37 import org.apache.hadoop.hbase.HRegionInfo;
38 import org.apache.hadoop.hbase.HTableDescriptor;
39 import org.apache.hadoop.hbase.KeyValue;
40 import org.apache.hadoop.hbase.KeyValueUtil;
41 import org.apache.hadoop.hbase.ServerName;
42 import org.apache.hadoop.hbase.client.Append;
43 import org.apache.hadoop.hbase.client.Delete;
44 import org.apache.hadoop.hbase.client.Get;
45 import org.apache.hadoop.hbase.client.Increment;
46 import org.apache.hadoop.hbase.client.Put;
47 import org.apache.hadoop.hbase.client.Result;
48 import org.apache.hadoop.hbase.client.Scan;
49 import org.apache.hadoop.hbase.coprocessor.*;
50 import org.apache.hadoop.hbase.exceptions.CoprocessorException;
51 import org.apache.hadoop.hbase.filter.CompareFilter;
52 import org.apache.hadoop.hbase.filter.FilterList;
53 import org.apache.hadoop.hbase.filter.ByteArrayComparable;
54 import org.apache.hadoop.hbase.ipc.RequestContext;
55 import org.apache.hadoop.hbase.master.RegionPlan;
56 import org.apache.hadoop.hbase.protobuf.ProtobufUtil;
57 import org.apache.hadoop.hbase.protobuf.ResponseConverter;
58 import org.apache.hadoop.hbase.protobuf.generated.AccessControlProtos;
59 import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.SnapshotDescription;
60 import org.apache.hadoop.hbase.regionserver.HRegion;
61 import org.apache.hadoop.hbase.regionserver.InternalScanner;
62 import org.apache.hadoop.hbase.regionserver.RegionScanner;
63 import org.apache.hadoop.hbase.regionserver.Store;
64 import org.apache.hadoop.hbase.regionserver.ScanType;
65 import org.apache.hadoop.hbase.regionserver.StoreFile;
66 import org.apache.hadoop.hbase.regionserver.wal.WALEdit;
67 import org.apache.hadoop.hbase.exceptions.AccessDeniedException;
68 import org.apache.hadoop.hbase.security.User;
69 import org.apache.hadoop.hbase.security.access.Permission.Action;
70 import org.apache.hadoop.hbase.util.Bytes;
71 import org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher;
72 import org.apache.hadoop.hbase.util.Pair;
73
74 import com.google.common.collect.ImmutableSet;
75 import com.google.common.collect.ListMultimap;
76 import com.google.common.collect.Lists;
77 import com.google.common.collect.MapMaker;
78 import com.google.common.collect.Maps;
79 import com.google.common.collect.Sets;
80
81 import static org.apache.hadoop.hbase.protobuf.generated.AccessControlProtos.AccessControlService;
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114 public class AccessController extends BaseRegionObserver
115 implements MasterObserver, RegionServerObserver,
116 AccessControlService.Interface, CoprocessorService {
117
118 public static final Log LOG = LogFactory.getLog(AccessController.class);
119
120 private static final Log AUDITLOG =
121 LogFactory.getLog("SecurityLogger."+AccessController.class.getName());
122
123 TableAuthManager authManager = null;
124
125
126 boolean aclRegion = false;
127
128
129
130 private RegionCoprocessorEnvironment regionEnv;
131
132
133 private Map<InternalScanner,String> scannerOwners =
134 new MapMaker().weakKeys().makeMap();
135
136 void initialize(RegionCoprocessorEnvironment e) throws IOException {
137 final HRegion region = e.getRegion();
138
139 Map<byte[],ListMultimap<String,TablePermission>> tables =
140 AccessControlLists.loadAll(region);
141
142
143 for (Map.Entry<byte[],ListMultimap<String,TablePermission>> t:
144 tables.entrySet()) {
145 byte[] table = t.getKey();
146 ListMultimap<String,TablePermission> perms = t.getValue();
147 byte[] serialized = AccessControlLists.writePermissionsAsBytes(perms, e.getConfiguration());
148 this.authManager.getZKPermissionWatcher().writeToZookeeper(table, serialized);
149 }
150 }
151
152
153
154
155
156
157 void updateACL(RegionCoprocessorEnvironment e,
158 final Map<byte[], List<? extends Cell>> familyMap) {
159 Set<byte[]> tableSet = new TreeSet<byte[]>(Bytes.BYTES_COMPARATOR);
160 for (Map.Entry<byte[], List<? extends Cell>> f : familyMap.entrySet()) {
161 List<? extends Cell> cells = f.getValue();
162 for (Cell cell: cells) {
163 KeyValue kv = KeyValueUtil.ensureKeyValue(cell);
164 if (Bytes.equals(kv.getBuffer(), kv.getFamilyOffset(),
165 kv.getFamilyLength(), AccessControlLists.ACL_LIST_FAMILY, 0,
166 AccessControlLists.ACL_LIST_FAMILY.length)) {
167 tableSet.add(kv.getRow());
168 }
169 }
170 }
171
172 ZKPermissionWatcher zkw = this.authManager.getZKPermissionWatcher();
173 Configuration conf = regionEnv.getConfiguration();
174 for (byte[] tableName: tableSet) {
175 try {
176 ListMultimap<String,TablePermission> perms =
177 AccessControlLists.getTablePermissions(conf, tableName);
178 byte[] serialized = AccessControlLists.writePermissionsAsBytes(perms, conf);
179 zkw.writeToZookeeper(tableName, serialized);
180 } catch (IOException ex) {
181 LOG.error("Failed updating permissions mirror for '" + Bytes.toString(tableName) + "'", ex);
182 }
183 }
184 }
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200 AuthResult permissionGranted(String request, User user, Permission.Action permRequest,
201 RegionCoprocessorEnvironment e,
202 Map<byte [], ? extends Collection<?>> families) {
203 HRegionInfo hri = e.getRegion().getRegionInfo();
204 byte[] tableName = hri.getTableName();
205
206
207
208 if (hri.isMetaRegion()) {
209 if (permRequest == Permission.Action.READ) {
210 return AuthResult.allow(request, "All users allowed", user,
211 permRequest, tableName, families);
212 }
213 }
214
215 if (user == null) {
216 return AuthResult.deny(request, "No user associated with request!", null,
217 permRequest, tableName, families);
218 }
219
220
221
222
223
224
225 if (permRequest == Permission.Action.WRITE &&
226 (hri.isMetaRegion() ||
227 Bytes.equals(tableName, AccessControlLists.ACL_GLOBAL_NAME)) &&
228 (authManager.authorize(user, Permission.Action.CREATE) ||
229 authManager.authorize(user, Permission.Action.ADMIN)))
230 {
231 return AuthResult.allow(request, "Table permission granted", user,
232 permRequest, tableName, families);
233 }
234
235
236 if (authManager.authorize(user, tableName, (byte[])null, permRequest)) {
237 return AuthResult.allow(request, "Table permission granted", user,
238 permRequest, tableName, families);
239 }
240
241
242 if (families != null && families.size() > 0) {
243
244 for (Map.Entry<byte [], ? extends Collection<?>> family : families.entrySet()) {
245
246 if (authManager.authorize(user, tableName, family.getKey(),
247 permRequest)) {
248 continue;
249 }
250
251
252 if ((family.getValue() != null) && (family.getValue().size() > 0)) {
253 if (family.getValue() instanceof Set) {
254
255 Set<byte[]> familySet = (Set<byte[]>)family.getValue();
256 for (byte[] qualifier : familySet) {
257 if (!authManager.authorize(user, tableName, family.getKey(),
258 qualifier, permRequest)) {
259 return AuthResult.deny(request, "Failed qualifier check", user,
260 permRequest, tableName, makeFamilyMap(family.getKey(), qualifier));
261 }
262 }
263 } else if (family.getValue() instanceof List) {
264 List<KeyValue> kvList = (List<KeyValue>)family.getValue();
265 for (KeyValue kv : kvList) {
266 if (!authManager.authorize(user, tableName, family.getKey(),
267 kv.getQualifier(), permRequest)) {
268 return AuthResult.deny(request, "Failed qualifier check", user,
269 permRequest, tableName, makeFamilyMap(family.getKey(), kv.getQualifier()));
270 }
271 }
272 }
273 } else {
274
275 return AuthResult.deny(request, "Failed family check", user, permRequest,
276 tableName, makeFamilyMap(family.getKey(), null));
277 }
278 }
279
280
281 return AuthResult.allow(request, "All family checks passed", user, permRequest,
282 tableName, families);
283 }
284
285
286 return AuthResult.deny(request, "No families to check and table permission failed",
287 user, permRequest, tableName, families);
288 }
289
290 private void logResult(AuthResult result) {
291 if (AUDITLOG.isTraceEnabled()) {
292 RequestContext ctx = RequestContext.get();
293 InetAddress remoteAddr = null;
294 if (ctx != null) {
295 remoteAddr = ctx.getRemoteAddress();
296 }
297 AUDITLOG.trace("Access " + (result.isAllowed() ? "allowed" : "denied") +
298 " for user " + (result.getUser() != null ? result.getUser().getShortName() : "UNKNOWN") +
299 "; reason: " + result.getReason() +
300 "; remote address: " + (remoteAddr != null ? remoteAddr : "") +
301 "; request: " + result.getRequest() +
302 "; context: " + result.toContextString());
303 }
304 }
305
306
307
308
309
310
311 private User getActiveUser() throws IOException {
312 User user = RequestContext.getRequestUser();
313 if (!RequestContext.isInRequestContext()) {
314
315 user = User.getCurrent();
316 }
317 return user;
318 }
319
320
321
322
323
324
325
326
327
328
329 private void requirePermission(String request, byte[] tableName, byte[] family, byte[] qualifier,
330 Action... permissions) throws IOException {
331 User user = getActiveUser();
332 AuthResult result = null;
333
334 for (Action permission : permissions) {
335 if (authManager.authorize(user, tableName, family, qualifier, permission)) {
336 result = AuthResult.allow(request, "Table permission granted", user,
337 permission, tableName, family, qualifier);
338 break;
339 } else {
340
341 result = AuthResult.deny(request, "Insufficient permissions", user,
342 permission, tableName, family, qualifier);
343 }
344 }
345 logResult(result);
346 if (!result.isAllowed()) {
347 throw new AccessDeniedException("Insufficient permissions " + result.toContextString());
348 }
349 }
350
351
352
353
354
355
356
357 private void requirePermission(String request, Permission.Action perm) throws IOException {
358 requireGlobalPermission(request, perm, null, null);
359 }
360
361
362
363
364
365
366
367
368
369 private void requirePermission(String request, Permission.Action perm,
370 RegionCoprocessorEnvironment env,
371 Map<byte[], ? extends Collection<?>> families)
372 throws IOException {
373 User user = getActiveUser();
374 AuthResult result = permissionGranted(request, user, perm, env, families);
375 logResult(result);
376
377 if (!result.isAllowed()) {
378 throw new AccessDeniedException("Insufficient permissions (table=" +
379 env.getRegion().getTableDesc().getNameAsString()+
380 ((families != null && families.size() > 0) ? ", family: " +
381 result.toFamilyString() : "") + ", action=" +
382 perm.toString() + ")");
383 }
384 }
385
386
387
388
389
390
391
392
393
394 private void requireGlobalPermission(String request, Permission.Action perm, byte[] tableName,
395 Map<byte[], ? extends Collection<byte[]>> familyMap) throws IOException {
396 User user = getActiveUser();
397 if (authManager.authorize(user, perm)) {
398 logResult(AuthResult.allow(request, "Global check allowed", user, perm, tableName, familyMap));
399 } else {
400 logResult(AuthResult.deny(request, "Global check failed", user, perm, tableName, familyMap));
401 throw new AccessDeniedException("Insufficient permissions for user '" +
402 (user != null ? user.getShortName() : "null") +"' (global, action=" +
403 perm.toString() + ")");
404 }
405 }
406
407
408
409
410
411 private boolean hasFamilyQualifierPermission(User user,
412 Permission.Action perm,
413 RegionCoprocessorEnvironment env,
414 Map<byte[], ? extends Set<byte[]>> familyMap)
415 throws IOException {
416 HRegionInfo hri = env.getRegion().getRegionInfo();
417 byte[] tableName = hri.getTableName();
418
419 if (user == null) {
420 return false;
421 }
422
423 if (familyMap != null && familyMap.size() > 0) {
424
425 for (Map.Entry<byte[], ? extends Set<byte[]>> family :
426 familyMap.entrySet()) {
427 if (family.getValue() != null && !family.getValue().isEmpty()) {
428 for (byte[] qualifier : family.getValue()) {
429 if (authManager.matchPermission(user, tableName,
430 family.getKey(), qualifier, perm)) {
431 return true;
432 }
433 }
434 } else {
435 if (authManager.matchPermission(user, tableName, family.getKey(),
436 perm)) {
437 return true;
438 }
439 }
440 }
441 } else if (LOG.isDebugEnabled()) {
442 LOG.debug("Empty family map passed for permission check");
443 }
444
445 return false;
446 }
447
448
449 public void start(CoprocessorEnvironment env) throws IOException {
450
451 ZooKeeperWatcher zk = null;
452 if (env instanceof MasterCoprocessorEnvironment) {
453
454 MasterCoprocessorEnvironment mEnv = (MasterCoprocessorEnvironment) env;
455 zk = mEnv.getMasterServices().getZooKeeper();
456 } else if (env instanceof RegionServerCoprocessorEnvironment) {
457 RegionServerCoprocessorEnvironment rsEnv = (RegionServerCoprocessorEnvironment) env;
458 zk = rsEnv.getRegionServerServices().getZooKeeper();
459 } else if (env instanceof RegionCoprocessorEnvironment) {
460
461 regionEnv = (RegionCoprocessorEnvironment) env;
462 zk = regionEnv.getRegionServerServices().getZooKeeper();
463 }
464
465
466
467 if (zk != null) {
468 try {
469 this.authManager = TableAuthManager.get(zk, env.getConfiguration());
470 } catch (IOException ioe) {
471 throw new RuntimeException("Error obtaining TableAuthManager", ioe);
472 }
473 } else {
474 throw new RuntimeException("Error obtaining TableAuthManager, zk found null.");
475 }
476 }
477
478 public void stop(CoprocessorEnvironment env) {
479
480 }
481
482 @Override
483 public void preCreateTable(ObserverContext<MasterCoprocessorEnvironment> c,
484 HTableDescriptor desc, HRegionInfo[] regions) throws IOException {
485 Set<byte[]> families = desc.getFamiliesKeys();
486 Map<byte[], Set<byte[]>> familyMap = Maps.newTreeMap(Bytes.BYTES_COMPARATOR);
487 for (byte[] family: families) {
488 familyMap.put(family, null);
489 }
490 requireGlobalPermission("createTable", Permission.Action.CREATE, desc.getName(), familyMap);
491 }
492
493 @Override
494 public void preCreateTableHandler(ObserverContext<MasterCoprocessorEnvironment> c,
495 HTableDescriptor desc, HRegionInfo[] regions) throws IOException {}
496
497 @Override
498 public void postCreateTable(ObserverContext<MasterCoprocessorEnvironment> c,
499 HTableDescriptor desc, HRegionInfo[] regions) throws IOException {
500 if (!AccessControlLists.isAclTable(desc)) {
501 String owner = desc.getOwnerString();
502
503 if (owner == null) owner = getActiveUser().getShortName();
504 UserPermission userperm = new UserPermission(Bytes.toBytes(owner), desc.getName(), null,
505 Action.values());
506 AccessControlLists.addUserPermission(c.getEnvironment().getConfiguration(), userperm);
507 }
508 }
509
510 @Override
511 public void postCreateTableHandler(ObserverContext<MasterCoprocessorEnvironment> c,
512 HTableDescriptor desc, HRegionInfo[] regions) throws IOException {}
513
514 @Override
515 public void preDeleteTable(ObserverContext<MasterCoprocessorEnvironment> c, byte[] tableName)
516 throws IOException {
517 requirePermission("deleteTable", tableName, null, null, Action.ADMIN, Action.CREATE);
518 }
519
520 @Override
521 public void preDeleteTableHandler(ObserverContext<MasterCoprocessorEnvironment> c,
522 byte[] tableName) throws IOException {}
523 @Override
524 public void postDeleteTable(ObserverContext<MasterCoprocessorEnvironment> c,
525 byte[] tableName) throws IOException {
526 AccessControlLists.removeTablePermissions(c.getEnvironment().getConfiguration(), tableName);
527 }
528 @Override
529 public void postDeleteTableHandler(ObserverContext<MasterCoprocessorEnvironment> c,
530 byte[] tableName) throws IOException {}
531
532 @Override
533 public void preModifyTable(ObserverContext<MasterCoprocessorEnvironment> c, byte[] tableName,
534 HTableDescriptor htd) throws IOException {
535 requirePermission("modifyTable", tableName, null, null, Action.ADMIN, Action.CREATE);
536 }
537
538 @Override
539 public void preModifyTableHandler(ObserverContext<MasterCoprocessorEnvironment> c,
540 byte[] tableName, HTableDescriptor htd) throws IOException {}
541
542 @Override
543 public void postModifyTable(ObserverContext<MasterCoprocessorEnvironment> c,
544 byte[] tableName, HTableDescriptor htd) throws IOException {
545 String owner = htd.getOwnerString();
546
547 if (owner == null) owner = getActiveUser().getShortName();
548 UserPermission userperm = new UserPermission(Bytes.toBytes(owner), htd.getName(), null,
549 Action.values());
550 AccessControlLists.addUserPermission(c.getEnvironment().getConfiguration(), userperm);
551 }
552
553 @Override
554 public void postModifyTableHandler(ObserverContext<MasterCoprocessorEnvironment> c,
555 byte[] tableName, HTableDescriptor htd) throws IOException {}
556
557
558 @Override
559 public void preAddColumn(ObserverContext<MasterCoprocessorEnvironment> c, byte[] tableName,
560 HColumnDescriptor column) throws IOException {
561 requirePermission("addColumn", tableName, null, null, Action.ADMIN, Action.CREATE);
562 }
563
564 @Override
565 public void preAddColumnHandler(ObserverContext<MasterCoprocessorEnvironment> c,
566 byte[] tableName, HColumnDescriptor column) throws IOException {}
567 @Override
568 public void postAddColumn(ObserverContext<MasterCoprocessorEnvironment> c,
569 byte[] tableName, HColumnDescriptor column) throws IOException {}
570 @Override
571 public void postAddColumnHandler(ObserverContext<MasterCoprocessorEnvironment> c,
572 byte[] tableName, HColumnDescriptor column) throws IOException {}
573
574 @Override
575 public void preModifyColumn(ObserverContext<MasterCoprocessorEnvironment> c, byte[] tableName,
576 HColumnDescriptor descriptor) throws IOException {
577 requirePermission("modifyColumn", tableName, null, null, Action.ADMIN, Action.CREATE);
578 }
579
580 @Override
581 public void preModifyColumnHandler(ObserverContext<MasterCoprocessorEnvironment> c,
582 byte[] tableName, HColumnDescriptor descriptor) throws IOException {}
583 @Override
584 public void postModifyColumn(ObserverContext<MasterCoprocessorEnvironment> c,
585 byte[] tableName, HColumnDescriptor descriptor) throws IOException {}
586 @Override
587 public void postModifyColumnHandler(ObserverContext<MasterCoprocessorEnvironment> c,
588 byte[] tableName, HColumnDescriptor descriptor) throws IOException {}
589
590
591 @Override
592 public void preDeleteColumn(ObserverContext<MasterCoprocessorEnvironment> c, byte[] tableName,
593 byte[] col) throws IOException {
594 requirePermission("deleteColumn", tableName, null, null, Action.ADMIN, Action.CREATE);
595 }
596
597 @Override
598 public void preDeleteColumnHandler(ObserverContext<MasterCoprocessorEnvironment> c,
599 byte[] tableName, byte[] col) throws IOException {}
600 @Override
601 public void postDeleteColumn(ObserverContext<MasterCoprocessorEnvironment> c,
602 byte[] tableName, byte[] col) throws IOException {
603 AccessControlLists.removeTablePermissions(c.getEnvironment().getConfiguration(),
604 tableName, col);
605 }
606 @Override
607 public void postDeleteColumnHandler(ObserverContext<MasterCoprocessorEnvironment> c,
608 byte[] tableName, byte[] col) throws IOException {}
609
610 @Override
611 public void preEnableTable(ObserverContext<MasterCoprocessorEnvironment> c, byte[] tableName)
612 throws IOException {
613 requirePermission("enableTable", tableName, null, null, Action.ADMIN, Action.CREATE);
614 }
615
616 @Override
617 public void preEnableTableHandler(ObserverContext<MasterCoprocessorEnvironment> c,
618 byte[] tableName) throws IOException {}
619 @Override
620 public void postEnableTable(ObserverContext<MasterCoprocessorEnvironment> c,
621 byte[] tableName) throws IOException {}
622 @Override
623 public void postEnableTableHandler(ObserverContext<MasterCoprocessorEnvironment> c,
624 byte[] tableName) throws IOException {}
625
626 @Override
627 public void preDisableTable(ObserverContext<MasterCoprocessorEnvironment> c, byte[] tableName)
628 throws IOException {
629 if (Bytes.equals(tableName, AccessControlLists.ACL_GLOBAL_NAME)) {
630 throw new AccessDeniedException("Not allowed to disable "
631 + AccessControlLists.ACL_TABLE_NAME_STR + " table.");
632 }
633 requirePermission("disableTable", tableName, null, null, Action.ADMIN, Action.CREATE);
634 }
635
636 @Override
637 public void preDisableTableHandler(ObserverContext<MasterCoprocessorEnvironment> c,
638 byte[] tableName) throws IOException {}
639 @Override
640 public void postDisableTable(ObserverContext<MasterCoprocessorEnvironment> c,
641 byte[] tableName) throws IOException {}
642 @Override
643 public void postDisableTableHandler(ObserverContext<MasterCoprocessorEnvironment> c,
644 byte[] tableName) throws IOException {}
645
646 @Override
647 public void preMove(ObserverContext<MasterCoprocessorEnvironment> c, HRegionInfo region,
648 ServerName srcServer, ServerName destServer) throws IOException {
649 requirePermission("move", region.getTableName(), null, null, Action.ADMIN);
650 }
651
652 @Override
653 public void postMove(ObserverContext<MasterCoprocessorEnvironment> c,
654 HRegionInfo region, ServerName srcServer, ServerName destServer)
655 throws IOException {}
656
657 @Override
658 public void preAssign(ObserverContext<MasterCoprocessorEnvironment> c, HRegionInfo regionInfo)
659 throws IOException {
660 requirePermission("assign", regionInfo.getTableName(), null, null, Action.ADMIN);
661 }
662
663 @Override
664 public void postAssign(ObserverContext<MasterCoprocessorEnvironment> c,
665 HRegionInfo regionInfo) throws IOException {}
666
667 @Override
668 public void preUnassign(ObserverContext<MasterCoprocessorEnvironment> c, HRegionInfo regionInfo,
669 boolean force) throws IOException {
670 requirePermission("unassign", regionInfo.getTableName(), null, null, Action.ADMIN);
671 }
672
673 @Override
674 public void postUnassign(ObserverContext<MasterCoprocessorEnvironment> c,
675 HRegionInfo regionInfo, boolean force) throws IOException {}
676
677 @Override
678 public void preRegionOffline(ObserverContext<MasterCoprocessorEnvironment> c,
679 HRegionInfo regionInfo) throws IOException {
680 requirePermission("regionOffline", regionInfo.getTableName(), null, null, Action.ADMIN);
681 }
682
683 @Override
684 public void postRegionOffline(ObserverContext<MasterCoprocessorEnvironment> c,
685 HRegionInfo regionInfo) throws IOException {
686 }
687
688 @Override
689 public void preBalance(ObserverContext<MasterCoprocessorEnvironment> c)
690 throws IOException {
691 requirePermission("balance", Permission.Action.ADMIN);
692 }
693 @Override
694 public void postBalance(ObserverContext<MasterCoprocessorEnvironment> c, List<RegionPlan> plans)
695 throws IOException {}
696
697 @Override
698 public boolean preBalanceSwitch(ObserverContext<MasterCoprocessorEnvironment> c,
699 boolean newValue) throws IOException {
700 requirePermission("balanceSwitch", Permission.Action.ADMIN);
701 return newValue;
702 }
703 @Override
704 public void postBalanceSwitch(ObserverContext<MasterCoprocessorEnvironment> c,
705 boolean oldValue, boolean newValue) throws IOException {}
706
707 @Override
708 public void preShutdown(ObserverContext<MasterCoprocessorEnvironment> c)
709 throws IOException {
710 requirePermission("shutdown", Permission.Action.ADMIN);
711 }
712
713 @Override
714 public void preStopMaster(ObserverContext<MasterCoprocessorEnvironment> c)
715 throws IOException {
716 requirePermission("stopMaster", Permission.Action.ADMIN);
717 }
718
719 @Override
720 public void postStartMaster(ObserverContext<MasterCoprocessorEnvironment> ctx)
721 throws IOException {
722
723 AccessControlLists.init(ctx.getEnvironment().getMasterServices());
724 }
725
726 @Override
727 public void preSnapshot(final ObserverContext<MasterCoprocessorEnvironment> ctx,
728 final SnapshotDescription snapshot, final HTableDescriptor hTableDescriptor)
729 throws IOException {
730 requirePermission("snapshot", Permission.Action.ADMIN);
731 }
732
733 @Override
734 public void postSnapshot(final ObserverContext<MasterCoprocessorEnvironment> ctx,
735 final SnapshotDescription snapshot, final HTableDescriptor hTableDescriptor)
736 throws IOException {
737 }
738
739 @Override
740 public void preCloneSnapshot(final ObserverContext<MasterCoprocessorEnvironment> ctx,
741 final SnapshotDescription snapshot, final HTableDescriptor hTableDescriptor)
742 throws IOException {
743 requirePermission("clone", Permission.Action.ADMIN);
744 }
745
746 @Override
747 public void postCloneSnapshot(final ObserverContext<MasterCoprocessorEnvironment> ctx,
748 final SnapshotDescription snapshot, final HTableDescriptor hTableDescriptor)
749 throws IOException {
750 }
751
752 @Override
753 public void preRestoreSnapshot(final ObserverContext<MasterCoprocessorEnvironment> ctx,
754 final SnapshotDescription snapshot, final HTableDescriptor hTableDescriptor)
755 throws IOException {
756 requirePermission("restore", Permission.Action.ADMIN);
757 }
758
759 @Override
760 public void postRestoreSnapshot(final ObserverContext<MasterCoprocessorEnvironment> ctx,
761 final SnapshotDescription snapshot, final HTableDescriptor hTableDescriptor)
762 throws IOException {
763 }
764
765 @Override
766 public void preDeleteSnapshot(final ObserverContext<MasterCoprocessorEnvironment> ctx,
767 final SnapshotDescription snapshot) throws IOException {
768 requirePermission("deleteSnapshot", Permission.Action.ADMIN);
769 }
770
771 @Override
772 public void postDeleteSnapshot(final ObserverContext<MasterCoprocessorEnvironment> ctx,
773 final SnapshotDescription snapshot) throws IOException {
774 }
775
776
777
778 @Override
779 public void preOpen(ObserverContext<RegionCoprocessorEnvironment> e)
780 throws IOException {
781 RegionCoprocessorEnvironment env = e.getEnvironment();
782 final HRegion region = env.getRegion();
783 if (region == null) {
784 LOG.error("NULL region from RegionCoprocessorEnvironment in preOpen()");
785 } else {
786 HRegionInfo regionInfo = region.getRegionInfo();
787 if (isSpecialTable(regionInfo)) {
788 isSystemOrSuperUser(regionEnv.getConfiguration());
789 } else {
790 requirePermission("preOpen", Action.ADMIN);
791 }
792 }
793 }
794
795 @Override
796 public void postOpen(ObserverContext<RegionCoprocessorEnvironment> c) {
797 RegionCoprocessorEnvironment env = c.getEnvironment();
798 final HRegion region = env.getRegion();
799 if (region == null) {
800 LOG.error("NULL region from RegionCoprocessorEnvironment in postOpen()");
801 return;
802 }
803 if (AccessControlLists.isAclRegion(region)) {
804 aclRegion = true;
805 try {
806 initialize(env);
807 } catch (IOException ex) {
808
809
810 throw new RuntimeException("Failed to initialize permissions cache", ex);
811 }
812 }
813 }
814
815 @Override
816 public void preFlush(ObserverContext<RegionCoprocessorEnvironment> e) throws IOException {
817 requirePermission("flush", getTableName(e.getEnvironment()), null, null, Action.ADMIN);
818 }
819
820 @Override
821 public void preSplit(ObserverContext<RegionCoprocessorEnvironment> e) throws IOException {
822 requirePermission("split", getTableName(e.getEnvironment()), null, null, Action.ADMIN);
823 }
824
825 @Override
826 public void preSplit(ObserverContext<RegionCoprocessorEnvironment> e,
827 byte[] splitRow) throws IOException {
828 requirePermission("split", getTableName(e.getEnvironment()), null, null, Action.ADMIN);
829 }
830
831 @Override
832 public InternalScanner preCompact(ObserverContext<RegionCoprocessorEnvironment> e,
833 final Store store, final InternalScanner scanner, final ScanType scanType)
834 throws IOException {
835 requirePermission("compact", getTableName(e.getEnvironment()), null, null, Action.ADMIN);
836 return scanner;
837 }
838
839 @Override
840 public void preCompactSelection(final ObserverContext<RegionCoprocessorEnvironment> e,
841 final Store store, final List<StoreFile> candidates) throws IOException {
842 requirePermission("compact", getTableName(e.getEnvironment()), null, null, Action.ADMIN);
843 }
844
845 @Override
846 public void preGetClosestRowBefore(final ObserverContext<RegionCoprocessorEnvironment> c,
847 final byte [] row, final byte [] family, final Result result)
848 throws IOException {
849 assert family != null;
850
851 requirePermission("getClosestRowBefore", Permission.Action.READ, c.getEnvironment(),
852 makeFamilyMap(family, null));
853 }
854
855 @Override
856 public void preGet(final ObserverContext<RegionCoprocessorEnvironment> c,
857 final Get get, final List<KeyValue> result) throws IOException {
858
859
860
861
862 RegionCoprocessorEnvironment e = c.getEnvironment();
863 User requestUser = getActiveUser();
864 AuthResult authResult = permissionGranted("get", requestUser,
865 Permission.Action.READ, e, get.getFamilyMap());
866 if (!authResult.isAllowed()) {
867 if (hasFamilyQualifierPermission(requestUser,
868 Permission.Action.READ, e, get.getFamilyMap())) {
869 byte[] table = getTableName(e);
870 AccessControlFilter filter = new AccessControlFilter(authManager,
871 requestUser, table);
872
873
874 if (get.getFilter() != null) {
875 FilterList wrapper = new FilterList(FilterList.Operator.MUST_PASS_ALL,
876 Lists.newArrayList(filter, get.getFilter()));
877 get.setFilter(wrapper);
878 } else {
879 get.setFilter(filter);
880 }
881 logResult(AuthResult.allow("get", "Access allowed with filter", requestUser,
882 Permission.Action.READ, authResult.getTable(), get.getFamilyMap()));
883 } else {
884 logResult(authResult);
885 throw new AccessDeniedException("Insufficient permissions (table=" +
886 e.getRegion().getTableDesc().getNameAsString() + ", action=READ)");
887 }
888 } else {
889
890 logResult(authResult);
891 }
892 }
893
894 @Override
895 public boolean preExists(final ObserverContext<RegionCoprocessorEnvironment> c,
896 final Get get, final boolean exists) throws IOException {
897 requirePermission("exists", Permission.Action.READ, c.getEnvironment(),
898 get.getFamilyMap());
899 return exists;
900 }
901
902 @Override
903 public void prePut(final ObserverContext<RegionCoprocessorEnvironment> c,
904 final Put put, final WALEdit edit, final boolean writeToWAL)
905 throws IOException {
906 requirePermission("put", Permission.Action.WRITE, c.getEnvironment(),
907 put.getFamilyMap());
908 }
909
910 @Override
911 public void postPut(final ObserverContext<RegionCoprocessorEnvironment> c,
912 final Put put, final WALEdit edit, final boolean writeToWAL) {
913 if (aclRegion) {
914 updateACL(c.getEnvironment(), put.getFamilyMap());
915 }
916 }
917
918 @Override
919 public void preDelete(final ObserverContext<RegionCoprocessorEnvironment> c,
920 final Delete delete, final WALEdit edit, final boolean writeToWAL)
921 throws IOException {
922 requirePermission("delete", Permission.Action.WRITE, c.getEnvironment(),
923 delete.getFamilyMap());
924 }
925
926 @Override
927 public void postDelete(final ObserverContext<RegionCoprocessorEnvironment> c,
928 final Delete delete, final WALEdit edit, final boolean writeToWAL)
929 throws IOException {
930 if (aclRegion) {
931 updateACL(c.getEnvironment(), delete.getFamilyMap());
932 }
933 }
934
935 @Override
936 public boolean preCheckAndPut(final ObserverContext<RegionCoprocessorEnvironment> c,
937 final byte [] row, final byte [] family, final byte [] qualifier,
938 final CompareFilter.CompareOp compareOp,
939 final ByteArrayComparable comparator, final Put put,
940 final boolean result) throws IOException {
941 Map<byte[], ? extends Collection<byte[]>> familyMap = makeFamilyMap(family, qualifier);
942 requirePermission("checkAndPut", Permission.Action.READ, c.getEnvironment(), familyMap);
943 requirePermission("checkAndPut", Permission.Action.WRITE, c.getEnvironment(), familyMap);
944 return result;
945 }
946
947 @Override
948 public boolean preCheckAndDelete(final ObserverContext<RegionCoprocessorEnvironment> c,
949 final byte [] row, final byte [] family, final byte [] qualifier,
950 final CompareFilter.CompareOp compareOp,
951 final ByteArrayComparable comparator, final Delete delete,
952 final boolean result) throws IOException {
953 Map<byte[], ? extends Collection<byte[]>> familyMap = makeFamilyMap(family, qualifier);
954 requirePermission("checkAndDelete", Permission.Action.READ, c.getEnvironment(), familyMap);
955 requirePermission("checkAndDelete", Permission.Action.WRITE, c.getEnvironment(), familyMap);
956 return result;
957 }
958
959 @Override
960 public long preIncrementColumnValue(final ObserverContext<RegionCoprocessorEnvironment> c,
961 final byte [] row, final byte [] family, final byte [] qualifier,
962 final long amount, final boolean writeToWAL)
963 throws IOException {
964 Map<byte[], ? extends Collection<byte[]>> familyMap = makeFamilyMap(family, qualifier);
965 requirePermission("incrementColumnValue", Permission.Action.WRITE, c.getEnvironment(), familyMap);
966 return -1;
967 }
968
969 @Override
970 public Result preAppend(ObserverContext<RegionCoprocessorEnvironment> c, Append append)
971 throws IOException {
972 requirePermission("append", Permission.Action.WRITE, c.getEnvironment(), append.getFamilyMap());
973 return null;
974 }
975
976 @Override
977 public Result preIncrement(final ObserverContext<RegionCoprocessorEnvironment> c,
978 final Increment increment)
979 throws IOException {
980
981 Map<byte[], Set<byte[]>> familyMap = Maps.newTreeMap(Bytes.BYTES_COMPARATOR);
982 for (Map.Entry<byte [], List<? extends Cell>> entry: increment.getFamilyMap().entrySet()) {
983 Set<byte[]> qualifiers = Sets.newTreeSet(Bytes.BYTES_COMPARATOR);
984 for (Cell cell: entry.getValue()) {
985 KeyValue kv = KeyValueUtil.ensureKeyValue(cell);
986 qualifiers.add(kv.getQualifier());
987 }
988 familyMap.put(entry.getKey(), qualifiers);
989 }
990 requirePermission("increment", Permission.Action.WRITE, c.getEnvironment(), familyMap);
991 return null;
992 }
993
994 @Override
995 public RegionScanner preScannerOpen(final ObserverContext<RegionCoprocessorEnvironment> c,
996 final Scan scan, final RegionScanner s) throws IOException {
997
998
999
1000
1001 RegionCoprocessorEnvironment e = c.getEnvironment();
1002 User user = getActiveUser();
1003 AuthResult authResult = permissionGranted("scannerOpen", user, Permission.Action.READ, e,
1004 scan.getFamilyMap());
1005 if (!authResult.isAllowed()) {
1006 if (hasFamilyQualifierPermission(user, Permission.Action.READ, e,
1007 scan.getFamilyMap())) {
1008 byte[] table = getTableName(e);
1009 AccessControlFilter filter = new AccessControlFilter(authManager,
1010 user, table);
1011
1012
1013 if (scan.hasFilter()) {
1014 FilterList wrapper = new FilterList(FilterList.Operator.MUST_PASS_ALL,
1015 Lists.newArrayList(filter, scan.getFilter()));
1016 scan.setFilter(wrapper);
1017 } else {
1018 scan.setFilter(filter);
1019 }
1020 logResult(AuthResult.allow("scannerOpen", "Access allowed with filter", user,
1021 Permission.Action.READ, authResult.getTable(), scan.getFamilyMap()));
1022 } else {
1023
1024 logResult(authResult);
1025 throw new AccessDeniedException("Insufficient permissions for user '"+
1026 (user != null ? user.getShortName() : "null")+"' "+
1027 "for scanner open on table " + Bytes.toString(getTableName(e)));
1028 }
1029 } else {
1030
1031 logResult(authResult);
1032 }
1033 return s;
1034 }
1035
1036 @Override
1037 public RegionScanner postScannerOpen(final ObserverContext<RegionCoprocessorEnvironment> c,
1038 final Scan scan, final RegionScanner s) throws IOException {
1039 User user = getActiveUser();
1040 if (user != null && user.getShortName() != null) {
1041 scannerOwners.put(s, user.getShortName());
1042 }
1043 return s;
1044 }
1045
1046 @Override
1047 public boolean preScannerNext(final ObserverContext<RegionCoprocessorEnvironment> c,
1048 final InternalScanner s, final List<Result> result,
1049 final int limit, final boolean hasNext) throws IOException {
1050 requireScannerOwner(s);
1051 return hasNext;
1052 }
1053
1054 @Override
1055 public void preScannerClose(final ObserverContext<RegionCoprocessorEnvironment> c,
1056 final InternalScanner s) throws IOException {
1057 requireScannerOwner(s);
1058 }
1059
1060 @Override
1061 public void postScannerClose(final ObserverContext<RegionCoprocessorEnvironment> c,
1062 final InternalScanner s) throws IOException {
1063
1064 scannerOwners.remove(s);
1065 }
1066
1067
1068
1069
1070
1071
1072 private void requireScannerOwner(InternalScanner s)
1073 throws AccessDeniedException {
1074 if (RequestContext.isInRequestContext()) {
1075 String requestUserName = RequestContext.getRequestUserName();
1076 String owner = scannerOwners.get(s);
1077 if (owner != null && !owner.equals(requestUserName)) {
1078 throw new AccessDeniedException("User '"+ requestUserName +"' is not the scanner owner!");
1079 }
1080 }
1081 }
1082
1083
1084
1085
1086
1087
1088
1089 @Override
1090 public void preBulkLoadHFile(ObserverContext<RegionCoprocessorEnvironment> ctx,
1091 List<Pair<byte[], String>> familyPaths) throws IOException {
1092 List<byte[]> cfs = new LinkedList<byte[]>();
1093 for(Pair<byte[],String> el : familyPaths) {
1094 requirePermission("preBulkLoadHFile",
1095 ctx.getEnvironment().getRegion().getTableDesc().getName(),
1096 el.getFirst(),
1097 null,
1098 Permission.Action.WRITE);
1099 }
1100 }
1101
1102 private AuthResult hasSomeAccess(RegionCoprocessorEnvironment e, String method, Action action) throws IOException {
1103 User requestUser = getActiveUser();
1104 byte[] tableName = e.getRegion().getTableDesc().getName();
1105 AuthResult authResult = permissionGranted(method, requestUser,
1106 action, e, Collections.EMPTY_MAP);
1107 if (!authResult.isAllowed()) {
1108 for(UserPermission userPerm:
1109 AccessControlLists.getUserPermissions(regionEnv.getConfiguration(), tableName)) {
1110 for(Permission.Action userAction: userPerm.getActions()) {
1111 if(userAction.equals(action)) {
1112 return AuthResult.allow(method, "Access allowed", requestUser,
1113 action, tableName, null, null);
1114 }
1115 }
1116 }
1117 }
1118 return authResult;
1119 }
1120
1121
1122
1123
1124
1125
1126
1127
1128 public void prePrepareBulkLoad(RegionCoprocessorEnvironment e) throws IOException {
1129 AuthResult authResult = hasSomeAccess(e, "prePrepareBulkLoad", Action.WRITE);
1130 logResult(authResult);
1131 if (!authResult.isAllowed()) {
1132 throw new AccessDeniedException("Insufficient permissions (table=" +
1133 e.getRegion().getTableDesc().getNameAsString() + ", action=WRITE)");
1134 }
1135 }
1136
1137
1138
1139
1140
1141
1142
1143
1144 public void preCleanupBulkLoad(RegionCoprocessorEnvironment e) throws IOException {
1145 AuthResult authResult = hasSomeAccess(e, "preCleanupBulkLoad", Action.WRITE);
1146 logResult(authResult);
1147 if (!authResult.isAllowed()) {
1148 throw new AccessDeniedException("Insufficient permissions (table=" +
1149 e.getRegion().getTableDesc().getNameAsString() + ", action=WRITE)");
1150 }
1151 }
1152
1153
1154 @Override
1155 public void grant(RpcController controller,
1156 AccessControlProtos.GrantRequest request,
1157 RpcCallback<AccessControlProtos.GrantResponse> done) {
1158 UserPermission perm = ProtobufUtil.toUserPermission(request.getPermission());
1159 AccessControlProtos.GrantResponse response = null;
1160 try {
1161
1162 if (aclRegion) {
1163 if (LOG.isDebugEnabled()) {
1164 LOG.debug("Received request to grant access permission " + perm.toString());
1165 }
1166
1167 requirePermission("grant", perm.getTable(), perm.getFamily(), perm.getQualifier(), Action.ADMIN);
1168
1169 AccessControlLists.addUserPermission(regionEnv.getConfiguration(), perm);
1170 if (AUDITLOG.isTraceEnabled()) {
1171
1172 AUDITLOG.trace("Granted permission " + perm.toString());
1173 }
1174 } else {
1175 throw new CoprocessorException(AccessController.class, "This method "
1176 + "can only execute at " + Bytes.toString(AccessControlLists.ACL_TABLE_NAME) + " table.");
1177 }
1178 response = AccessControlProtos.GrantResponse.getDefaultInstance();
1179 } catch (IOException ioe) {
1180
1181 ResponseConverter.setControllerException(controller, ioe);
1182 }
1183 done.run(response);
1184 }
1185
1186 @Override
1187 public void revoke(RpcController controller,
1188 AccessControlProtos.RevokeRequest request,
1189 RpcCallback<AccessControlProtos.RevokeResponse> done) {
1190 UserPermission perm = ProtobufUtil.toUserPermission(request.getPermission());
1191 AccessControlProtos.RevokeResponse response = null;
1192 try {
1193
1194 if (aclRegion) {
1195 if (LOG.isDebugEnabled()) {
1196 LOG.debug("Received request to revoke access permission " + perm.toString());
1197 }
1198
1199 requirePermission("revoke", perm.getTable(), perm.getFamily(),
1200 perm.getQualifier(), Action.ADMIN);
1201
1202 AccessControlLists.removeUserPermission(regionEnv.getConfiguration(), perm);
1203 if (AUDITLOG.isTraceEnabled()) {
1204
1205 AUDITLOG.trace("Revoked permission " + perm.toString());
1206 }
1207 } else {
1208 throw new CoprocessorException(AccessController.class, "This method "
1209 + "can only execute at " + Bytes.toString(AccessControlLists.ACL_TABLE_NAME) + " table.");
1210 }
1211 response = AccessControlProtos.RevokeResponse.getDefaultInstance();
1212 } catch (IOException ioe) {
1213
1214 ResponseConverter.setControllerException(controller, ioe);
1215 }
1216 done.run(response);
1217 }
1218
1219 @Override
1220 public void getUserPermissions(RpcController controller,
1221 AccessControlProtos.UserPermissionsRequest request,
1222 RpcCallback<AccessControlProtos.UserPermissionsResponse> done) {
1223 AccessControlProtos.UserPermissionsResponse response = null;
1224 byte[] table = null;
1225 if (request.hasTable()) {
1226 table = request.getTable().toByteArray();
1227 }
1228 try {
1229
1230 if (aclRegion) {
1231 requirePermission("userPermissions", table, null, null, Action.ADMIN);
1232
1233 List<UserPermission> perms = AccessControlLists.getUserPermissions(
1234 regionEnv.getConfiguration(), table);
1235 response = ResponseConverter.buildUserPermissionsResponse(perms);
1236 } else {
1237 throw new CoprocessorException(AccessController.class, "This method "
1238 + "can only execute at " + Bytes.toString(AccessControlLists.ACL_TABLE_NAME) + " table.");
1239 }
1240 } catch (IOException ioe) {
1241
1242 ResponseConverter.setControllerException(controller, ioe);
1243 }
1244 done.run(response);
1245 }
1246
1247 @Override
1248 public void checkPermissions(RpcController controller,
1249 AccessControlProtos.CheckPermissionsRequest request,
1250 RpcCallback<AccessControlProtos.CheckPermissionsResponse> done) {
1251 Permission[] permissions = new Permission[request.getPermissionCount()];
1252 for (int i=0; i < request.getPermissionCount(); i++) {
1253 permissions[i] = ProtobufUtil.toPermission(request.getPermission(i));
1254 }
1255 AccessControlProtos.CheckPermissionsResponse response = null;
1256 try {
1257 byte[] tableName = regionEnv.getRegion().getTableDesc().getName();
1258 for (Permission permission : permissions) {
1259 if (permission instanceof TablePermission) {
1260 TablePermission tperm = (TablePermission) permission;
1261 for (Permission.Action action : permission.getActions()) {
1262 if (!Arrays.equals(tperm.getTable(), tableName)) {
1263 throw new CoprocessorException(AccessController.class, String.format("This method "
1264 + "can only execute at the table specified in TablePermission. " +
1265 "Table of the region:%s , requested table:%s", Bytes.toString(tableName),
1266 Bytes.toString(tperm.getTable())));
1267 }
1268
1269 Map<byte[], Set<byte[]>> familyMap = Maps.newTreeMap(Bytes.BYTES_COMPARATOR);
1270 if (tperm.getFamily() != null) {
1271 if (tperm.getQualifier() != null) {
1272 Set<byte[]> qualifiers = Sets.newTreeSet(Bytes.BYTES_COMPARATOR);
1273 qualifiers.add(tperm.getQualifier());
1274 familyMap.put(tperm.getFamily(), qualifiers);
1275 } else {
1276 familyMap.put(tperm.getFamily(), null);
1277 }
1278 }
1279
1280 requirePermission("checkPermissions", action, regionEnv, familyMap);
1281 }
1282
1283 } else {
1284 for (Permission.Action action : permission.getActions()) {
1285 requirePermission("checkPermissions", action);
1286 }
1287 }
1288 }
1289 response = AccessControlProtos.CheckPermissionsResponse.getDefaultInstance();
1290 } catch (IOException ioe) {
1291 ResponseConverter.setControllerException(controller, ioe);
1292 }
1293 done.run(response);
1294 }
1295
1296 @Override
1297 public Service getService() {
1298 return AccessControlProtos.AccessControlService.newReflectiveService(this);
1299 }
1300
1301 private byte[] getTableName(RegionCoprocessorEnvironment e) {
1302 HRegion region = e.getRegion();
1303 byte[] tableName = null;
1304
1305 if (region != null) {
1306 HRegionInfo regionInfo = region.getRegionInfo();
1307 if (regionInfo != null) {
1308 tableName = regionInfo.getTableName();
1309 }
1310 }
1311 return tableName;
1312 }
1313
1314
1315 @Override
1316 public void preClose(ObserverContext<RegionCoprocessorEnvironment> e, boolean abortRequested)
1317 throws IOException {
1318 requirePermission("preClose", Action.ADMIN);
1319 }
1320
1321 private void isSystemOrSuperUser(Configuration conf) throws IOException {
1322 User user = User.getCurrent();
1323 if (user == null) {
1324 throw new IOException("Unable to obtain the current user, " +
1325 "authorization checks for internal operations will not work correctly!");
1326 }
1327
1328 String currentUser = user.getShortName();
1329 List<String> superusers = Lists.asList(currentUser, conf.getStrings(
1330 AccessControlLists.SUPERUSER_CONF_KEY, new String[0]));
1331
1332 User activeUser = getActiveUser();
1333 if (!(superusers.contains(activeUser.getShortName()))) {
1334 throw new AccessDeniedException("User '" + (user != null ? user.getShortName() : "null") +
1335 "is not system or super user.");
1336 }
1337 }
1338
1339 private boolean isSpecialTable(HRegionInfo regionInfo) {
1340 byte[] tableName = regionInfo.getTableName();
1341 return Arrays.equals(tableName, AccessControlLists.ACL_TABLE_NAME)
1342 || Arrays.equals(tableName, Bytes.toBytes("-ROOT-"))
1343 || Arrays.equals(tableName, Bytes.toBytes(".META."));
1344 }
1345
1346 @Override
1347 public void preStopRegionServer(
1348 ObserverContext<RegionServerCoprocessorEnvironment> env)
1349 throws IOException {
1350 requirePermission("preStopRegionServer", Permission.Action.ADMIN);
1351 }
1352
1353 private Map<byte[], ? extends Collection<byte[]>> makeFamilyMap(byte[] family,
1354 byte[] qualifier) {
1355 if (family == null) {
1356 return null;
1357 }
1358
1359 Map<byte[], Collection<byte[]>> familyMap = Maps.newTreeMap(Bytes.BYTES_COMPARATOR);
1360 familyMap.put(family, qualifier != null ? ImmutableSet.of(qualifier) : null);
1361 return familyMap;
1362 }
1363 }