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 }
业务需求变更永无休止,技术前进就永无止境!