Compare commits
No commits in common. "fa4c2e45ab94992a32d4c0de434f8d62796b8d66" and "f21029e15b571476642083ff1aff8ee3b1d37a82" have entirely different histories.
fa4c2e45ab
...
f21029e15b
6 changed files with 35 additions and 48 deletions
|
|
@ -102,6 +102,7 @@ class CertificateType(Enum):
|
|||
Possible types of certificates
|
||||
"""
|
||||
|
||||
ca = auto()
|
||||
client = auto()
|
||||
server = auto()
|
||||
|
||||
|
|
@ -237,16 +238,20 @@ class EasyRSA:
|
|||
def get_certificate(
|
||||
self,
|
||||
*,
|
||||
cert_type: CertificateType | None = None,
|
||||
dn: DistinguishedName | None = None,
|
||||
) -> x509.Certificate | None:
|
||||
"""
|
||||
Get a certificate from the PKI directory
|
||||
"""
|
||||
|
||||
if dn is None:
|
||||
if cert_type is CertificateType.ca:
|
||||
cert_filename = self.output_directory.joinpath("ca.crt")
|
||||
|
||||
else:
|
||||
if dn is None:
|
||||
dn = DistinguishedName.build()
|
||||
|
||||
cert_filename = (self.output_directory.joinpath("issued")
|
||||
.joinpath(f"{dn.common_name}.crt"))
|
||||
|
||||
|
|
@ -279,7 +284,7 @@ class EasyRSA:
|
|||
EASYRSA_REQ_CN="kiwi-vpn-ca",
|
||||
)
|
||||
|
||||
cert = self.get_certificate()
|
||||
cert = self.get_certificate(cert_type=CertificateType.ca)
|
||||
assert cert is not None
|
||||
|
||||
# # this takes long!
|
||||
|
|
@ -310,7 +315,10 @@ class EasyRSA:
|
|||
**dn.easyrsa_env,
|
||||
)
|
||||
|
||||
return self.get_certificate(dn=dn)
|
||||
return self.get_certificate(
|
||||
cert_type=cert_type,
|
||||
dn=dn,
|
||||
)
|
||||
|
||||
def renew(
|
||||
self,
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ from fastapi.security import OAuth2PasswordBearer
|
|||
|
||||
from ..config import SETTINGS, Config
|
||||
from ..db import Device, User
|
||||
from ..easyrsa import EASYRSA, EasyRSA
|
||||
from ..easyrsa import EASYRSA, CertificateType, EasyRSA
|
||||
|
||||
oauth2_scheme = OAuth2PasswordBearer(
|
||||
tokenUrl=f"{SETTINGS.api_v1_prefix}/user/authenticate"
|
||||
|
|
@ -22,15 +22,8 @@ class Responses:
|
|||
"""
|
||||
|
||||
OK = {
|
||||
"description": "Operation successful",
|
||||
}
|
||||
OK_NONE = {
|
||||
"description": "Operation successful",
|
||||
"content": None,
|
||||
}
|
||||
OK_WAIT = {
|
||||
"description": "Operation successful, waiting for approval",
|
||||
}
|
||||
NOT_INSTALLED = {
|
||||
"description": "kiwi-vpn not installed",
|
||||
"content": None,
|
||||
|
|
@ -152,7 +145,7 @@ async def get_pki() -> EasyRSA:
|
|||
- 425: EasyRSA not initialized
|
||||
"""
|
||||
|
||||
if EASYRSA.get_certificate() is None:
|
||||
if EASYRSA.get_certificate(cert_type=CertificateType.ca) is None:
|
||||
raise HTTPException(status_code=status.HTTP_425_TOO_EARLY)
|
||||
|
||||
return EASYRSA
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ router = APIRouter(prefix="/admin", tags=["admin"])
|
|||
@router.put(
|
||||
"/install/config",
|
||||
responses={
|
||||
status.HTTP_200_OK: Responses.OK_NONE,
|
||||
status.HTTP_200_OK: Responses.OK,
|
||||
status.HTTP_409_CONFLICT: Responses.ENTRY_EXISTS,
|
||||
},
|
||||
)
|
||||
|
|
@ -43,7 +43,7 @@ async def initial_configure(
|
|||
@router.put(
|
||||
"/install/admin",
|
||||
responses={
|
||||
status.HTTP_201_CREATED: Responses.OK_NONE,
|
||||
status.HTTP_201_CREATED: Responses.OK,
|
||||
status.HTTP_400_BAD_REQUEST: Responses.NOT_INSTALLED,
|
||||
status.HTTP_409_CONFLICT: Responses.ENTRY_EXISTS,
|
||||
},
|
||||
|
|
@ -77,7 +77,7 @@ async def create_initial_admin(
|
|||
@router.put(
|
||||
"/config",
|
||||
responses={
|
||||
status.HTTP_200_OK: Responses.OK_NONE,
|
||||
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_PERMISSION,
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
/device endpoints.
|
||||
"""
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, Response, status
|
||||
from fastapi import APIRouter, Depends, HTTPException, status
|
||||
|
||||
from ..db import Device, DeviceCreate, DeviceRead, DeviceStatus, User
|
||||
from ..easyrsa import DistinguishedName, EasyRSA
|
||||
|
|
@ -59,7 +59,7 @@ async def add_device(
|
|||
@router.delete(
|
||||
"/{device_id}",
|
||||
responses={
|
||||
status.HTTP_200_OK: Responses.OK_NONE,
|
||||
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_PERMISSION,
|
||||
|
|
@ -87,11 +87,10 @@ async def remove_device(
|
|||
device.delete()
|
||||
|
||||
|
||||
@router.put(
|
||||
"/{device_id}/certificate",
|
||||
@router.post(
|
||||
"/{device_id}/issue",
|
||||
responses={
|
||||
status.HTTP_200_OK: Responses.OK | {"model": DeviceRead},
|
||||
status.HTTP_202_ACCEPTED: Responses.OK_WAIT | {"model": DeviceRead},
|
||||
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_PERMISSION,
|
||||
|
|
@ -100,21 +99,17 @@ async def remove_device(
|
|||
status.HTTP_425_TOO_EARLY: Responses.NEEDS_PKI,
|
||||
},
|
||||
response_model=DeviceRead,
|
||||
status_code=status.HTTP_202_ACCEPTED,
|
||||
)
|
||||
async def request_certificate_issuance(
|
||||
response: Response,
|
||||
current_user: User = Depends(get_current_user),
|
||||
device: Device = Depends(get_device_by_id),
|
||||
pki: EasyRSA = Depends(get_pki),
|
||||
) -> Device:
|
||||
"""
|
||||
PUT ./{device_id}/certificate: Request certificate issuance for a device.
|
||||
POST ./{device_id}/issue: Request certificate issuance for a device.
|
||||
|
||||
Status:
|
||||
|
||||
- 200: certificate issued
|
||||
- 202: issuance requested
|
||||
- 403: no user permission to edit device
|
||||
- 409: device certificate cannot be "issued"
|
||||
"""
|
||||
|
|
@ -137,18 +132,15 @@ async def request_certificate_issuance(
|
|||
device.set_status(DeviceStatus.certified)
|
||||
device.expiry = certificate.not_valid_after
|
||||
|
||||
response.status_code = status.HTTP_200_OK
|
||||
|
||||
# return updated device
|
||||
device.update()
|
||||
return device
|
||||
|
||||
|
||||
@router.patch(
|
||||
"/{device_id}/certificate",
|
||||
@router.post(
|
||||
"/{device_id}/renew",
|
||||
responses={
|
||||
status.HTTP_200_OK: Responses.OK | {"model": DeviceRead},
|
||||
status.HTTP_202_ACCEPTED: Responses.OK_WAIT | {"model": DeviceRead},
|
||||
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_PERMISSION,
|
||||
|
|
@ -157,21 +149,17 @@ async def request_certificate_issuance(
|
|||
status.HTTP_425_TOO_EARLY: Responses.NEEDS_PKI,
|
||||
},
|
||||
response_model=DeviceRead,
|
||||
status_code=status.HTTP_202_ACCEPTED,
|
||||
)
|
||||
async def request_certificate_renewal(
|
||||
response: Response,
|
||||
current_user: User = Depends(get_current_user),
|
||||
device: Device = Depends(get_device_by_id),
|
||||
pki: EasyRSA = Depends(get_pki),
|
||||
) -> Device:
|
||||
"""
|
||||
PATCH ./{device_id}/certificate: Request certificate renewal for a device.
|
||||
POST ./{device_id}/renew: Request certificate renewal for a device.
|
||||
|
||||
Status:
|
||||
|
||||
- 200: certificate renewed
|
||||
- 202: renewal requested
|
||||
- 403: no user permission to edit device
|
||||
- 409: device certificate cannot be "renewed"
|
||||
"""
|
||||
|
|
@ -194,17 +182,15 @@ async def request_certificate_renewal(
|
|||
device.set_status(DeviceStatus.certified)
|
||||
device.expiry = certificate.not_valid_after
|
||||
|
||||
response.status_code = status.HTTP_200_OK
|
||||
|
||||
# return updated device
|
||||
device.update()
|
||||
return device
|
||||
|
||||
|
||||
@router.delete(
|
||||
"/{device_id}/certificate",
|
||||
@router.post(
|
||||
"/{device_id}/revoke",
|
||||
responses={
|
||||
status.HTTP_200_OK: Responses.OK_NONE,
|
||||
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_PERMISSION,
|
||||
|
|
@ -220,7 +206,7 @@ async def revoke_certificate(
|
|||
pki: EasyRSA = Depends(get_pki),
|
||||
) -> Device:
|
||||
"""
|
||||
DELETE ./{device_id}/certificate: Revoke a device certificate.
|
||||
POST ./{device_id}/revoke: Revoke a device certificate.
|
||||
|
||||
Status:
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ router = APIRouter(prefix="/service", tags=["service"])
|
|||
@router.put(
|
||||
"/pki/init",
|
||||
responses={
|
||||
status.HTTP_200_OK: Responses.OK_NONE,
|
||||
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_PERMISSION,
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ class Token(BaseModel):
|
|||
@router.post(
|
||||
"/authenticate",
|
||||
responses={
|
||||
status.HTTP_200_OK: Responses.OK_NONE,
|
||||
status.HTTP_200_OK: Responses.OK,
|
||||
status.HTTP_400_BAD_REQUEST: Responses.NOT_INSTALLED,
|
||||
status.HTTP_401_UNAUTHORIZED: Responses.NEEDS_USER,
|
||||
},
|
||||
|
|
@ -64,7 +64,7 @@ async def login(
|
|||
@router.get(
|
||||
"/current",
|
||||
responses={
|
||||
status.HTTP_200_OK: Responses.OK_NONE,
|
||||
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_USER,
|
||||
|
|
@ -127,7 +127,7 @@ async def add_user(
|
|||
@router.delete(
|
||||
"/{user_name}",
|
||||
responses={
|
||||
status.HTTP_200_OK: Responses.OK_NONE,
|
||||
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_PERMISSION,
|
||||
|
|
@ -189,7 +189,7 @@ async def extend_tags(
|
|||
@router.delete(
|
||||
"/{user_name}/tags",
|
||||
responses={
|
||||
status.HTTP_200_OK: Responses.OK_NONE,
|
||||
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_PERMISSION,
|
||||
|
|
|
|||
Loading…
Reference in a new issue