mirror of
https://github.com/ae-utbm/sith.git
synced 2025-06-08 04:05:22 +00:00
use 54 bytes keys and sha512 hashing
This commit is contained in:
parent
2dd28a37ab
commit
e765fcc96e
@ -4,14 +4,12 @@ from ninja.security import APIKeyHeader
|
|||||||
from apikey.hashers import get_hasher
|
from apikey.hashers import get_hasher
|
||||||
from apikey.models import ApiClient, ApiKey
|
from apikey.models import ApiClient, ApiKey
|
||||||
|
|
||||||
_UUID_LENGTH = 36
|
|
||||||
|
|
||||||
|
|
||||||
class ApiKeyAuth(APIKeyHeader):
|
class ApiKeyAuth(APIKeyHeader):
|
||||||
param_name = "X-APIKey"
|
param_name = "X-APIKey"
|
||||||
|
|
||||||
def authenticate(self, request: HttpRequest, key: str | None) -> ApiClient | None:
|
def authenticate(self, request: HttpRequest, key: str | None) -> ApiClient | None:
|
||||||
if not key or len(key) != _UUID_LENGTH:
|
if not key or len(key) != ApiKey.KEY_LENGTH:
|
||||||
return None
|
return None
|
||||||
hasher = get_hasher()
|
hasher = get_hasher()
|
||||||
hashed_key = hasher.encode(key)
|
hashed_key = hasher.encode(key)
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
import functools
|
import functools
|
||||||
import hashlib
|
import hashlib
|
||||||
import uuid
|
import secrets
|
||||||
|
|
||||||
from django.contrib.auth.hashers import BasePasswordHasher
|
from django.contrib.auth.hashers import BasePasswordHasher
|
||||||
from django.utils.crypto import constant_time_compare
|
from django.utils.crypto import constant_time_compare
|
||||||
|
|
||||||
|
|
||||||
class Sha256ApiKeyHasher(BasePasswordHasher):
|
class Sha512ApiKeyHasher(BasePasswordHasher):
|
||||||
"""
|
"""
|
||||||
An API key hasher using the sha256 algorithm.
|
An API key hasher using the sha256 algorithm.
|
||||||
|
|
||||||
@ -15,14 +15,14 @@ class Sha256ApiKeyHasher(BasePasswordHasher):
|
|||||||
high entropy, randomly generated API keys.
|
high entropy, randomly generated API keys.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
algorithm = "sha256"
|
algorithm = "sha512"
|
||||||
|
|
||||||
def salt(self) -> str:
|
def salt(self) -> str:
|
||||||
# No need for a salt on a high entropy key.
|
# No need for a salt on a high entropy key.
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
def encode(self, password: str, salt: str = "") -> str:
|
def encode(self, password: str, salt: str = "") -> str:
|
||||||
hashed = hashlib.sha256(password.encode()).hexdigest()
|
hashed = hashlib.sha512(password.encode()).hexdigest()
|
||||||
return f"{self.algorithm}$${hashed}"
|
return f"{self.algorithm}$${hashed}"
|
||||||
|
|
||||||
def verify(self, password: str, encoded: str) -> bool:
|
def verify(self, password: str, encoded: str) -> bool:
|
||||||
@ -32,11 +32,12 @@ class Sha256ApiKeyHasher(BasePasswordHasher):
|
|||||||
|
|
||||||
@functools.cache
|
@functools.cache
|
||||||
def get_hasher():
|
def get_hasher():
|
||||||
return Sha256ApiKeyHasher()
|
return Sha512ApiKeyHasher()
|
||||||
|
|
||||||
|
|
||||||
def generate_key() -> tuple[str, str]:
|
def generate_key() -> tuple[str, str]:
|
||||||
"""Generate a [key, hash] couple."""
|
"""Generate a [key, hash] couple."""
|
||||||
key = str(uuid.uuid4())
|
# this will result in key with a length of 72
|
||||||
|
key = str(secrets.token_urlsafe(54))
|
||||||
hasher = get_hasher()
|
hasher = get_hasher()
|
||||||
return key, hasher.encode(key)
|
return key, hasher.encode(key)
|
||||||
|
@ -88,7 +88,7 @@ class Migration(migrations.Migration):
|
|||||||
models.CharField(
|
models.CharField(
|
||||||
db_index=True,
|
db_index=True,
|
||||||
editable=False,
|
editable=False,
|
||||||
max_length=150,
|
max_length=136,
|
||||||
verbose_name="hashed key",
|
verbose_name="hashed key",
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -17,9 +17,7 @@ class ApiClient(models.Model):
|
|||||||
on_delete=models.CASCADE,
|
on_delete=models.CASCADE,
|
||||||
)
|
)
|
||||||
groups = models.ManyToManyField(
|
groups = models.ManyToManyField(
|
||||||
Group,
|
Group, verbose_name=_("groups"), related_name="api_clients", blank=True
|
||||||
verbose_name=_("groups"),
|
|
||||||
related_name="api_clients",
|
|
||||||
)
|
)
|
||||||
client_permissions = models.ManyToManyField(
|
client_permissions = models.ManyToManyField(
|
||||||
Permission,
|
Permission,
|
||||||
@ -70,11 +68,13 @@ class ApiClient(models.Model):
|
|||||||
|
|
||||||
class ApiKey(models.Model):
|
class ApiKey(models.Model):
|
||||||
PREFIX_LENGTH = 5
|
PREFIX_LENGTH = 5
|
||||||
|
KEY_LENGTH = 72
|
||||||
|
HASHED_KEY_LENGTH = 136
|
||||||
|
|
||||||
name = models.CharField(_("name"), blank=True, default="")
|
name = models.CharField(_("name"), blank=True, default="")
|
||||||
prefix = models.CharField(_("prefix"), max_length=PREFIX_LENGTH, editable=False)
|
prefix = models.CharField(_("prefix"), max_length=PREFIX_LENGTH, editable=False)
|
||||||
hashed_key = models.CharField(
|
hashed_key = models.CharField(
|
||||||
_("hashed key"), max_length=150, db_index=True, editable=False
|
_("hashed key"), max_length=HASHED_KEY_LENGTH, db_index=True, editable=False
|
||||||
)
|
)
|
||||||
client = models.ForeignKey(
|
client = models.ForeignKey(
|
||||||
ApiClient,
|
ApiClient,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user