1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.hadoop.hbase.security.access;
20
21 import org.apache.commons.logging.Log;
22 import org.apache.commons.logging.LogFactory;
23 import org.apache.hadoop.conf.Configuration;
24 import org.apache.hadoop.hbase.TableName;
25 import org.apache.hadoop.hbase.util.Bytes;
26 import org.apache.hadoop.hbase.zookeeper.ZKUtil;
27 import org.apache.hadoop.hbase.zookeeper.ZooKeeperListener;
28 import org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher;
29 import org.apache.zookeeper.KeeperException;
30
31 import java.io.IOException;
32 import java.util.List;
33
34
35
36
37
38
39
40
41
42
43 public class ZKPermissionWatcher extends ZooKeeperListener {
44 private static Log LOG = LogFactory.getLog(ZKPermissionWatcher.class);
45
46 static final String ACL_NODE = "acl";
47 TableAuthManager authManager;
48 String aclZNode;
49
50 public ZKPermissionWatcher(ZooKeeperWatcher watcher,
51 TableAuthManager authManager, Configuration conf) {
52 super(watcher);
53 this.authManager = authManager;
54 String aclZnodeParent = conf.get("zookeeper.znode.acl.parent", ACL_NODE);
55 this.aclZNode = ZKUtil.joinZNode(watcher.baseZNode, aclZnodeParent);
56 }
57
58 public void start() throws KeeperException {
59 watcher.registerListener(this);
60 if (ZKUtil.watchAndCheckExists(watcher, aclZNode)) {
61 List<ZKUtil.NodeAndData> existing =
62 ZKUtil.getChildDataAndWatchForNewChildren(watcher, aclZNode);
63 if (existing != null) {
64 refreshNodes(existing);
65 }
66 }
67 }
68
69 @Override
70 public void nodeCreated(String path) {
71 if (path.equals(aclZNode)) {
72 try {
73 List<ZKUtil.NodeAndData> nodes =
74 ZKUtil.getChildDataAndWatchForNewChildren(watcher, aclZNode);
75 refreshNodes(nodes);
76 } catch (KeeperException ke) {
77 LOG.error("Error reading data from zookeeper", ke);
78
79 watcher.abort("Zookeeper error obtaining acl node children", ke);
80 }
81 }
82 }
83
84 @Override
85 public void nodeDeleted(String path) {
86 if (aclZNode.equals(ZKUtil.getParent(path))) {
87 String table = ZKUtil.getNodeName(path);
88 if(AccessControlLists.isNamespaceEntry(table)) {
89 authManager.removeNamespace(Bytes.toBytes(table));
90 } else {
91 authManager.removeTable(TableName.valueOf(table));
92 }
93 }
94 }
95
96 @Override
97 public void nodeDataChanged(String path) {
98 if (aclZNode.equals(ZKUtil.getParent(path))) {
99
100 String entry = ZKUtil.getNodeName(path);
101 try {
102 byte[] data = ZKUtil.getDataAndWatch(watcher, path);
103 refreshAuthManager(entry, data);
104 } catch (KeeperException ke) {
105 LOG.error("Error reading data from zookeeper for node " + entry, ke);
106
107 watcher.abort("Zookeeper error getting data for node " + entry, ke);
108 } catch (IOException ioe) {
109 LOG.error("Error reading permissions writables", ioe);
110 }
111 }
112 }
113
114 @Override
115 public void nodeChildrenChanged(String path) {
116 if (path.equals(aclZNode)) {
117
118 try {
119 List<ZKUtil.NodeAndData> nodes =
120 ZKUtil.getChildDataAndWatchForNewChildren(watcher, aclZNode);
121 refreshNodes(nodes);
122 } catch (KeeperException ke) {
123 LOG.error("Error reading data from zookeeper for path "+path, ke);
124 watcher.abort("Zookeeper error get node children for path "+path, ke);
125 }
126 }
127 }
128
129 private void refreshNodes(List<ZKUtil.NodeAndData> nodes) {
130 for (ZKUtil.NodeAndData n : nodes) {
131 if (n.isEmpty()) continue;
132 String path = n.getNode();
133 String entry = (ZKUtil.getNodeName(path));
134 try {
135 refreshAuthManager(entry, n.getData());
136 } catch (IOException ioe) {
137 LOG.error("Failed parsing permissions for table '" + entry +
138 "' from zk", ioe);
139 }
140 }
141 }
142
143 private void refreshAuthManager(String entry, byte[] nodeData) throws IOException {
144 if (LOG.isDebugEnabled()) {
145 LOG.debug("Updating permissions cache from node "+entry+" with data: "+
146 Bytes.toStringBinary(nodeData));
147 }
148 if(AccessControlLists.isNamespaceEntry(entry)) {
149 authManager.refreshNamespaceCacheFromWritable(
150 AccessControlLists.fromNamespaceEntry(entry), nodeData);
151 } else {
152 authManager.refreshTableCacheFromWritable(TableName.valueOf(entry), nodeData);
153 }
154 }
155
156
157
158
159
160
161 public void writeToZookeeper(byte[] entry, byte[] permsData) {
162 String entryName = Bytes.toString(entry);
163 String zkNode = ZKUtil.joinZNode(watcher.baseZNode, ACL_NODE);
164 zkNode = ZKUtil.joinZNode(zkNode, entryName);
165
166 try {
167 ZKUtil.createWithParents(watcher, zkNode);
168 ZKUtil.updateExistingNodeData(watcher, zkNode, permsData, -1);
169 } catch (KeeperException e) {
170 LOG.error("Failed updating permissions for entry '" +
171 entryName + "'", e);
172 watcher.abort("Failed writing node "+zkNode+" to zookeeper", e);
173 }
174 }
175 }