Dette dokument beskriver design og arkitektur af 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. I de følgende afsnit gennemgåes modellen i NSP Security API mere detaljeret og ansvarsfordelingen mellem den anvendende NSP komponent og NSP Security API gennemgås.

Motivation for NSP Security API

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.

Modellen i NSP Security API

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. TODO Menes der at modellen er mere generel end de udfaldsrum de nuværende sikkerhedsprotokoller- og billetter giver anledning til, og er derfor godt rystet på til at håndtere fremtidige protokoller?

F.eks. findes der i praksis i dag ikke en 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).

Modellen for den kaldende brugeres sikkerhedsmæssige egenskaber stilles til rådighed for den anvendende komponent gennem en statisk metode på en eneste klasse:

dk.sds.nsp.security.SecurityContext dk.sds.nsp.security.Security.getSecurityContext()

Retursvaret er den model, som NSP Security API udbyder. Nedenstående tabel er en oversigt over egenskaberne for denne model:

TicketisValid


Er sikkerhedsbilletten gyldig (udsteder, gyldighedsperiode o.s.v)?

Federation


Federation billetten giver adgang til.

Audience


Begrænsning i forhold til, hvor den givne sikkerhedsbillet kan anvendes

Created


Dato/tidspunkt for hvornår billetten er oprettet

ValidFrom


Dato/tidspunkt for hvornår billetten er gyldig fra

ValidTo


Dato/tidspunkt for hvornår billetten er gyldig til
MessageIdentifier


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
ActingUserUserType

Udfaldsrum: HealthcareProfessional, CitizenDen udførende brugers (d.v.s den bruger, der udfører af kaldet) brugertype

IdentifierFormat

Udfaldsrum: CPRUdførende brugers identifikator type

Identifier


Udførende brugers identifikator - i praksis et CPR nummer

GivenName


Udførende brugers fornavn

SurName


Udførende brugers efternavn

CredentialsAuthorizationCode

Er udfyldt, hvis den udførende bruger er en sundhedsfaglige bruger med et autorisations-id. Autorisations-id er et unikt alment tilgængeligt id, er udstedes til alle autoriserede sundhedsfaglige i Danmark. Se f.eks. Autorisation.


EducationCode

Er udfyldt, hvis den udførende bruger er en sundhedsfaglige bruger, der tilhører en specifik faggruppe. F.eks. angiver uddannelseskoden '7170', at brugeren er 'læge'. Se f.eks. Autorisation for en liste over uddannelseskoder.


NationalRole

Er udfyldt, hvis den udførende bruger er i besiddelse af en national rolle opsat i Sundhedsdatastyrelsens Elektoniske Brugerstyring (SEB). Se Stamdataregister: SEB. Udfyldelse af NationalRole og UnverifiedRole er i praksis gensidigt udelukkende.


UnverifiedRole

Udførende brugers rolle (er ikke verificeret af den udstedende part - i praksis SOSI STS). I praksis er disse roller "lokale" roller dvs. roller, der ikke er nationale roller (se ovenfor). Udfyldelse af NationalRole og UnverifiedRole er i praksis gensidigt udelukkende.


PowerOfAttorneyPrivileges

Er udfyldt, hvis den udførende bruger er en borger og hvis der findes en anden borger som Principal User i sikkerhedsmodllen. Hvis dette er tilfældet så udtrykker denne liste "udførende brugers fuldmagtsstrenge i forhold til den ansvarlige bruger". De konkrete fuldmagtsstrenge vedligeholdes hos Digitaliseringsstyrelsen.

Borgere kan vedligeholde deres fuldmagtstildelinger via portalen http://borger.dk.



BlurringInstructionsSalt
Den salt der er anvendt ved slørede organisationer



BlurredOrganisations
Ansvarlige brugers slørede organisationer

PersistentUniqueKey


TODO: Udførende brugers autentifikations unikke nøgle

Relation

Udfaldsrum:

ProxyHolder,
ChildCustodyHolder,
Guardian,
Principal,
Child,
Ward

Relation mellem ActingUser og PrincipalUser

Age


Udførende brugers alder
PrincipalUserUserType

Udfaldsrum: HealthcareProfessional, CitizenDen ansvarlige brugers (d.v.s den bruger, kaldet foretages "på vegne af") brugertype

IdentifierFormat

Udfaldsrum: CPRAnsvarlige brugers identifikator type. Se tilsvarende beskrivelse for ActiveUser.

Identifier


Ansvarlige brugers identifikator. Se tilsvarende beskrivelse for ActiveUser.

GivenName


Ansvarlige brugers fornavn. Se tilsvarende beskrivelse for ActiveUser.

SurName


Ansvarlige brugers efternavn. Se tilsvarende beskrivelse for ActiveUser.

CredentialsAuthorizationCode

Ansvarlige brugers legitimationsoplysninger. Se tilsvarende beskrivelse for ActiveUser.


EducataionCode

Ansvarlige brugers uddannelseskode. Se tilsvarende beskrivelse for ActiveUser.


NationalRole

Ansvarlige brugers nationale rolle. Se tilsvarende beskrivelse for ActiveUser.


UnverifiedRole

Ansvarlige brugers rolle. Se tilsvarende beskrivelse for ActiveUser.


PowerOfAttorneyPrivileges

Ansvarlige brugers fuldmagtsstrenge. Findes ikke på PrincipalUser men udelukkende på ActiveUser, da fuldmagt udtrykker ActiveUsers privilegier i relation til PrincipalUser.


BlurringInstructionsSalt
Den salt der er anvendt ved slørede organisationer



BlurredOrganisations
Ansvarlige brugers slørede organisationer

PersistentUniqueKey


TODO Ansvarlige brugers autentifikations unikke nøgle

Relation

Udfaldsrum:

ProxyHolder,
ChildCustodyHolder,
Guardian,
Principal,
Child,
Ward

Relation mellem ActingUser og PrincipalUser

Age


Ansvarlige brugers alder
OrganisationIdentifierFormat

Udfaldsrum: CVRDen udførende brugers organisations identifikator type - i praksis et CVR nummer.

Identifier


Den udførende brugers organisations identifikator - i praksis et CVR nummer.

Name


Den udførende brugers organisations navn
ClientName


Den udførende klients navn (kaldende systems navn)

PersistentUniqueKey


TODO

Eksempel på DGWS billet

Hvis billetten indeholder denne SAML attribute, så er der tale om en DGWS billet:

<saml:Attribute Name="sosi:IDCardVersion">
    <saml:AttributeValue>1.0.1</saml:AttributeValue>
</saml:Attribute>

DGWS request:

<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
    xmlns:ds="http://www.w3.org/2000/09/xmldsig#"
    xmlns:medcom="http://www.medcom.dk/dgws/2006/04/dgws-1.0.xsd"
    xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
    xmlns:sosi="http://www.sosi.dk/sosi/2006/04/sosi-1.0.xsd"
    xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing"
    xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
    xmlns:wst="http://schemas.xmlsoap.org/ws/2005/02/trust"
    xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" id="Envelope">
    <soapenv:Header>
        <wsse:Security>
            <wsu:Timestamp>
                <wsu:Created>2020-02-21T13:37:40Z</wsu:Created>
            </wsu:Timestamp>
            <saml:Assertion IssueInstant="2020-02-21T13:32:33Z" Version="2.0" id="IDCard">
                <saml:Issuer>CSTAG-NSP-STS</saml:Issuer>
                <saml:Subject>
                    <saml:NameID Format="medcom:other">SubjectDN={SERIALNUMBER=CVR:30808460-UID:25351738
                        + CN=NETS DANID A/S - TU VOCES gyldig, O=NETS DANID A/S // CVR:30808460,
                        C=DK},IssuerDN={CN=TRUST2408 Systemtest XXII CA, O=TRUST2408,
                        C=DK},CertSerial={1538079460}</saml:NameID>
                    <saml:SubjectConfirmation>
                        <saml:ConfirmationMethod>urn:oasis:names:tc:SAML:2.0:cm:holder-of-key</saml:ConfirmationMethod>
                        <saml:SubjectConfirmationData>
                            <ds:KeyInfo>
                                <ds:KeyName>OCESSignature</ds:KeyName>
                            </ds:KeyInfo>
                        </saml:SubjectConfirmationData>
                    </saml:SubjectConfirmation>
                </saml:Subject>
                <saml:Conditions NotBefore="2020-02-21T13:32:33Z"
                    NotOnOrAfter="2020-02-22T13:32:33Z" />
                <saml:AttributeStatement id="IDCardData">
                    <saml:Attribute Name="sosi:IDCardID">
                        <saml:AttributeValue>+Z/Pwyh53J8NNTFy+lil/g==</saml:AttributeValue>
                    </saml:Attribute>
                    <saml:Attribute Name="sosi:IDCardVersion">
                        <saml:AttributeValue>1.0.1</saml:AttributeValue>
                    </saml:Attribute>
                    <saml:Attribute Name="sosi:IDCardType">
                        <saml:AttributeValue>system</saml:AttributeValue>
                    </saml:Attribute>
                    <saml:Attribute Name="sosi:AuthenticationLevel">
                        <saml:AttributeValue>3</saml:AttributeValue>
                    </saml:Attribute>
                    <saml:Attribute Name="sosi:OCESCertHash">
                        <saml:AttributeValue>6FrE4qXtnOTM/vQvP53h5KUhzd0=</saml:AttributeValue>
                    </saml:Attribute>
                </saml:AttributeStatement>
                <saml:AttributeStatement id="SystemLog">
                    <saml:Attribute Name="medcom:ITSystemName">
                        <saml:AttributeValue>SOSITEST</saml:AttributeValue>
                    </saml:Attribute>
                    <saml:Attribute Name="medcom:CareProviderID" NameFormat="medcom:cvrnumber">
                        <saml:AttributeValue>30808460</saml:AttributeValue>
                    </saml:Attribute>
                    <saml:Attribute Name="medcom:CareProviderName">
                        <saml:AttributeValue>orgName</saml:AttributeValue>
                    </saml:Attribute>
                </saml:AttributeStatement>
                <ds:Signature id="OCESSignature">
                    <ds:SignedInfo>
                        <ds:CanonicalizationMethod
                            Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
                        <ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1" />
                        <ds:Reference URI="#IDCard">
                            <ds:Transforms>
                                <ds:Transform
                                    Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" />
                                <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
                            </ds:Transforms>
                            <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
                            <ds:DigestValue>ISAWquDPx9zE1U+o5mW4R7w+hLA=</ds:DigestValue>
                        </ds:Reference>
                    </ds:SignedInfo>
                    <ds:SignatureValue>
                        wspDBdACGNRFaRtVumj4jWq3BD3fcPcTsB7vJx/6vFlb1CPpcXLdozOPCSDy0Yio8X4UQK49g6FZrb+TK9mkgvR7lyUEe8hLd+FRkF03uOmo1BoFuL/2mHsGgeQJdPLtjlmrYTXWqpqK2T5XS84fFWEIqFWljtV2bXWSR2u6Y+8xutgWdtSa0gBeGKHHwnWDXH8x7Zr6ooslFB2/FbaysrUEj8Q6kpyQ9QO4gh1AvMp8bVAMc7Z8EOsybbiMBfxBzT0RcMLGrG546x+SvdrYIY60jW+QyPMowmQumlsvDt5HnJmYYq+y81EwrBDGtpbXxRyPNQIK3wyE/wuFCa/Kqw==</ds:SignatureValue>
                    <ds:KeyInfo>
                        <ds:X509Data>
                            <ds:X509Certificate>
                                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</ds:X509Certificate>
                        </ds:X509Data>
                    </ds:KeyInfo>
                </ds:Signature>
            </saml:Assertion>
        </wsse:Security>
        <medcom:Header>
            <medcom:SecurityLevel>3</medcom:SecurityLevel>
            <medcom:Linking>
                <medcom:MessageID>AAABcGf313k2LiC/mzg5OVNPU0k=</medcom:MessageID>
            </medcom:Linking>
            <medcom:RequireNonRepudiationReceipt>no</medcom:RequireNonRepudiationReceipt>
        </medcom:Header>
    </soapenv:Header>
    <soapenv:Body>
        <ml:ListLogStatementsRequest xmlns:ml="http://nsi.dk/minlog/2014/05/23/">
            <cprNR xsi:type="II" root="B2E25F59-46A7-4E28-BF49-8D334E2AA756"
                xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">1410772120</cprNR>
            <pageSize>30</pageSize>
        </ml:ListLogStatementsRequest>
    </soapenv:Body>
</soapenv:Envelope>

Resulterende sikkerhedsmodel:


Eksempel på IDWS billet

Hvis billetten indeholder denne SAML attribute, så er der tale om en IDWS billet:

<saml:Attribute Name="dk:gov:saml:attribute:SpecVer" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
    <saml:AttributeValue xsi:type="xs:string">DK-SAML-2.0</saml:AttributeValue>
</saml:Attribute>

IDWS request:

Resulterende sikkerhedsmodel:

Eksempel på JTP-H token

Hvis Content-Type for requestet indeholder "JSON", så håndteres det som en JTP-H token, da det pt. er det eneste der er understøttet i NSP Access Handler.

Eksempel på JTP-H token:

Resulterende sikkerhedsmodel:

TicketAudiencehttp://audience.nspop.dk/test

Validitytrue

Created2025-06-19T11:14:48+02:00

ValidFrom2025-06-19T11:14:48+02:00

ValidTo2025-06-19T11:16:48+02:00
MessageIdentifier

ConversationIdentifier

Action
ActingUserTypeCitizen

IdentifierFormatCPR

Identifier1234567890

GivenNameHenning

SurNameThomsen

Age

RelationChildCustodyHolder

PersistentUniqueKey46f8cb60-4e29-42ba-8d08-501a34375b6b
PrincipalUserTypeCitizen

IdentifierFormatCPR

Identifier0987654321

GivenName

SurName

Age

RelationChild
ClientNameMyTestSystem

Ansvarsfordeling mellem komponent og NSP Security API

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.

F.eks kan eksemplet fra før, hvor en sundhedsfaglig, der handler på vegne af en anden sundhedsfaglig, udtrykkes i Security API, men der findes ikke (i dag) en sikkerhedsbillet, der kan bære denne information.

Komponenten bør dog forholde sig til, hvad der er muligt i Security API'ets 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.

Hvad med alt det, der ikke er i sikkerhedsbilletten?

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 en ekstra kontekst).