文档章节

Zookeeper ACL

trayvon
 trayvon
发布于 2017/06/01 22:02
字数 1870
阅读 59
收藏 0
点赞 0
评论 0

简介

Zookeeper安装与配置可以参考Zookeeper初遇

zookeeper本身提供了ACL机制,表示为scheme:id:permissions 第一个字段表示采用哪一种机制,第二个id表示用户,permissions表示相关权限 zookeeper提供了如下几种机制(scheme) 1. world: 它下面只有一个id, 叫anyone, world:anyone代表任何人,zookeeper中对所有人有权限的结点就是属于world:anyone的 2. auth: 它不需要id, 只要是通过authentication的user都有权限(zookeeper支持通过kerberos来进行authencation, 也支持username/password形式的authentication) 3. digest: 它对应的id为username:BASE64(SHA1(password)),它需要先通过username:password形式的authentication 4. ip: 它对应的id为客户机的IP地址,设置的时候可以设置一个ip段,比如ip:192.168.1.0/16, 表示匹配前16个bit的IP段 5. x509

Zookeeper根目录/的权限是任何用户都有create,delete,read,write,admin(cdrwa) admin权限是设置ACL的权限。

zk 根目录ACL

如上图所示是zookeeper根目录/的ACL

注意:后面的zookeeper可能代指2个不同的东西,一个是zookeeper本身,另一个是org.apach.zookeeper包。

注意:znode是没有继承关系的,也就是说如果没有父目录如果有子目录权限可以直接访问子目录

WORLD

先来一个小例子:

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.apache.zookeeper.ZooDefs.Perms;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.data.ACL;
import org.apache.zookeeper.data.Id;
import org.junit.Test;

public class ZookeeperWorldACLTest {
    

    private static final String WORLD = "world";

    @Test
    public void testWorldSchema(){
        List<ACL> acls = getWorldACL();
        ZooKeeper zookeeper = null;
        try {
            zookeeper = new ZooKeeper("localhost:2181",3000,null);
        } catch (IOException e) {
            e.printStackTrace();
        }
        create(zookeeper,acls);
        getData(zookeeper,acls);
        
    }
    
    private void create(ZooKeeper zookeeper,List<ACL> acls){
        try {
            String actualPath = zookeeper.create("/world", "world scheme".getBytes(), acls, CreateMode.EPHEMERAL);
            System.out.println(actualPath);
            actualPath = zookeeper.create("/world/xxx", "violate".getBytes(), acls, CreateMode.PERSISTENT);
            System.out.println(actualPath);
        } catch (KeeperException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    
    private void getData(ZooKeeper zookeeper,List<ACL> acls){
        try {
            byte[] data = zookeeper.getData("/world", false, null);
            System.out.println(new String(data));
        } catch (KeeperException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    
    private List<ACL> getWorldACL(){
        Id id = new Id(WORLD,"anyone");//id = Ids.ANYONE_ID_UNSAFE;
        ACL acl = new ACL(Perms.READ,id);
        ArrayList<ACL> acls = new ArrayList<ACL>();
        acls.add(acl);
        return acls;
    }
    

}

下面是上面测试的输出:

/world
org.apache.zookeeper.KeeperException$NoAuthException: KeeperErrorCode = NoAuth for /world/xxx
    at org.apache.zookeeper.KeeperException.create(KeeperException.java:104)
    at org.apache.zookeeper.KeeperException.create(KeeperException.java:42)
    at org.apache.zookeeper.ZooKeeper.create(ZooKeeper.java:637)
    at cn.freemethod.zk.ZookeeperWorldACLTest.create(ZookeeperWorldACLTest.java:38)
    at cn.freemethod.zk.ZookeeperWorldACLTest.testWorldSchema(ZookeeperWorldACLTest.java:29)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:45)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:42)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:263)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:68)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:47)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:300)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
world scheme

首先看在getWorldACL方法中的

Id id = new Id(WORLD,"anyone");//id = Ids.ANYONE_ID_UNSAFE;
ACL acl = new ACL(Perms.READ,id);

zookeeper包把zookeeper中的scheme:id:permissions的scheme:id封装成为了org.apache.zookeeper.data.Id,权限封装成为了Perms。每一个scheme下的id都不一样,甚至可能没有id。 上面的就使用的是world scheme(注意不是schema)获取的ACL,表示任何用户都有读取的权限。那么问题来了,为什么第一次创建可以成功呢?

那是因为第一次创建"/world"的路径是在根目录/下,而根目录/是所有用户都有权限的。所以创建成功了。第二次创建以为ACL只有"/world"的read权限,所以抛出了异常。

注意:创建目录的时候,父目录必须存在

DIGEST

老规矩,还是先来一个小例子:

import java.io.IOException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;

import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.ZooDefs;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.data.ACL;
import org.apache.zookeeper.data.Id;
import org.apache.zookeeper.server.auth.DigestAuthenticationProvider;
import org.junit.Before;
import org.junit.Test;


public class ZookeeperDigestACLTest {
    
    private static final String DIGEST = "digest";

    private ZooKeeper zookeeper;

    @Before
    public void setUp() {
        try {
            zookeeper = new ZooKeeper("127.0.0.1:2181", 3000, null);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
    @Test
    public void testDigestACL(){
        try {
            String actualPath = zookeeper.create("/digest", "digest".getBytes(), getDigestACL(), CreateMode.EPHEMERAL);
            System.out.println(actualPath);
        } catch (KeeperException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    
    @Test
    public void testGetDigestSchemaData(){
        ZooKeeper zookeeper = getDigestZK();
        try {
            byte[] data = zookeeper.getData("/digest", false, null);
            System.out.println(new String(data));
        } catch (KeeperException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    
    List<ACL> getDigestACL(){
        List<ACL> acls = new ArrayList<ACL>();
        Id id = null;
        try {
            //设置ACL的时候使用密文
            String sid = DigestAuthenticationProvider.generateDigest("admin:admin");
            System.out.println(sid);
            id = new Id(DIGEST,sid);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        ACL acl = new ACL(ZooDefs.Perms.ALL, id);
        acls.add(acl);
        return acls;
    }
    
    ZooKeeper getDigestZK(){
        ZooKeeper zk = null;
        try {
            zk = new ZooKeeper("localhost:2181",2000, null);
        } catch (IOException e) {
            e.printStackTrace();
        }
        //连接auth的时候使用明文
        zk.addAuthInfo(DIGEST, "admin:admin".getBytes());
        return zk;
    }
}

digest其实就是一个加密认证,主要需要注意的是设置认证的时候是使用的密文,可以通过zookeeper包的DigestAuthenticationProvider.generateDigest来获取,认证的时候是使用的明文。digest它对应的id为username:BASE64(SHA1(password)) 我们可以看一下DigestAuthenticationProvider.generateDigest的源码就知道了:

static public String generateDigest(String idPassword)
            throws NoSuchAlgorithmException {
        String parts[] = idPassword.split(":", 2);
        byte digest[] = MessageDigest.getInstance("SHA1").digest(
                idPassword.getBytes());
        return parts[0] + ":" + base64Encode(digest);
    }

知道是使用base64对sha1加密后的数据进行编码,我们也可以很容易的自己实现,下面就是使用Apache的codec实现和DigestAuthenticationProvider.generateDigest的对比:

@Test 
    public void printPass(){
        try {
            String pass = DigestAuthenticationProvider.generateDigest("admin:admin");
            System.out.println(pass);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        byte[] sha1 = DigestUtils.sha1("admin:admin");
        String result = Base64.encodeBase64String(sha1);
        System.out.println("admin:"+result);
    }

auth

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.ZooDefs;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.data.ACL;
import org.apache.zookeeper.data.Id;
import org.junit.Before;
import org.junit.Test;

public class ZookeeperAuthACLTest {
    
    private static final String DIGEST = "digest";
    
    private static final String AUTH = "auth";

    ZooKeeper zookeeper;

    @Before
    public void setUp() {
        try {
            zookeeper = new ZooKeeper("127.0.0.1:2181", 3000, null);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
    @Test
    public void testAuthACL(){
//      ZooKeeper zookeeper = getDigestZK();
        ZooKeeper zookeeper = getAnotherDigestZK();
        try {
            String actualPath = zookeeper.create("/auth", "auth".getBytes(), getAuthACL(), CreateMode.EPHEMERAL);
            System.out.println(actualPath);
        } catch (KeeperException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    
    @Test
    public void testAuthGet(){
        ZooKeeper zk = getAnotherDigestZK();
//      ZooKeeper zk = getDigestZK();
        try {
            byte[] data = zk.getData("/auth", false, null);
            System.out.println(new String(data));
        } catch (KeeperException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    
    List<ACL> getAuthACL(){
        List<ACL> acls = new ArrayList<ACL>();
        Id id = new Id(AUTH,"");
        ACL acl = new ACL(ZooDefs.Perms.ALL, id);
        acls.add(acl);
        return acls;
    }
    
    ZooKeeper getDigestZK(){
        ZooKeeper zk = null;
        try {
            zk = new ZooKeeper("localhost:2181",2000, null);
        } catch (IOException e) {
            e.printStackTrace();
        }
        //连接auth的时候使用明文
        zk.addAuthInfo(DIGEST, "admin:admin".getBytes());
        return zk;
    }
    
    ZooKeeper getAnotherDigestZK(){
        ZooKeeper zk = null;
        try {
            zk = new ZooKeeper("localhost:2181",2000, null);
        } catch (IOException e) {
            e.printStackTrace();
        }
        //连接auth的时候使用明文
        zk.addAuthInfo(DIGEST, "xxx:xxx".getBytes());
        return zk;
    }
}

auth和digest差不多auth也需要使用digest认证,不同的是创建znode节点和访问znode节点的必须是相同的认证。所以使用auth scheme的时候创建节点的时候就必须把认证加上,否则就会出错。

IP

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.ZooDefs;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.data.ACL;
import org.apache.zookeeper.data.Id;
import org.junit.Before;
import org.junit.Test;

public class ZookeeperIPACLTest {
    
    private static final String IP = "ip";

    ZooKeeper zookeeper;

    @Before
    public void setUp() {
        try {
            zookeeper = new ZooKeeper("127.0.0.1:2181", 3000, null);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
    @Test
    public void testIPACL(){
        try {
            String actualPath = zookeeper.create("/ip", "ip".getBytes(), getIPACL(), CreateMode.EPHEMERAL);
            System.out.println(actualPath);
        } catch (KeeperException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    
    @Test
    public void testIPGet(){
        try {
            byte[] data = zookeeper.getData("/ip", false, null);
            System.out.println(new String(data));
        } catch (KeeperException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    
    List<ACL> getIPACL(){
        List<ACL> acls = new ArrayList<ACL>();
//      Id id = new Id(IP,"127.0.0.1");
        Id id = new Id(IP,"192.168.1.255");
//      Id id = new Id(IP,"192.168.1.0/24");
        ACL acl = new ACL(ZooDefs.Perms.ALL, id);
        acls.add(acl);
        return acls;
    }
}

ip scheme是通过客户端ip来过滤权限的。

附录

log4j配置

因为org.apache.zookeeper使用的是log4j,所以可以配置一个日志输出文件,可以获取一些Zookeeper的信息。比如当使用ZooKeeper不设置Watcher的时候就会抛出异常,但是这个异常是在ZooKeeper中处理的,所以如果不配做log4j是获取不到这些错误信息的。

#log4j.rootLogger  =   [ level ]   ,  appenderName1 ,  appenderName2 
#输出到控制台
#log4j.rootLogger=INFO,CONSOLE
#输出到文件
log4j.rootLogger=INFO,F
  
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender  
log4j.appender.CONSOLE.Threshold=INFO  
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout  
log4j.appender.CONSOLE.layout.ConversionPattern=%d{ISO8601} - %m%n  
  
  
log4j.appender.F=org.apache.log4j.DailyRollingFileAppender  
log4j.appender.F.Threshold=INFO
#可以修改配置日志输出目录
log4j.appender.F.File=F:/log/zookeeper.log  
log4j.appender.F.DatePattern='.'yyyy-MM-dd  
  
log4j.appender.F.layout=org.apache.log4j.PatternLayout  
log4j.appender.F.layout.ConversionPattern=[%d{yyyy-MM-dd HH:mm:ss}] - %m%n  
  
log4j.logger.org.displaytag=WARN  
log4j.logger.org.apache.zookeeper=ERROR  
log4j.logger.org.springframework=WARN  
log4j.logger.org.I0Itec=WARN

pom

上面zookeeper包的版本使用的是3.3.3,commons-codec是1.10

<dependencies>
        <dependency>
            <groupId>org.apache.zookeeper</groupId>
            <artifactId>zookeeper</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>junit</groupId>
                    <artifactId>junit</artifactId>
                </exclusion>
                <exclusion>
                    <artifactId>slf4j-log4j12</artifactId>
                    <groupId>org.slf4j</groupId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>commons-codec</groupId>
            <artifactId>commons-codec</artifactId>
        </dependency>
    </dependencies>

参考

ZooKeeper Zookeeper初遇

© 著作权归作者所有

共有 人打赏支持
trayvon
粉丝 14
博文 120
码字总数 178809
作品 1
程序员
ZooKeeper学习第六期---ZooKeeper机制架构

一、ZooKeeper权限管理机制  1.1 权限管理ACL(Access Control List)  ZooKeeper 的权限管理亦即ACL 控制功能,使用ACL来对Znode进行访问控制。ACL的实现和Unix文件访问许可非常相似:它使用...

卯金刀GG
2017/10/25
0
0
ZooKeeper开发手册中文翻译

本文Github地址:https://github.com/sundiontheway/zookeeper-guide-cn 本文假设你已经具有一定分布式计算的基础知识。你将在第一部分看到以下内容: ZooKeeper数据模型 ZooKeeper Sessions...

__Steve__
2014/11/19
0
16
ZooKeeper学习笔记三 ZooKeeper与Paxos

本文学习内容来自: 《从Paxos到ZooKeeper分布式一致性原理与实践》 电子工业出版社 Apache ZooKeeper是由Apache Hadoop的子项目发展而来,于2010年11月正式成为了Apache的顶级项目。ZooKeep...

xundh
04/27
0
0
【分布式协调zookeeper】基础篇

一、zookeeper介绍 它是一个为分布式应用提供一致性服务的软件,提供的功能包括:配置维护、名字服务、分布式同步、组服务等 zookeeper做了什么? 1.命名服务 2.配置管理 3.集群管理 4.分布式...

次渠龙哥
06/26
0
0
zookeeper conceptual

Zookeeper 数据模型 Zookeeper 拥有着类似文件系统的命名空间,唯一的区别是在命名空间下的每一个节点都有数据和他关联 Znodes zookeeper 的节点 znode, znode 维护着一些列状态信息 包含数据...

triankg
2014/01/13
0
0
zookeeper 入门讲解实例

转 http://www.blogjava.net/BucketLi/archive/2010/12/21/341268.html zookeeper使用和原理探究(一) zookeeper介绍 zookeeper是一个为分布式应用提供一致性服务的软件,它是开源的Hadoop项...

方宏春
2017/10/29
0
0
zookeeper java客户端使用

ZooKeeper是一个优秀的分布式协同工具,很多分布式项目都基于它进行架构设计,不过要想要对其有一个深入的理解(如果你想阅读其源代码),对其客户端API的熟悉必不可少。下面就简要记录一下Z...

我就是我110
2015/08/13
0
0
转载:zookeeper 介绍

zookeeper介绍 zookeeper是一个为分布式应用提供一致性服务的软件,它是开源的Hadoop项目中的一个子项目,并且根据google发表的<The Chubby lock service for loosely-coupled distributed ...

kernal
2014/12/10
0
0
ZooKeeper架构设计及其应用要点

ZooKeeper是一个开源的分布式服务框架,它是Apache Hadoop项目的一个子项目,主要用来解决分布式应用场景中存在的一些问题,如:统一命名服务、状态同步服务、集群管理、分布式应用配置管理等...

xionghuiCoder
2015/07/13
0
0
【Zookeeper系列三】ZooKeeper Java API使用

Zookeeper系列 【Zookeeper系列一】Zookeeper应用介绍与安装部署 【Zookeeper系列二】ZooKeeper典型应用场景实践 【Zookeeper系列三】ZooKeeper Java API使用 【Zookeeper系列四】ZooKeeper...

陶邦仁
2015/11/18
0
2

没有更多内容

加载失败,请刷新页面

加载更多

下一页

Git 2.18版本发布:支持Git协议v2,提升性能

Git 2.18版本发布:支持Git协议v2,提升性能Git 2.18版本发布:支持Git协议v2,提升性能 新版本协议的主要驱动力是使 Git 服务端能够对各种 ref(分支与 tag)进行过滤操作。 这就意味着,G...

linux-tao
21分钟前
0
0
python浏览器自动化测试库【2018/7/22-更新】

64位py2.7版本 更新 document_GetResources 枚举页面资源 document_GetresourceText 获取指定url的内容 包括页面图片 下载地址下载地址 密码:upr47x...

开飞色
37分钟前
27
0
关于DCL双重锁失效及解决方案

关于DCL双重锁失效及解决方案 Double Check Lock (DCL)实现单例 DCL 方式实现单例的优点是既能够在需要时才初始化单例,又能够保证线程安全,且单例对象初始化后调用getInstance方法不进行...

DannyCoder
43分钟前
0
0
PowerDesigner 16.5 安装配置

PowerDesigner16.5破解版是一款业内领先且开发人员常用的数据库建模工具,PowerDesigner可以从物理和概念两个层面设计数据库,方便用户制作处清晰直观的数据流程图和结构模型,欢迎有需要的朋...

Gibbons
今天
0
0
mac Homebrew 指令积累

1通用命令 brew install [包名] //安装包 brew list //列举安装的包 brew info [包名] // 显示安装包的详细信息 mysql 相关 #启动mysql 服务 brew service start mysql my...

Kenny100120
今天
0
0
前端Tips: 创建, 发布自己的 Vue UI 组件库

创建, 发布自己的 Vue UI 组件库 前言 在使用 Vue 进行日常开发时, 我们经常会用到一些开源的 UI 库, 如: Element-UI, Vuetify 等. 只需一行命令, 即可方便的将这些库引入我们当前的项目: n...

ssthouse_hust
今天
1
0
大数据教程(2.13):keepalived+nginx(多主多活)高可用集群搭建教程【自动化脚本】

上一章节博主为大家介绍了目前大型互联网项目的keepalived+nginx(主备)高可用系统架构体系,相信大家应该看了博主的文章对keepalived/nginx技术已经有一定的了解,在本节博主将为大家分享k...

em_aaron
今天
5
0
Git 2.18版本发布:支持Git协议v2,提升性能

在最新的官方 Git 客户端正式版2.18中添加了对 Git wire 协议 v2 的支持,并引入了一些性能与 UI 改进的新特性。在 Git 的核心团队成员 Brandon Williams 公开宣布这一消息前几周,Git 协议 ...

六库科技
今天
0
0
Java8新特性之接口

在JDK8以前,我们定义接口类中,方法都是抽象的,并且不能存在静态方法。所有的方法命名规则基本上都是 public [返回类型] [方法名](参数params) throws [异常类型] {}。 JDK8为接口的定义带...

developlee的潇洒人生
今天
0
0
aop + annotation 实现统一日志记录

aop + annotation 实现统一日志记录 在开发中,我们可能需要记录异常日志。由于异常比较分散,每个 service 方法都可能发生异常,如果我们都去做处理,会出现很多重复编码,也不好维护。这种...

长安一梦
今天
2
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部