[feat][apiKey] show token only on create, fix decorator

This commit is contained in:
Tim Gröger 2024-10-15 08:26:16 +02:00
parent 7dd3321246
commit df02808fb7
3 changed files with 16 additions and 11 deletions

View File

@ -1,5 +1,7 @@
import secrets import secrets
from werkzeug.exceptions import Unauthorized
from .. import logger from .. import logger
from ..database import db from ..database import db
from ..models import ApiKey from ..models import ApiKey
@ -21,7 +23,7 @@ def validate_api_key(api_key, permission):
Forbidden: If permission is insufficient Forbidden: If permission is insufficient
""" """
logger.debug("check api_key {{ {} }} is valid".format(api_key)) logger.debug("check api_key {{ {} }} is valid".format(api_key))
api_key = ApiKey.query.filter_by(api_key=api_key).one_or_none() api_key = ApiKey.query.filter_by(_token=api_key).one_or_none()
if api_key: if api_key:
logger.debug("api_key found") logger.debug("api_key found")
if not permission or api_key.user_.has_permission(permission): if not permission or api_key.user_.has_permission(permission):
@ -44,9 +46,10 @@ def create(user, name, description=None) -> ApiKey:
logger.debug("create api key token") logger.debug("create api key token")
token_str = secrets.token_hex(16) token_str = secrets.token_hex(16)
logger.debug("create api_key for user {{ {} }}".format(user)) logger.debug("create api_key for user {{ {} }}".format(user))
api_key = ApiKey(_user_id=user.id__, name=name, description=description, token=token_str) api_key = ApiKey(_user_id=user.id_, name=name, description=description, _token=token_str)
db.session.add(api_key) db.session.add(api_key)
db.session.commit() db.session.commit()
api_key.token = api_key._token
return api_key return api_key

View File

@ -1,7 +1,9 @@
from __future__ import annotations # TODO: Remove if python requirement is >= 3.12 (? PEP 563 is defered) from __future__ import \
annotations # TODO: Remove if python requirement is >= 3.12 (? PEP 563 is defered)
from datetime import datetime, timedelta, timezone from datetime import datetime, timedelta, timezone
from secrets import compare_digest from secrets import compare_digest
from typing import Union
from .. import logger from .. import logger
from ..database import db from ..database import db
@ -20,7 +22,7 @@ class ApiKey(db.Model, ModelSerializeMixin):
__allow_unmapped__ = True __allow_unmapped__ = True
__tablename__ = "api_key" __tablename__ = "api_key"
expires: datetime = db.Column(UtcDateTime, nullable=True) expires: datetime = db.Column(UtcDateTime, nullable=True)
token: str = db.Column(db.String(32), unique=True) _token: str = db.Column("token", db.String(32), unique=True)
name: str = db.Column(db.String(32)) name: str = db.Column(db.String(32))
description: str = db.Column(db.String(255), nullable=True) description: str = db.Column(db.String(255), nullable=True)
lifetime: int = db.Column(db.Integer, nullable=True) lifetime: int = db.Column(db.Integer, nullable=True)
@ -29,6 +31,7 @@ class ApiKey(db.Model, ModelSerializeMixin):
id: int = db.Column("id", Serial, primary_key=True) id: int = db.Column("id", Serial, primary_key=True)
_user_id = db.Column("user_id", Serial, db.ForeignKey("user.id")) _user_id = db.Column("user_id", Serial, db.ForeignKey("user.id"))
user_: User = db.relationship("User", back_populates="api_keys_") user_: User = db.relationship("User", back_populates="api_keys_")
token: Union[str, None] = None
@property @property
def userid(self): def userid(self):
@ -39,11 +42,11 @@ class ApiKey(db.Model, ModelSerializeMixin):
Update the Timestamp to the current Time. Update the Timestamp to the current Time.
""" """
logger.debug("update timestamp from session with token {{ {} }}".format(self.token)) logger.debug("update timestamp from session with token {{ {} }}".format(self._token))
self.expires = datetime.now(timezone.utc) + timedelta(seconds=self.lifetime) self.expires = datetime.now(timezone.utc) + timedelta(seconds=self.lifetime)
def __eq__(self, token): def __eq__(self, token):
if isinstance(token, str): if isinstance(token, str):
return compare_digest(self.token, token) return compare_digest(self._token, token)
else: else:
return super(Session, self).__eq__(token) return super(Session, self).__eq__(token)

View File

@ -3,21 +3,20 @@ from functools import wraps
from werkzeug.exceptions import Unauthorized from werkzeug.exceptions import Unauthorized
from flaschengeist import logger from flaschengeist import logger
from flaschengeist.controller import sessionController from flaschengeist.controller import apiKeyController, sessionController
def extract_api_key(permission=None): def extract_api_key(permission=None):
from flask import request from flask import request
try: try:
api_key = request.headers.get("X-API-KEY") apiKey = request.headers.get("X-API-KEY")
logger.debug(f"api_key {{ {api_key} }} | headers {{ {request.headers} }}")
except AttributeError: except AttributeError:
logger.debug("Missing X-API-KEY header") logger.debug("Missing X-API-KEY header")
raise Unauthorized raise Unauthorized
session = sessionController.validate_api_key(api_key, request.headers, permission) apiKey = apiKeyController.validate_api_key(apiKey, permission)
return session return apiKey
def extract_session(permission=None): def extract_session(permission=None):