Files
roa2web-service-auto/docs/service-auto/grants-audit.md
2026-06-05 15:00:42 +00:00

233 lines
9.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Grants Audit — ROA_WEB on MARIUSM_AUTO
**Date**: 2026-04-11
**Auditor**: oracle-agent (team service-auto-sapt3)
**Oracle target**: `10.0.20.121:1521/ROA`
**Queries run as**: `CONTAFIN_ORACLE`
---
## 1. Findings
### 1.1. ROA_WEB user — DOES NOT EXIST
| Source query | Result |
|---|---|
| `SELECT * FROM DBA_USERS WHERE USERNAME='ROA_WEB'` | 0 rows |
| `SELECT * FROM DBA_TAB_PRIVS WHERE GRANTEE='ROA_WEB'` | 0 rows |
| `SELECT * FROM DBA_SYS_PRIVS WHERE GRANTEE='ROA_WEB'` | 0 rows |
| `SELECT * FROM DBA_ROLE_PRIVS WHERE GRANTEE='ROA_WEB'` | 0 rows |
No Oracle user `ROA_WEB` exists on the `ROA` instance. All four privilege dictionaries
are empty for this grantee. Clean slate — no cleanup needed before creation.
### 1.2. Why CONTAFIN_ORACLE "just works" on MARIUSM_AUTO
```
USER_ROLE_PRIVS for CONTAFIN_ORACLE:
RESOURCE, CONNECT, IMP_FULL_DATABASE, DBA, EXP_FULL_DATABASE
```
`CONTAFIN_ORACLE` holds the `DBA` role, so it has `SELECT/INSERT/UPDATE/DELETE/EXECUTE
ANY TABLE/PROCEDURE`. No explicit per-table grants are needed — that's why the Săpt 1
POC (`poc/hello_oracle.py`) and this audit script both queried MARIUSM_AUTO without
any explicit grant work.
**Implication for prototype (Săpt 3)**: we can connect as `CONTAFIN_ORACLE` directly,
skip `ROA_WEB` entirely, and still validate hypotheses #1 (oracledb + OUT params) and
#2 (SP creation + call). Only hypothesis #3 (grant-scoped access via SP, read-only
SELECT rejected) **requires** the scoped `ROA_WEB` user and is therefore the only
reason to ask DBA for the create.
### 1.3. Required target objects — exist
| Object | Type | Status |
|---|---|---|
| `MARIUSM_AUTO.AUTO_VMASINICLIENTI` | VIEW | present |
| `MARIUSM_AUTO.DEV_TIP_DEVIZ` | TABLE | present |
| `MARIUSM_AUTO.SP_CREEAZA_COMANDA_PROTOTIP` | — | **not yet created** (task #3) |
---
## 2. Decision — Two-phase approach
### Phase A — Săpt 3 (this week): use CONTAFIN_ORACLE
- No DBA request needed.
- Prototype backend module `service_auto` connects via the existing
`CONTAFIN_ORACLE` credentials (already in `backend/.env`).
- Proves hypotheses #1 + #2 (sync-facade + PL/SQL OUT params) end-to-end.
- `backend/.env` entry for MARIUSM_AUTO (task #5) points to existing
CONTAFIN_ORACLE user; only schema owner changes (`MARIUSM_AUTO` instead of
whichever the login uses for current companies).
### Phase B — Săpt 4+ (after prototype): create ROA_WEB and migrate
Needed only to prove hypothesis #3 (grant-scoped access through SP while direct
DML/SELECT is rejected). This requires DBA action.
---
## 3. Motivare securitate — de ce ROA_WEB cu SP-only
**Oracle version** (confirmat 2026-04-12): `Oracle Database 21c Express Edition`.
Schema-level grants (23ai+) nu sunt disponibile. Proxy auth (12c+) există dar anulează
beneficiul de securitate — vezi §4.
### 3.1. Attack surface comparison
| User conectare | SQL injection poate face | Attack surface |
|---|---|---|
| `CONTAFIN_ORACLE` (DBA) | SELECT/INSERT/DELETE pe **orice tabelă, orice schemă** | maxim |
| `ROA_WEB` proxied ca schemă | SELECT/INSERT/DELETE pe **orice tabelă din schemă** | mediu |
| `ROA_WEB` cu EXECUTE-only pe SP | doar apel SP cu parametri validați de SP | **minim** |
`CONTAFIN_ORACLE` conectat din web = punct slab critic: SQL injection prin parametrii
unui request HTTP poate exfiltra sau modifica date din orice schemă de pe server.
`ROA_WEB` cu EXECUTE-only: atacatorul poate cel mult apela SP-urile cu parametri
injectați. SP-urile Oracle sunt compilate, nu interpretate — parametrii sunt bind
variables, nu SQL concatenat. Suprafața de atac e redusă la logica validată din SP.
### 3.2. De ce nu proxy authentication
Proxy auth (`ALTER USER MARIUSM_AUTO GRANT CONNECT THROUGH ROA_WEB`) dă `ROA_WEB`
identitatea completă a schemei proxied → SELECT/INSERT direct pe orice tabelă din
acea schemă. Pierde exact beneficiul de securitate pentru care creăm `ROA_WEB`.
---
## 4. Arhitectura multi-tenant scalabilă (Oracle 21c)
### 4.1. Workflow firmă nouă
Firmele noi se creează via `impdp` dintr-o schemă template menținută la zi:
```bash
impdp system/... SCHEMAS=TEMPLATE_AUTO REMAP_SCHEMA=TEMPLATE_AUTO:FIRMA_NOUA ...
```
Schema nouă conține deja **toate** obiectele (SP-uri, view-uri, tabele) din template.
Onboarding-ul ROA_WEB = 1 script rulat după impdp:
```sql
-- onboarding_roa_web.sql — rulat ca CONTAFIN_ORACLE după impdp pentru fiecare firmă nouă
-- Înlocuiește FIRMA_NOUA cu schema reală
GRANT EXECUTE ON FIRMA_NOUA.SP_CREEAZA_COMANDA_PROTOTIP TO ROA_WEB;
GRANT SELECT ON FIRMA_NOUA.AUTO_VMASINICLIENTI TO ROA_WEB;
GRANT SELECT ON FIRMA_NOUA.DEV_TIP_DEVIZ TO ROA_WEB;
GRANT SELECT ON FIRMA_NOUA.CALENDAR TO ROA_WEB;
-- CALENDAR: period selector AppHeader (shared/routes/calendar.py)
GRANT SELECT ON FIRMA_NOUA.DEV_ORDL TO ROA_WEB;
-- DEV_ORDL: GET /api/service-auto/comenzi (list comenzi)
GRANT SELECT ON FIRMA_NOUA.NOM_LUCRARI TO ROA_WEB;
-- NOM_LUCRARI: JOIN cu DEV_ORDL pentru nrord (get_comenzi)
-- adaugă orice alte SP/view-uri noi apărute de la ultimul onboarding
```
### 4.2. Workflow SP/obiect nou
Când un SP nou se adaugă în **toate** schemele (ca parte dintr-o migrare), scriptul
de migrare are două componente:
**Componenta 1**`migration_YYYYMMDD_sp_noua.sql` — rulat per schemă (existent deja):
```sql
CREATE OR REPLACE PROCEDURE MARIUSM_AUTO.SP_NOUA (...) AS ...;
-- (repetat pentru fiecare schemă/firmă)
```
**Componenta 2**`migration_YYYYMMDD_sp_noua_grants.sql` — rulat O SINGURĂ DATĂ,
loopează automat toate schemele din `V_NOM_FIRME`:
```sql
-- Rulat ca CONTAFIN_ORACLE după ce migration_1 a rulat pe toate schemele
BEGIN
FOR firm IN (
SELECT DISTINCT schema
FROM contafin_oracle.v_nom_firme
WHERE schema IS NOT NULL
) LOOP
BEGIN
EXECUTE IMMEDIATE
'GRANT EXECUTE ON ' || firm.schema || '.SP_NOUA TO ROA_WEB';
EXCEPTION WHEN OTHERS THEN
NULL; -- skip dacă schema nu a primit încă migrarea SP (deployment order)
END;
END LOOP;
END;
/
```
`V_NOM_FIRME` e sursa de adevăr pentru toate schemele active — același tabel folosit
de backend pentru login JWT. Orice firmă adăugată în `V_NOM_FIRME` e inclusă automat
la **următoarea** migrare grants.
### 4.3. ROA_WEB creation script (one-time, DBA action)
```sql
-- Rulat O SINGURĂ DATĂ ca SYS sau CONTAFIN_ORACLE
CREATE USER ROA_WEB IDENTIFIED BY "<REPLACE_WITH_STRONG_PASSWORD_FROM_VAULT>";
GRANT CREATE SESSION TO ROA_WEB;
-- Fără alte privilegii sistem. Accesul la date = exclusiv prin granturi per-obiect.
```
### 4.4. Negative test — confirmă hypothesis #3 (scoped access)
```sql
-- Conectat ca ROA_WEB (NU CONTAFIN_ORACLE):
SELECT * FROM MARIUSM_AUTO.DEV_ORDL WHERE ROWNUM < 2; -- ORA-00942 așteptat
INSERT INTO MARIUSM_AUTO.DEV_ORDL (id_ordl, id_lucrare) VALUES (1, 1); -- ORA-00942 așteptat
-- SP call via bind vars — succes așteptat (ROLLBACK după verificare):
BEGIN
MARIUSM_AUTO.SP_CREEAZA_COMANDA_PROTOTIP(
p_id_tip => 1,
p_id_masiniclient => <existing_id>,
p_id_firma => 110,
p_solicitari => 'Test H3',
p_id_ordl => :o_id_ordl,
p_nrord => :o_nrord
);
END;
/
ROLLBACK;
```
### 4.5. Sumar scalabilitate
| Eveniment | Acțiune ROA_WEB | Cost |
|---|---|---|
| ROA_WEB creat (o dată) | `CREATE USER` + `GRANT CREATE SESSION` | O dată |
| Firmă nouă (`impdp`) | `onboarding_roa_web.sql` cu schema nouă | 1 script per firmă |
| SP nou în toate schemele | `migration_YYYYMMDD_sp_noua_grants.sql` (loop V_NOM_FIRME) | 1 script per migrare |
| View/tabelă nouă expusă | același pattern ca SP | 1 script per migrare |
| Expunere `CALENDAR` pentru period selector | `GRANT SELECT {SCHEMA}.CALENDAR TO ROA_WEB` per schemă | 1 linie per schemă (parte din onboarding §4.1) |
| Expunere `DEV_ORDL` + `NOM_LUCRARI` pentru GET /comenzi | `GRANT SELECT {SCHEMA}.DEV_ORDL/NOM_LUCRARI TO ROA_WEB` per schemă | 2 linii per schemă (parte din onboarding §4.1) |
---
## 4.6. Deploy procedure
Procedura completă de onboarding pentru o schemă/server nou (impdp → granturi →
`.env` → migrații → smoke tests → rollback) este documentată separat în:
**[deploy-schema-noua.md](deploy-schema-noua.md)**
Acest audit (§4.1§4.5) stabilește *de ce* onboarding-ul arată așa; fișierul
`deploy-schema-noua.md` stabilește *cum* îl execuți pas-cu-pas. Scriptul
`onboarding_roa_web.sql` e referința canonică pentru GRANT-urile per-schemă,
cu header self-documenting și placeholder `<SCHEMA>`.
---
## 5. Action items
- [x] **Task #1** — Grants audit completat (2026-04-11)
- [x] **Task #3**`SP_CREEAZA_COMANDA_PROTOTIP` creat + testat cu rollback (2026-04-11)
- [x] **Task #5**`mariusm_test` entry în `backend/.env` cu CONTAFIN_ORACLE (2026-04-11)
- [ ] **Săpt 4** (deferred, DBA action):
1. `CREATE USER ROA_WEB` + `GRANT CREATE SESSION` (§4.3)
2. Rulează `onboarding_roa_web.sql` pentru MARIUSM_AUTO (§4.1)
3. Switch `backend/secrets/mariusm_test.oracle_pass` + user → ROA_WEB în `.env`
4. Rulează `test_grants_integration.py` → 3 skipped trebuie să devină 3 passed
5. Rulează negative test din §4.4 manual (SQL Developer sau sqlplus)