mumble-scripts icon indicating copy to clipboard operation
mumble-scripts copied to clipboard

LDAP authenticator: number_attr - use hash(username_attr) instead

Open stumbaumr opened this issue 10 years ago • 4 comments

Hi, instead of using a possibly unused field in LDAP why do you not just use a hash function to generate a unique number from the unique username_attr instead.

This would also save time when creating user accounts.

Thanks Rainer

stumbaumr avatar May 13 '15 08:05 stumbaumr

The mumble user ID is a signed 32 bit Integer. The negative space is reserved for unregistered users and 0 is superuser. That leaves you with 2^31-1 numbers minus whatever you exclude for the offset you configure. Imho this is not really enough for collision resistant hashing of usernames in a long living server. With a thousand accounts over the server life-time you are already at p > 10^-4 for a collision.

hacst avatar May 14 '15 09:05 hacst

Are you sure it's 32 bits wide? I was given to believe it was 64. Been working on something like the following:

@lru_cache(maxsize=1000)
def dn_to_uid(dn, max_bits=64, make_hash=hashlib.sha1):
    """
    This function maps LDAP distinguished names to Murmur user IDs. It works by computing a hash of the given DN, taking
    the unsigned integer value of the least significant 8 bytes of the hash, and then mapping that value into the signed
    integer space of the same bit width. SQLite integer columns can hold signed integers up to 8 bytes wide.

    Yeah, there's faster ways to do this, but this implementation is portable--which is desirable when you consider the
    UIDs returned to Murmur are saved in an external database.
    """

    def hash_integer_value():
        h = make_hash()
        h.update(dn)
        return int(h.hexdigest(), 16)

    bitmask = 2 ** max_bits - 1
    return (hash_integer_value() & bitmask) - (bitmask >> 1)

Don't have the thing working yet because I can't get Ice to load the slice file. Complains: ImportError: No module named Ice_SliceChecksumDict_ice even though I'm passing it the correct include directory in Ice.loadSlice("-I/usr/share/Ice/slice {}".format(slice_name)).

IronSavior avatar Dec 30 '19 23:12 IronSavior

Did more testing and found that the UID value must be an unsigned integer less than 31-bits wide. I'm guessing it has to be 31 bits unsigned because the value at a low level is 32 bits signed, but negative UIDs are not valid. Correct DN-to-UID mapping function with decently low risk of collisions:

@lru_cache(maxsize=1000)
def dn_to_uid(dn, max_bits=31, make_hash=hashlib.sha1):
    """
    This function maps LDAP distinguished names to Murmur user IDs. It works by computing a hash of the given DN, taking
    the unsigned integer value of the least significant 31-bits of the hash.
    """

    def hash_integer_value():
        h = make_hash()
        h.update(dn)
        return int(h.hexdigest(), 16)

    bitmask = 2 ** max_bits - 1
    return hash_integer_value() & bitmask

IronSavior avatar Jan 02 '20 01:01 IronSavior

By the way, the authenticator process would sometimes get killed if we returned a value out of range. When that happens, it allows any user to connect unauthenticated.

IronSavior avatar Jan 02 '20 02:01 IronSavior