ACL(Access Control List),Zookeeper作为一个分布式协调框架,其内部存储的都是一些关乎分布式系统运行时状态的元数据,尤其是设计到一些分布式锁,Master选举和协调等应用场景。我们需要有效地保障Zookeeper中的数据安全,Zookeeper提供一套完善的ACL权限控制机制来保障数据的安全。
ZK提供了三种模式。权限模式,授权对象,权限。
权限模式:Scheme,开发人员最多使用的如下四种权限模式:
IP:
ip模式通过ip地址粒度来进行权限控制,例如配置了:ip:192.168.1.107即表示权限控制都是针对这个ip地址的,同时也支持按网段分配,比如:192.168.1.*
Digest:
digest是最常用的权限控制模式,也更符合我们对权限控制的认识,其类似于"username:password"形式的权限标识进行权限配置。ZK会对形成的权限标识先后进行两次编码处理,分别是SHA-1加密算法,BASE64编码。
World:
World是一直最开发的权限控制模式。这种模式可以看做特殊的Digest,它仅仅是标识而已。
Super:
超级用户模式,在超级用户模式下可以对ZK任意进行操作。
权限对象:指的是权限赋予的用户或者一个指定的实体,例如IP地址火机器等。在不同的模式下,授权对象是不同的。这种模式和授权对象一一对应。
权限:权限就是指哪些通过权限检测后可以被允许执行的操作,在ZK中,对数据的操作权限分别如下五大类:
CREATE、DELETE、READ、WRITE、ADMIN
我们通过一个示例,详细学习Auth的概念和其目的。Auth示例:
【ZookeeperAuth】
1 package bhz.zookeeper.auth;
2
3 import java.util.ArrayList;
4 import java.util.List;
5 import java.util.concurrent.CountDownLatch;
6 import java.util.concurrent.atomic.AtomicInteger;
7
8 import org.apache.zookeeper.CreateMode;
9 import org.apache.zookeeper.WatchedEvent;
10 import org.apache.zookeeper.Watcher;
11 import org.apache.zookeeper.Watcher.Event.EventType;
12 import org.apache.zookeeper.Watcher.Event.KeeperState;
13 import org.apache.zookeeper.ZooDefs.Ids;
14 import org.apache.zookeeper.ZooKeeper;
15 import org.apache.zookeeper.data.ACL;
16 import org.apache.zookeeper.data.Stat;
17 /**
18 * Zookeeper 节点授权
19 * @author(alienware)
20 * @since 2015-6-14
21 */
22 public class ZookeeperAuth implements Watcher {
23
24 /** 连接地址 */
25 final static String CONNECT_ADDR = "192.168.80.88:2181";
26 /** 测试路径 */
27 final static String PATH = "/testAuth";
28 final static String PATH_DEL = "/testAuth/delNode";
29 /** 认证类型 */
30 final static String authentication_type = "digest";
31 /** 认证正确方法 */
32 final static String correctAuthentication = "123456";
33 /** 认证错误方法 */
34 final static String badAuthentication = "654321";
35
36 static ZooKeeper zk = null;
37 /** 计时器 */
38 AtomicInteger seq = new AtomicInteger();
39 /** 标识 */
40 private static final String LOG_PREFIX_OF_MAIN = "【Main】";
41
42 private CountDownLatch connectedSemaphore = new CountDownLatch(1);
43
44 @Override
45 public void process(WatchedEvent event) {
46 try {
47 Thread.sleep(200);
48 } catch (InterruptedException e) {
49 e.printStackTrace();
50 }
51 if (event==null) {
52 return;
53 }
54 // 连接状态
55 KeeperState keeperState = event.getState();
56 // 事件类型
57 EventType eventType = event.getType();
58 // 受影响的path
59 String path = event.getPath();
60
61 String logPrefix = "【Watcher-" + this.seq.incrementAndGet() + "】";
62
63 System.out.println(logPrefix + "收到Watcher通知");
64 System.out.println(logPrefix + "连接状态:\t" + keeperState.toString());
65 System.out.println(logPrefix + "事件类型:\t" + eventType.toString());
66 if (KeeperState.SyncConnected == keeperState) {
67 // 成功连接上ZK服务器
68 if (EventType.None == eventType) {
69 System.out.println(logPrefix + "成功连接上ZK服务器");
70 connectedSemaphore.countDown();
71 }
72 } else if (KeeperState.Disconnected == keeperState) {
73 System.out.println(logPrefix + "与ZK服务器断开连接");
74 } else if (KeeperState.AuthFailed == keeperState) {
75 System.out.println(logPrefix + "权限检查失败");
76 } else if (KeeperState.Expired == keeperState) {
77 System.out.println(logPrefix + "会话失效");
78 }
79 System.out.println("--------------------------------------------");
80 }
81 /**
82 * 创建ZK连接
83 *
84 * @param connectString
85 * ZK服务器地址列表
86 * @param sessionTimeout
87 * Session超时时间
88 */
89 public void createConnection(String connectString, int sessionTimeout) {
90 this.releaseConnection();
91 try {
92 zk = new ZooKeeper(connectString, sessionTimeout, this);
93 //添加节点授权
94 zk.addAuthInfo(authentication_type,correctAuthentication.getBytes());
95 System.out.println(LOG_PREFIX_OF_MAIN + "开始连接ZK服务器");
96 //倒数等待
97 connectedSemaphore.await();
98 } catch (Exception e) {
99 e.printStackTrace();
100 }
101 }
102
103 /**
104 * 关闭ZK连接
105 */
106 public void releaseConnection() {
107 if (this.zk!=null) {
108 try {
109 this.zk.close();
110 } catch (InterruptedException e) {
111 }
112 }
113 }
114
115 /**
116 *
117 * <B>方法名称:</B>测试函数<BR>
118 * <B>概要说明:</B>测试认证<BR>
119 * @param args
120 * @throws Exception
121 */
122 public static void main(String[] args) throws Exception {
123
124 ZookeeperAuth testAuth = new ZookeeperAuth();
125 testAuth.createConnection(CONNECT_ADDR,2000);
126 List<ACL> acls = new ArrayList<ACL>(1);
127 for (ACL ids_acl : Ids.CREATOR_ALL_ACL) {
128 acls.add(ids_acl);
129 }
130
131 try {
132 zk.create(PATH, "init content".getBytes(), acls, CreateMode.PERSISTENT);
133 System.out.println("使用授权key:" + correctAuthentication + "创建节点:"+ PATH + ", 初始内容是: init content");
134 } catch (Exception e) {
135 e.printStackTrace();
136 }
137 try {
138 zk.create(PATH_DEL, "will be deleted! ".getBytes(), acls, CreateMode.PERSISTENT);
139 System.out.println("使用授权key:" + correctAuthentication + "创建节点:"+ PATH_DEL + ", 初始内容是: init content");
140 } catch (Exception e) {
141 e.printStackTrace();
142 }
143
144 // 获取数据
145 getDataByNoAuthentication();
146 getDataByBadAuthentication();
147 getDataByCorrectAuthentication();
148
149 // 更新数据
150 updateDataByNoAuthentication();
151 updateDataByBadAuthentication();
152 updateDataByCorrectAuthentication();
153
154 // 删除数据
155 deleteNodeByBadAuthentication();
156 deleteNodeByNoAuthentication();
157 deleteNodeByCorrectAuthentication();
158 //
159 Thread.sleep(1000);
160
161 deleteParent();
162 //释放连接
163 testAuth.releaseConnection();
164 }
165 /** 获取数据:采用错误的密码 */
166 static void getDataByBadAuthentication() {
167 String prefix = "[使用错误的授权信息]";
168 try {
169 ZooKeeper badzk = new ZooKeeper(CONNECT_ADDR, 2000, null);
170 //授权
171 badzk.addAuthInfo(authentication_type,badAuthentication.getBytes());
172 Thread.sleep(2000);
173 System.out.println(prefix + "获取数据:" + PATH);
174 System.out.println(prefix + "成功获取数据:" + badzk.getData(PATH, false, null));
175 } catch (Exception e) {
176 System.err.println(prefix + "获取数据失败,原因:" + e.getMessage());
177 }
178 }
179
180 /** 获取数据:不采用密码 */
181 static void getDataByNoAuthentication() {
182 String prefix = "[不使用任何授权信息]";
183 try {
184 System.out.println(prefix + "获取数据:" + PATH);
185 ZooKeeper nozk = new ZooKeeper(CONNECT_ADDR, 2000, null);
186 Thread.sleep(2000);
187 System.out.println(prefix + "成功获取数据:" + nozk.getData(PATH, false, null));
188 } catch (Exception e) {
189 System.err.println(prefix + "获取数据失败,原因:" + e.getMessage());
190 }
191 }
192
193 /** 采用正确的密码 */
194 static void getDataByCorrectAuthentication() {
195 String prefix = "[使用正确的授权信息]";
196 try {
197 System.out.println(prefix + "获取数据:" + PATH);
198
199 System.out.println(prefix + "成功获取数据:" + zk.getData(PATH, false, null));
200 } catch (Exception e) {
201 System.out.println(prefix + "获取数据失败,原因:" + e.getMessage());
202 }
203 }
204
205 /**
206 * 更新数据:不采用密码
207 */
208 static void updateDataByNoAuthentication() {
209
210 String prefix = "[不使用任何授权信息]";
211
212 System.out.println(prefix + "更新数据: " + PATH);
213 try {
214 ZooKeeper nozk = new ZooKeeper(CONNECT_ADDR, 2000, null);
215 Thread.sleep(2000);
216 Stat stat = nozk.exists(PATH, false);
217 if (stat!=null) {
218 nozk.setData(PATH, prefix.getBytes(), -1);
219 System.out.println(prefix + "更新成功");
220 }
221 } catch (Exception e) {
222 System.err.println(prefix + "更新失败,原因是:" + e.getMessage());
223 }
224 }
225
226 /**
227 * 更新数据:采用错误的密码
228 */
229 static void updateDataByBadAuthentication() {
230
231 String prefix = "[使用错误的授权信息]";
232
233 System.out.println(prefix + "更新数据:" + PATH);
234 try {
235 ZooKeeper badzk = new ZooKeeper(CONNECT_ADDR, 2000, null);
236 //授权
237 badzk.addAuthInfo(authentication_type,badAuthentication.getBytes());
238 Thread.sleep(2000);
239 Stat stat = badzk.exists(PATH, false);
240 if (stat!=null) {
241 badzk.setData(PATH, prefix.getBytes(), -1);
242 System.out.println(prefix + "更新成功");
243 }
244 } catch (Exception e) {
245 System.err.println(prefix + "更新失败,原因是:" + e.getMessage());
246 }
247 }
248
249 /**
250 * 更新数据:采用正确的密码
251 */
252 static void updateDataByCorrectAuthentication() {
253
254 String prefix = "[使用正确的授权信息]";
255
256 System.out.println(prefix + "更新数据:" + PATH);
257 try {
258 Stat stat = zk.exists(PATH, false);
259 if (stat!=null) {
260 zk.setData(PATH, prefix.getBytes(), -1);
261 System.out.println(prefix + "更新成功");
262 }
263 } catch (Exception e) {
264 System.err.println(prefix + "更新失败,原因是:" + e.getMessage());
265 }
266 }
267
268 /**
269 * 不使用密码 删除节点
270 */
271 static void deleteNodeByNoAuthentication() throws Exception {
272
273 String prefix = "[不使用任何授权信息]";
274
275 try {
276 System.out.println(prefix + "删除节点:" + PATH_DEL);
277 ZooKeeper nozk = new ZooKeeper(CONNECT_ADDR, 2000, null);
278 Thread.sleep(2000);
279 Stat stat = nozk.exists(PATH_DEL, false);
280 if (stat!=null) {
281 nozk.delete(PATH_DEL,-1);
282 System.out.println(prefix + "删除成功");
283 }
284 } catch (Exception e) {
285 System.err.println(prefix + "删除失败,原因是:" + e.getMessage());
286 }
287 }
288
289 /**
290 * 采用错误的密码删除节点
291 */
292 static void deleteNodeByBadAuthentication() throws Exception {
293
294 String prefix = "[使用错误的授权信息]";
295
296 try {
297 System.out.println(prefix + "删除节点:" + PATH_DEL);
298 ZooKeeper badzk = new ZooKeeper(CONNECT_ADDR, 2000, null);
299 //授权
300 badzk.addAuthInfo(authentication_type,badAuthentication.getBytes());
301 Thread.sleep(2000);
302 Stat stat = badzk.exists(PATH_DEL, false);
303 if (stat!=null) {
304 badzk.delete(PATH_DEL, -1);
305 System.out.println(prefix + "删除成功");
306 }
307 } catch (Exception e) {
308 System.err.println(prefix + "删除失败,原因是:" + e.getMessage());
309 }
310 }
311
312 /**
313 * 使用正确的密码删除节点
314 */
315 static void deleteNodeByCorrectAuthentication() throws Exception {
316
317 String prefix = "[使用正确的授权信息]";
318
319 try {
320 System.out.println(prefix + "删除节点:" + PATH_DEL);
321 Stat stat = zk.exists(PATH_DEL, false);
322 if (stat!=null) {
323 zk.delete(PATH_DEL, -1);
324 System.out.println(prefix + "删除成功");
325 }
326 } catch (Exception e) {
327 System.out.println(prefix + "删除失败,原因是:" + e.getMessage());
328 }
329 }
330
331 /**
332 * 使用正确的密码删除节点
333 */
334 static void deleteParent() throws Exception {
335 try {
336 Stat stat = zk.exists(PATH_DEL, false);
337 if (stat == null) {
338 zk.delete(PATH, -1);
339 }
340 } catch (Exception e) {
341 e.printStackTrace();
342 }
343 }
344
345 }
业务需求变更永无休止,技术前进就永无止境!