flake8 style

main
Bob Mottram 2020-04-01 19:29:56 +00:00
parent 65d3ace372
commit 805aef6a74
1 changed files with 77 additions and 69 deletions

146
auth.py
View File

@ -1,54 +1,56 @@
__filename__="auth.py" __filename__ = "auth.py"
__author__="Bob Mottram" __author__ = "Bob Mottram"
__license__="AGPL3+" __license__ = "AGPL3+"
__version__="1.1.0" __version__ = "1.1.0"
__maintainer__="Bob Mottram" __maintainer__ = "Bob Mottram"
__email__="bob@freedombone.net" __email__ = "bob@freedombone.net"
__status__="Production" __status__ = "Production"
import base64 import base64
import hashlib import hashlib
import binascii import binascii
import os import os
import shutil
import random import random
def hashPassword(password: str) -> str: def hashPassword(password: str) -> str:
"""Hash a password for storing """Hash a password for storing
""" """
salt=hashlib.sha256(os.urandom(60)).hexdigest().encode('ascii') salt = hashlib.sha256(os.urandom(60)).hexdigest().encode('ascii')
pwdhash= \ pwdhash = hashlib.pbkdf2_hmac('sha512',
hashlib.pbkdf2_hmac('sha512', \ password.encode('utf-8'),
password.encode('utf-8'), \ salt, 100000)
salt, 100000) pwdhash = binascii.hexlify(pwdhash)
pwdhash=binascii.hexlify(pwdhash) return (salt + pwdhash).decode('ascii')
return (salt+pwdhash).decode('ascii')
def verifyPassword(storedPassword: str,providedPassword: str) -> bool:
def verifyPassword(storedPassword: str, providedPassword: str) -> bool:
"""Verify a stored password against one provided by user """Verify a stored password against one provided by user
""" """
salt=storedPassword[:64] salt = storedPassword[:64]
storedPassword=storedPassword[64:] storedPassword = storedPassword[64:]
pwdhash= \ pwdhash = hashlib.pbkdf2_hmac('sha512',
hashlib.pbkdf2_hmac('sha512', \ providedPassword.encode('utf-8'),
providedPassword.encode('utf-8'), \ salt.encode('ascii'),
salt.encode('ascii'), \ 100000)
100000) pwdhash = binascii.hexlify(pwdhash).decode('ascii')
pwdhash=binascii.hexlify(pwdhash).decode('ascii') return pwdhash == storedPassword
return pwdhash==storedPassword
def createBasicAuthHeader(nickname: str,password: str) -> str:
def createBasicAuthHeader(nickname: str, password: str) -> str:
"""This is only used by tests """This is only used by tests
""" """
authStr=nickname.replace('\n','')+':'+password.replace('\n','') authStr = nickname.replace('\n', '') + ':' + password.replace('\n', '')
return 'Basic '+base64.b64encode(authStr.encode('utf-8')).decode('utf-8') return 'Basic ' + base64.b64encode(authStr.encode('utf-8')).decode('utf-8')
def authorizeBasic(baseDir: str,path: str,authHeader: str,debug: bool) -> bool:
def authorizeBasic(baseDir: str, path: str, authHeader: str,
debug: bool) -> bool:
"""HTTP basic auth """HTTP basic auth
""" """
if ' ' not in authHeader: if ' ' not in authHeader:
if debug: if debug:
print('DEBUG: Authorixation header does not '+ \ print('DEBUG: Authorixation header does not ' +
'contain a space character') 'contain a space character')
return False return False
if '/users/' not in path and \ if '/users/' not in path and \
@ -57,96 +59,102 @@ def authorizeBasic(baseDir: str,path: str,authHeader: str,debug: bool) -> bool:
if debug: if debug:
print('DEBUG: Path for Authorization does not contain a user') print('DEBUG: Path for Authorization does not contain a user')
return False return False
pathUsersSection=path.split('/users/')[1] pathUsersSection = path.split('/users/')[1]
if '/' not in pathUsersSection: if '/' not in pathUsersSection:
if debug: if debug:
print('DEBUG: This is not a users endpoint') print('DEBUG: This is not a users endpoint')
return False return False
nicknameFromPath=pathUsersSection.split('/')[0] nicknameFromPath = pathUsersSection.split('/')[0]
base64Str=authHeader.split(' ')[1].replace('\n','') base64Str = authHeader.split(' ')[1].replace('\n', '')
plain=base64.b64decode(base64Str).decode('utf-8') plain = base64.b64decode(base64Str).decode('utf-8')
if ':' not in plain: if ':' not in plain:
if debug: if debug:
print('DEBUG: Basic Auth header does not contain a ":" '+ \ print('DEBUG: Basic Auth header does not contain a ":" ' +
'separator for username:password') 'separator for username:password')
return False return False
nickname=plain.split(':')[0] nickname = plain.split(':')[0]
if nickname!=nicknameFromPath: if nickname != nicknameFromPath:
if debug: if debug:
print('DEBUG: Nickname given in the path ('+nicknameFromPath+ \ print('DEBUG: Nickname given in the path (' + nicknameFromPath +
') does not match the one in the Authorization header ('+ \ ') does not match the one in the Authorization header (' +
nickname+')') nickname + ')')
return False return False
passwordFile=baseDir+'/accounts/passwords' passwordFile = baseDir+'/accounts/passwords'
if not os.path.isfile(passwordFile): if not os.path.isfile(passwordFile):
if debug: if debug:
print('DEBUG: passwords file missing') print('DEBUG: passwords file missing')
return False return False
providedPassword=plain.split(':')[1] providedPassword = plain.split(':')[1]
passfile=open(passwordFile, "r") passfile = open(passwordFile, "r")
for line in passfile: for line in passfile:
if line.startswith(nickname+':'): if line.startswith(nickname+':'):
storedPassword=line.split(':')[1].replace('\n','') storedPassword = line.split(':')[1].replace('\n', '')
success=verifyPassword(storedPassword,providedPassword) success = verifyPassword(storedPassword, providedPassword)
if not success: if not success:
if debug: if debug:
print('DEBUG: Password check failed for '+nickname) print('DEBUG: Password check failed for ' + nickname)
return success return success
print('DEBUG: Did not find credentials for '+nickname+' in '+passwordFile) print('DEBUG: Did not find credentials for ' + nickname +
' in ' + passwordFile)
return False return False
def storeBasicCredentials(baseDir: str,nickname: str,password: str) -> bool:
def storeBasicCredentials(baseDir: str, nickname: str, password: str) -> bool:
"""Stores login credentials to a file """Stores login credentials to a file
""" """
if ':' in nickname or ':' in password: if ':' in nickname or ':' in password:
return False return False
nickname=nickname.replace('\n','').strip() nickname = nickname.replace('\n', '').strip()
password=password.replace('\n','').strip() password = password.replace('\n', '').strip()
if not os.path.isdir(baseDir+'/accounts'): if not os.path.isdir(baseDir + '/accounts'):
os.mkdir(baseDir+'/accounts') os.mkdir(baseDir + '/accounts')
passwordFile=baseDir+'/accounts/passwords' passwordFile = baseDir + '/accounts/passwords'
storeStr=nickname+':'+hashPassword(password) storeStr = nickname + ':' + hashPassword(password)
if os.path.isfile(passwordFile): if os.path.isfile(passwordFile):
if nickname+':' in open(passwordFile).read(): if nickname + ':' in open(passwordFile).read():
with open(passwordFile, "r") as fin: with open(passwordFile, "r") as fin:
with open(passwordFile+'.new', "w") as fout: with open(passwordFile + '.new', "w") as fout:
for line in fin: for line in fin:
if not line.startswith(nickname+':'): if not line.startswith(nickname + ':'):
fout.write(line) fout.write(line)
else: else:
fout.write(storeStr+'\n') fout.write(storeStr + '\n')
os.rename(passwordFile+'.new', passwordFile) os.rename(passwordFile + '.new', passwordFile)
else: else:
# append to password file # append to password file
with open(passwordFile, "a") as passfile: with open(passwordFile, "a") as passfile:
passfile.write(storeStr+'\n') passfile.write(storeStr + '\n')
else: else:
with open(passwordFile, "w") as passfile: with open(passwordFile, "w") as passfile:
passfile.write(storeStr+'\n') passfile.write(storeStr + '\n')
return True return True
def removePassword(baseDir: str,nickname: str) -> None:
def removePassword(baseDir: str, nickname: str) -> None:
"""Removes the password entry for the given nickname """Removes the password entry for the given nickname
This is called during account removal This is called during account removal
""" """
passwordFile=baseDir+'/accounts/passwords' passwordFile = baseDir + '/accounts/passwords'
if os.path.isfile(passwordFile): if os.path.isfile(passwordFile):
with open(passwordFile, "r") as fin: with open(passwordFile, "r") as fin:
with open(passwordFile+'.new', "w") as fout: with open(passwordFile + '.new', "w") as fout:
for line in fin: for line in fin:
if not line.startswith(nickname+':'): if not line.startswith(nickname + ':'):
fout.write(line) fout.write(line)
os.rename(passwordFile+'.new', passwordFile) os.rename(passwordFile + '.new', passwordFile)
def authorize(baseDir: str,path: str,authHeader: str,debug: bool) -> bool:
def authorize(baseDir: str, path: str, authHeader: str, debug: bool) -> bool:
"""Authorize using http header """Authorize using http header
""" """
if authHeader.lower().startswith('basic '): if authHeader.lower().startswith('basic '):
return authorizeBasic(baseDir,path,authHeader,debug) return authorizeBasic(baseDir, path, authHeader, debug)
return False return False
def createPassword(length=10): def createPassword(length=10):
validChars='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789' validChars = 'abcdefghijklmnopqrstuvwxyz' + \
'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
return ''.join((random.choice(validChars) for i in range(length))) return ''.join((random.choice(validChars) for i in range(length)))