application and pwhash

This commit is contained in:
2021-01-26 21:27:17 +01:00
parent c9478935cd
commit ca9e0b81d3
3 changed files with 64 additions and 24 deletions

54
auth.py
View File

@ -5,7 +5,7 @@ import werkzeug
import os import os
import mariadb import mariadb
from collections import namedtuple from collections import namedtuple
from pbkdf2 import crypt
DB_USER = os.environ["DB_USER"] DB_USER = os.environ["DB_USER"]
DB_PASS = os.environ["DB_PASS"] DB_PASS = os.environ["DB_PASS"]
@ -13,14 +13,21 @@ DB_HOST = os.environ["DB_HOST"]
DB_NAME = os.environ["DB_NAME"] DB_NAME = os.environ["DB_NAME"]
class NoUserException(Exception): pass class NoUserException(Exception):
class ManyUsersException(Exception): pass pass
UserEntry = namedtuple('UserEntry', ['id', 'login', 'issuer', 'secret', 'expiry', 'claims']) class ManyUsersException(Exception):
pass
class PasswordMismatchException(Exception):
pass
UserEntry = namedtuple('UserEntry', ['id', 'login', 'pwhash', 'issuer', 'secret', 'expiry', 'claims'])
def getUserEntryFromDB(login: str, password: str) -> UserEntry: def getUserEntryFromDB(application: str, login: str) -> UserEntry:
conn = None conn = None
cur = None cur = None
try: try:
@ -29,9 +36,9 @@ def getUserEntryFromDB(login: str, password: str) -> UserEntry:
conn.autocommit = False conn.autocommit = False
cur = conn.cursor(dictionary=True) cur = conn.cursor(dictionary=True)
# print("DEBUG: getUserEntryFromDB: login: <{}>, password: <{}>".format(login, password)) cur.execute("SELECT id, password, issuer, secret, expiry FROM user_application_and_issuer " +
cur.execute("SELECT id, issuer, secret, expiry FROM user_and_issuer WHERE login = ? AND password = ?", " WHERE application = ? AND login = ?",
[login, password]) [application, login])
resObj = cur.next() resObj = cur.next()
print("DEBUG: getUserEntryFromDB: resObj: {}".format(resObj)) print("DEBUG: getUserEntryFromDB: resObj: {}".format(resObj))
if not resObj: if not resObj:
@ -55,9 +62,9 @@ def getUserEntryFromDB(login: str, password: str) -> UserEntry:
else: else:
claims[claimObj["key"]] = claimObj["value"] claims[claimObj["key"]] = claimObj["value"]
userEntry = UserEntry(id=userId, login=login, secret=resObj["secret"], userEntry = UserEntry(id=userId, login=login, pwhash=resObj["password"],
issuer=resObj["issuer"], expiry=resObj["expiry"], secret=resObj["secret"], issuer=resObj["issuer"],
claims=claims) expiry=resObj["expiry"], claims=claims)
return userEntry return userEntry
except mariadb.Error as err: except mariadb.Error as err:
@ -69,17 +76,23 @@ def getUserEntryFromDB(login: str, password: str) -> UserEntry:
conn.rollback() conn.rollback()
conn.close() conn.close()
def checkPassword(inputPassword, passwordHash) -> bool:
def getUserEntry(login: str, password: str) -> UserEntry: print("DEBUG, checkPassword: {} {}".format(inputPassword, passwordHash))
return getUserEntryFromDB(login, password) if passwordHash != crypt(inputPassword, passwordHash, 100000):
raise PasswordMismatchException()
return True
def generateToken(**args): def generateToken(**args):
try: try:
body = args["body"] body = args["body"]
application = body["application"]
login = body["login"] login = body["login"]
password = body["password"] inputPassword = body["password"]
userEntry = getUserEntryFromDB(login, password)
userEntry = getUserEntryFromDB(application, login)
if inputPassword != crypt(inputPassword, userEntry.pwhash, 100000):
raise PasswordMismatchException()
timestamp = int(time.time()) timestamp = int(time.time())
payload = { payload = {
@ -94,13 +107,16 @@ def generateToken(**args):
return jwt.encode(payload, userEntry.secret) return jwt.encode(payload, userEntry.secret)
except NoUserException: except NoUserException:
print("ERROR: generateToken: no user found, login or password wrong") print("ERROR: generateToken: no user found, login or application wrong")
raise werkzeug.exceptions.Unauthorized() raise werkzeug.exceptions.Unauthorized()
except ManyUsersException: except ManyUsersException:
print("ERROR: generateToken: too many users found") print("ERROR: generateToken: too many users found")
raise werkzeug.exceptions.Unauthorized() raise werkzeug.exceptions.Unauthorized()
except PasswordMismatchException:
print("ERROR: generateToken: wrong password")
raise werkzeug.exceptions.Unauthorized()
except KeyError: except KeyError:
print("ERROR: generateToken: login or password missing") print("ERROR: generateToken: application, login or password missing")
raise werkzeug.exceptions.Unauthorized() raise werkzeug.exceptions.Unauthorized()
except Exception as e: except Exception as e:
print("ERROR: generateToken: unspecific exception: {}".format(str(e))) print("ERROR: generateToken: unspecific exception: {}".format(str(e)))

View File

@ -8,7 +8,14 @@ CREATE TABLE `issuers` (
) ENGINE=InnoDB; ) ENGINE=InnoDB;
ALTER TABLE `issuers` ALTER TABLE `issuers`
MODIFY COLUMN `max_expiry` int(10) unsigned NOT NULL; MODIFY COLUMN `max_expiry` int(10) unsigned NOT NULL;
CREATE TABLE `applications` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(128) NOT NULL,
CONSTRAINT PRIMARY KEY (`id`),
CONSTRAINT UNIQUE KEY `uk_applications_name` (`name`)
) ENGINE=InnoDB;
CREATE TABLE `users` ( CREATE TABLE `users` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT, `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
@ -58,6 +65,16 @@ CREATE TABLE `user_claims_mapping` (
REFERENCES `claims`(`id`) REFERENCES `claims`(`id`)
) ENGINE=InnoDB; ) ENGINE=InnoDB;
CREATE TABLE `user_applications_mapping` (
`user` int(10) unsigned NOT NULL,
`application` int(10) unsigned NOT NULL,
CONSTRAINT UNIQUE KEY `uk_user_applications_mapping` (`user`, `application` ),
CONSTRAINT FOREIGN KEY `fk_user_applications_mapping_user` (`user`)
REFERENCES `users`(`id`),
CONSTRAINT FOREIGN KEY `fk_user_applications_mapping_application` (`application`)
REFERENCES `applications`(`id`)
) ENGINE=InnoDB;
CREATE OR REPLACE VIEW claims_for_user AS CREATE OR REPLACE VIEW claims_for_user AS
SELECT u.id AS user, SELECT u.id AS user,
c.`key` AS `key`, c.`key` AS `key`,
@ -68,14 +85,19 @@ CREATE OR REPLACE VIEW claims_for_user AS
WHERE m.user = u.id AND WHERE m.user = u.id AND
m.claim = c.id; m.claim = c.id;
CREATE OR REPLACE VIEW user_and_issuer AS CREATE OR REPLACE VIEW user_application_and_issuer AS
SELECT u.login AS login, SELECT u.login AS login,
u.password AS password, u.password AS password,
u.id AS id, u.id AS id,
a.name as application,
i.name AS issuer, i.name AS issuer,
i.secret AS secret, i.secret AS secret,
least(u.expiry, i.max_expiry) AS expiry least(u.expiry, i.max_expiry) AS expiry
FROM users u, FROM users u,
issuers i issuers i,
WHERE u.issuer = i.id; applications a,
user_applications_mapping m
WHERE u.issuer = i.id AND
u.id = m.user AND
a.id = m.application;

View File

@ -45,9 +45,11 @@ components:
x-bearerInfoFunc: test.decodeToken x-bearerInfoFunc: test.decodeToken
schemas: schemas:
User: User:
description: Login/Password tuple description: Application/Login/Password tuple
type: object type: object
properties: properties:
application:
type: string
login: login:
type: string type: string
password: password: