Here's a version that seems to work (doesn't fail).

The issue was that the sha1 digest should be run on the credentials, not just the password (so sha1(user:pass)).


Please open a JIRA for this (better docs on how to do digest auth, I'm sure there's a wealth of other issues that could also be created around this code, feel free to open other issues as you see fit).

Patrick

On 04/28/2010 02:50 PM, Kapil Thangavelu wrote:
Hi Folks,

I'm trying to use zookeeper via zkpython to set an acl on a node, and
then test that acl. I've configured a super user, and create a node with
an acl with the all permission and a digest scheme. However i find that
i end up not being able to touch the node with the credentials as per
the configured acl user, perhaps even more oddly i can't access the node
with the super user (passed in via system property on the cli via
Dzookeeper.DigestAuthenticationProvider.superDigest). Any attempt to
acces the node raises an exception
zookeeper.NoAuthException: not authenticated

i've attached a demonstration script that exhibits the problem. Is there
something i'm doing wrong here or is it an issue with zkpython?

thanks,

Kapil
import zookeeper
import threading
import hashlib
import base64

ZOO_OPEN_ACL_UNSAFE = {'scheme': 'world',
                       'id': 'anyone',
                       'perms': zookeeper.PERM_ALL}


class Connection(object):

    def __init__(self, servers):
        self.servers = servers
        self.connected = False
        self.timeout = 10000
        self.cv = threading.Condition()
        self.handle = None

        self.cv.acquire()
        self.handle = zookeeper.init(
            servers, self.connection_watcher, self.timeout)

        self.cv.wait(self.timeout/1000)
        if not self.connected:
            raise RuntimeError("unable to connect %s" % servers)

    def connection_watcher(self, handle, type, state, path):
        print type, state, path
        self.handle = handle
        self.cv.acquire()
        self.connected = True
        self.cv.notifyAll()
        self.cv.release()

    def close(self):
        return zookeeper.close(self.handle)

    def authenticate(self, scheme, credentials):

        def callback(handle, result):
            self.cv.acquire()
            assert self.handle == handle
            self.cv.notify()
            self.cv.release()

        self.cv.acquire()
        zookeeper.add_auth(
            self.handle, scheme, credentials, callback)
        self.cv.wait()

    def create(self, path, data="", acl=[ZOO_OPEN_ACL_UNSAFE]):
        return zookeeper.create(self.handle, path, data, acl,
                                zookeeper.EPHEMERAL)

    def get_children(self, path):
        return zookeeper.get_children(self.handle, path)


def identity(credentials):
    user, password = credentials.split(":")
    return "%s:%s" % (user,
               base64.b64encode(hashlib.sha1(credentials).digest()))


USER_ROOT = "super:test"
USER_TRUCKS = "trucks:foobar"


def main():
    conn = Connection("127.0.0.1:2181")
    conn.authenticate("digest", USER_ROOT)
    conn.create("/cars")

    children = conn.get_children("/cars")
    assert not children

    truck_acl = [
        {'scheme': 'digest',
         'perms': zookeeper.PERM_ALL,
         'id': identity(USER_TRUCKS)}]

    # create an ephemeral truck node with the given acl
    conn.create("/trucks", acl=truck_acl)

    # this also fails, but demonstrating with another conn for completeness.
    #conn.get_children("/trucks")

    conn2 = Connection("127.0.0.1:2181")
    conn2.authenticate("digest", USER_TRUCKS)

    try:
        conn2.get_children("/trucks")
    finally:
        conn.close()
        conn2.close()

if __name__ == '__main__':
    main()

Reply via email to