feat(service-auto): săpt 3-phase2 — toate ipotezele confirmate + modul funcțional
Backend: - service_auto module complet: router, service, schemas, 5 teste suites (22/22 passed) - 5 endpoints: GET /ping, /firme, /tip-deviz, /masini, POST /comenzi - SP_CREEAZA_COMANDA_PROTOTIP creat în MARIUSM_AUTO (VALID, 5.9ms) - oracle_pool.py: session_callback backward-compat patch - ROA_WEB user: grants SP-only confirmate (H3), mariusm_test pool switchat - pyproject.toml: integration pytest marker înregistrat Frontend: - ComandaNoua.vue: date reale din Oracle (firme/tip-deviz/masini), nu hardcodate - src/modules/service-auto/services/api.js: axios service cu Bearer token - src/router/index.js: rută /service-auto/comanda-noua Docs: - decision-log.md: verdict MERGE, toate 6 ipoteze CONFIRMED - learnings.md: 7 patterns reutilizabile - grants-audit.md: arhitectura multi-tenant + proxy auth analysis + V_NOM_FIRME loop - template-modul-oracle.md: rețetă completă pentru module Oracle noi - TODO-phase2.md: 7 items concrete Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
210
docs/service-auto/grants-audit.md
Normal file
210
docs/service-auto/grants-audit.md
Normal file
@@ -0,0 +1,210 @@
|
||||
# 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;
|
||||
-- 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 |
|
||||
|
||||
---
|
||||
|
||||
## 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)
|
||||
Reference in New Issue
Block a user