authservice/auth.py

121 lines
4.1 KiB
Python
Raw Normal View History

2021-01-25 21:52:52 +01:00
import time
import connexion
from jose import JWTError, jwt
2021-01-26 13:43:09 +01:00
import werkzeug
2021-01-25 21:52:52 +01:00
import os
import mariadb
2021-01-26 13:43:09 +01:00
from collections import namedtuple
2021-01-26 21:27:17 +01:00
from pbkdf2 import crypt
2021-01-25 21:52:52 +01:00
DB_USER = os.environ["DB_USER"]
DB_PASS = os.environ["DB_PASS"]
DB_HOST = os.environ["DB_HOST"]
DB_NAME = os.environ["DB_NAME"]
2021-01-26 21:27:17 +01:00
class NoUserException(Exception):
pass
class ManyUsersException(Exception):
pass
class PasswordMismatchException(Exception):
pass
2021-01-26 13:43:09 +01:00
2021-01-26 22:06:39 +01:00
UserEntry = namedtuple('UserEntry', ['id', 'login', 'issuer', 'secret', 'expiry', 'claims'])
2021-01-26 13:43:09 +01:00
2021-01-26 22:06:39 +01:00
def getUserEntryFromDB(application: str, login: str):
2021-01-25 21:52:52 +01:00
conn = None
cur = None
try:
conn = mariadb.connect(user = DB_USER, password = DB_PASS,
host = DB_HOST, database = DB_NAME)
conn.autocommit = False
cur = conn.cursor(dictionary=True)
2021-01-26 21:27:17 +01:00
cur.execute("SELECT id, password, issuer, secret, expiry FROM user_application_and_issuer " +
" WHERE application = ? AND login = ?",
[application, login])
2021-01-26 13:43:09 +01:00
resObj = cur.next()
print("DEBUG: getUserEntryFromDB: resObj: {}".format(resObj))
if not resObj:
raise NoUserException()
2021-01-25 21:52:52 +01:00
invObj = cur.next()
if invObj:
2021-01-26 13:43:09 +01:00
raise ManyUsersException()
userId = resObj["id"]
cur.execute("SELECT user, `key`, `value` FROM claims_for_user where user = ?",
[userId])
claims = {}
for claimObj in cur:
print("DEBUG: getUserEntryFromDB: add claim {} -> {}".format(claimObj["key"], claimObj["value"]))
if claimObj["key"] in claims:
if isinstance(claimObj["key"], list):
claims[claimObj["key"]].append(claimObj["value"])
else:
claims[claimObj["key"]] = [ claims[claimObj["key"]] ]
claims[claimObj["key"]].append(claimObj["value"])
else:
claims[claimObj["key"]] = claimObj["value"]
2021-01-26 22:06:39 +01:00
userEntry = UserEntry(id=userId, login=login,
2021-01-26 21:27:17 +01:00
secret=resObj["secret"], issuer=resObj["issuer"],
expiry=resObj["expiry"], claims=claims)
2021-01-25 21:52:52 +01:00
2021-01-26 22:06:39 +01:00
return userEntry, resObj["password"]
2021-01-25 21:52:52 +01:00
except mariadb.Error as err:
raise Exception("Error when connecting to database: {}".format(err))
finally:
if cur:
cur.close()
if conn:
conn.rollback()
conn.close()
2021-01-26 22:06:39 +01:00
def getUserEntry(application, login, password):
userEntry, pwhash = getUserEntryFromDB(application, login)
if pwhash != crypt(password, pwhash):
2021-01-26 21:27:17 +01:00
raise PasswordMismatchException()
2021-01-26 22:06:39 +01:00
return userEntry
2021-01-25 21:52:52 +01:00
2021-01-26 13:43:09 +01:00
def generateToken(**args):
2021-01-25 21:52:52 +01:00
try:
2021-01-26 13:43:09 +01:00
body = args["body"]
2021-01-26 21:27:17 +01:00
application = body["application"]
2021-01-26 13:43:09 +01:00
login = body["login"]
2021-01-26 22:06:39 +01:00
password = body["password"]
2021-01-26 21:27:17 +01:00
2021-01-26 22:06:39 +01:00
userEntry = getUserEntry(application, login, password)
2021-01-26 21:27:17 +01:00
2021-01-26 13:43:09 +01:00
timestamp = int(time.time())
payload = {
"iss": userEntry.issuer,
"iat": int(timestamp),
"exp": int(timestamp + userEntry.expiry),
"sub": str(userEntry.id)
}
for claim in userEntry.claims.items():
# print("DEBUG: generateToken: add claim {} -> {}".format(claim[0], claim[1]))
payload["x-{}".format(claim[0])] = claim[1]
return jwt.encode(payload, userEntry.secret)
except NoUserException:
2021-01-26 21:27:17 +01:00
print("ERROR: generateToken: no user found, login or application wrong")
2021-01-26 13:43:09 +01:00
raise werkzeug.exceptions.Unauthorized()
except ManyUsersException:
print("ERROR: generateToken: too many users found")
raise werkzeug.exceptions.Unauthorized()
2021-01-26 21:27:17 +01:00
except PasswordMismatchException:
print("ERROR: generateToken: wrong password")
raise werkzeug.exceptions.Unauthorized()
2021-01-26 13:43:09 +01:00
except KeyError:
2021-01-26 21:27:17 +01:00
print("ERROR: generateToken: application, login or password missing")
2021-01-26 13:43:09 +01:00
raise werkzeug.exceptions.Unauthorized()
except Exception as e:
print("ERROR: generateToken: unspecific exception: {}".format(str(e)))
raise werkzeug.exceptions.Unauthorized()