from datetime import datetime, timedelta import json import mysql.connector as sql from mysql.connector import IntegrityError import requests class BackendException(Exception): def __init__(self, status_code, status_message): self.status = status_code self.message = status_message class Authenticator: def __init__(self, config, logger): self.logger = logger self.perm_url = config['api']['permission_url'].rstrip('/') self.headers = {'Accept': 'application/json', 'Content-Type': 'application/json'} self.ttl = timedelta(seconds=int(config['api']['cache_seconds'])) self.session = requests.Session() self.conninfo = { 'user': config['db']['user'], 'password': config['db']['password'], 'database': config['db']['database'], 'host': config['db'].get('host' 'localhost'), 'port': config['db'].get('port', 3306) } def authenticate(self, token): # DEBUG #return 'granted' # END DEBUG # DEBUG #result = self._make_request(token) #self.logger.error("Got response %s for %s", result, token) #return result # END DEBUG self._cache_clean() result = self._cache_read(token) if result: self.logger.debug("Got %s from cache for %s", result, token) return result result = self._make_request(token) self.logger.debug("Got %s from auth for %s", result, token) try: self._cache_save(token, result) self.logger.debug("Saved %s to cache for %s", result, token) except IntegrityError as e: result = self._cache_read(token) self.logger.debug("Got %s from cache under race for %s", result, token) return result def _cache_clean(self): with sql.connect(**self.conninfo) as db: with db.cursor() as c: c.execute("delete from `cache` where `end` < %s", (datetime.now().timestamp(),)) db.commit() def _cache_read(self, token): with sql.connect(**self.conninfo) as db: with db.cursor() as c: c.execute("select `result` from `cache` where `token` = %s", (token,)) result = c.fetchone() if result: return result[0] return None def _cache_save(self, token, result): with sql.connect(**self.conninfo) as db: with db.cursor() as c: stmt = "insert into `cache`(`token`, `result`, `end`) " + \ "values (%s, %s, %s)" end = datetime.now() + self.ttl c.execute(stmt, (token, result, end.timestamp())) db.commit() def _make_request(self, token): data = {'token': token} response = self.session.post(self.perm_url, headers=self.headers, data=json.dumps(data)) if not response.ok: raise BackendException(response.status_code, response.json()['message']) return response.json()['permission']