Endpoint POST api/dn

This commit is contained in:
Jörn-Michael Miehe 2022-03-23 15:44:35 +00:00
parent ac6e506486
commit 437bc570e4
4 changed files with 121 additions and 10 deletions

View file

@ -10,7 +10,7 @@ from enum import Enum
from typing import Any from typing import Any
from passlib.context import CryptContext from passlib.context import CryptContext
from pydantic import BaseModel, validator from pydantic import BaseModel, Field, constr, validator
from sqlalchemy.exc import IntegrityError from sqlalchemy.exc import IntegrityError
from sqlalchemy.orm import Session from sqlalchemy.orm import Session
@ -23,12 +23,12 @@ from . import models
class DistinguishedNameBase(BaseModel): class DistinguishedNameBase(BaseModel):
cn_only: bool cn_only: bool
country: str country: constr(max_length=2) | None
state: str state: str | None
city: str city: str | None
organization: str organization: str | None
organizational_unit: str organizational_unit: str | None
email: str email: str | None
common_name: str common_name: str
@ -40,6 +40,45 @@ class DistinguishedName(DistinguishedNameBase):
class Config: class Config:
orm_mode = True orm_mode = True
@classmethod
def create(
cls,
db: Session,
dn: DistinguishedNameCreate,
owner: User,
) -> User | None:
"""
Create a new distinguished name in the database.
"""
try:
db_owner = models.User.load(
db=db,
name=owner.name,
)
dn = models.DistinguishedName(
cn_only=dn.cn_only,
country=dn.country,
state=dn.state,
city=dn.city,
organization=dn.organization,
organizational_unit=dn.organizational_unit,
email=dn.email,
common_name=dn.common_name,
owner=db_owner,
)
db.add(dn)
db.commit()
db.refresh(dn)
return cls.from_orm(dn)
except IntegrityError:
# distinguished name already existed
pass
########## ##########
# table: certificates # table: certificates
########## ##########
@ -67,6 +106,9 @@ class Certificate(CertificateBase):
class UserCapability(Enum): class UserCapability(Enum):
admin = "admin" admin = "admin"
def __repr__(self) -> str:
return self.value
@classmethod @classmethod
def from_value(cls, value) -> UserCapability: def from_value(cls, value) -> UserCapability:
""" """
@ -100,8 +142,14 @@ class UserCreate(UserBase):
class User(UserBase): class User(UserBase):
capabilities: list[UserCapability] = [] capabilities: list[UserCapability] = []
distinguished_names: list[DistinguishedName] = []
certificates: list[Certificate] = [] distinguished_names: list[DistinguishedName] = Field(
default=[], repr=False
)
certificates: list[Certificate] = Field(
default=[], repr=False
)
class Config: class Config:
orm_mode = True orm_mode = True

View file

@ -15,7 +15,7 @@ from fastapi import FastAPI
from .config import Config, Settings from .config import Config, Settings
from .db import Connection from .db import Connection
from .db.schemas import User from .db.schemas import User
from .routers import admin, user from .routers import admin, dn, user
settings = Settings.get() settings = Settings.get()
@ -39,6 +39,7 @@ api = FastAPI(
api.include_router(admin.router) api.include_router(admin.router)
api.include_router(user.router) api.include_router(user.router)
api.include_router(dn.router)
app.mount("/api", api) app.mount("/api", api)

View file

@ -40,6 +40,10 @@ class Responses:
"description": "Must be admin", "description": "Must be admin",
"content": None, "content": None,
} }
NEEDS_ADMIN_OR_SELF = {
"description": "Must be the requested user",
"content": None,
}
ENTRY_EXISTS = { ENTRY_EXISTS = {
"description": "Entry exists in database", "description": "Entry exists in database",
"content": None, "content": None,

View file

@ -0,0 +1,58 @@
"""
/dn endpoints.
"""
from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy.orm import Session
from ..db import Connection
from ..db.schemas import DistinguishedName, DistinguishedNameCreate, User
from ._common import Responses, get_current_user_if_admin_or_self
router = APIRouter(prefix="/dn")
@router.post(
"",
responses={
status.HTTP_200_OK: Responses.OK,
status.HTTP_400_BAD_REQUEST: Responses.NOT_INSTALLED,
status.HTTP_401_UNAUTHORIZED: Responses.NEEDS_USER,
status.HTTP_403_FORBIDDEN: Responses.NEEDS_ADMIN,
status.HTTP_404_NOT_FOUND: Responses.ENTRY_DOESNT_EXIST,
status.HTTP_409_CONFLICT: Responses.ENTRY_EXISTS,
},
)
async def add_distinguished_name(
user_name: str,
distinguished_name: DistinguishedNameCreate,
_: User = Depends(get_current_user_if_admin_or_self),
db: Session | None = Depends(Connection.get),
):
"""
POST ./: Create a new distinguished name in the database.
"""
owner = User.from_db(
db=db,
name=user_name,
)
# fail if owner doesn't exist
if owner is None:
raise HTTPException(status_code=status.HTTP_409_CONFLICT)
# actually create the new user
new_dn = DistinguishedName.create(
db=db,
dn=distinguished_name,
owner=owner,
)
# fail if creation was unsuccessful
if new_dn is None:
raise HTTPException(status_code=status.HTTP_409_CONFLICT)
# return the created user on success
return new_dn