Metadata-Version: 2.4
Name: umacs
Version: 0.9.0
Summary: UMACS is a unified management and access control service.
Requires-Python: >=3.13
Description-Content-Type: text/markdown
Requires-Dist: pydantic>=2.11.7
Requires-Dist: httpx>=0.28.1

# UMACS User Management and Access Control Service

[![codecov](https://codecov.io/github/csed-ucm/umacs/graph/badge.svg?token=NDVM21XN8W)](https://codecov.io/github/csed-ucm/umacs)

UMACS (User Management and Access Control Service) is a lightweight, reusable Authorization service.

## Features

- [x] **Policy Engine** based on Casbin for flexible access control, supporting RBAC and ABAC.
- [x] **Logging** using SQL tables for efficient storage and auditing of decision logs.
- [x] **JWKS discovery** + **caching** for validating tokens from configured IdPs and rejecting invalid tokens.
- [x] **API** for managing users, roles, and permissions.
- [x] **Python SDK** (`umacs.client`) for consumer apps to call `/enforce/check` with a bearer token.

## Core Dependencies

The service is built using:

- FastAPI + Uvicorn
- Authlib (OIDC JWT verification)
- Casbin (RBAC + optional ABAC)
- SQLModel + AsyncSQLAlchemy (Policies, Users, Resources, Decision Logs)
- Alembic (Database Migrations)

## Quickstart

### Prerequisites

#### Environment

Copy `.env.example` to `.env` and set at least:

| Variable | Purpose | Default |
|----------|---------|---------|
| `SECRET_KEY` | HS256 signing for local login JWTs | `supersecret` |
| `DATABASE_URL` | Async SQLAlchemy URL | `sqlite+aiosqlite:///./test.db` |

### Install, migrate, bootstrap, run

```sh
uv sync
uv run alembic upgrade head
uv run python scripts/bootstrap_local.py
uv run fastapi dev
# or: uv run uvicorn app.app:app --reload
```

Bootstrap seeds Casbin path policies (login/docs public, admin full access) and users:

| User | Password | Role |
|------|----------|------|
| `admin` | `admin` | admin |
| `demo` | `demo` | user |
| `service` | `service` | service (machine credential for `POST /enforce/check`) |

Without bootstrap, an empty Casbin policy set will 403 login and other routes.
`GET /health` stays public and does not require bootstrap.

### Docker

Build a multi-stage runtime image and run with the same env vars as [`.env.example`](.env.example):

```sh
docker build -t umacs:local .
docker run --rm -p 8000:8000 \
  -e SECRET_KEY=change-me \
  -e DATABASE_URL=sqlite+aiosqlite:///./umacs.db \
  umacs:local
# probe: curl http://localhost:8000/health
```

For gated API use inside the container, still run migrations/bootstrap (or mount a pre-seeded DB). Health checks do not require bootstrap.

### Consumer apps (SDK)

See [examples/consumer_fastapi.py](examples/consumer_fastapi.py) for a T4-shaped FastAPI snippet:

1. Log in as `service` (or set a token another way).
2. Set `UMACS_URL` + `UMACS_TOKEN` (or call `configure_client(token=...)`).
3. Call `AsyncUMACS.check` / protect routes with `@require_permission`.

Gateway auth uses the **service** bearer token; the enforce body `sub` is the **end user** whose permission you are checking.
