zookeeper(五)zookeeper的ACL(AUTH)

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 }

 

posted @ 2017-10-31 22:40  喻聪  阅读(2469)  评论(0编辑  收藏  举报