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