From 00edbd67c326a4c71c882f409c8459e5a2df13fa Mon Sep 17 00:00:00 2001 From: "Benjamin W. Smith" Date: Mon, 19 Oct 2009 11:08:44 -0400 Subject: Pep8 cleanup, dbm module to manage a hash DB of users for an apache htdigest/htpasswd setup. --- __init__.py | 0 dbm.py | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ htpasswd.py | 6 ++++-- md5.py | 25 +++++++++++++++---------- password.py | 5 ++++- 5 files changed, 83 insertions(+), 13 deletions(-) mode change 100644 => 100755 __init__.py create mode 100755 dbm.py mode change 100644 => 100755 htpasswd.py mode change 100644 => 100755 password.py diff --git a/__init__.py b/__init__.py old mode 100644 new mode 100755 diff --git a/dbm.py b/dbm.py new file mode 100755 index 0000000..36b6233 --- /dev/null +++ b/dbm.py @@ -0,0 +1,60 @@ +#!/usr/bin/env python +""" +Utilities to manage a hash db of users for apache +""" +import anydbm +import htpasswd +__all__ = ["add_user", "delete_user", "update_user", + "get_user", "list_users", "raw_add"] + + +def get_user(user, db): + """ Get user info from the DB """ + db_dict = anydbm.open(db, 'r') + ret_user = "%s:%s" %(user, db_dict[user]) + db_dict.close() + return ret_user + + +def list_users(db): + """ List all the users in the DB """ + db_dict = anydbm.open(db, 'r') + ret_str = '\n'.join(["%s:%s" %(k, v) for k, v in db_dict.iteritems()]) + db_dict.close() + return ret_str + + +def add_user(user, passwd, db): + """ Add user to the DB, creating if need be """ + db_dict = anydbm.open(db, 'c') + db_dict[user] = htpasswd.hash_password(passwd) + db_dict.close() + return True + + +def raw_add(line, db): + """ Add raw line to the DB """ + db_dict = anydbm.open(db, 'w') + user, passwd = line.split(':') + db_dict[user] = passwd + db_dict.close() + return True + + +def delete_user(user, db): + """ Remove user from the DB """ + db_dict = anydbm.open(db, 'w') + del db_dict[user] + db_dict.close() + return True + + +def update_user(user, passwd, db): + """ Change the users pass in the DB """ + db_dict = anydbm.open(db, 'w') + if user in db_dict: + db_dict[user] = htpasswd.hash_password(passwd) + db_dict.close() + return True + else: + return False diff --git a/htpasswd.py b/htpasswd.py old mode 100644 new mode 100755 index 3641c34..0b79445 --- a/htpasswd.py +++ b/htpasswd.py @@ -8,7 +8,8 @@ Released under the terms of the BSD license. A collection of classes and functions to manipulate apache htaccess files. """ -__all__ = [ "generate_user" ] +__all__ = ["generate_user"] + def hash_password(passwd, ctype="crypt"): """Create an Apache-style password hash. @@ -25,10 +26,11 @@ def hash_password(passwd, ctype="crypt"): elif ctype is "md5": from apachelib.password import md5_password return md5_password(passwd) - + # We should never get here raise ValueError("%s is not a valid value for ctype." % ctype) + def generate_user(username, passwd, ctype="crypt"): """Generate a single htaccess line. """ diff --git a/md5.py b/md5.py index 917612e..0098c56 100755 --- a/md5.py +++ b/md5.py @@ -12,7 +12,7 @@ little bit wierd. This is a pythonic adaption of the C code in the APR library. If there are any questions please refer directly to the C code. -You'll find it in apache subversion under +You'll find it in apache subversion under /ap/apr-util/crypto/apr_md5.c """ @@ -21,11 +21,12 @@ from hashlib import md5 from random import random from math import floor -__all__ = [ "generate_md5", "generate_salt", "generate_short_salt" ] +__all__ = ["generate_md5", "generate_salt", "generate_short_salt"] # Defined as such for brevity md5digest = lambda x: md5(x).digest() + def ap_to64(input, count=4): """Weird-ass implementation of base64 conversion used by the APR library. @@ -33,19 +34,21 @@ def ap_to64(input, count=4): chars = "./0123456789%s%s" % (string.uppercase, string.lowercase) output = "" input = int(input) # Need ints to do binary math - + for i in range(0, count): output += chars[input & 0x3f] # Take 6 bits right input >>= 6 # shift by 6 bits return output + def generate_short_salt(): """Generate a short, 2-character salt. This is suitable for use in the htpasswd crypt routine. """ return generate_salt()[0:2] + def generate_salt(): """Mine a little salt for your passwords. Returns 8 random characters in base64. It is 4 + 4 because the original @@ -55,6 +58,7 @@ def generate_salt(): salt += ap_to64(floor(random() * 16777215)) return salt + def generate_md5(passwd, salt=None): """Generate an APRfied MD5 hash. This was adapted directly from the C code in the APR library. @@ -66,10 +70,10 @@ def generate_md5(passwd, salt=None): # I don't think it is really "checked" by Apache but I'm too # lazy to confirm this. MAGIC_TOKEN = "$apr1$" - + # Mainly just used for testing but why not leave it? salt = salt if salt else generate_salt() - + # Start with our password in the clear, a little magic and # a pinch of salt message = "%s%s%s" % (passwd, MAGIC_TOKEN, salt) @@ -89,21 +93,21 @@ def generate_md5(passwd, salt=None): message += chr(0) else: message += passwd[0] - passlen >>= 1 + passlen >>= 1 retval = md5digest(message) - + for i in range(0, 1000): if i & 1: message = passwd else: message = retval[0:16] - + if i % 3: message += salt if i % 7: - message += passwd + message += passwd if i & 1: message += retval[0:16] @@ -111,7 +115,7 @@ def generate_md5(passwd, salt=None): message += passwd retval = md5digest(message) - + # Now make the output string output = ap_to64((ord(retval[0]) << 16) | (ord(retval[6]) << 8) | ord(retval[12])) output += ap_to64((ord(retval[1]) << 16) | (ord(retval[7]) << 8) | ord(retval[13])) @@ -122,6 +126,7 @@ def generate_md5(passwd, salt=None): return "%s%s$%s" % (MAGIC_TOKEN, salt, output) + def test_driver(): """Run this to verify that the library is functioning properly. This one test case should be enough to verify the functionality. diff --git a/password.py b/password.py old mode 100644 new mode 100755 index 3570cf4..fe861e0 --- a/password.py +++ b/password.py @@ -10,6 +10,7 @@ Algorithm information was collected for various sources around the web and from analysis of the APR C code. """ + def crypt_password(passwd): """Generate Apache-style CRYPT password hash. """ @@ -17,6 +18,7 @@ def crypt_password(passwd): from apachelib.md5 import generate_short_salt return crypt(passwd, generate_short_salt()) + def sha_password(passwd): """Generate Apache-style SHA1 password hash. """ @@ -24,8 +26,9 @@ def sha_password(passwd): from base64 import b64encode return "{SHA}%s" % b64encode(sha1(passwd).digest()) + def md5_password(passwd): """Generate Apache-style MD5 password hash. """ from apachelib.md5 import generate_md5 - return generate_md5(passwd) + return generate_md5(passwd) -- cgit v1.2.3