This commit is contained in:
Jonas Bengtsson
2026-09-17 06:23:29 +02:00
parent 8d2c54beae
commit ee4800993d
17 changed files with 1043 additions and 189 deletions
+152 -1
View File
@@ -18,7 +18,10 @@ from app.deps import CurrentUser, require_roles
from app.dynsec import DynsecError, dynsec_client
from app.models import ManagementRole, MqttClientMetadata
from app.schemas import (
ClientRoleAssign,
GroupIn,
GroupMemberAssign,
GroupRoleAssign,
MqttClientCreate,
MqttClientOut,
MqttPasswordReset,
@@ -39,12 +42,13 @@ def _metadata(db: Session, username: str) -> MqttClientMetadata | None:
def _client_out(db: Session, client: dict) -> MqttClientOut:
meta = _metadata(db, client.get("username", ""))
# dynsec reports `disabled` (absent == enabled); the API exposes `enabled`.
return MqttClientOut(
username=client.get("username", ""),
clientid=client.get("clientid") or None,
text_name=client.get("textname"),
text_description=client.get("textdescription"),
enabled=client.get("enabled", False),
enabled=not client.get("disabled", False),
groups=client.get("groups", []),
roles=client.get("roles", []),
owner=meta.owner if meta else None,
@@ -181,6 +185,55 @@ def reset_password(
return MqttPasswordReset(username=username, password=password)
@router.post("/clients/{username}/roles", status_code=status.HTTP_204_NO_CONTENT)
def assign_client_role(
username: str,
body: ClientRoleAssign,
request: Request,
db: DbDep,
_user: BrokerAdmin,
):
"""Add one role to an existing client (incremental, spec section 11)."""
try:
dynsec_client.add_client_role(username, body.rolename, body.priority)
except DynsecError as exc:
raise HTTPException(status.HTTP_404_NOT_FOUND, str(exc)) from exc
audit.record(
db,
"CLIENT_ROLE_ADDED",
request=request,
object_type="mqtt_client",
object_id=username,
new_value={"rolename": body.rolename, "priority": body.priority},
)
return None
@router.delete(
"/clients/{username}/roles/{rolename}", status_code=status.HTTP_204_NO_CONTENT
)
def unassign_client_role(
username: str,
rolename: str,
request: Request,
db: DbDep,
_user: BrokerAdmin,
):
try:
dynsec_client.remove_client_role(username, rolename)
except DynsecError as exc:
raise HTTPException(status.HTTP_404_NOT_FOUND, str(exc)) from exc
audit.record(
db,
"CLIENT_ROLE_REMOVED",
request=request,
object_type="mqtt_client",
object_id=username,
old_value={"rolename": rolename},
)
return None
# --- Groups ------------------------------------------------------------------
@@ -228,6 +281,104 @@ def delete_group(
return None
@router.post("/groups/{groupname}/clients", status_code=status.HTTP_204_NO_CONTENT)
def add_group_member(
groupname: str,
body: GroupMemberAssign,
request: Request,
db: DbDep,
_user: BrokerAdmin,
):
"""Add one client to a group (spec section 12)."""
try:
dynsec_client.add_group_client(groupname, body.username, body.priority)
except DynsecError as exc:
raise HTTPException(status.HTTP_404_NOT_FOUND, str(exc)) from exc
audit.record(
db,
"GROUP_MEMBER_ADDED",
request=request,
object_type="mqtt_group",
object_id=groupname,
new_value={"username": body.username, "priority": body.priority},
)
return None
@router.delete(
"/groups/{groupname}/clients/{username}", status_code=status.HTTP_204_NO_CONTENT
)
def remove_group_member(
groupname: str,
username: str,
request: Request,
db: DbDep,
_user: BrokerAdmin,
):
try:
dynsec_client.remove_group_client(groupname, username)
except DynsecError as exc:
raise HTTPException(status.HTTP_404_NOT_FOUND, str(exc)) from exc
audit.record(
db,
"GROUP_MEMBER_REMOVED",
request=request,
object_type="mqtt_group",
object_id=groupname,
old_value={"username": username},
)
return None
@router.post("/groups/{groupname}/roles", status_code=status.HTTP_204_NO_CONTENT)
def assign_group_role(
groupname: str,
body: GroupRoleAssign,
request: Request,
db: DbDep,
_user: BrokerAdmin,
):
"""Add one role to a group (spec section 12)."""
try:
dynsec_client.add_group_role(groupname, body.rolename, body.priority)
except DynsecError as exc:
raise HTTPException(status.HTTP_404_NOT_FOUND, str(exc)) from exc
audit.record(
db,
"GROUP_ROLE_ADDED",
request=request,
object_type="mqtt_group",
object_id=groupname,
new_value={"rolename": body.rolename, "priority": body.priority},
)
return None
@router.delete(
"/groups/{groupname}/roles/{rolename}", status_code=status.HTTP_204_NO_CONTENT
)
def unassign_group_role(
groupname: str,
rolename: str,
request: Request,
db: DbDep,
_user: BrokerAdmin,
):
try:
dynsec_client.remove_group_role(groupname, rolename)
except DynsecError as exc:
raise HTTPException(status.HTTP_404_NOT_FOUND, str(exc)) from exc
audit.record(
db,
"GROUP_ROLE_REMOVED",
request=request,
object_type="mqtt_group",
object_id=groupname,
old_value={"rolename": rolename},
)
return None
@router.get("/roles")
def list_roles(_user: BrokerAdmin):
return dynsec_client.list_roles()