Write new secret manager using existing RSA logic

This commit is contained in:
2025-06-22 17:17:56 +02:00
parent 5985a726e3
commit 82ec7fabb4
34 changed files with 2042 additions and 640 deletions

View File

@ -5,9 +5,9 @@ import logging
from typing import Annotated
from fastapi import APIRouter, Depends, HTTPException, status
from fastapi.security import OAuth2PasswordRequestForm
from sqlalchemy.orm import Session
from sqlalchemy.ext.asyncio import AsyncSession
from sshecret_admin.auth import Token, authenticate_user, create_access_token
from sshecret_admin.auth import Token, authenticate_user_async, create_access_token
from sshecret_admin.core.dependencies import AdminDependencies
LOG = logging.getLogger(__name__)
@ -19,11 +19,12 @@ def create_router(dependencies: AdminDependencies) -> APIRouter:
@app.post("/token")
async def login_for_access_token(
session: Annotated[Session, Depends(dependencies.get_db_session)],
session: Annotated[AsyncSession, Depends(dependencies.get_async_session)],
form_data: Annotated[OAuth2PasswordRequestForm, Depends()],
) -> Token:
"""Login user and generate token."""
user = authenticate_user(session, form_data.username, form_data.password)
user = await authenticate_user_async(session, form_data.username, form_data.password)
if not user:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,

View File

@ -128,7 +128,7 @@ def create_router(dependencies: AdminDependencies) -> APIRouter:
group = await admin.get_secret_group(group_name)
if not group:
return
await admin.delete_secret_group(group_name, keep_entries=True)
await admin.delete_secret_group(group_name)
@app.post("/secrets/groups/{group_name}/{secret_name}")
async def move_secret_to_group(

View File

@ -5,8 +5,9 @@
import logging
from typing import Annotated
from fastapi import APIRouter, Depends, HTTPException, status
from fastapi import APIRouter, Depends, HTTPException, Request, status
from fastapi.security import OAuth2PasswordBearer
from fastapi.security.utils import get_authorization_scheme_param
from sqlalchemy import select
from sqlalchemy.orm import Session
@ -57,6 +58,31 @@ def create_router(dependencies: BaseDependencies) -> APIRouter:
raise credentials_exception
return user
def get_client_origin(request: Request) -> str:
"""Get client origin."""
fallback_origin = "UNKNOWN"
if request.client:
return request.client.host
return fallback_origin
def get_optional_username(request: Request) -> str | None:
"""Get username, if available.
This is purely used for auditing purposes.
"""
authorization = request.headers.get("Authorization")
scheme, param = get_authorization_scheme_param(authorization)
if not authorization or scheme.lower() != "bearer":
return None
claims = decode_token(dependencies.settings, param)
if not claims:
return None
if claims.provider == LOCAL_ISSUER:
return claims.sub
return f"oidc:{claims.email}"
async def get_current_active_user(
current_user: Annotated[User, Depends(get_current_user)],
) -> User:
@ -66,9 +92,12 @@ def create_router(dependencies: BaseDependencies) -> APIRouter:
return current_user
async def get_admin_backend(
request: Request,
session: Annotated[Session, Depends(dependencies.get_db_session)],
):
"""Get admin backend API."""
username = get_optional_username(request)
origin = get_client_origin(request)
password_db = session.scalars(
select(PasswordDB).where(PasswordDB.id == 1)
).first()
@ -76,7 +105,11 @@ def create_router(dependencies: BaseDependencies) -> APIRouter:
raise HTTPException(
500, detail="Error: The password manager has not yet been set up."
)
admin = AdminBackend(dependencies.settings, password_db.encrypted_password)
admin = AdminBackend(
dependencies.settings,
username=username,
origin=origin,
)
yield admin
app = APIRouter(prefix=f"/api/{API_VERSION}")