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