Åtkomsthärdning: kontospärr, omedelbar återkallelse, takt på inloggning
Två luckor från genomgången, båda i auth. En utfärdad token gällde sina tolv timmar ut. Det fanns dessutom inget sätt att stänga av ett konto alls — en person som slutade behöll åtkomsten till organisationens ärenden. Nu bär token en version, och varje autentiserat anrop slår upp kontot och kontrollerar att det är aktivt och att versionen stämmer. Det kostar ett uppslag på primärnyckeln per anrop och ger i gengäld omedelbar verkan i stället för en avstängning som börjar gälla någon gång i morgon. Administratören stänger av och öppnar konton i användarlistan. Att stänga av höjer token-versionen, så pågående sessioner upphör direkt; öppnas kontot igen förblir de gamla token döda. Ingen kan stänga av sig själv och organisationsgränsen gäller. Var och en kan dessutom logga ut på alla enheter — vägen ut när en telefon tappats bort. Händelseloggen rörs aldrig: historiken är fortfarande knuten till den som utförde arbetet. Lösenord kunde gissas i obegränsad takt. Spärren ligger nu i databasen, inte i minnet, så den håller bakom flera repliker: 10 misslyckade försök per konto och 30 per källadress inom 15 minuter. Spärren gäller kontot även vid rätt lösenord — annars kunde den kringgås av den som till slut gissar rätt. Andra konton påverkas inte. Inget lösenord lagras, bara att ett försök skedde och om det lyckades, och rader äldre än ett dygn städas bort i skrivvägen. Ett avstängt konto räknas som misslyckat försök så att svarstiden inte avslöjar vilka konton som finns. Verifierat: 87 vitest-tester, typkontroll, eslint, OpenAPI-validering och integrationstest mot riktig Postgres med 13 nya kontroller — rollstyrning, självavstängning, organisationsgränsen, att en utfärdad token dör direkt, att den förblir död efter återöppning, logga-ut-alla samt att spärren slår till, gäller även rätt lösenord och inte smittar andra konton. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012EQg3rJsrQ1ZNTvkzmQAtt
This commit is contained in:
@@ -108,6 +108,33 @@ upp dess CRD redan vid plan. I `extern` läge kör ni
|
||||
`infra/postgres-init.sql` mot databasen själva; det är samma fil som
|
||||
integrationstestet kör.
|
||||
|
||||
## Åtkomst: spärr och återkallelse
|
||||
|
||||
En giltig JWT-signatur räcker inte. Varje autentiserat anrop slår upp
|
||||
kontot och kontrollerar två saker till: att det fortfarande är aktivt och
|
||||
att token-versionen stämmer. Det kostar ett uppslag på primärnyckeln per
|
||||
anrop och ger i gengäld **omedelbar** återkallelse i stället för att en
|
||||
avstängning börjar gälla först när token går ut om upp till tolv timmar.
|
||||
|
||||
| Situation | Väg | Effekt |
|
||||
| --- | --- | --- |
|
||||
| Någon slutar | `POST /api/anvandare/{id}/avaktivera` (admin) | Inloggning stängs och pågående sessioner upphör direkt |
|
||||
| Kontot ska tillbaka | `POST /api/anvandare/{id}/aktivera` (admin) | Kan logga in igen; tidigare återkallade tokens förblir döda |
|
||||
| Telefon borttappad | `POST /api/auth/logga-ut-alla` (sig själv) | Alla enheter loggas ut |
|
||||
|
||||
En administratör kan inte stänga av sig själv, och gränsen mellan
|
||||
organisationer gäller — org B kan inte röra org A:s användare.
|
||||
Händelseloggen rörs aldrig: historiken är fortfarande knuten till
|
||||
personen som utförde arbetet.
|
||||
|
||||
**Takt-begränsning på inloggning** ligger i databasen, inte i minnet, så
|
||||
spärren håller bakom flera repliker: 10 misslyckade försök per konto och
|
||||
30 per källadress inom 15 minuter ger 429. Spärren gäller kontot även vid
|
||||
rätt lösenord — annars kunde den kringgås av den som till slut gissar
|
||||
rätt. Andra konton påverkas inte. Inget lösenord lagras, bara att ett
|
||||
försök skedde och om det lyckades; rader äldre än ett dygn städas bort i
|
||||
skrivvägen.
|
||||
|
||||
## Multi-tenant och roller
|
||||
|
||||
Enligt Master Prompt: varje kund är en egen tenant, ingen data blandas mellan kunder.
|
||||
|
||||
@@ -55,6 +55,7 @@ Demomanus för visning: [DEMO.md](DEMO.md). Knappen **Skapa demoärende** på st
|
||||
| Instrumentavläsning (visual-first) | ✅ Kameran som universellt gränssnitt: `📷 Instrument` i Dokumentera-panelen fotograferar multimetrar, diagnosskärmar, batteritestare m.m. — bildtolkningen identifierar instrumenttyp och extraherar värden/enheter/felkoder med konfidens per värde; teknikern bekräftar innan något loggas. Originalbilden loggas alltid tillsammans med de strukturerade mätvärdena — strukturerad data ersätter aldrig originalevidensen. Ingen integration mot diagnossystem krävs. |
|
||||
| Utskrift | ✅ Kundrapport och Live Share-vy skrivs ut svart på vitt; interaktiva element döljs automatiskt. Utskriften går genom ECM-kvalitetsgrinden. |
|
||||
| Märkesspecifika kopplingar | ✅ Verkstaden konfigurerar sina egna OEM-/fordonsdataleverantörer under Inställningar med sina egna credentials ([moduler/markesspecifika-kopplingar.md](moduler/markesspecifika-kopplingar.md)): uppgifterna krypteras med AES-256-GCM i vila, returneras alltid maskerade (`••••3456`) och **alla uppslag görs av servern** — leverantörsnycklar når aldrig webbläsaren. Endast systemadministratören hanterar dem, kopplingarna är organisationsknutna och saknas krypteringsnyckeln sparas ingenting alls (fail closed). Leverantörer är data, inte kod: URL-mall, autentiseringstyp (bearer/header/basic/query) och svarsmappning beskrivs i `integrationer.json` (ConfigMap-utbytbar via `INTEGRATIONER_FIL`) — nya märken läggs till utan ombyggnad. Varje uppslag loggar teststatus, så ett utgånget abonnemang syns i inställningarna i stället för att ge tysta tomma svar. Verifierat i integrationstestet (rollstyrning, maskering, kryptering i databasen, organisationsisolering, fail closed). |
|
||||
| Åtkomstkontroll | ✅ **Återkallelse är omedelbar**: varje autentiserat anrop kontrollerar att kontot är aktivt och att token-versionen stämmer, i stället för att en avstängning börjar gälla när token går ut. Administratören stänger av och öppnar konton i användarlistan (kan inte stänga av sig själv, aldrig över organisationsgränsen), och var och en kan logga ut på alla enheter när en telefon tappats bort. **Takt-begränsning på inloggning** ligger i databasen och håller därför bakom flera repliker: 10 försök per konto och 30 per källadress inom 15 minuter, och spärren gäller kontot även vid rätt lösenord. Samtliga gränser verifierade i integrationstestet. |
|
||||
| Infrastruktur som kod | ✅ `infra/terraform` är systemets definition ([README](../infra/terraform/README.md)): `karta.tf` beskriver hela systemet en gång som data — tjänster, portar, routing, hemligheter per tjänst, dataflöden och gränser — och `terraform output karta` skriver ut samma sak i klartext. Namnrymden är stängd med nätverkspolicyer (bara ingress→tjänster, plattform→postgres, HTTPS ut utom privata nät), Postgres kör med säkerhetskontext, hemligheter kan genereras eller komma från en secrets-hanterare. **Databasen har tre lägen** och `databas_lage` saknar standardvärde med flit — valet avgör om det finns säkerhetskopiering: `extern` (managerad Postgres, leverantörens PITR — rekommenderat i produktion), `cnpg` (CloudNativePG i klustret: basbackup 02:30 + WAL-arkivering + failover) och `inbyggd` (en volym, ingen backup, spärrad av en precondition när miljön är produktion). Driftsättning är ett eget CI-flöde som startas för hand med en bildtagg mot en miljö med godkännandekrav, kör plan/apply, skriver ut kartan och rökkontrollerar. Kustomize-/Argo CD-vägen är borttagen. |
|
||||
| Öppet API | ✅ Plattforms-API:t är dokumenterat med OpenAPI 3.0 (`services/plattform/openapi.yaml`) — auth, användare, ärenden/händelser (append-only), översikt, publik delning och AI-orkestern, med scheman för alla händelsetyper. Specen valideras maskinellt, paritetstestas mot serverns rutter och serveras live på `GET /api/openapi.yaml`. |
|
||||
|
||||
|
||||
Reference in New Issue
Block a user