Dette dokument beskriver NSP Security API til brugerautentificering og autorisering på NSP.
Det første afsnit beskriver den arkitekturmæssige motivation for indførelsen af NSP Security API.
Dernæst vises hvordan NSP Security API rent praktisk indføres i en NSP komponent med konkrete eksempler på anvendelse. Denne sektion er især relevant for udviklere, der skal bruge NSP Security API i forbindelse med en konkret opgave. Det anvendelsesorienterede afsnit er delt op i følgende underafsnit:
Målet med NSP Security API er at gøre det let for services at tjekke sikkerhed - både DGWS, IDWS. Derudover skal NSP Security API gøre det muligt at understøtte sikkerhedsprotokoller i fremtiden.
Dette skal gøres på en måde, så de anvendende services/komponenter tilbydes de nødvendige abstraktioner/termer og passende mapning fra de konkrete sikkerhedsprotokoller til en model, der gør det muligt at tilgå forskellige elementer i den indkommende sikkerhedsbillet.
Termerne spiller også ind i måden, som SDS ønsker at modellere brugere/aktører i forhold til de user stories som beskriver opførsel og komponenter. Det er op til komponenterne selv at modellere de aktører, som de skal servicere, så NSP Security API opererer på et lavere niveau, hvor denne mapning giver mening.
Overordnet princip: Udtrykker kun den information, som findes i sikkerhedsbilletten - og ikke andet.
Stiller informationen til rådighed for komponenten gennnem SecurityContext hvorfra, der er adgang til alle information bl.a. ActingUser (den bruger, der trykker på knapperne), PrincipalUser (den bruger, der er ansvarlig for handlingen), Organisation, Message og Ticket.
Modellen er mere generel end de nuværende sikkerhedsprotokoller og udfaldrummet for de aktuelle sikkerhedsbilletter giver anledning til.
F.eks. finder der i praksis i dag ikke billet, hvor en sundhedsperson kan arbejde på vegne af en anden sundhedsperson (dvs. både ActingUser og PrincipalUser er tilstede). Dette kan udtrykkes i Security API'ets model og det er meget tænkeligt, at der kommer support for dette i fremtiden (når XUA kommer på banen).
Nedenstående tabel er en oversigt over den model, der stilles til rådighed for anvenderen af NSP Security API:
TODO: Mere forklaring på de enkelte properties (hvad er en autorisationskode f.eks.? Hvad er en uddannelseskode?)
TODO: eksempel hvor vi har en DGWS billet og en IDWS billet og kan se hvilken model de så giver anledning til.
Ticket | Audience | Begrænsning i forhold til, hvor den givne sikkerhedsbillet kan anvendes | ||
Validity | Er sikkerhedsbilletten gyldig (udsteder, gyldighedsperiode o.s.v)? | |||
Message | Identifier | Identifier på beskeden (web service kaldet) | ||
ConversationIdentifier | Identifier på "samtalen" mellem anvender og komponent. Flere beskeder kan således grupperes til en samlet interaktion. | |||
Action | Den action, som ønskes udført på den modtagende service | |||
ActingUser | UserType | Udfaldsrum: HealthcareProfessional, Citizen | Den udførende brugers (d.v.s den bruger, der udfører af kaldet) brugertype | |
IdentifierFormat | Udfaldsrum: CPR | Udførende brugers identifikator type | ||
Identifier | Udførende brugers identifikator | |||
GivenName | Udførende brugers fornavn | |||
SurName | Udførende brugers efternavn | |||
Credentials | AuthorizationCode | Udførende brugers legitimationsoplysninger | ||
EducationCode | Udførende brugers uddannelseskode | |||
NationalRole | Udførende brugers nationale rolle | |||
UnverifiedRole | Udførende brugers rolle (er ikke verificeret af den udstedende part - i praksis SOSI STS) | |||
PowerOfAttorneyPrivileges | Udførende brugers fuldmagtsstrenge | |||
PersistentUniqueKey | TODO: Udførende brugers autentifikations unikke nøgle | |||
PrincipalUser | UserType | Udfaldsrum: HealthcareProfessional, Citizen | Den ansvarlige brugers (d.v.s den bruger, kaldet foretages "på vegne af") brugertype | |
IdentifierFormat | Udfaldsrum: CPR | Ansvarlige brugers identifikator type | ||
Identifier | Ansvarlige brugers identifikator | |||
GivenName | Ansvarlige brugers fornavn | |||
SurName | Ansvarlige brugers efternavn | |||
Credentials | AuthorizationCode | Ansvarlige brugers legitimationsoplysninger | ||
EducataionCode | Ansvarlige brugers uddannelseskode | |||
NationalRole | Ansvarlige brugers nationale rolle | |||
UnverifiedRole | Ansvarlige brugers rolle (er ikke verificeret af den udstedende part - i praksis SOSI STS) | |||
PowerOfAttorneyPrivileges | Ansvarlige brugers fuldmagtsstrenge | |||
PersistentUniqueKey | TODO Ansvarlige brugers autentifikations unikke nøgle | |||
Organisation | IdentifierFormat | Udfaldsrum: CVR | Den udførende brugers organisations identifikator type | |
Identifier | Den udførende brugers organisations identifikator | |||
Name | Den udførende brugers organisations navn | |||
Client | Name | Den udførende klients navn (kaldende systems navn) | ||
PersistentUniqueKey | TODO |
Som det blev beskrevet før, så er NSP Security APIs model meget generel og kan udtrykke ting, som der i øjeblikket ikke kan forekomme i praksis.
Dette betyder dog, at det kan være ligeså vigtigt, at en komponent validerer både attributter der findes, og dem der ikke findes, for at mappe korrekt til de relevante aktører.
I eksemplet fra før, hvor en sundhedsfaglig, der handler på vegne af en anden sundhedsfaglig: Dette kan udtrykkes i Security API, men der findes ikke (i dag) en sikkerhedsbillet, der kan bærer denne information.
Komponenten bør dog forholde sig til, hvad der er muligt i Security API'et model, og ikke kun på, hvad der er muligt i de aktuelle sikkerhedsbilletter. Hvis en komponent ikke ekplicit tillader "på-vegne-af" bør den tjekke, at sikkerhedsbilletten ikke er af en sådan type.
I mange komponenter er forretningslogikken og aktør-modelleringen afhængig af oplysninger, der ikke er en del af Security API. Eksempler kan være:
I aktørmodellen må komponenten gerne tage disse oplysninger med i aktørmodelleringen.
Det skal dog være tydeligt i dokumentationen og mapningen for den enkelte komponent, hvilke oplysninger, der stammer hvorfra (hvilke, der er en del af de STS-validerede oplysninger og hvilke der er kontekst-oplysninger, der essentielt bare er en udvidelse af det af komponenten udbudte API med ekstra kontekst).
For at anvende NSP Security API i en konkret NSP komponent i udviklingsmæssig sammenhæng, så er der et par tekniske øvelser, der skal være på plads. Da hovedparten af NSP'ens komponenter er bygget op på samme måde, så vil denne vejledning umiddelbart kunne anvendes i langt de fleste tilfælde. Antagelsen i denne vejledning er derfor at:
I de følgende afsnit gennemgåes først, hvordan en komponent forberedes teknisk til at kunne anvende NSP Security API ved at udtrykke både en kodemæssig og en afviklingsmæssig afhængighed til NSP Security API.
Dernæst vises det med et praktisk eksempel hentet fra DROS og Dokumentdelingsservicen, hvordan NSP Security API bliver anvendt i dokumentation og applikationskode til at implementere brugerautentificering og -autorisation.
Det er vigtigt at notere sig, at eksempler i denne anvenderguide er ment som inspiration til anvendere af NSP Security API. Det er således ikke en udtømmende facitliste. Anvendelsen af NSP Security API kræver komponentspecifikke og forretningsspecifikke overvejelser:
I forgående afsnit blev det fremhævet, at det ikke er en NSP komponents ansvar selv at inkludere NSP Security API i dens færdigbyggede modul.
I stedet udtrykker komponenten, at den regner med, at de omgivelser, hvori den efterfølgende afvikles, stiller NSP Security API til rådighed på afviklingstidspunktet.
Langt de fleste NSP komponenter anvender Maven til at holde styr på afhængigheder til tredjeparts biblioteker.
NSP Security API adskiller sig ikke fra andre tredjeparts biblioteker i den forstand og kræver således blot, at følgende tilføjes til rækken af dependencies (NB! tjek versionsnummer i forhold til den gældende version) i konfigurationsfilen (pom.xml):
<dependency> <groupId>dk.sds.nsp.security</groupId> <artifactId>security-api</artifactId> <version>1.0.6</version> <scope>provided</scope> </dependency> |
Det er vigtigt at notere sig, at afhængigheden til NSP Security API skal have provided scope.
Provided scope i Maven benyttes til at udtrykke en afhængighed til et library uden dette inkluderes i det færdigbyggede modul (jar/war), men som i stedet antages at blive stillet til rådighed (provided) af de omgivelser, som modulet afvikles i.
Afviklingsomgivelserne for en NSP komponent er Wildfly (evt via et af NSP'ens Docker images). I det følgende afsnit vises, hvordan man sørger for, at Wildfly rent faktisk stiller NSP Security API til rådighed for den anvendende komponent og derved opfylder kontrakten, som blev udtrykt i Maven konfigurationsfilen.
Afviklingsomgivelserne for en standard NSP komponent er Wildfly (evt via et af NSP'ens Docker images). På Wildfly findes en række tredjeparts biblioteker, der leveres med platformen - herunder også NSP Security API.
Som default er de fleste af disse bibliotekter afskærmet og således ikke til rådighed for komponenten på afviklingstidspunktet - men via en særlig konfigurationsfil (som Wildfly forstår) kan det udtrykkes, at komponenten ønsker, at få adgang til et eller flere af disse biblioteker.
For at Wildfly kan stiller NSP Security API til rådighed for en komponent skal filen /src/main/webapp/WEB-INF/jboss-deployment-structure.xml findes i Maven projektet og i det byggede modul og have følgende indhold:
<jboss-deployment-structure xmlns="urn:jboss:deployment-structure:1.2"> <deployment> <!-- NSP komponenter styrer selv logning --> <exclude-subsystems> <subsystem name="logging"/> </exclude-subsystems> <!-- Denne komponent anvender NSP Security API --> <dependencies> <module name="dk.sds.nsp.security"/> </dependencies> </deployment> </jboss-deployment-structure> |
Det er vigtigt af forstå, at der ikke nødvendigvis er sammenhæng mellem det versionsnummer af NSP Security API, som bliver udtrykt i Maven afhængigheden, og den version af NSP Security API, der bliver stillet til rådighed af Wildfly.
Det er komponentens eget ansvar at sørge for, at der er sammenhæng mellem disse. Eventuelle versionsforskelle mellem det, som en komponent tror, at den får stillet til rådighed, og det, som den rent faktisk får stillet til rådighed, kan give en masse udfordringer og underlige fejl (NoSuchMethodException, ClassNotFoundException med flere), når komponenten afvikles og anvender NSP Security API.
I praksis kan man tjekke versionen af NSP Security API, der bliver stillet til rådighed af Wildfly, på følgende måde:
root@7e07691acb13:~# cd /tmp root@7e07691acb13:/tmp# jar xf /pack/wildfly/modules/system/layers/base/dk/sds/nsp/security/main/nsp-security-api.jar root@7e07691acb13:/tmp# cat META-INF/MANIFEST.MF Manifest-Version: 1.0 Implementation-Title: NSP Security API Implementation-Version: Archiver-Version: Plexus Archiver Built-By: root Created-By: Apache Maven 3.5.4 Build-Jdk: 1.8.0_275 Specification-Version: 1.0.6 |
I ovenstående eksempel er det NSP Security API version 1.0.6, der stilles til rådighed af den konkrete version af Wildfly, hvilket hænger fint sammen med det versionsnummer, der blev udtrykt i Maven afhængigheden (i pom.xml).
Førhen håndterede og verificerede komponenterne selv sikkerheden. Det gav derfor mening, at sikkerhedsmodellen blev udtrykt i snitfladebeskrivelserne for komponenterne. I flere komponenter har vi således for nuværende flere version af den samme snitflade: En til DGWS og en til IDWS.
Med introduktionen af NSP Security API er det ikke længere nødvendigt for den enkelte komponent at beskrive og håndtere DGWS og IDWS konkret i koden. Det kan derfor lade sig gøre at udstille snitfladebeskrivelser, der er renset for sikkerhedsprotokollen, da komponenten kan anvende NSP Security API.
Hvis komponenterne renses for sikkerhedsprotokol-afhængige snitfladebeskrivelser og kode, vil der på sigt blive mindre kode at vedligeholde.
I forhold til at rapportere fejl tilbage til anvenderne ville man før NSP Security API være tvunget til at gøre dette på en sikkerhedsprotokolafhængig måde f.eks. ved at sende en DGWSFault tilbage.
Med introduktionen af NSP Security API gives ansvaret for at levere fejl tilbage til anvenderne på den rigtige (i praksis DGWS-agtige eller IDWS-agtige) måde til NSP Security API. Komponenten skal blot kaste en javax.xml.ws.soap.SOAPFaultException, også vil platformen tage sig af resten.
Som nævnt i første afsnit, så stiller NSP Security API en række håndtag til rådighed for den anvendende komponent. Det er komponentens egen opgave at
En given NSP komponent skal forholde sig til, hvilke brugertyper den understøtter. Dette er i høj grad en forretningsmæssig beslutning, og det er vigtigt at en komponent dokumenterer de understøttede brugertyper. Dokumentationen af brugertyperne og de brugerhistorier, som de indgår i foretages i dokumenttypen Brugerhistorier. Et eksempel på et sådant dokument er DROS - Brugerhistorier. Mange eksisterende NSP komponenter har ikke dette dokument, men en succesfuld anvendelse af NSP Security API forudsætter, at det eksisterer. Derfor bør indførelsen af NSP Security API først ske efter, at denne dokumentation er udarbejdet. Denne dokumenttype er ikke et teknisk dokument og indholdet skal som minimum gennemlæses og verificeres af SDS NSP arkitekt og Product Owner.
Dokumentation af brugerhistorier er den forretningsrettede dokumentation af, hvad en komponent kan, og hvem der kan anvende den og er således også en forudsætning for at anvendere kan scope og designe deres integration i henhold til dokumentationen i Guide til Anvendere. Se f.eks. DROS - Guide til anvendere for et eksempel på at sammenholde anvenderguide og brugerhistorier.
Fremadrettet vil det give mening at ændringer til en NSP komponent udtrykkes som brugerhistorier.
Når dokumentationen af de understøttede brugertyper er på plads, så skal den konkrete mapning og verifikation fra NSP Security APIs context til sin egen aktørmodel laves.
Komponenten skal modellere disse aktører på en eller anden måde så det giver mening. Dette kan f.eks laves ved hjælp af nedarvningshierarkier eller en simpel enumeration, der lister brugertyperne.
For hver af de understøttede brugertyper, skal det i Design og Arkitektur dokumentet for en komponent fremgå, hvorledes disse brugertyper bestemmes, verificeres og mappes.
Som et eksempel tages her udgangspunkt i Dokumentdelingsservicen.
I Dokumentdelingsservicen understøttes blandt andre brugertypen borger. En borger er en myndig person, som tilgår information om sig selv.
I Dokumentdelingsservicen kan man ende med at blive borger på to forskellige måder:
Begge tilfælde kræver mapning og verifikation fra NSP Security API, men i tilfælde 2 skal der anvendes yderligere information (fra den indkommende HSUID header).
Til dokumentationsformål kan man for eksempel anvende følgende metode, hvor de to tilfælde dokumenteres i tabelformat som nedenstående (udgangspunktet er tabellen ovenfor i dokumentationen af NSP Security API.
Brugertypen Borger (borgerbillet) | Verifikation | Mapning til DDS ServiceActor | ||
SecurityContext | Ticket | Audience | Matche audience som findes som konfiguration i Dokumentdelingsservice | |
Validity | Er valid | |||
Message | Verificeres ikke - må gerne være der | |||
ActingUser | UserType | Skal være Citizen | Brugertypen: Borger | |
IdentifierFormat | Skal være CPR | |||
Identifier | Skal være sat | PersonIdentifier | ||
GivenName | Verificeres ikke - må gerne være der | |||
SurName | Verificeres ikke - må gerne være der | |||
Credentials | Verificeres ikke - må gerne være der | |||
PersistentUniqueKey | Verificeres ikke - må gerne være der | |||
PrincipalUser | Må ikke være der | |||
Organisation | Må ikke være der | |||
Client | Verificeres ikke - må gerne være der |
Brugertypen Borger (sundhed.dk) | Verifikation | Mapning til DDS ServiceActor | ||
SecurityContext | Ticket | Audience | Verificeres ikke - må gerne være der | |
Validity | Er valid | |||
Message | Verificeres ikke - må gerne være der | |||
ActingUser | UserType | Må ikke være der | ||
PrincipalUser | UserType | Må ikke være der | ||
Organisation | IdentifierFormat | Skal være CVR | ||
Identifier | Skal være der og skal være "niveau 3" whitelistet | |||
Name | Verificeres ikke - må gerne være der | |||
Client | Verificeres ikke - må gerne være der | |||
HSUID Header | Det verificeres, at HSUID headeren findes, og at den modellerer en borger | Brugertypen: Borger PersonIdentifier |
TODO kode eksempel fra DDS (måske pseudokode for at hjælpe)?
TODO Hvordan beskrive brugertyper og sikkerhedsprotokoller for anvenderne?