ZooKeeper运行在带有数量众多并且各不相同的身份认证schemes(视图)的各种不同环境中,所以它拥有完整的可插入式身份验证框架。甚至它内置的身份验证schemes也使用了可插入式身份验证框架。
想搞清楚身份验证框架式是如何工作的,你首先必须弄明白两个主要的身份验证操作。该框架首先必须验证客户端(client)。这一步通常都会被完成只要客户端连接到服务器并且它包含了从服务器发送过来或收集到相关的关于客户端与连接进行关联的验证信息。第二步由框架处理的操作时找出一个对客户端进行响应的ACL中的entries(我翻译成“标识”)。ACL entries是一对<idspec, permissions>对。Idspec可能是一个匹配关联连接的验证信息的简单字符串(simple string)或者它也可能是一个用来评估该验证信息的表达式(expression)、它关注于实现身份验证插件的匹配。这里是身份验证插件中必须被实现的接口:
public interface AuthenticationProvider {
String getScheme();
KeeperException.Code handleAuthentication(ServerCnxn cnxn, byte authData[]);
boolean isValid(String id);
boolean matches(String id, String aclExpr);
boolean isAuthenticated();
}
第一个方法“getScheme”返回一个验证插件的字符串。因为我们支持多样化身份验证的方法,而一个身份验证凭证或一个idspec通常会带有scheme,所以ZooKeeper服务器通过身份验证插件返回的scheme去确定是哪一个ids被scheme应用了。
一个客户端发送身份验证信息去跟连接进行关联,(这一步骤)通常被称为“处理身份验证”(handleAuthentication)。客户端将shceme指定给那些响应信息。ZooKeeper服务器将该信息传递给那些getScheme与客户端传递过来的scheme相匹配的身份验证插件。如果handleAuthentication的实现(implementation)确定该信息是坏的它通常都会返回一个错误,然后它会使用cnxn.getAuthInfo().add(new Id(getScheme(), data))方法与连接关联信息。
身份验证插件在设置和使用ACLs(的情况)中都被调用了。当一个ACL因为znode而被创建时,ZooKeeper服务器将会传递部分标识(entry)的id给isValid(String id)方法。它被插件用来验证id是否拥有一个正确的form(找不到合适译意)。举个例子,IP:172.16.0.0/16是一个非法id,但ip:host.com却是合法的。如果一个新的ACL包含了一个“auth”标识,那么“isAuthenticated”会被使用来判断这个与连接相关联的scheme的身份验证信息是否应该被加到ACL里。一些schemes不应该被包含在auth里。比如,如果auth被(用户)指定了那么客户端的IP地址不会被视为一个应该被加入到ACL里的id。
在检查一个ACL的时候ZooKeeper会调用matches(String id, String aclExpr)方法。它需要匹配对应的含有相关ACL标识的客户端它的身份验证信息。为了找出那些被应用到客户端的标识,ZooKeeper服务器将会找出每一个标识的scheme,同时,如果有一个来自对应scheme的客户端验证信息,matches(String id, String aclExpr)方法会在使用了提前被添加到handleAuthentication连接的验证信息的id和用于ACL标识id的aclExpr这两个参数后被调用。身份验证插件里含有两个内置对象:iP和digest。通过使用系统properties可以添加额外插件。启动的时候ZooKeeper服务器会查找以“zookeeper.authProvider”开头的系统properties并且解析那些properties里面的值,比如一个身份验证插件的类名。通过使用“Dzookeeper.authProvider.X=com.f.MyAuth”可以建立那些properties,或者你可以像下面一样在服务器配置文件里添加标识:
authProvider.1=com.f.MyAuth
authProvider.2=com.f.MyAuth2
应该注意的是我们要确保property的后缀是独一无二的。如果有相同的比如:Dzookeeper.authProvider.x=com.f.MyAuth
和Dzookeeper.authProvider.x=com.f.MyAuth2
,那么只有其中一个会被使用。另外所有的服务器必须拥有相同的被定义插件,否则使用了插件提供的身份验证schemes的客户端们将会在连接到某些服务器时发生很多问题。