f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankg# -*- coding: utf-8 -*-
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankg# $Id: auth.py 1634 2013-04-12 15:36:36Z amelung $
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankg#
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankg# Copyright (c) 2007-2011 Otto-von-Guericke-Universität Magdeburg
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankg#
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankg# This file is part of ECSpooler.
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankg#
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankg#import md5
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankg
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankgfrom types import StringType, UnicodeType, DictionaryType
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankg#import shelve
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankg#import os
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankgimport time
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankgimport logging
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankg
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankgtry:
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankg import crypt
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankgexcept ImportError, ierr:
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankg crypt = None
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankg
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankgtry:
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankg import hashlib
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankgexcept ImportError:
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankg import md5 as hashlib
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankg
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankgLOG = logging.getLogger();
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankg
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankg# this will prevent dictionary attacks
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankgUSER_AUTH_FAIL_SLEEP = 3.0
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankg
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankg# authorization levels
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankgSHUTDOWN = 9
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankgADD_BACKEND = 9
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankgSTOP_BACKEND = 9
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankgREMOVE_BACKEND = 9
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankgPUT = 1
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankgPOP = 1
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankgGET_STATUS = 1
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankgGET_BACKEND_INFO = 1
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankg
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankgROOT_USER = 'root'
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankgREQUIRES_ROOT = 5 # Operations with a higher level require root privilege
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankg
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankgclass UserAuthMD5():
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankg """
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankg User/password authentification with a file containing
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankg md5 encrypted passwords
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankg """
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankg
95475ded9ec220bbb2576cae62b155425a77b2c7gsmith def __init__(self, userFile='passwd'):
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankg """
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankg @param: userFile Absolute path to a file containing usernames and
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankg md5 encrypted passwords
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankg """
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankg self.db = self._load(userFile)
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankg
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankg def test(self, args, level):
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankg """
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankg @param: args A dictionary with keys and values for username and encrypted password
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankg @param: level
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankg @return: True if username and password are correct, otherwise False
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankg """
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankg try:
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankg assert type(args) == DictionaryType, \
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankg "Invalid data structure (%s)" % str(type(args))
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankg
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankg username = args.get("username")
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankg password = args.get("password")
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankg
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankg if level > REQUIRES_ROOT and username != ROOT_USER:
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankg LOG.warn("Authorization failed for %s: Root privileges "
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankg "required for level %d operation" % (username, level))
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankg return False
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankg
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankg # do some parameter testing
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankg assert username and type(username) in (StringType, UnicodeType), \
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankg "Missing or invalid 'username'"
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankg assert password and type(password) in (StringType, UnicodeType), \
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankg "Missing or invalid 'password'"
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankg
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankg return self.authorize(username, password)
95475ded9ec220bbb2576cae62b155425a77b2c7gsmith
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankg except AssertionError, err:
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankg LOG.info("Authorization failed: %s" % err)
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankg return False
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankg
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankg
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankg def authorize(self, username, password):
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankg """
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankg @return: True if username and password are correct, otherwise False
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankg """
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankg ans = self.db.has_key(username) and \
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankg self.db[username] == hashlib.md5(password).hexdigest()
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankg
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankg if not ans:
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankg LOG.warn('Wrong password. Waiting %d seconds to prevent '
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankg 'dictionary attacks' % USER_AUTH_FAIL_SLEEP)
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankg time.sleep(USER_AUTH_FAIL_SLEEP)
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankg
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankg return ans
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankg
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankg
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankg def users(self):
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankg """
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankg @return: A list with all usernames
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankg """
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankg return self.db.keys()
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankg
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankg
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankg def _load(self, userFile):
f83d2c5238c9d61f4420d2f7406c70a591a9b593fuankg """
@return: A dictionary containing username-password pairs
"""
lines = []
usrdb = {}
try:
pwdFile = open(userFile, "r")
lines = pwdFile.readlines()
pwdFile.close()
except IOError, ioe:
LOG.error(ioe)
LOG.warn('No user accounts available.')
for line in lines:
if line.startswith("#"): continue
if not line.strip(): continue
if line.find(":") != -1:
username = line[0:line.find(":")].strip()
usrdb[username] = line[line.find(":")+1:].strip()
#LOG.debug("Added user '%s'" % username)
return usrdb
# -- --------------------------------------------------------------------------
if __name__ == '__main__':
from os.path import join, dirname
# testing UserAuthMD5
uamd5 = UserAuthMD5(join(dirname(__file__), '..', '..', 'etc', 'passwd'))
print uamd5.authorize('test', 'SuPPe')
print uamd5.authorize('demo', 'foobar')
#print md5.md5('Asdf,.').hexdigest()
print hashlib.md5('Asdf,.').hexdigest()