Integrate group in admin rest API

This commit is contained in:
2025-05-31 14:13:49 +02:00
parent 18f61631c9
commit 773a1e2976
8 changed files with 352 additions and 15 deletions

View File

@ -23,7 +23,7 @@ from sshecret.crypto import encrypt_string, load_public_key
from .keepass import PasswordContext, load_password_manager
from sshecret_admin.core.settings import AdminServerSettings
from .models import SecretView
from .models import ClientSecretGroup, SecretClientMapping, SecretGroup, SecretView
class ClientManagementError(Exception):
@ -45,6 +45,38 @@ class BackendUnavailableError(ClientManagementError):
LOG = logging.getLogger(__name__)
def add_clients_to_secret_group(
group: SecretGroup,
client_secret_mapping: dict[str, DetailedSecrets],
parent: ClientSecretGroup | None = None,
) -> ClientSecretGroup:
"""Add client information to a secret group."""
client_secret_group = ClientSecretGroup(
group_name=group.name,
path=group.path,
description=group.description,
parent_group=parent,
)
for entry in group.entries:
secret_entries = SecretClientMapping(name=entry)
if details := client_secret_mapping.get(entry):
secret_entries.clients = details.clients
client_secret_group.entries.append(secret_entries)
for subgroup in group.children:
client_secret_group.children.append(
add_clients_to_secret_group(
subgroup, client_secret_mapping, client_secret_group
)
)
# We'll save a bit of memory and complexity by just adding the name of the parent, if available.
if not parent and group.parent_group:
client_secret_group.parent_group = ClientSecretGroup(
group_name=group.parent_group.name,
path=group.parent_group.path,
)
return client_secret_group
class AdminBackend:
"""Admin backend API."""
@ -277,6 +309,74 @@ class AdminBackend:
except Exception as e:
raise BackendUnavailableError() from e
async def add_secret_group(
self,
group_name: str,
description: str | None = None,
parent_group: str | None = None,
) -> None:
"""Add secret group."""
with self.password_manager() as password_manager:
password_manager.add_group(group_name, description, parent_group)
async def set_secret_group(self, secret_name: str, group_name: str | None) -> None:
"""Assign a group to a secret."""
with self.password_manager() as password_manager:
password_manager.set_secret_group(secret_name, group_name)
async def move_secret_group(
self, group_name: str, parent_group: str | None
) -> None:
"""Move a group.
If parent_group is None, it will be moved to the root.
"""
with self.password_manager() as password_manager:
password_manager.move_group(group_name, parent_group)
async def set_group_description(self, group_name: str, description: str) -> None:
"""Set a group description."""
with self.password_manager() as password_manager:
password_manager.set_group_description(group_name, description)
async def delete_secret_group(
self, group_name: str, keep_entries: bool = True
) -> None:
"""Delete a group.
If keep_entries is set to False, all entries in the group will be deleted.
"""
with self.password_manager() as password_manager:
password_manager.delete_group(group_name, keep_entries)
async def get_secret_groups(
self,
group_filter: str | None = None,
regex: bool = True,
) -> list[ClientSecretGroup]:
"""Get secret groups.
The starting group can be filtered with the group_name argument, which
may be a regular expression.
"""
all_secrets = await self.backend.get_detailed_secrets()
secrets_mapping = {secret.name: secret for secret in all_secrets}
with self.password_manager() as password_manager:
all_groups = password_manager.get_secret_groups(group_filter, regex=regex)
result: list[ClientSecretGroup] = []
for group in all_groups:
# We have to do this recursively.
result.append(add_clients_to_secret_group(group, secrets_mapping))
return result
async def get_secret_group(self, name: str) -> ClientSecretGroup | None:
"""Get a single secret group by name."""
matches = await self.get_secret_groups(group_filter=name, regex=False)
if not matches:
return None
return matches[0]
async def get_secret(self, name: str) -> SecretView | None:
"""Get secrets from backend."""
try:
@ -322,11 +422,16 @@ class AdminBackend:
await self.backend.delete_client_secret(client, name)
async def _add_secret(
self, name: str, value: str, clients: list[str] | None, update: bool = False
self,
name: str,
value: str,
clients: list[str] | None,
update: bool = False,
group: str | None = None,
) -> None:
"""Add a secret."""
with self.password_manager() as password_manager:
password_manager.add_entry(name, value, update)
password_manager.add_entry(name, value, update, group_name=group)
if update:
secret_map = await self.backend.get_secret(name)
@ -348,11 +453,15 @@ class AdminBackend:
await self.backend.create_client_secret(client_name, name, encrypted)
async def add_secret(
self, name: str, value: str, clients: list[str] | None = None
self,
name: str,
value: str,
clients: list[str] | None = None,
group: str | None = None,
) -> None:
"""Add a secret."""
try:
await self._add_secret(name, value, clients)
await self._add_secret(name=name, value=value, clients=clients, group=group)
except ClientManagementError:
raise
except Exception as e: