From 33c1e7278b29108eed954090671e0db424a80c78 Mon Sep 17 00:00:00 2001 From: Allan Eising Date: Wed, 16 Jul 2025 21:44:20 +0200 Subject: [PATCH] Implement OIDC login --- .../src/sshecret_admin/api/endpoints/auth.py | 107 +++++++++++++++++- .../src/sshecret_admin/auth/models.py | 5 + .../src/sshecret_admin/core/settings.py | 1 + packages/sshecret-frontend/openapi.json | 2 +- .../sshecret-frontend/src/client/sdk.gen.ts | 56 ++++++++- .../sshecret-frontend/src/client/types.gen.ts | 94 +++++++++++++++ .../src/components/auth/OidcCallback.vue | 21 ++++ .../src/components/layout/Navbar.vue | 12 +- .../sshecret-frontend/src/router/index.ts | 8 +- packages/sshecret-frontend/src/store/auth.ts | 36 ++++++ .../sshecret-frontend/src/views/LoginPage.vue | 80 ++++++++----- 11 files changed, 385 insertions(+), 37 deletions(-) create mode 100644 packages/sshecret-frontend/src/components/auth/OidcCallback.vue diff --git a/packages/sshecret-admin/src/sshecret_admin/api/endpoints/auth.py b/packages/sshecret-admin/src/sshecret_admin/api/endpoints/auth.py index 3c3f781..2ca67ec 100644 --- a/packages/sshecret-admin/src/sshecret_admin/api/endpoints/auth.py +++ b/packages/sshecret-admin/src/sshecret_admin/api/endpoints/auth.py @@ -1,14 +1,26 @@ """Authentication related endpoints factory.""" # pyright: reportUnusedFunction=false +import os +from datetime import datetime import logging from typing import Annotated, Literal -from fastapi import APIRouter, Depends, Form, HTTPException, Request, Security, status +from fastapi import ( + APIRouter, + Depends, + Form, + HTTPException, + Request, + Security, + status, +) +from fastapi.responses import RedirectResponse from fastapi.security import OAuth2PasswordRequestForm -from pydantic import BaseModel +from pydantic import BaseModel, ValidationError from sqlalchemy.ext.asyncio import AsyncSession from sshecret_admin.auth import ( + LocalUserInfo, Token, User, authenticate_user_async, @@ -16,8 +28,12 @@ from sshecret_admin.auth import ( create_refresh_token, decode_token, ) -from sshecret_admin.auth.authentication import hash_password +from sshecret_admin.auth.authentication import handle_oidc_claim, hash_password +from sshecret_admin.auth.exceptions import AuthenticationFailedError +from sshecret_admin.auth.models import AuthProvider, LoginInfo +from sshecret_admin.auth.oidc import AdminOidc from sshecret_admin.core.dependencies import AdminDependencies +from sshecret_admin.core.settings import AdminServerSettings from sshecret_admin.services import AdminBackend from sshecret_admin.services.models import UserPasswordChange @@ -37,6 +53,16 @@ def create_router(dependencies: AdminDependencies) -> APIRouter: """Create auth router.""" app = APIRouter() + def get_oidc_client() -> AdminOidc: + """Get OIDC client dependency.""" + if not dependencies.settings.oidc: + raise HTTPException( + status_code=status.HTTP_400_BAD_REQUEST, + detail="OIDC authentication not available.", + ) + oidc = AdminOidc(dependencies.settings.oidc) + return oidc + @app.post("/token") async def login_for_access_token( session: Annotated[AsyncSession, Depends(dependencies.get_async_session)], @@ -122,4 +148,79 @@ def create_router(dependencies: AdminDependencies) -> APIRouter: username=user.username, ) + @app.get("/oidc/login") + async def start_oidc_login( + request: Request, oidc: Annotated[AdminOidc, Depends(get_oidc_client)] + ) -> RedirectResponse: + """Redirect for OIDC login.""" + redirect_url = request.url_for("oidc_callback") + return await oidc.start_auth(request, redirect_url) + + @app.get("/oidc/callback") + async def oidc_callback( + request: Request, + session: Annotated[AsyncSession, Depends(dependencies.get_async_session)], + admin: Annotated[AdminBackend, Depends(dependencies.get_admin_backend)], + oidc: Annotated[AdminOidc, Depends(get_oidc_client)], + ): + """Callback for OIDC auth.""" + try: + claims = await oidc.handle_auth_callback(request) + except AuthenticationFailedError as error: + raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail=error) + except ValidationError as error: + LOG.error("Validation error: %s", error, exc_info=True) + raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail=error) + + # We now have a IdentityClaims object. + # We need to check if this matches an existing user, or we need to create a new one. + + user = await handle_oidc_claim(session, claims) + user.last_login = datetime.now() + session.add(user) + await session.commit() + # Set cookies + token_data: dict[str, str] = {"sub": claims.sub} + access_token = create_access_token( + dependencies.settings, data=token_data, provider=claims.provider + ) + refresh_token = create_refresh_token( + dependencies.settings, data=token_data, provider=claims.provider + ) + + path = f"/auth_cb#access_token={access_token}&refresh_token={refresh_token}" + callback_url = os.path.join(dependencies.settings.frontend_url, path) + origin = "UNKNOWN" + if request.client: + origin = request.client.host + + await admin.write_audit_message( + operation=Operation.LOGIN, + message="Logged in to admin frontend", + origin=origin, + username=user.username, + oidc=claims.provider, + ) + + return RedirectResponse(callback_url) + + @app.get("/users/me") + async def get_current_user( + current_user: Annotated[User, Security(dependencies.get_current_active_user)], + ) -> LocalUserInfo: + """Get information about the user currently logged in.""" + is_local = current_user.provider is AuthProvider.LOCAL + return LocalUserInfo( + id=current_user.id, display_name=current_user.username, local=is_local + ) + + @app.get("/oidc/status") + async def get_auth_info() -> LoginInfo: + """Check if OIDC login is available.""" + if dependencies.settings.oidc: + return LoginInfo( + enabled=True, oidc_provider=dependencies.settings.oidc.name + ) + return LoginInfo(enabled=False) + return app diff --git a/packages/sshecret-admin/src/sshecret_admin/auth/models.py b/packages/sshecret-admin/src/sshecret_admin/auth/models.py index 3fafdd5..4cd63e6 100644 --- a/packages/sshecret-admin/src/sshecret_admin/auth/models.py +++ b/packages/sshecret-admin/src/sshecret_admin/auth/models.py @@ -189,3 +189,8 @@ class LocalUserInfo(BaseModel): local: bool +class LoginInfo(BaseModel): + """Model containing information about login providers.""" + + enabled: bool + oidc_provider: str | None = None diff --git a/packages/sshecret-admin/src/sshecret_admin/core/settings.py b/packages/sshecret-admin/src/sshecret_admin/core/settings.py index 21189ff..8178cfe 100644 --- a/packages/sshecret-admin/src/sshecret_admin/core/settings.py +++ b/packages/sshecret-admin/src/sshecret_admin/core/settings.py @@ -40,6 +40,7 @@ class AdminServerSettings(BaseSettings): password_manager_directory: Path | None = None oidc: OidcSettings | None = None frontend_origin: str = Field(default="*") + frontend_url: str @property def admin_db(self) -> URL: diff --git a/packages/sshecret-frontend/openapi.json b/packages/sshecret-frontend/openapi.json index fcc7072..1669c1a 100644 --- a/packages/sshecret-frontend/openapi.json +++ b/packages/sshecret-frontend/openapi.json @@ -1 +1 @@ -{"openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": {"/health": {"get": {"summary": "Get Health", "description": "Provide simple health check.", "operationId": "get_health_health_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}}}}, "/api/v1/audit/": {"get": {"summary": "Get Audit Log", "description": "Query audit log.", "operationId": "get_audit_log_api_v1_audit__get", "security": [{"OAuth2PasswordBearer": []}], "parameters": [{"name": "subsystem", "in": "query", "required": false, "schema": {"anyOf": [{"$ref": "#/components/schemas/SubSystem"}, {"type": "null"}], "title": "Subsystem"}}, {"name": "operation", "in": "query", "required": false, "schema": {"anyOf": [{"$ref": "#/components/schemas/Operation"}, {"type": "null"}], "title": "Operation"}}, {"name": "client_id", "in": "query", "required": false, "schema": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Client Id"}}, {"name": "client_name", "in": "query", "required": false, "schema": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Client Name"}}, {"name": "secret_id", "in": "query", "required": false, "schema": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Secret Id"}}, {"name": "secret_name", "in": "query", "required": false, "schema": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Secret Name"}}, {"name": "origin", "in": "query", "required": false, "schema": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Origin"}}, {"name": "offset", "in": "query", "required": false, "schema": {"type": "integer", "default": 0, "title": "Offset"}}, {"name": "limit", "in": "query", "required": false, "schema": {"type": "integer", "default": 100, "title": "Limit"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/AuditListResult"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/v1/token": {"post": {"summary": "Login For Access Token", "description": "Login user and generate token.", "operationId": "login_for_access_token_api_v1_token_post", "requestBody": {"content": {"application/x-www-form-urlencoded": {"schema": {"$ref": "#/components/schemas/Body_login_for_access_token_api_v1_token_post"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Token"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/v1/refresh": {"post": {"summary": "Refresh Token", "description": "Refresh access token.", "operationId": "refresh_token_api_v1_refresh_post", "requestBody": {"content": {"application/x-www-form-urlencoded": {"schema": {"$ref": "#/components/schemas/RefreshTokenForm"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Token"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/v1/password": {"post": {"summary": "Change Password", "description": "Change user password", "operationId": "change_password_api_v1_password_post", "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/UserPasswordChange"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"OAuth2PasswordBearer": []}]}}, "/api/v1/clients/": {"get": {"summary": "Get Clients", "description": "Get clients.", "operationId": "get_clients_api_v1_clients__get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"items": {"$ref": "#/components/schemas/Client"}, "type": "array", "title": "Response Get Clients Api V1 Clients Get"}}}}}, "security": [{"OAuth2PasswordBearer": []}]}, "post": {"summary": "Create Client", "description": "Create a new client.", "operationId": "create_client_api_v1_clients__post", "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/ClientCreate"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Client"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"OAuth2PasswordBearer": []}]}}, "/api/v1/clients/terse/": {"get": {"summary": "Get Clients Terse", "description": "Get a list of client ids and names.", "operationId": "get_clients_terse_api_v1_clients_terse__get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"items": {"$ref": "#/components/schemas/ClientReference"}, "type": "array", "title": "Response Get Clients Terse Api V1 Clients Terse Get"}}}}}, "security": [{"OAuth2PasswordBearer": []}]}}, "/api/v1/query/clients/": {"get": {"summary": "Query Clients", "description": "Query clients.", "operationId": "query_clients_api_v1_query_clients__get", "security": [{"OAuth2PasswordBearer": []}], "parameters": [{"name": "limit", "in": "query", "required": false, "schema": {"type": "integer", "maximum": 100, "exclusiveMinimum": 0, "default": 100, "title": "Limit"}}, {"name": "offset", "in": "query", "required": false, "schema": {"type": "integer", "minimum": 0, "default": 0, "title": "Offset"}}, {"name": "id", "in": "query", "required": false, "schema": {"anyOf": [{"type": "string", "format": "uuid"}, {"type": "null"}], "title": "Id"}}, {"name": "name", "in": "query", "required": false, "schema": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Name"}}, {"name": "name__like", "in": "query", "required": false, "schema": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Name Like"}}, {"name": "name__contains", "in": "query", "required": false, "schema": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Name Contains"}}, {"name": "order_by", "in": "query", "required": false, "schema": {"type": "string", "default": "created_at", "title": "Order By"}}, {"name": "order_reverse", "in": "query", "required": false, "schema": {"type": "boolean", "default": true, "title": "Order Reverse"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ClientQueryResult"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/v1/clients/{id}": {"get": {"summary": "Get Client", "description": "Get a client.", "operationId": "get_client_api_v1_clients__id__get", "security": [{"OAuth2PasswordBearer": []}], "parameters": [{"name": "id", "in": "path", "required": true, "schema": {"type": "string", "title": "Client identifier", "description": "Identifier of path, may include the prefix 'id:' or 'name:'", "examples": ["name:myclient", "id:8eab15a4-a8eb-4d1b-b47f-2283b9f6f6b0"]}, "description": "Identifier of path, may include the prefix 'id:' or 'name:'"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Client"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}, "put": {"summary": "Update Client", "description": "Update a client.", "operationId": "update_client_api_v1_clients__id__put", "security": [{"OAuth2PasswordBearer": []}], "parameters": [{"name": "id", "in": "path", "required": true, "schema": {"type": "string", "title": "Client identifier", "description": "Identifier of path, may include the prefix 'id:' or 'name:'", "examples": ["name:myclient", "id:8eab15a4-a8eb-4d1b-b47f-2283b9f6f6b0"]}, "description": "Identifier of path, may include the prefix 'id:' or 'name:'"}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ClientCreate"}}}}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Client"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}, "delete": {"summary": "Delete Client", "description": "Delete a client.", "operationId": "delete_client_api_v1_clients__id__delete", "security": [{"OAuth2PasswordBearer": []}], "parameters": [{"name": "id", "in": "path", "required": true, "schema": {"type": "string", "title": "Client identifier", "description": "Identifier of path, may include the prefix 'id:' or 'name:'", "examples": ["name:myclient", "id:8eab15a4-a8eb-4d1b-b47f-2283b9f6f6b0"]}, "description": "Identifier of path, may include the prefix 'id:' or 'name:'"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/v1/clients/{id}/secrets/{secret_name}": {"delete": {"summary": "Delete Secret From Client", "description": "Delete a secret from a client.", "operationId": "delete_secret_from_client_api_v1_clients__id__secrets__secret_name__delete", "security": [{"OAuth2PasswordBearer": []}], "parameters": [{"name": "id", "in": "path", "required": true, "schema": {"type": "string", "title": "Client identifier", "description": "Identifier of path, may include the prefix 'id:' or 'name:'", "examples": ["name:myclient", "id:8eab15a4-a8eb-4d1b-b47f-2283b9f6f6b0"]}, "description": "Identifier of path, may include the prefix 'id:' or 'name:'"}, {"name": "secret_name", "in": "path", "required": true, "schema": {"type": "string", "title": "Secret Name"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}, "put": {"summary": "Add Secret To Client", "description": "Add secret to a client.", "operationId": "add_secret_to_client_api_v1_clients__id__secrets__secret_name__put", "security": [{"OAuth2PasswordBearer": []}], "parameters": [{"name": "id", "in": "path", "required": true, "schema": {"type": "string", "title": "Client identifier", "description": "Identifier of path, may include the prefix 'id:' or 'name:'", "examples": ["name:myclient", "id:8eab15a4-a8eb-4d1b-b47f-2283b9f6f6b0"]}, "description": "Identifier of path, may include the prefix 'id:' or 'name:'"}, {"name": "secret_name", "in": "path", "required": true, "schema": {"type": "string", "title": "Secret Name"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/v1/clients/{id}/policies": {"put": {"summary": "Update Client Policies", "description": "Update the client access policies.", "operationId": "update_client_policies_api_v1_clients__id__policies_put", "security": [{"OAuth2PasswordBearer": []}], "parameters": [{"name": "id", "in": "path", "required": true, "schema": {"type": "string", "title": "Id"}}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/UpdatePoliciesRequest"}}}}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Client"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/v1/clients/{id}/public-key": {"put": {"summary": "Update Client Public Key", "description": "Update client public key.\n\nUpdating the public key will invalidate the current secrets, so these well\nbe resolved first, and re-encrypted using the new key.", "operationId": "update_client_public_key_api_v1_clients__id__public_key_put", "security": [{"OAuth2PasswordBearer": []}], "parameters": [{"name": "id", "in": "path", "required": true, "schema": {"type": "string", "title": "Client identifier", "description": "Identifier of path, may include the prefix 'id:' or 'name:'", "examples": ["name:myclient", "id:8eab15a4-a8eb-4d1b-b47f-2283b9f6f6b0"]}, "description": "Identifier of path, may include the prefix 'id:' or 'name:'"}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/UpdateKeyModel"}}}}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/UpdateKeyResponse"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/v1/stats": {"get": {"summary": "Get System Stats", "description": "Get system stats.", "operationId": "get_system_stats_api_v1_stats_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SystemStats"}}}}}, "security": [{"OAuth2PasswordBearer": []}]}}, "/api/v1/secrets/": {"get": {"summary": "Get Secret Names", "description": "Get Secret Names.", "operationId": "get_secret_names_api_v1_secrets__get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"items": {"$ref": "#/components/schemas/SecretListView"}, "type": "array", "title": "Response Get Secret Names Api V1 Secrets Get"}}}}}, "security": [{"OAuth2PasswordBearer": []}]}, "post": {"summary": "Add Secret", "description": "Create a secret.", "operationId": "add_secret_api_v1_secrets__post", "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/SecretCreate"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"OAuth2PasswordBearer": []}]}}, "/api/v1/secrets/{name}": {"get": {"summary": "Get Secret", "description": "Get a secret.", "operationId": "get_secret_api_v1_secrets__name__get", "security": [{"OAuth2PasswordBearer": []}], "parameters": [{"name": "name", "in": "path", "required": true, "schema": {"type": "string", "title": "Name"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SecretView"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}, "put": {"summary": "Update Secret", "operationId": "update_secret_api_v1_secrets__name__put", "security": [{"OAuth2PasswordBearer": []}], "parameters": [{"name": "name", "in": "path", "required": true, "schema": {"type": "string", "title": "Name"}}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SecretUpdate"}}}}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}, "delete": {"summary": "Delete Secret", "description": "Delete secret.", "operationId": "delete_secret_api_v1_secrets__name__delete", "security": [{"OAuth2PasswordBearer": []}], "parameters": [{"name": "name", "in": "path", "required": true, "schema": {"type": "string", "title": "Name"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/v1/secrets/groups/": {"get": {"summary": "Get Secret Groups", "description": "Get secret groups.", "operationId": "get_secret_groups_api_v1_secrets_groups__get", "security": [{"OAuth2PasswordBearer": []}], "parameters": [{"name": "filter_regex", "in": "query", "required": false, "schema": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Filter Regex"}}, {"name": "flat", "in": "query", "required": false, "schema": {"type": "boolean", "default": false, "title": "Flat"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ClientSecretGroupList"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}, "post": {"summary": "Add Secret Group", "description": "Create a secret grouping.", "operationId": "add_secret_group_api_v1_secrets_groups__post", "security": [{"OAuth2PasswordBearer": []}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SecretGroupCreate"}}}}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ClientSecretGroup"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/v1/secrets/groups/{group_path}/": {"get": {"summary": "Get Secret Group", "description": "Get a specific secret group.", "operationId": "get_secret_group_api_v1_secrets_groups__group_path___get", "security": [{"OAuth2PasswordBearer": []}], "parameters": [{"name": "group_path", "in": "path", "required": true, "schema": {"type": "string", "title": "Group Path"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ClientSecretGroup"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}, "put": {"summary": "Update Secret Group", "description": "Update a secret group.", "operationId": "update_secret_group_api_v1_secrets_groups__group_path___put", "security": [{"OAuth2PasswordBearer": []}], "parameters": [{"name": "group_path", "in": "path", "required": true, "schema": {"type": "string", "title": "Group Path"}}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SecretGroupUdate"}}}}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ClientSecretGroup"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}, "delete": {"summary": "Delete Secret Group", "description": "Remove a group.\n\nEntries within the group will be moved to the root.\nThis also includes nested entries further down from the group.", "operationId": "delete_secret_group_api_v1_secrets_groups__group_path___delete", "security": [{"OAuth2PasswordBearer": []}], "parameters": [{"name": "group_path", "in": "path", "required": true, "schema": {"type": "string", "title": "Group Path"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/v1/secrets/group/{id}": {"delete": {"summary": "Delete Group Id", "description": "Remove a group by ID.", "operationId": "delete_group_id_api_v1_secrets_group__id__delete", "security": [{"OAuth2PasswordBearer": []}], "parameters": [{"name": "id", "in": "path", "required": true, "schema": {"type": "string", "title": "Id"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/v1/secrets/set-group": {"post": {"summary": "Assign Secret Group", "description": "Assign a secret to a group or root.", "operationId": "assign_secret_group_api_v1_secrets_set_group_post", "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/SecretGroupAssign"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"OAuth2PasswordBearer": []}]}}, "/api/v1/secrets/move-group/{group_name}": {"post": {"summary": "Move Group", "description": "Move a group.", "operationId": "move_group_api_v1_secrets_move_group__group_name__post", "security": [{"OAuth2PasswordBearer": []}], "parameters": [{"name": "group_name", "in": "path", "required": true, "schema": {"type": "string", "title": "Group Name"}}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GroupPath"}}}}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}}, "components": {"schemas": {"AuditListResult": {"properties": {"results": {"items": {"$ref": "#/components/schemas/AuditLog"}, "type": "array", "title": "Results"}, "total": {"type": "integer", "title": "Total"}, "remaining": {"type": "integer", "title": "Remaining"}}, "type": "object", "required": ["results", "total", "remaining"], "title": "AuditListResult", "description": "Class to return when listing audit entries."}, "AuditLog": {"properties": {"id": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Id"}, "subsystem": {"$ref": "#/components/schemas/SubSystem"}, "operation": {"$ref": "#/components/schemas/Operation"}, "client_id": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Client Id"}, "client_name": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Client Name"}, "secret_id": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Secret Id"}, "secret_name": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Secret Name"}, "data": {"anyOf": [{"additionalProperties": {"type": "string"}, "type": "object"}, {"type": "null"}], "title": "Data"}, "message": {"type": "string", "title": "Message"}, "origin": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Origin"}, "timestamp": {"anyOf": [{"type": "string", "format": "date-time"}, {"type": "null"}], "title": "Timestamp"}}, "type": "object", "required": ["subsystem", "operation", "message"], "title": "AuditLog", "description": "Implementation of the backend class AuditView."}, "AutoGenerateOpts": {"properties": {"auto_generate": {"type": "boolean", "const": true, "title": "Auto Generate"}, "length": {"type": "integer", "title": "Length", "default": 32}}, "type": "object", "required": ["auto_generate"], "title": "AutoGenerateOpts", "description": "Option to auto-generate a password."}, "Body_login_for_access_token_api_v1_token_post": {"properties": {"grant_type": {"anyOf": [{"type": "string", "pattern": "^password$"}, {"type": "null"}], "title": "Grant Type"}, "username": {"type": "string", "title": "Username"}, "password": {"type": "string", "format": "password", "title": "Password"}, "scope": {"type": "string", "title": "Scope", "default": ""}, "client_id": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Client Id"}, "client_secret": {"anyOf": [{"type": "string"}, {"type": "null"}], "format": "password", "title": "Client Secret"}}, "type": "object", "required": ["username", "password"], "title": "Body_login_for_access_token_api_v1_token_post"}, "Client": {"properties": {"id": {"type": "string", "format": "uuid", "title": "Id"}, "name": {"type": "string", "title": "Name"}, "description": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Description"}, "public_key": {"type": "string", "title": "Public Key"}, "version": {"type": "integer", "title": "Version"}, "is_active": {"type": "boolean", "title": "Is Active"}, "is_deleted": {"type": "boolean", "title": "Is Deleted"}, "secrets": {"items": {"type": "string"}, "type": "array", "title": "Secrets"}, "policies": {"items": {"anyOf": [{"type": "string", "format": "ipvanynetwork"}, {"type": "string", "format": "ipvanyaddress"}]}, "type": "array", "title": "Policies"}, "created_at": {"type": "string", "format": "date-time", "title": "Created At"}, "updated_at": {"anyOf": [{"type": "string", "format": "date-time"}, {"type": "null"}], "title": "Updated At"}, "deleted_at": {"anyOf": [{"type": "string", "format": "date-time"}, {"type": "null"}], "title": "Deleted At"}}, "type": "object", "required": ["id", "name", "description", "public_key", "version", "is_active", "is_deleted", "secrets", "policies", "created_at", "updated_at", "deleted_at"], "title": "Client", "description": "Implementation of the backend class ClientView."}, "ClientCreate": {"properties": {"name": {"type": "string", "title": "Name"}, "description": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Description"}, "public_key": {"type": "string", "title": "Public Key"}, "sources": {"items": {"anyOf": [{"type": "string", "format": "ipvanyaddress"}, {"type": "string", "format": "ipvanynetwork"}]}, "type": "array", "title": "Sources"}}, "type": "object", "required": ["name", "public_key"], "title": "ClientCreate", "description": "Model to create a client."}, "ClientQueryResult": {"properties": {"clients": {"items": {"$ref": "#/components/schemas/Client"}, "type": "array", "title": "Clients"}, "total_results": {"type": "integer", "title": "Total Results"}, "remaining_results": {"type": "integer", "title": "Remaining Results"}}, "type": "object", "required": ["clients", "total_results", "remaining_results"], "title": "ClientQueryResult", "description": "Implementation of the backend ClientQueryResult class."}, "ClientReference": {"properties": {"id": {"type": "string", "title": "Id"}, "name": {"type": "string", "title": "Name"}}, "type": "object", "required": ["id", "name"], "title": "ClientReference", "description": "Implementation of the backend class ClientReference."}, "ClientSecretGroup": {"properties": {"id": {"type": "string", "format": "uuid", "title": "Id"}, "group_name": {"type": "string", "title": "Group Name"}, "path": {"type": "string", "title": "Path"}, "description": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Description"}, "parent_group": {"anyOf": [{"$ref": "#/components/schemas/GroupReference"}, {"type": "null"}]}, "children": {"items": {"$ref": "#/components/schemas/ClientSecretGroup"}, "type": "array", "title": "Children"}, "entries": {"items": {"$ref": "#/components/schemas/SecretClientMapping"}, "type": "array", "title": "Entries"}}, "type": "object", "required": ["id", "group_name", "path"], "title": "ClientSecretGroup", "description": "Client secrets grouped."}, "ClientSecretGroupList": {"properties": {"ungrouped": {"items": {"$ref": "#/components/schemas/SecretClientMapping"}, "type": "array", "title": "Ungrouped"}, "groups": {"items": {"$ref": "#/components/schemas/ClientSecretGroup"}, "type": "array", "title": "Groups"}}, "type": "object", "title": "ClientSecretGroupList", "description": "Secret group list."}, "GroupPath": {"properties": {"path": {"type": "string", "pattern": "^/.*", "title": "Path"}}, "type": "object", "required": ["path"], "title": "GroupPath", "description": "Path to a group."}, "GroupReference": {"properties": {"group_name": {"type": "string", "title": "Group Name"}, "path": {"type": "string", "title": "Path"}}, "type": "object", "required": ["group_name", "path"], "title": "GroupReference", "description": "Reference to a group.\n\nThis will be used for references to parent groups to avoid circular\nreferences."}, "HTTPValidationError": {"properties": {"detail": {"items": {"$ref": "#/components/schemas/ValidationError"}, "type": "array", "title": "Detail"}}, "type": "object", "title": "HTTPValidationError"}, "Operation": {"type": "string", "enum": ["create", "read", "update", "delete", "deny", "permit", "login", "none"], "title": "Operation", "description": "Various operations for the audit logging module."}, "RefreshTokenForm": {"properties": {"grant_type": {"type": "string", "const": "refresh_token", "title": "Grant Type"}, "refresh_token": {"type": "string", "title": "Refresh Token"}}, "type": "object", "required": ["grant_type", "refresh_token"], "title": "RefreshTokenForm", "description": "The refresh token form data."}, "SecretClientMapping": {"properties": {"name": {"type": "string", "title": "Name"}, "unmanaged": {"type": "boolean", "title": "Unmanaged", "default": false}, "clients": {"items": {"$ref": "#/components/schemas/ClientReference"}, "type": "array", "title": "Clients"}}, "type": "object", "required": ["name"], "title": "SecretClientMapping", "description": "Secret name with list of clients."}, "SecretCreate": {"properties": {"value": {"anyOf": [{"type": "string"}, {"$ref": "#/components/schemas/AutoGenerateOpts"}], "title": "Value", "description": "Secret as string value or auto-generated with optional length", "examples": ["MySecretString", {"auto_generate": true, "length": 32}]}, "name": {"type": "string", "title": "Name"}, "clients": {"anyOf": [{"items": {"type": "string"}, "type": "array"}, {"type": "null"}], "title": "Clients", "description": "Assign the secret to a list of clients."}, "client_distinguisher": {"type": "string", "enum": ["id", "name"], "title": "Client Distinguisher", "default": "name"}, "group": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Group"}}, "type": "object", "required": ["value", "name"], "title": "SecretCreate", "description": "Model to create a secret.", "examples": [{"clients": ["client-1", "client-2"], "name": "MySecret", "value": {"auto_generate": true, "length": 32}}, {"group": "MySecretGroup", "name": "MySecret", "value": "mysecretstring"}]}, "SecretGroupAssign": {"properties": {"secret_name": {"type": "string", "title": "Secret Name"}, "group_path": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Group Path"}}, "type": "object", "required": ["secret_name", "group_path"], "title": "SecretGroupAssign", "description": "Model for assigning secrets to a group.\n\nIf group is None, then it will be placed in the root."}, "SecretGroupCreate": {"properties": {"name": {"type": "string", "minLength": 1, "title": "Name"}, "description": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Description"}, "parent_group": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Parent Group"}}, "type": "object", "required": ["name"], "title": "SecretGroupCreate", "description": "Create model for creating secret groups."}, "SecretGroupUdate": {"properties": {"name": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Name"}, "description": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Description"}, "parent_group": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Parent Group"}}, "type": "object", "title": "SecretGroupUdate", "description": "Update model for updating secret groups."}, "SecretListView": {"properties": {"name": {"type": "string", "title": "Name"}, "unmanaged": {"type": "boolean", "title": "Unmanaged", "default": false}, "clients": {"items": {"type": "string"}, "type": "array", "title": "Clients"}}, "type": "object", "required": ["name"], "title": "SecretListView", "description": "Model containing a list of all available secrets."}, "SecretUpdate": {"properties": {"value": {"anyOf": [{"type": "string"}, {"$ref": "#/components/schemas/AutoGenerateOpts"}], "title": "Value", "description": "Secret as string value or auto-generated with optional length", "examples": ["MySecretString", {"auto_generate": true, "length": 32}]}}, "type": "object", "required": ["value"], "title": "SecretUpdate", "description": "Model to update a secret."}, "SecretView": {"properties": {"name": {"type": "string", "title": "Name"}, "secret": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Secret"}, "group": {"anyOf": [{"$ref": "#/components/schemas/GroupReference"}, {"type": "null"}]}, "clients": {"items": {"$ref": "#/components/schemas/ClientReference"}, "type": "array", "title": "Clients"}}, "type": "object", "required": ["name", "secret"], "title": "SecretView", "description": "Model containing a secret, including its clear-text value."}, "SubSystem": {"type": "string", "enum": ["admin", "sshd", "backend"], "title": "SubSystem", "description": "Available subsystems."}, "SystemStats": {"properties": {"clients": {"type": "integer", "title": "Clients"}, "secrets": {"type": "integer", "title": "Secrets"}, "audit_events": {"type": "integer", "title": "Audit Events"}}, "type": "object", "required": ["clients", "secrets", "audit_events"], "title": "SystemStats", "description": "Generic system stats."}, "Token": {"properties": {"access_token": {"type": "string", "title": "Access Token"}, "refresh_token": {"type": "string", "title": "Refresh Token"}, "token_type": {"type": "string", "title": "Token Type"}}, "type": "object", "required": ["access_token", "refresh_token", "token_type"], "title": "Token"}, "UpdateKeyModel": {"properties": {"public_key": {"type": "string", "title": "Public Key"}}, "type": "object", "required": ["public_key"], "title": "UpdateKeyModel", "description": "Model for updating client public key."}, "UpdateKeyResponse": {"properties": {"public_key": {"type": "string", "title": "Public Key"}, "updated_secrets": {"items": {"type": "string"}, "type": "array", "title": "Updated Secrets"}, "detail": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Detail"}}, "type": "object", "required": ["public_key"], "title": "UpdateKeyResponse", "description": "Response model after updating the public key."}, "UpdatePoliciesRequest": {"properties": {"sources": {"items": {"anyOf": [{"type": "string", "format": "ipvanyaddress"}, {"type": "string", "format": "ipvanynetwork"}]}, "type": "array", "title": "Sources"}}, "type": "object", "required": ["sources"], "title": "UpdatePoliciesRequest", "description": "Update policy request."}, "UserPasswordChange": {"properties": {"current_password": {"type": "string", "title": "Current Password"}, "new_password": {"type": "string", "title": "New Password"}, "new_password_confirm": {"type": "string", "title": "New Password Confirm"}}, "type": "object", "required": ["current_password", "new_password", "new_password_confirm"], "title": "UserPasswordChange", "description": "Model for changing the password of a user."}, "ValidationError": {"properties": {"loc": {"items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, "type": "array", "title": "Location"}, "msg": {"type": "string", "title": "Message"}, "type": {"type": "string", "title": "Error Type"}}, "type": "object", "required": ["loc", "msg", "type"], "title": "ValidationError"}}, "securitySchemes": {"OAuth2PasswordBearer": {"type": "oauth2", "flows": {"password": {"refreshUrl": "/api/v1/refresh", "scopes": {}, "tokenUrl": "/api/v1/token"}}}}}} \ No newline at end of file +{"openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": {"/health": {"get": {"summary": "Get Health", "description": "Provide simple health check.", "operationId": "get_health_health_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}}}}, "/api/v1/audit/": {"get": {"summary": "Get Audit Log", "description": "Query audit log.", "operationId": "get_audit_log_api_v1_audit__get", "security": [{"OAuth2PasswordBearer": []}], "parameters": [{"name": "subsystem", "in": "query", "required": false, "schema": {"anyOf": [{"$ref": "#/components/schemas/SubSystem"}, {"type": "null"}], "title": "Subsystem"}}, {"name": "operation", "in": "query", "required": false, "schema": {"anyOf": [{"$ref": "#/components/schemas/Operation"}, {"type": "null"}], "title": "Operation"}}, {"name": "client_id", "in": "query", "required": false, "schema": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Client Id"}}, {"name": "client_name", "in": "query", "required": false, "schema": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Client Name"}}, {"name": "secret_id", "in": "query", "required": false, "schema": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Secret Id"}}, {"name": "secret_name", "in": "query", "required": false, "schema": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Secret Name"}}, {"name": "origin", "in": "query", "required": false, "schema": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Origin"}}, {"name": "offset", "in": "query", "required": false, "schema": {"type": "integer", "default": 0, "title": "Offset"}}, {"name": "limit", "in": "query", "required": false, "schema": {"type": "integer", "default": 100, "title": "Limit"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/AuditListResult"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/v1/token": {"post": {"summary": "Login For Access Token", "description": "Login user and generate token.", "operationId": "login_for_access_token_api_v1_token_post", "requestBody": {"content": {"application/x-www-form-urlencoded": {"schema": {"$ref": "#/components/schemas/Body_login_for_access_token_api_v1_token_post"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Token"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/v1/refresh": {"post": {"summary": "Refresh Token", "description": "Refresh access token.", "operationId": "refresh_token_api_v1_refresh_post", "requestBody": {"content": {"application/x-www-form-urlencoded": {"schema": {"$ref": "#/components/schemas/RefreshTokenForm"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Token"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/v1/password": {"post": {"summary": "Change Password", "description": "Change user password", "operationId": "change_password_api_v1_password_post", "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/UserPasswordChange"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"OAuth2PasswordBearer": []}]}}, "/api/v1/oidc/login": {"get": {"summary": "Start Oidc Login", "description": "Redirect for OIDC login.", "operationId": "start_oidc_login_api_v1_oidc_login_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}}}}, "/api/v1/oidc/callback": {"get": {"summary": "Oidc Callback", "description": "Callback for OIDC auth.", "operationId": "oidc_callback_api_v1_oidc_callback_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}}}}, "/api/v1/users/me": {"get": {"summary": "Get Current User", "description": "Get information about the user currently logged in.", "operationId": "get_current_user_api_v1_users_me_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/LocalUserInfo"}}}}}, "security": [{"OAuth2PasswordBearer": []}]}}, "/api/v1/oidc/status": {"get": {"summary": "Get Auth Info", "description": "Check if OIDC login is available.", "operationId": "get_auth_info_api_v1_oidc_status_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/LoginInfo"}}}}}}}, "/api/v1/clients/": {"get": {"summary": "Get Clients", "description": "Get clients.", "operationId": "get_clients_api_v1_clients__get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"items": {"$ref": "#/components/schemas/Client"}, "type": "array", "title": "Response Get Clients Api V1 Clients Get"}}}}}, "security": [{"OAuth2PasswordBearer": []}]}, "post": {"summary": "Create Client", "description": "Create a new client.", "operationId": "create_client_api_v1_clients__post", "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/ClientCreate"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Client"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"OAuth2PasswordBearer": []}]}}, "/api/v1/clients/terse/": {"get": {"summary": "Get Clients Terse", "description": "Get a list of client ids and names.", "operationId": "get_clients_terse_api_v1_clients_terse__get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"items": {"$ref": "#/components/schemas/ClientReference"}, "type": "array", "title": "Response Get Clients Terse Api V1 Clients Terse Get"}}}}}, "security": [{"OAuth2PasswordBearer": []}]}}, "/api/v1/query/clients/": {"get": {"summary": "Query Clients", "description": "Query clients.", "operationId": "query_clients_api_v1_query_clients__get", "security": [{"OAuth2PasswordBearer": []}], "parameters": [{"name": "limit", "in": "query", "required": false, "schema": {"type": "integer", "maximum": 100, "exclusiveMinimum": 0, "default": 100, "title": "Limit"}}, {"name": "offset", "in": "query", "required": false, "schema": {"type": "integer", "minimum": 0, "default": 0, "title": "Offset"}}, {"name": "id", "in": "query", "required": false, "schema": {"anyOf": [{"type": "string", "format": "uuid"}, {"type": "null"}], "title": "Id"}}, {"name": "name", "in": "query", "required": false, "schema": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Name"}}, {"name": "name__like", "in": "query", "required": false, "schema": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Name Like"}}, {"name": "name__contains", "in": "query", "required": false, "schema": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Name Contains"}}, {"name": "order_by", "in": "query", "required": false, "schema": {"type": "string", "default": "created_at", "title": "Order By"}}, {"name": "order_reverse", "in": "query", "required": false, "schema": {"type": "boolean", "default": true, "title": "Order Reverse"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ClientQueryResult"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/v1/clients/{id}": {"get": {"summary": "Get Client", "description": "Get a client.", "operationId": "get_client_api_v1_clients__id__get", "security": [{"OAuth2PasswordBearer": []}], "parameters": [{"name": "id", "in": "path", "required": true, "schema": {"type": "string", "title": "Client identifier", "description": "Identifier of path, may include the prefix 'id:' or 'name:'", "examples": ["name:myclient", "id:8eab15a4-a8eb-4d1b-b47f-2283b9f6f6b0"]}, "description": "Identifier of path, may include the prefix 'id:' or 'name:'"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Client"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}, "put": {"summary": "Update Client", "description": "Update a client.", "operationId": "update_client_api_v1_clients__id__put", "security": [{"OAuth2PasswordBearer": []}], "parameters": [{"name": "id", "in": "path", "required": true, "schema": {"type": "string", "title": "Client identifier", "description": "Identifier of path, may include the prefix 'id:' or 'name:'", "examples": ["name:myclient", "id:8eab15a4-a8eb-4d1b-b47f-2283b9f6f6b0"]}, "description": "Identifier of path, may include the prefix 'id:' or 'name:'"}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ClientCreate"}}}}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Client"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}, "delete": {"summary": "Delete Client", "description": "Delete a client.", "operationId": "delete_client_api_v1_clients__id__delete", "security": [{"OAuth2PasswordBearer": []}], "parameters": [{"name": "id", "in": "path", "required": true, "schema": {"type": "string", "title": "Client identifier", "description": "Identifier of path, may include the prefix 'id:' or 'name:'", "examples": ["name:myclient", "id:8eab15a4-a8eb-4d1b-b47f-2283b9f6f6b0"]}, "description": "Identifier of path, may include the prefix 'id:' or 'name:'"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/v1/clients/{id}/secrets/{secret_name}": {"delete": {"summary": "Delete Secret From Client", "description": "Delete a secret from a client.", "operationId": "delete_secret_from_client_api_v1_clients__id__secrets__secret_name__delete", "security": [{"OAuth2PasswordBearer": []}], "parameters": [{"name": "id", "in": "path", "required": true, "schema": {"type": "string", "title": "Client identifier", "description": "Identifier of path, may include the prefix 'id:' or 'name:'", "examples": ["name:myclient", "id:8eab15a4-a8eb-4d1b-b47f-2283b9f6f6b0"]}, "description": "Identifier of path, may include the prefix 'id:' or 'name:'"}, {"name": "secret_name", "in": "path", "required": true, "schema": {"type": "string", "title": "Secret Name"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}, "put": {"summary": "Add Secret To Client", "description": "Add secret to a client.", "operationId": "add_secret_to_client_api_v1_clients__id__secrets__secret_name__put", "security": [{"OAuth2PasswordBearer": []}], "parameters": [{"name": "id", "in": "path", "required": true, "schema": {"type": "string", "title": "Client identifier", "description": "Identifier of path, may include the prefix 'id:' or 'name:'", "examples": ["name:myclient", "id:8eab15a4-a8eb-4d1b-b47f-2283b9f6f6b0"]}, "description": "Identifier of path, may include the prefix 'id:' or 'name:'"}, {"name": "secret_name", "in": "path", "required": true, "schema": {"type": "string", "title": "Secret Name"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/v1/clients/{id}/policies": {"put": {"summary": "Update Client Policies", "description": "Update the client access policies.", "operationId": "update_client_policies_api_v1_clients__id__policies_put", "security": [{"OAuth2PasswordBearer": []}], "parameters": [{"name": "id", "in": "path", "required": true, "schema": {"type": "string", "title": "Id"}}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/UpdatePoliciesRequest"}}}}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Client"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/v1/clients/{id}/public-key": {"put": {"summary": "Update Client Public Key", "description": "Update client public key.\n\nUpdating the public key will invalidate the current secrets, so these well\nbe resolved first, and re-encrypted using the new key.", "operationId": "update_client_public_key_api_v1_clients__id__public_key_put", "security": [{"OAuth2PasswordBearer": []}], "parameters": [{"name": "id", "in": "path", "required": true, "schema": {"type": "string", "title": "Client identifier", "description": "Identifier of path, may include the prefix 'id:' or 'name:'", "examples": ["name:myclient", "id:8eab15a4-a8eb-4d1b-b47f-2283b9f6f6b0"]}, "description": "Identifier of path, may include the prefix 'id:' or 'name:'"}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/UpdateKeyModel"}}}}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/UpdateKeyResponse"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/v1/stats": {"get": {"summary": "Get System Stats", "description": "Get system stats.", "operationId": "get_system_stats_api_v1_stats_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SystemStats"}}}}}, "security": [{"OAuth2PasswordBearer": []}]}}, "/api/v1/secrets/": {"get": {"summary": "Get Secret Names", "description": "Get Secret Names.", "operationId": "get_secret_names_api_v1_secrets__get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"items": {"$ref": "#/components/schemas/SecretListView"}, "type": "array", "title": "Response Get Secret Names Api V1 Secrets Get"}}}}}, "security": [{"OAuth2PasswordBearer": []}]}, "post": {"summary": "Add Secret", "description": "Create a secret.", "operationId": "add_secret_api_v1_secrets__post", "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/SecretCreate"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"OAuth2PasswordBearer": []}]}}, "/api/v1/secrets/{name}": {"get": {"summary": "Get Secret", "description": "Get a secret.", "operationId": "get_secret_api_v1_secrets__name__get", "security": [{"OAuth2PasswordBearer": []}], "parameters": [{"name": "name", "in": "path", "required": true, "schema": {"type": "string", "title": "Name"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SecretView"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}, "put": {"summary": "Update Secret", "operationId": "update_secret_api_v1_secrets__name__put", "security": [{"OAuth2PasswordBearer": []}], "parameters": [{"name": "name", "in": "path", "required": true, "schema": {"type": "string", "title": "Name"}}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SecretUpdate"}}}}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}, "delete": {"summary": "Delete Secret", "description": "Delete secret.", "operationId": "delete_secret_api_v1_secrets__name__delete", "security": [{"OAuth2PasswordBearer": []}], "parameters": [{"name": "name", "in": "path", "required": true, "schema": {"type": "string", "title": "Name"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/v1/secrets/groups/": {"get": {"summary": "Get Secret Groups", "description": "Get secret groups.", "operationId": "get_secret_groups_api_v1_secrets_groups__get", "security": [{"OAuth2PasswordBearer": []}], "parameters": [{"name": "filter_regex", "in": "query", "required": false, "schema": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Filter Regex"}}, {"name": "flat", "in": "query", "required": false, "schema": {"type": "boolean", "default": false, "title": "Flat"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ClientSecretGroupList"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}, "post": {"summary": "Add Secret Group", "description": "Create a secret grouping.", "operationId": "add_secret_group_api_v1_secrets_groups__post", "security": [{"OAuth2PasswordBearer": []}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SecretGroupCreate"}}}}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ClientSecretGroup"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/v1/secrets/groups/{group_path}/": {"get": {"summary": "Get Secret Group", "description": "Get a specific secret group.", "operationId": "get_secret_group_api_v1_secrets_groups__group_path___get", "security": [{"OAuth2PasswordBearer": []}], "parameters": [{"name": "group_path", "in": "path", "required": true, "schema": {"type": "string", "title": "Group Path"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ClientSecretGroup"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}, "put": {"summary": "Update Secret Group", "description": "Update a secret group.", "operationId": "update_secret_group_api_v1_secrets_groups__group_path___put", "security": [{"OAuth2PasswordBearer": []}], "parameters": [{"name": "group_path", "in": "path", "required": true, "schema": {"type": "string", "title": "Group Path"}}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SecretGroupUdate"}}}}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ClientSecretGroup"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}, "delete": {"summary": "Delete Secret Group", "description": "Remove a group.\n\nEntries within the group will be moved to the root.\nThis also includes nested entries further down from the group.", "operationId": "delete_secret_group_api_v1_secrets_groups__group_path___delete", "security": [{"OAuth2PasswordBearer": []}], "parameters": [{"name": "group_path", "in": "path", "required": true, "schema": {"type": "string", "title": "Group Path"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/v1/secrets/group/{id}": {"delete": {"summary": "Delete Group Id", "description": "Remove a group by ID.", "operationId": "delete_group_id_api_v1_secrets_group__id__delete", "security": [{"OAuth2PasswordBearer": []}], "parameters": [{"name": "id", "in": "path", "required": true, "schema": {"type": "string", "title": "Id"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/v1/secrets/set-group": {"post": {"summary": "Assign Secret Group", "description": "Assign a secret to a group or root.", "operationId": "assign_secret_group_api_v1_secrets_set_group_post", "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/SecretGroupAssign"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"OAuth2PasswordBearer": []}]}}, "/api/v1/secrets/move-group/{group_name}": {"post": {"summary": "Move Group", "description": "Move a group.", "operationId": "move_group_api_v1_secrets_move_group__group_name__post", "security": [{"OAuth2PasswordBearer": []}], "parameters": [{"name": "group_name", "in": "path", "required": true, "schema": {"type": "string", "title": "Group Name"}}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GroupPath"}}}}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}}, "components": {"schemas": {"AuditListResult": {"properties": {"results": {"items": {"$ref": "#/components/schemas/AuditLog"}, "type": "array", "title": "Results"}, "total": {"type": "integer", "title": "Total"}, "remaining": {"type": "integer", "title": "Remaining"}}, "type": "object", "required": ["results", "total", "remaining"], "title": "AuditListResult", "description": "Class to return when listing audit entries."}, "AuditLog": {"properties": {"id": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Id"}, "subsystem": {"$ref": "#/components/schemas/SubSystem"}, "operation": {"$ref": "#/components/schemas/Operation"}, "client_id": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Client Id"}, "client_name": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Client Name"}, "secret_id": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Secret Id"}, "secret_name": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Secret Name"}, "data": {"anyOf": [{"additionalProperties": {"type": "string"}, "type": "object"}, {"type": "null"}], "title": "Data"}, "message": {"type": "string", "title": "Message"}, "origin": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Origin"}, "timestamp": {"anyOf": [{"type": "string", "format": "date-time"}, {"type": "null"}], "title": "Timestamp"}}, "type": "object", "required": ["subsystem", "operation", "message"], "title": "AuditLog", "description": "Implementation of the backend class AuditView."}, "AutoGenerateOpts": {"properties": {"auto_generate": {"type": "boolean", "const": true, "title": "Auto Generate"}, "length": {"type": "integer", "title": "Length", "default": 32}}, "type": "object", "required": ["auto_generate"], "title": "AutoGenerateOpts", "description": "Option to auto-generate a password."}, "Body_login_for_access_token_api_v1_token_post": {"properties": {"grant_type": {"anyOf": [{"type": "string", "pattern": "^password$"}, {"type": "null"}], "title": "Grant Type"}, "username": {"type": "string", "title": "Username"}, "password": {"type": "string", "format": "password", "title": "Password"}, "scope": {"type": "string", "title": "Scope", "default": ""}, "client_id": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Client Id"}, "client_secret": {"anyOf": [{"type": "string"}, {"type": "null"}], "format": "password", "title": "Client Secret"}}, "type": "object", "required": ["username", "password"], "title": "Body_login_for_access_token_api_v1_token_post"}, "Client": {"properties": {"id": {"type": "string", "format": "uuid", "title": "Id"}, "name": {"type": "string", "title": "Name"}, "description": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Description"}, "public_key": {"type": "string", "title": "Public Key"}, "version": {"type": "integer", "title": "Version"}, "is_active": {"type": "boolean", "title": "Is Active"}, "is_deleted": {"type": "boolean", "title": "Is Deleted"}, "secrets": {"items": {"type": "string"}, "type": "array", "title": "Secrets"}, "policies": {"items": {"anyOf": [{"type": "string", "format": "ipvanynetwork"}, {"type": "string", "format": "ipvanyaddress"}]}, "type": "array", "title": "Policies"}, "created_at": {"type": "string", "format": "date-time", "title": "Created At"}, "updated_at": {"anyOf": [{"type": "string", "format": "date-time"}, {"type": "null"}], "title": "Updated At"}, "deleted_at": {"anyOf": [{"type": "string", "format": "date-time"}, {"type": "null"}], "title": "Deleted At"}}, "type": "object", "required": ["id", "name", "description", "public_key", "version", "is_active", "is_deleted", "secrets", "policies", "created_at", "updated_at", "deleted_at"], "title": "Client", "description": "Implementation of the backend class ClientView."}, "ClientCreate": {"properties": {"name": {"type": "string", "title": "Name"}, "description": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Description"}, "public_key": {"type": "string", "title": "Public Key"}, "sources": {"items": {"anyOf": [{"type": "string", "format": "ipvanyaddress"}, {"type": "string", "format": "ipvanynetwork"}]}, "type": "array", "title": "Sources"}}, "type": "object", "required": ["name", "public_key"], "title": "ClientCreate", "description": "Model to create a client."}, "ClientQueryResult": {"properties": {"clients": {"items": {"$ref": "#/components/schemas/Client"}, "type": "array", "title": "Clients"}, "total_results": {"type": "integer", "title": "Total Results"}, "remaining_results": {"type": "integer", "title": "Remaining Results"}}, "type": "object", "required": ["clients", "total_results", "remaining_results"], "title": "ClientQueryResult", "description": "Implementation of the backend ClientQueryResult class."}, "ClientReference": {"properties": {"id": {"type": "string", "title": "Id"}, "name": {"type": "string", "title": "Name"}}, "type": "object", "required": ["id", "name"], "title": "ClientReference", "description": "Implementation of the backend class ClientReference."}, "ClientSecretGroup": {"properties": {"id": {"type": "string", "format": "uuid", "title": "Id"}, "group_name": {"type": "string", "title": "Group Name"}, "path": {"type": "string", "title": "Path"}, "description": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Description"}, "parent_group": {"anyOf": [{"$ref": "#/components/schemas/GroupReference"}, {"type": "null"}]}, "children": {"items": {"$ref": "#/components/schemas/ClientSecretGroup"}, "type": "array", "title": "Children"}, "entries": {"items": {"$ref": "#/components/schemas/SecretClientMapping"}, "type": "array", "title": "Entries"}}, "type": "object", "required": ["id", "group_name", "path"], "title": "ClientSecretGroup", "description": "Client secrets grouped."}, "ClientSecretGroupList": {"properties": {"ungrouped": {"items": {"$ref": "#/components/schemas/SecretClientMapping"}, "type": "array", "title": "Ungrouped"}, "groups": {"items": {"$ref": "#/components/schemas/ClientSecretGroup"}, "type": "array", "title": "Groups"}}, "type": "object", "title": "ClientSecretGroupList", "description": "Secret group list."}, "GroupPath": {"properties": {"path": {"type": "string", "pattern": "^/.*", "title": "Path"}}, "type": "object", "required": ["path"], "title": "GroupPath", "description": "Path to a group."}, "GroupReference": {"properties": {"group_name": {"type": "string", "title": "Group Name"}, "path": {"type": "string", "title": "Path"}}, "type": "object", "required": ["group_name", "path"], "title": "GroupReference", "description": "Reference to a group.\n\nThis will be used for references to parent groups to avoid circular\nreferences."}, "HTTPValidationError": {"properties": {"detail": {"items": {"$ref": "#/components/schemas/ValidationError"}, "type": "array", "title": "Detail"}}, "type": "object", "title": "HTTPValidationError"}, "LocalUserInfo": {"properties": {"id": {"type": "string", "format": "uuid", "title": "Id"}, "display_name": {"type": "string", "title": "Display Name"}, "local": {"type": "boolean", "title": "Local"}}, "type": "object", "required": ["id", "display_name", "local"], "title": "LocalUserInfo", "description": "Model used to present a user in the web ui."}, "LoginInfo": {"properties": {"enabled": {"type": "boolean", "title": "Enabled"}, "oidc_provider": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Oidc Provider"}}, "type": "object", "required": ["enabled"], "title": "LoginInfo", "description": "Model containing information about login providers."}, "Operation": {"type": "string", "enum": ["create", "read", "update", "delete", "deny", "permit", "login", "none"], "title": "Operation", "description": "Various operations for the audit logging module."}, "RefreshTokenForm": {"properties": {"grant_type": {"type": "string", "const": "refresh_token", "title": "Grant Type"}, "refresh_token": {"type": "string", "title": "Refresh Token"}}, "type": "object", "required": ["grant_type", "refresh_token"], "title": "RefreshTokenForm", "description": "The refresh token form data."}, "SecretClientMapping": {"properties": {"name": {"type": "string", "title": "Name"}, "unmanaged": {"type": "boolean", "title": "Unmanaged", "default": false}, "clients": {"items": {"$ref": "#/components/schemas/ClientReference"}, "type": "array", "title": "Clients"}}, "type": "object", "required": ["name"], "title": "SecretClientMapping", "description": "Secret name with list of clients."}, "SecretCreate": {"properties": {"value": {"anyOf": [{"type": "string"}, {"$ref": "#/components/schemas/AutoGenerateOpts"}], "title": "Value", "description": "Secret as string value or auto-generated with optional length", "examples": ["MySecretString", {"auto_generate": true, "length": 32}]}, "name": {"type": "string", "title": "Name"}, "clients": {"anyOf": [{"items": {"type": "string"}, "type": "array"}, {"type": "null"}], "title": "Clients", "description": "Assign the secret to a list of clients."}, "client_distinguisher": {"type": "string", "enum": ["id", "name"], "title": "Client Distinguisher", "default": "name"}, "group": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Group"}}, "type": "object", "required": ["value", "name"], "title": "SecretCreate", "description": "Model to create a secret.", "examples": [{"clients": ["client-1", "client-2"], "name": "MySecret", "value": {"auto_generate": true, "length": 32}}, {"group": "MySecretGroup", "name": "MySecret", "value": "mysecretstring"}]}, "SecretGroupAssign": {"properties": {"secret_name": {"type": "string", "title": "Secret Name"}, "group_path": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Group Path"}}, "type": "object", "required": ["secret_name", "group_path"], "title": "SecretGroupAssign", "description": "Model for assigning secrets to a group.\n\nIf group is None, then it will be placed in the root."}, "SecretGroupCreate": {"properties": {"name": {"type": "string", "minLength": 1, "title": "Name"}, "description": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Description"}, "parent_group": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Parent Group"}}, "type": "object", "required": ["name"], "title": "SecretGroupCreate", "description": "Create model for creating secret groups."}, "SecretGroupUdate": {"properties": {"name": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Name"}, "description": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Description"}, "parent_group": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Parent Group"}}, "type": "object", "title": "SecretGroupUdate", "description": "Update model for updating secret groups."}, "SecretListView": {"properties": {"name": {"type": "string", "title": "Name"}, "unmanaged": {"type": "boolean", "title": "Unmanaged", "default": false}, "clients": {"items": {"type": "string"}, "type": "array", "title": "Clients"}}, "type": "object", "required": ["name"], "title": "SecretListView", "description": "Model containing a list of all available secrets."}, "SecretUpdate": {"properties": {"value": {"anyOf": [{"type": "string"}, {"$ref": "#/components/schemas/AutoGenerateOpts"}], "title": "Value", "description": "Secret as string value or auto-generated with optional length", "examples": ["MySecretString", {"auto_generate": true, "length": 32}]}}, "type": "object", "required": ["value"], "title": "SecretUpdate", "description": "Model to update a secret."}, "SecretView": {"properties": {"name": {"type": "string", "title": "Name"}, "secret": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Secret"}, "group": {"anyOf": [{"$ref": "#/components/schemas/GroupReference"}, {"type": "null"}]}, "clients": {"items": {"$ref": "#/components/schemas/ClientReference"}, "type": "array", "title": "Clients"}}, "type": "object", "required": ["name", "secret"], "title": "SecretView", "description": "Model containing a secret, including its clear-text value."}, "SubSystem": {"type": "string", "enum": ["admin", "sshd", "backend"], "title": "SubSystem", "description": "Available subsystems."}, "SystemStats": {"properties": {"clients": {"type": "integer", "title": "Clients"}, "secrets": {"type": "integer", "title": "Secrets"}, "audit_events": {"type": "integer", "title": "Audit Events"}}, "type": "object", "required": ["clients", "secrets", "audit_events"], "title": "SystemStats", "description": "Generic system stats."}, "Token": {"properties": {"access_token": {"type": "string", "title": "Access Token"}, "refresh_token": {"type": "string", "title": "Refresh Token"}, "token_type": {"type": "string", "title": "Token Type"}}, "type": "object", "required": ["access_token", "refresh_token", "token_type"], "title": "Token"}, "UpdateKeyModel": {"properties": {"public_key": {"type": "string", "title": "Public Key"}}, "type": "object", "required": ["public_key"], "title": "UpdateKeyModel", "description": "Model for updating client public key."}, "UpdateKeyResponse": {"properties": {"public_key": {"type": "string", "title": "Public Key"}, "updated_secrets": {"items": {"type": "string"}, "type": "array", "title": "Updated Secrets"}, "detail": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Detail"}}, "type": "object", "required": ["public_key"], "title": "UpdateKeyResponse", "description": "Response model after updating the public key."}, "UpdatePoliciesRequest": {"properties": {"sources": {"items": {"anyOf": [{"type": "string", "format": "ipvanyaddress"}, {"type": "string", "format": "ipvanynetwork"}]}, "type": "array", "title": "Sources"}}, "type": "object", "required": ["sources"], "title": "UpdatePoliciesRequest", "description": "Update policy request."}, "UserPasswordChange": {"properties": {"current_password": {"type": "string", "title": "Current Password"}, "new_password": {"type": "string", "title": "New Password"}, "new_password_confirm": {"type": "string", "title": "New Password Confirm"}}, "type": "object", "required": ["current_password", "new_password", "new_password_confirm"], "title": "UserPasswordChange", "description": "Model for changing the password of a user."}, "ValidationError": {"properties": {"loc": {"items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, "type": "array", "title": "Location"}, "msg": {"type": "string", "title": "Message"}, "type": {"type": "string", "title": "Error Type"}}, "type": "object", "required": ["loc", "msg", "type"], "title": "ValidationError"}}, "securitySchemes": {"OAuth2PasswordBearer": {"type": "oauth2", "flows": {"password": {"refreshUrl": "/api/v1/refresh", "scopes": {}, "tokenUrl": "/api/v1/token"}}}}}} \ No newline at end of file diff --git a/packages/sshecret-frontend/src/client/sdk.gen.ts b/packages/sshecret-frontend/src/client/sdk.gen.ts index 71c4794..5f53438 100644 --- a/packages/sshecret-frontend/src/client/sdk.gen.ts +++ b/packages/sshecret-frontend/src/client/sdk.gen.ts @@ -1,7 +1,7 @@ // This file is auto-generated by @hey-api/openapi-ts import { type Options as ClientOptions, type TDataShape, type Client, urlSearchParamsBodySerializer } from './client'; -import type { GetHealthHealthGetData, GetHealthHealthGetResponses, GetAuditLogApiV1AuditGetData, GetAuditLogApiV1AuditGetResponses, GetAuditLogApiV1AuditGetErrors, LoginForAccessTokenApiV1TokenPostData, LoginForAccessTokenApiV1TokenPostResponses, LoginForAccessTokenApiV1TokenPostErrors, RefreshTokenApiV1RefreshPostData, RefreshTokenApiV1RefreshPostResponses, RefreshTokenApiV1RefreshPostErrors, ChangePasswordApiV1PasswordPostData, ChangePasswordApiV1PasswordPostResponses, ChangePasswordApiV1PasswordPostErrors, GetClientsApiV1ClientsGetData, GetClientsApiV1ClientsGetResponses, CreateClientApiV1ClientsPostData, CreateClientApiV1ClientsPostResponses, CreateClientApiV1ClientsPostErrors, GetClientsTerseApiV1ClientsTerseGetData, GetClientsTerseApiV1ClientsTerseGetResponses, QueryClientsApiV1QueryClientsGetData, QueryClientsApiV1QueryClientsGetResponses, QueryClientsApiV1QueryClientsGetErrors, DeleteClientApiV1ClientsIdDeleteData, DeleteClientApiV1ClientsIdDeleteResponses, DeleteClientApiV1ClientsIdDeleteErrors, GetClientApiV1ClientsIdGetData, GetClientApiV1ClientsIdGetResponses, GetClientApiV1ClientsIdGetErrors, UpdateClientApiV1ClientsIdPutData, UpdateClientApiV1ClientsIdPutResponses, UpdateClientApiV1ClientsIdPutErrors, DeleteSecretFromClientApiV1ClientsIdSecretsSecretNameDeleteData, DeleteSecretFromClientApiV1ClientsIdSecretsSecretNameDeleteResponses, DeleteSecretFromClientApiV1ClientsIdSecretsSecretNameDeleteErrors, AddSecretToClientApiV1ClientsIdSecretsSecretNamePutData, AddSecretToClientApiV1ClientsIdSecretsSecretNamePutResponses, AddSecretToClientApiV1ClientsIdSecretsSecretNamePutErrors, UpdateClientPoliciesApiV1ClientsIdPoliciesPutData, UpdateClientPoliciesApiV1ClientsIdPoliciesPutResponses, UpdateClientPoliciesApiV1ClientsIdPoliciesPutErrors, UpdateClientPublicKeyApiV1ClientsIdPublicKeyPutData, UpdateClientPublicKeyApiV1ClientsIdPublicKeyPutResponses, UpdateClientPublicKeyApiV1ClientsIdPublicKeyPutErrors, GetSystemStatsApiV1StatsGetData, GetSystemStatsApiV1StatsGetResponses, GetSecretNamesApiV1SecretsGetData, GetSecretNamesApiV1SecretsGetResponses, AddSecretApiV1SecretsPostData, AddSecretApiV1SecretsPostResponses, AddSecretApiV1SecretsPostErrors, DeleteSecretApiV1SecretsNameDeleteData, DeleteSecretApiV1SecretsNameDeleteResponses, DeleteSecretApiV1SecretsNameDeleteErrors, GetSecretApiV1SecretsNameGetData, GetSecretApiV1SecretsNameGetResponses, GetSecretApiV1SecretsNameGetErrors, UpdateSecretApiV1SecretsNamePutData, UpdateSecretApiV1SecretsNamePutResponses, UpdateSecretApiV1SecretsNamePutErrors, GetSecretGroupsApiV1SecretsGroupsGetData, GetSecretGroupsApiV1SecretsGroupsGetResponses, GetSecretGroupsApiV1SecretsGroupsGetErrors, AddSecretGroupApiV1SecretsGroupsPostData, AddSecretGroupApiV1SecretsGroupsPostResponses, AddSecretGroupApiV1SecretsGroupsPostErrors, DeleteSecretGroupApiV1SecretsGroupsGroupPathDeleteData, DeleteSecretGroupApiV1SecretsGroupsGroupPathDeleteResponses, DeleteSecretGroupApiV1SecretsGroupsGroupPathDeleteErrors, GetSecretGroupApiV1SecretsGroupsGroupPathGetData, GetSecretGroupApiV1SecretsGroupsGroupPathGetResponses, GetSecretGroupApiV1SecretsGroupsGroupPathGetErrors, UpdateSecretGroupApiV1SecretsGroupsGroupPathPutData, UpdateSecretGroupApiV1SecretsGroupsGroupPathPutResponses, UpdateSecretGroupApiV1SecretsGroupsGroupPathPutErrors, DeleteGroupIdApiV1SecretsGroupIdDeleteData, DeleteGroupIdApiV1SecretsGroupIdDeleteResponses, DeleteGroupIdApiV1SecretsGroupIdDeleteErrors, AssignSecretGroupApiV1SecretsSetGroupPostData, AssignSecretGroupApiV1SecretsSetGroupPostResponses, AssignSecretGroupApiV1SecretsSetGroupPostErrors, MoveGroupApiV1SecretsMoveGroupGroupNamePostData, MoveGroupApiV1SecretsMoveGroupGroupNamePostResponses, MoveGroupApiV1SecretsMoveGroupGroupNamePostErrors } from './types.gen'; +import type { GetHealthHealthGetData, GetHealthHealthGetResponses, GetAuditLogApiV1AuditGetData, GetAuditLogApiV1AuditGetResponses, GetAuditLogApiV1AuditGetErrors, LoginForAccessTokenApiV1TokenPostData, LoginForAccessTokenApiV1TokenPostResponses, LoginForAccessTokenApiV1TokenPostErrors, RefreshTokenApiV1RefreshPostData, RefreshTokenApiV1RefreshPostResponses, RefreshTokenApiV1RefreshPostErrors, ChangePasswordApiV1PasswordPostData, ChangePasswordApiV1PasswordPostResponses, ChangePasswordApiV1PasswordPostErrors, StartOidcLoginApiV1OidcLoginGetData, StartOidcLoginApiV1OidcLoginGetResponses, OidcCallbackApiV1OidcCallbackGetData, OidcCallbackApiV1OidcCallbackGetResponses, GetCurrentUserApiV1UsersMeGetData, GetCurrentUserApiV1UsersMeGetResponses, GetAuthInfoApiV1OidcStatusGetData, GetAuthInfoApiV1OidcStatusGetResponses, GetClientsApiV1ClientsGetData, GetClientsApiV1ClientsGetResponses, CreateClientApiV1ClientsPostData, CreateClientApiV1ClientsPostResponses, CreateClientApiV1ClientsPostErrors, GetClientsTerseApiV1ClientsTerseGetData, GetClientsTerseApiV1ClientsTerseGetResponses, QueryClientsApiV1QueryClientsGetData, QueryClientsApiV1QueryClientsGetResponses, QueryClientsApiV1QueryClientsGetErrors, DeleteClientApiV1ClientsIdDeleteData, DeleteClientApiV1ClientsIdDeleteResponses, DeleteClientApiV1ClientsIdDeleteErrors, GetClientApiV1ClientsIdGetData, GetClientApiV1ClientsIdGetResponses, GetClientApiV1ClientsIdGetErrors, UpdateClientApiV1ClientsIdPutData, UpdateClientApiV1ClientsIdPutResponses, UpdateClientApiV1ClientsIdPutErrors, DeleteSecretFromClientApiV1ClientsIdSecretsSecretNameDeleteData, DeleteSecretFromClientApiV1ClientsIdSecretsSecretNameDeleteResponses, DeleteSecretFromClientApiV1ClientsIdSecretsSecretNameDeleteErrors, AddSecretToClientApiV1ClientsIdSecretsSecretNamePutData, AddSecretToClientApiV1ClientsIdSecretsSecretNamePutResponses, AddSecretToClientApiV1ClientsIdSecretsSecretNamePutErrors, UpdateClientPoliciesApiV1ClientsIdPoliciesPutData, UpdateClientPoliciesApiV1ClientsIdPoliciesPutResponses, UpdateClientPoliciesApiV1ClientsIdPoliciesPutErrors, UpdateClientPublicKeyApiV1ClientsIdPublicKeyPutData, UpdateClientPublicKeyApiV1ClientsIdPublicKeyPutResponses, UpdateClientPublicKeyApiV1ClientsIdPublicKeyPutErrors, GetSystemStatsApiV1StatsGetData, GetSystemStatsApiV1StatsGetResponses, GetSecretNamesApiV1SecretsGetData, GetSecretNamesApiV1SecretsGetResponses, AddSecretApiV1SecretsPostData, AddSecretApiV1SecretsPostResponses, AddSecretApiV1SecretsPostErrors, DeleteSecretApiV1SecretsNameDeleteData, DeleteSecretApiV1SecretsNameDeleteResponses, DeleteSecretApiV1SecretsNameDeleteErrors, GetSecretApiV1SecretsNameGetData, GetSecretApiV1SecretsNameGetResponses, GetSecretApiV1SecretsNameGetErrors, UpdateSecretApiV1SecretsNamePutData, UpdateSecretApiV1SecretsNamePutResponses, UpdateSecretApiV1SecretsNamePutErrors, GetSecretGroupsApiV1SecretsGroupsGetData, GetSecretGroupsApiV1SecretsGroupsGetResponses, GetSecretGroupsApiV1SecretsGroupsGetErrors, AddSecretGroupApiV1SecretsGroupsPostData, AddSecretGroupApiV1SecretsGroupsPostResponses, AddSecretGroupApiV1SecretsGroupsPostErrors, DeleteSecretGroupApiV1SecretsGroupsGroupPathDeleteData, DeleteSecretGroupApiV1SecretsGroupsGroupPathDeleteResponses, DeleteSecretGroupApiV1SecretsGroupsGroupPathDeleteErrors, GetSecretGroupApiV1SecretsGroupsGroupPathGetData, GetSecretGroupApiV1SecretsGroupsGroupPathGetResponses, GetSecretGroupApiV1SecretsGroupsGroupPathGetErrors, UpdateSecretGroupApiV1SecretsGroupsGroupPathPutData, UpdateSecretGroupApiV1SecretsGroupsGroupPathPutResponses, UpdateSecretGroupApiV1SecretsGroupsGroupPathPutErrors, DeleteGroupIdApiV1SecretsGroupIdDeleteData, DeleteGroupIdApiV1SecretsGroupIdDeleteResponses, DeleteGroupIdApiV1SecretsGroupIdDeleteErrors, AssignSecretGroupApiV1SecretsSetGroupPostData, AssignSecretGroupApiV1SecretsSetGroupPostResponses, AssignSecretGroupApiV1SecretsSetGroupPostErrors, MoveGroupApiV1SecretsMoveGroupGroupNamePostData, MoveGroupApiV1SecretsMoveGroupGroupNamePostResponses, MoveGroupApiV1SecretsMoveGroupGroupNamePostErrors } from './types.gen'; import { client as _heyApiClient } from './client.gen'; export type Options = ClientOptions & { @@ -105,6 +105,60 @@ export class SshecretAdmin { }); } + /** + * Start Oidc Login + * Redirect for OIDC login. + */ + public static startOidcLoginApiV1OidcLoginGet(options?: Options) { + return (options?.client ?? _heyApiClient).get({ + responseType: 'json', + url: '/api/v1/oidc/login', + ...options + }); + } + + /** + * Oidc Callback + * Callback for OIDC auth. + */ + public static oidcCallbackApiV1OidcCallbackGet(options?: Options) { + return (options?.client ?? _heyApiClient).get({ + responseType: 'json', + url: '/api/v1/oidc/callback', + ...options + }); + } + + /** + * Get Current User + * Get information about the user currently logged in. + */ + public static getCurrentUserApiV1UsersMeGet(options?: Options) { + return (options?.client ?? _heyApiClient).get({ + responseType: 'json', + security: [ + { + scheme: 'bearer', + type: 'http' + } + ], + url: '/api/v1/users/me', + ...options + }); + } + + /** + * Get Auth Info + * Check if OIDC login is available. + */ + public static getAuthInfoApiV1OidcStatusGet(options?: Options) { + return (options?.client ?? _heyApiClient).get({ + responseType: 'json', + url: '/api/v1/oidc/status', + ...options + }); + } + /** * Get Clients * Get clients. diff --git a/packages/sshecret-frontend/src/client/types.gen.ts b/packages/sshecret-frontend/src/client/types.gen.ts index 1fa57be..6c17cbd 100644 --- a/packages/sshecret-frontend/src/client/types.gen.ts +++ b/packages/sshecret-frontend/src/client/types.gen.ts @@ -309,6 +309,40 @@ export type HttpValidationError = { detail?: Array; }; +/** + * LocalUserInfo + * Model used to present a user in the web ui. + */ +export type LocalUserInfo = { + /** + * Id + */ + id: string; + /** + * Display Name + */ + display_name: string; + /** + * Local + */ + local: boolean; +}; + +/** + * LoginInfo + * Model containing information about login providers. + */ +export type LoginInfo = { + /** + * Enabled + */ + enabled: boolean; + /** + * Oidc Provider + */ + oidc_provider?: string | null; +}; + /** * Operation * Various operations for the audit logging module. @@ -754,6 +788,66 @@ export type ChangePasswordApiV1PasswordPostResponses = { 200: unknown; }; +export type StartOidcLoginApiV1OidcLoginGetData = { + body?: never; + path?: never; + query?: never; + url: '/api/v1/oidc/login'; +}; + +export type StartOidcLoginApiV1OidcLoginGetResponses = { + /** + * Successful Response + */ + 200: unknown; +}; + +export type OidcCallbackApiV1OidcCallbackGetData = { + body?: never; + path?: never; + query?: never; + url: '/api/v1/oidc/callback'; +}; + +export type OidcCallbackApiV1OidcCallbackGetResponses = { + /** + * Successful Response + */ + 200: unknown; +}; + +export type GetCurrentUserApiV1UsersMeGetData = { + body?: never; + path?: never; + query?: never; + url: '/api/v1/users/me'; +}; + +export type GetCurrentUserApiV1UsersMeGetResponses = { + /** + * Successful Response + */ + 200: LocalUserInfo; +}; + +export type GetCurrentUserApiV1UsersMeGetResponse = GetCurrentUserApiV1UsersMeGetResponses[keyof GetCurrentUserApiV1UsersMeGetResponses]; + +export type GetAuthInfoApiV1OidcStatusGetData = { + body?: never; + path?: never; + query?: never; + url: '/api/v1/oidc/status'; +}; + +export type GetAuthInfoApiV1OidcStatusGetResponses = { + /** + * Successful Response + */ + 200: LoginInfo; +}; + +export type GetAuthInfoApiV1OidcStatusGetResponse = GetAuthInfoApiV1OidcStatusGetResponses[keyof GetAuthInfoApiV1OidcStatusGetResponses]; + export type GetClientsApiV1ClientsGetData = { body?: never; path?: never; diff --git a/packages/sshecret-frontend/src/components/auth/OidcCallback.vue b/packages/sshecret-frontend/src/components/auth/OidcCallback.vue new file mode 100644 index 0000000..65149d1 --- /dev/null +++ b/packages/sshecret-frontend/src/components/auth/OidcCallback.vue @@ -0,0 +1,21 @@ + diff --git a/packages/sshecret-frontend/src/components/layout/Navbar.vue b/packages/sshecret-frontend/src/components/layout/Navbar.vue index 0743f94..e925948 100644 --- a/packages/sshecret-frontend/src/components/layout/Navbar.vue +++ b/packages/sshecret-frontend/src/components/layout/Navbar.vue @@ -18,7 +18,7 @@ {{ auth.username }} - Change Password + Change Password Logout @@ -31,7 +31,7 @@