Share
## https://sploitus.com/exploit?id=B7E559EF-D75D-5EF9-8719-8055B9CE28E6
# RM OneView โ€” Proof of Concept

A working POC of the Relationship Manager daily dashboard, built to demonstrate
the **production security model** with dummy data: AD-style login โ†’ server-side
identity โ†’ RM-scoped data โ†’ audit logging. Nothing is enforced in the browser.

---

## What this proves

1. **Username/password login** that mimics AD sign-in.
2. **Server-side entitlement** โ€” every data query is filtered by the logged-in
   RM's ID *on the server*. An RM literally cannot request another RM's book.
3. **Role separation** โ€” RMs get the RM dashboard; managers get a team-aggregate
   view (no individual client PII at the manager level).
4. **Audit logging** โ€” every login and data access is recorded.
5. **Rules-based recommendation engine** โ€” leads/opportunities are *derived* from
   client data by transparent if-then rules (e.g. `balance>โ‚น2Cr & products=1`),
   ranked with bonus-gate impact on top.
6. **GenAI call-prep brief** โ€” on any lead, "โœฆ Prep brief" generates an
   AI-assisted briefing. Critically, it demonstrates the **de-identification
   boundary** required for external-API GenAI (see below).

---

## GenAI: the de-identification boundary

This bank can only use **external** LLM APIs (no in-house model). Sending real
client PII to an external API is not acceptable, so the call-prep brief shows the
only defensible pattern:

1. **Entitlement check** โ€” the client must be in the requesting RM's book
   (same server-side join as everything else; briefing another RM's client โ†’ 404).
2. **De-identify** โ€” strip name/IDs; build a neutral, token-based payload
   (`"CLIENT_A", UHNI, idle balance high, no login 71d`). Balances become bands,
   not exact figures.
3. **External call** โ€” only that payload leaves the perimeter. *(In the POC this
   is a mock `mock_llm()` with no network call; in production it's an HTTPS call
   to the approved endpoint sending exactly this payload.)*
4. **Re-identify locally** โ€” the real name is re-inserted inside your environment,
   never sent out.

The brief modal deliberately **shows the RM the exact de-identified payload that
left the perimeter**, so the privacy boundary is visible, not hidden. Every brief
is audit-logged as `BRIEF_GENERATED (de-identified payload sent)`.

> **Compliance caveat:** even de-identified, some banks prohibit *any*
> client-derived data leaving. Get sign-off before wiring a real external API.
> The core ranking/gate engine stays fully deterministic and on-prem โ€” GenAI is
> only at the language edge (briefs, drafting), never computing KRAs or advice.

---



## How it maps to the real architecture

| POC stand-in | Production equivalent |
|---|---|
| SQLite `rm_oneview.db` | On-prem BI **Postgres** (daily refresh) |
| `rm_client_map` table | The RM-to-client mapping already in your BI DB |
| Username/password form | **AD / ADFS** via SAML/OIDC (or LDAPS bind) |
| `employee_id` as the key | The shared employee-ID key common to AD + BI DB |
| Server-side `WHERE rm_id=?` filter | Same query **+ Postgres row-level security** |
| `role` column (`RM`/`MANAGER`) | **AD group** membership |
| In-memory session dict | Signed session cookie / server session store |
| `audit_log` table | Your enterprise audit/SIEM sink |
| FastAPI on localhost | App server hosted **on-prem**, behind corporate VPN |

The entitlement SQL is written exactly as it runs against Postgres, so porting is
mostly a database-driver swap plus wiring real AD auth in place of the login form.

---

## Run it locally

Requires Python 3.10+.

```bash
# 1. install dependencies
pip install fastapi uvicorn python-multipart

# 2. build the dummy database (10 RMs, 2 managers, ~200 clients)
python seed_data.py

# 3. start the server
python -m uvicorn app:app --host 127.0.0.1 --port 8000

# 4. open in a browser
#    http://127.0.0.1:8000
```

## Demo accounts

| Username | Password | Role |
|---|---|---|
| `arao` | `rm123` | RM (mid-performer) |
| `kmehta` | `rm123` | RM |
| `mnair` | `rm123` | RM (top-tier book) |
| `msharma` | `manager123` | Manager (team view) |
| `kreddy` | `manager123` | Manager |

Other RM usernames are first-initial + surname, lowercased (printed when you run
`seed_data.py` if you inspect the DB). All RMs use `rm123`.

**Try this to see the security in action:** log in as one RM, note the clients
shown, sign out, log in as another โ€” completely different book. Then open browser
dev-tools network tab: the server only ever sends that RM's rows.

---

## Publish it on the web (Render โ€” free tier)

To let others see it work live, deploy to **Render**. The repo includes
`render.yaml`, `requirements.txt`, and an auto-build step, so it's nearly one-click.

1. Push this folder to a **GitHub** repo.
2. In Render: **New + โ†’ Blueprint**, point it at the repo. Render reads
   `render.yaml` and provisions a free web service.
3. Wait for the build (installs deps, builds the dummy DB), then open the public URL.

The app auto-builds the database on first start and serves over HTTPS. The
`HTTPS_DEPLOY=true` env var (set in `render.yaml`) turns on secure cookies.

**Keep it to one instance** (the blueprint already sets `numInstances: 1`).
Sessions and SQLite are in-process, so scaling out would break login.

> **Public-demo reminder:** this is a *functional* showcase with fake data and
> shared demo logins (shown on the login screen, now behind a "Demo mode" banner).
> The real system is **never** public โ€” it runs on-prem behind your VPN with AD.
> A public demo should not be treated as a hosting precedent.

### Other quick options
- **Temporary tunnel:** run locally, then `ngrok http 8000` for an instant public
  URL that dies when you close it โ€” good for a single meeting.
- **Railway / Fly.io:** same idea as Render; the `requirements.txt` and start
  command (`uvicorn app:app --host 0.0.0.0 --port $PORT`) work there too.

---



```bash
python test_poc.py
```

Runs 8 checks: unauthenticated requests blocked, bad credentials rejected, each RM
scoped to their own book, **zero client overlap between RMs**, RMs can't reach the
manager endpoint, managers see aggregates only (no client PII), audit logging
works, and the **GenAI brief is entitlement-checked + de-identified** (no name in
the external payload, others' clients blocked).

---

## Files

- `seed_data.py` โ€” generates the dummy database
- `app.py` โ€” FastAPI backend (auth, scoped data API, audit)
- `static/index.html` โ€” login screen + dashboard front-end
- `test_poc.py` โ€” security & functionality test suite
- `requirements.txt` โ€” Python dependencies for deployment
- `render.yaml` โ€” Render Blueprint for one-click web deploy
- `rm_oneview.db` โ€” the generated SQLite database (after step 2, or auto-built on deploy)

---

## Important caveats (this is a POC)

- The password hashing here is a toy (`sha256`); production uses AD โ€” the app
  never stores or checks passwords itself.
- Sessions are in-memory and reset on restart.
- Data is randomly generated dummy data โ€” no real clients.
- Not hardened for deployment (no rate-limiting, HTTPS, CSRF tokens, etc.) โ€” those
  come with the real on-prem hosting + AD integration.

The point of the POC is to prove the **shape** of the system โ€” especially that
data scoping is enforced server-side โ€” not to be production-ready.