1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.accumulo.server.security.handler;
18
19 import java.util.Collections;
20 import java.util.HashMap;
21 import java.util.Map;
22 import java.util.Map.Entry;
23 import java.util.Set;
24 import java.util.TreeSet;
25
26 import org.apache.accumulo.core.Constants;
27 import org.apache.accumulo.core.client.AccumuloSecurityException;
28 import org.apache.accumulo.core.client.TableNotFoundException;
29 import org.apache.accumulo.core.security.SystemPermission;
30 import org.apache.accumulo.core.security.TablePermission;
31 import org.apache.accumulo.core.security.thrift.Credential;
32 import org.apache.accumulo.core.security.thrift.SecurityErrorCode;
33 import org.apache.accumulo.fate.zookeeper.IZooReaderWriter;
34 import org.apache.accumulo.fate.zookeeper.ZooUtil.NodeExistsPolicy;
35 import org.apache.accumulo.fate.zookeeper.ZooUtil.NodeMissingPolicy;
36 import org.apache.accumulo.server.zookeeper.ZooCache;
37 import org.apache.accumulo.server.zookeeper.ZooReaderWriter;
38 import org.apache.log4j.Logger;
39 import org.apache.zookeeper.KeeperException;
40 import org.apache.zookeeper.KeeperException.Code;
41
42 /**
43 *
44 */
45 public class ZKPermHandler implements PermissionHandler {
46 private static final Logger log = Logger.getLogger(ZKAuthorizor.class);
47 private static PermissionHandler zkPermHandlerInstance = null;
48
49 private String ZKUserPath;
50 private final ZooCache zooCache;
51 private final String ZKUserSysPerms = "/System";
52 private final String ZKUserTablePerms = "/Tables";
53
54 public static synchronized PermissionHandler getInstance() {
55 if (zkPermHandlerInstance == null)
56 zkPermHandlerInstance = new ZKPermHandler();
57 return zkPermHandlerInstance;
58 }
59
60 public void initialize(String instanceId, boolean initialize) {
61 ZKUserPath = ZKSecurityTool.getInstancePath(instanceId) + "/users";
62 }
63
64 public ZKPermHandler() {
65 zooCache = new ZooCache();
66 }
67
68 @Override
69 public boolean hasTablePermission(String user, String table, TablePermission permission) {
70 byte[] serializedPerms;
71 try {
72 serializedPerms = ZooReaderWriter.getRetryingInstance().getData(ZKUserPath + "/" + user + ZKUserTablePerms + "/" + table, null);
73 } catch (KeeperException e) {
74 if (e.code() == Code.NONODE) {
75 return false;
76 }
77 log.warn("Unhandled KeeperException, failing closed for table permission check", e);
78 return false;
79 } catch (InterruptedException e) {
80 log.warn("Unhandled InterruptedException, failing closed for table permission check", e);
81 return false;
82 }
83 if (serializedPerms != null) {
84 return ZKSecurityTool.convertTablePermissions(serializedPerms).contains(permission);
85 }
86 return false;
87 }
88
89 @Override
90 public boolean hasCachedTablePermission(String user, String table, TablePermission permission) throws AccumuloSecurityException, TableNotFoundException {
91 byte[] serializedPerms = zooCache.get(ZKUserPath + "/" + user + ZKUserTablePerms + "/" + table);
92 if (serializedPerms != null) {
93 return ZKSecurityTool.convertTablePermissions(serializedPerms).contains(permission);
94 }
95 return false;
96 }
97
98 @Override
99 public void grantSystemPermission(String user, SystemPermission permission) throws AccumuloSecurityException {
100 try {
101 byte[] permBytes = zooCache.get(ZKUserPath + "/" + user + ZKUserSysPerms);
102 Set<SystemPermission> perms;
103 if (permBytes == null) {
104 perms = new TreeSet<SystemPermission>();
105 } else {
106 perms = ZKSecurityTool.convertSystemPermissions(permBytes);
107 }
108
109 if (perms.add(permission)) {
110 synchronized (zooCache) {
111 zooCache.clear();
112 ZooReaderWriter.getRetryingInstance().putPersistentData(ZKUserPath + "/" + user + ZKUserSysPerms, ZKSecurityTool.convertSystemPermissions(perms),
113 NodeExistsPolicy.OVERWRITE);
114 }
115 }
116 } catch (KeeperException e) {
117 log.error(e, e);
118 throw new AccumuloSecurityException(user, SecurityErrorCode.CONNECTION_ERROR, e);
119 } catch (InterruptedException e) {
120 log.error(e, e);
121 throw new RuntimeException(e);
122 }
123 }
124
125 @Override
126 public void grantTablePermission(String user, String table, TablePermission permission) throws AccumuloSecurityException {
127 Set<TablePermission> tablePerms;
128 byte[] serializedPerms = zooCache.get(ZKUserPath + "/" + user + ZKUserTablePerms + "/" + table);
129 if (serializedPerms != null)
130 tablePerms = ZKSecurityTool.convertTablePermissions(serializedPerms);
131 else
132 tablePerms = new TreeSet<TablePermission>();
133
134 try {
135 if (tablePerms.add(permission)) {
136 synchronized (zooCache) {
137 zooCache.clear(ZKUserPath + "/" + user + ZKUserTablePerms + "/" + table);
138 IZooReaderWriter zoo = ZooReaderWriter.getRetryingInstance();
139 zoo.putPersistentData(ZKUserPath + "/" + user + ZKUserTablePerms + "/" + table, ZKSecurityTool.convertTablePermissions(tablePerms),
140 NodeExistsPolicy.OVERWRITE);
141 }
142 }
143 } catch (KeeperException e) {
144 log.error(e, e);
145 throw new AccumuloSecurityException(user, SecurityErrorCode.CONNECTION_ERROR, e);
146 } catch (InterruptedException e) {
147 log.error(e, e);
148 throw new RuntimeException(e);
149 }
150 }
151
152 @Override
153 public void revokeSystemPermission(String user, SystemPermission permission) throws AccumuloSecurityException {
154 byte[] sysPermBytes = zooCache.get(ZKUserPath + "/" + user + ZKUserSysPerms);
155
156
157 if (sysPermBytes == null)
158 return;
159
160 Set<SystemPermission> sysPerms = ZKSecurityTool.convertSystemPermissions(sysPermBytes);
161
162 try {
163 if (sysPerms.remove(permission)) {
164 synchronized (zooCache) {
165 zooCache.clear();
166 ZooReaderWriter.getRetryingInstance().putPersistentData(ZKUserPath + "/" + user + ZKUserSysPerms, ZKSecurityTool.convertSystemPermissions(sysPerms),
167 NodeExistsPolicy.OVERWRITE);
168 }
169 }
170 } catch (KeeperException e) {
171 log.error(e, e);
172 throw new AccumuloSecurityException(user, SecurityErrorCode.CONNECTION_ERROR, e);
173 } catch (InterruptedException e) {
174 log.error(e, e);
175 throw new RuntimeException(e);
176 }
177 }
178
179 @Override
180 public void revokeTablePermission(String user, String table, TablePermission permission) throws AccumuloSecurityException {
181 byte[] serializedPerms = zooCache.get(ZKUserPath + "/" + user + ZKUserTablePerms + "/" + table);
182
183
184 if (serializedPerms == null)
185 return;
186
187 Set<TablePermission> tablePerms = ZKSecurityTool.convertTablePermissions(serializedPerms);
188 try {
189 if (tablePerms.remove(permission)) {
190 zooCache.clear();
191 IZooReaderWriter zoo = ZooReaderWriter.getRetryingInstance();
192 if (tablePerms.size() == 0)
193 zoo.recursiveDelete(ZKUserPath + "/" + user + ZKUserTablePerms + "/" + table, NodeMissingPolicy.SKIP);
194 else
195 zoo.putPersistentData(ZKUserPath + "/" + user + ZKUserTablePerms + "/" + table, ZKSecurityTool.convertTablePermissions(tablePerms),
196 NodeExistsPolicy.OVERWRITE);
197 }
198 } catch (KeeperException e) {
199 log.error(e, e);
200 throw new AccumuloSecurityException(user, SecurityErrorCode.CONNECTION_ERROR, e);
201 } catch (InterruptedException e) {
202 log.error(e, e);
203 throw new RuntimeException(e);
204 }
205 }
206
207 @Override
208 public void cleanTablePermissions(String table) throws AccumuloSecurityException {
209 try {
210 synchronized (zooCache) {
211 zooCache.clear();
212 IZooReaderWriter zoo = ZooReaderWriter.getRetryingInstance();
213 for (String user : zooCache.getChildren(ZKUserPath))
214 zoo.recursiveDelete(ZKUserPath + "/" + user + ZKUserTablePerms + "/" + table, NodeMissingPolicy.SKIP);
215 }
216 } catch (KeeperException e) {
217 log.error(e, e);
218 throw new AccumuloSecurityException("unknownUser", SecurityErrorCode.CONNECTION_ERROR, e);
219 } catch (InterruptedException e) {
220 log.error(e, e);
221 throw new RuntimeException(e);
222 }
223 }
224
225 @Override
226 public void initializeSecurity(Credential itw, String rootuser) throws AccumuloSecurityException {
227 IZooReaderWriter zoo = ZooReaderWriter.getRetryingInstance();
228
229
230 Set<SystemPermission> rootPerms = new TreeSet<SystemPermission>();
231 for (SystemPermission p : SystemPermission.values())
232 rootPerms.add(p);
233 Map<String,Set<TablePermission>> tablePerms = new HashMap<String,Set<TablePermission>>();
234
235 tablePerms.put(Constants.METADATA_TABLE_ID, Collections.singleton(TablePermission.ALTER_TABLE));
236
237 try {
238
239 if (!zoo.exists(ZKUserPath))
240 zoo.putPersistentData(ZKUserPath, rootuser.getBytes(), NodeExistsPolicy.FAIL);
241
242 initUser(rootuser);
243 zoo.putPersistentData(ZKUserPath + "/" + rootuser + ZKUserSysPerms, ZKSecurityTool.convertSystemPermissions(rootPerms), NodeExistsPolicy.FAIL);
244 for (Entry<String,Set<TablePermission>> entry : tablePerms.entrySet())
245 createTablePerm(rootuser, entry.getKey(), entry.getValue());
246 } catch (KeeperException e) {
247 log.error(e, e);
248 throw new RuntimeException(e);
249 } catch (InterruptedException e) {
250 log.error(e, e);
251 throw new RuntimeException(e);
252 }
253 }
254
255 /**
256 * @param user
257 * @throws AccumuloSecurityException
258 */
259 public void initUser(String user) throws AccumuloSecurityException {
260 IZooReaderWriter zoo = ZooReaderWriter.getRetryingInstance();
261 try {
262 zoo.putPersistentData(ZKUserPath + "/" + user, new byte[0], NodeExistsPolicy.SKIP);
263 zoo.putPersistentData(ZKUserPath + "/" + user + ZKUserTablePerms, new byte[0], NodeExistsPolicy.SKIP);
264 } catch (KeeperException e) {
265 log.error(e, e);
266 throw new AccumuloSecurityException(user, SecurityErrorCode.CONNECTION_ERROR, e);
267 } catch (InterruptedException e) {
268 log.error(e, e);
269 throw new RuntimeException(e);
270 }
271 }
272
273 /**
274 * Sets up a new table configuration for the provided user/table. No checking for existence is done here, it should be done before calling.
275 */
276 private void createTablePerm(String user, String table, Set<TablePermission> perms) throws KeeperException, InterruptedException {
277 synchronized (zooCache) {
278 zooCache.clear();
279 ZooReaderWriter.getRetryingInstance().putPersistentData(ZKUserPath + "/" + user + ZKUserTablePerms + "/" + table,
280 ZKSecurityTool.convertTablePermissions(perms), NodeExistsPolicy.FAIL);
281 }
282 }
283
284 @Override
285 public void cleanUser(String user) throws AccumuloSecurityException {
286 try {
287 synchronized (zooCache) {
288 IZooReaderWriter zoo = ZooReaderWriter.getRetryingInstance();
289 zoo.recursiveDelete(ZKUserPath + "/" + user + ZKUserSysPerms, NodeMissingPolicy.SKIP);
290 zoo.recursiveDelete(ZKUserPath + "/" + user + ZKUserTablePerms, NodeMissingPolicy.SKIP);
291 zooCache.clear(ZKUserPath + "/" + user);
292 }
293 } catch (InterruptedException e) {
294 log.error(e, e);
295 throw new RuntimeException(e);
296 } catch (KeeperException e) {
297 log.error(e, e);
298 if (e.code().equals(KeeperException.Code.NONODE))
299 throw new AccumuloSecurityException(user, SecurityErrorCode.USER_DOESNT_EXIST, e);
300 throw new AccumuloSecurityException(user, SecurityErrorCode.CONNECTION_ERROR, e);
301
302 }
303 }
304
305 @Override
306 public boolean hasSystemPermission(String user, SystemPermission permission) throws AccumuloSecurityException {
307 byte[] perms;
308 try {
309 perms = ZooReaderWriter.getRetryingInstance().getData(ZKUserPath + "/" + user + ZKUserSysPerms, null);
310 } catch (KeeperException e) {
311 if (e.code() == Code.NONODE) {
312 return false;
313 }
314 log.warn("Unhandled KeeperException, failing closed for table permission check", e);
315 return false;
316 } catch (InterruptedException e) {
317 log.warn("Unhandled InterruptedException, failing closed for table permission check", e);
318 return false;
319 }
320
321 if (perms == null)
322 return false;
323 return ZKSecurityTool.convertSystemPermissions(perms).contains(permission);
324 }
325
326 @Override
327 public boolean hasCachedSystemPermission(String user, SystemPermission permission) throws AccumuloSecurityException {
328 byte[] perms = zooCache.get(ZKUserPath + "/" + user + ZKUserSysPerms);
329 if (perms == null)
330 return false;
331 return ZKSecurityTool.convertSystemPermissions(perms).contains(permission);
332 }
333
334 @Override
335 public boolean validSecurityHandlers(Authenticator authent, Authorizor author) {
336 return true;
337 }
338
339 @Override
340 public void initTable(String table) throws AccumuloSecurityException {
341
342 }
343 }