check issue permission

This commit is contained in:
Jörn-Michael Miehe 2022-04-02 21:24:44 +00:00
parent 2d39c4aaa3
commit d8bdb46a5c
4 changed files with 51 additions and 15 deletions

View file

@ -23,7 +23,6 @@ class DeviceBase(SQLModel):
name: str
type: str
expiry: datetime | None
class DeviceCreate(DeviceBase):
@ -37,11 +36,13 @@ class DeviceRead(DeviceBase):
Representation of a device read via the API
"""
approved: bool
owner_name: str | None
id: int | None = Field(primary_key=True)
approved: bool | None = Field(default=None)
expiry: datetime | None = Field(default=None)
owner_name: str = Field(foreign_key="user.name")
class Device(DeviceBase, table=True):
class Device(DeviceRead, table=True):
"""
Representation of `device` table
"""
@ -51,10 +52,6 @@ class Device(DeviceBase, table=True):
"name",
),)
id: int | None = Field(primary_key=True)
approved: bool = Field(default=False)
owner_name: str | None = Field(foreign_key="user.name")
# no idea, but "User" (in quotes) doesn't work here
# might be a future problem?
owner: User = Relationship(
@ -74,8 +71,7 @@ class Device(DeviceBase, table=True):
try:
with Connection.session as db:
new_device = cls.from_orm(device)
new_device.owner = owner
new_device = cls.from_orm(device, {"owner_name": owner.name})
db.add(new_device)
db.commit()

View file

@ -281,3 +281,23 @@ class User(UserBase, table=True):
# deny be default
return False
def can_issue(self, device: Device) -> bool:
"""
Check if this user can issue a certificate without approval.
"""
return (
device.approved in (None, False)
and (self.is_admin or self.has_tag(TagValue.issue))
)
def can_renew(self, device: Device) -> bool:
"""
Check if this user can renew a certificate without approval.
"""
return (
device.approved is True
and (self.is_admin or self.has_tag(TagValue.renew))
)

View file

@ -2,6 +2,8 @@
/device endpoints.
"""
from datetime import datetime
from fastapi import APIRouter, Depends, HTTPException, status
from ..db import Connection, Device, DeviceCreate, DeviceRead, User
@ -106,7 +108,20 @@ async def request_certificate(
db.add(device)
dn = DistinguishedName.build(device)
easy_rsa.issue(
dn=dn,
cert_type=CertificateType.server,
)
if current_user.can_issue(device):
device.approved = True
if (cert := easy_rsa.issue(
dn=dn,
cert_type=CertificateType.server,
)) is not None:
assert (expiry := cert.get_notAfter()) is not None
date_format, encoding = "%Y%m%d%H%M%SZ", "ascii"
expiry = datetime.strptime(
expiry.decode(encoding),
date_format,
)
device.expiry = expiry
db.commit()

View file

@ -26,6 +26,11 @@
- approved: bool
- expiry
## Device status
- created (approved = NULL): device has been newly created
- requested (approved = false): certificate has been requested (issue or renew)
- issued (approved = true): certificate has been granted (may be expired)
## Permissions
- admin cannot "admin" itself (to prevent self decapitation)
- admin can "edit", "admin" and "create" everything else
@ -37,5 +42,5 @@
- admin: add or remove tag, delete, generate password
### Device
- edit: change type, delete
- edit: change type, delete, request
- admin: approve