Page History
Revisionshistorik:
VersionVersion | Dato | Ændring | Ansvarlig |
0.8 | 29-11-2012 | Oprettet | IO |
1.0 | 04-04-2013 | redigeret | IO |
3.0.0 | 03-01-2017 | Fjernet .net 3.5 referancer | FMO |
4.0.0 | 26-06-2017 | Tilføjet IdCards og OioSamlFactory | KRO og SKS |
4.0.1 | 13-10-2022 | Rettet "SOSI Gateway SBO" dokumentation så den passer til ændringerne i '4.2.5'. | KvalitetsIT |
5.0.0 | 09-11-2022 | Tilføj migreringsguide for version '5.0.0'. Ret og opdater dokumentation. | KvalitetsIT |
...
Den Gode WebService (DGWS) er en profil for webservices, som bygger på flere WebService standarder fra WS* stakken. Det er ikke en triviel opgave at designe en klient eller en webservice implementering, der overholder DGWS profilen. Seal.Net Api'ets formål er, at sænke den tærskel der uvægerligt er forbundet med at udvikle software der overholder Den Gode WebService. Seal.Net indpakker alle DGWS specifikke detaljer og abstraherer alle typer fra XML til objektform. API'et tager sig af validering og signering.
Seal.NET udgives som en NuGet pakke.
Denne guiden er beregnet til it-faglige personer som skal til eller er i gang med at udvikle systemer, der skal benytte sig af Seal.Net. Det anbefales at platformsintroduktionen læses inden denne guide.
Læseren af denne guide forudsættes at have indsigt i .NET, C#, WCF (WSDL), og XML.
Hvis der er brug for support, kan der laves en indberetning til Service desk. Her kan der også indrapporteres fejl og oprette testdata.
Historik
Den Gode WebService er specificeret i tre versioner 1.0, 1.0.1 og 1.1. Ingen af versionerne er bagud- eller forudkompatible og der er tidligere udviklet individuelle API'er til at understøtte disse versioner.
Dette Api understøtter alle nuværende versioner af DGWS i samme implementering for hhv. klient og service.
Der er dog væsentlige designforskelle mellem dette API og tidligere versioner.
...
Relaterede komponenter
Seal.NET target'er .NET Standard 2.0, så den er kompatibel med .NET 5+ og .NET Core, samt .NET Framework projekter.
Migrering til version 5.0.0 fra ældre version
5.0.0 skifter target til .NET Standard 2.0, som medførerer API ændringer. Derudover er der lavet forsimplinger og oprydning af API'et.
Generelt
app.config er erstattet af appsettings.json og bruges kun til at sætte enkelte parametre:
Code Block | ||
---|---|---|
| ||
{
"CheckTrust": true,
"CheckDate": true,
"CheckCrl": false,
"sosi:dgws.version": "1.0.1",
"sosi:issuer": "TheSOSILibrary",
"credentialVault:alias": "SOSI:ALIAS_SYSTEM"
} |
Værdierne her er også default-værdierne, hvis en parameter eller hele appsettings-filen udelades.
...
Generelt for .NET Standard og WCF gælder det, at det der før blev konfigureret i app.config, nu konfigureres i kode.
Her er et eksempel på en klient, NtsWSProviderClient, der er genereret ud fra en WCF service reference, som konfigureres i kode, frem for gennem app.config:
Code Block | ||
---|---|---|
| ||
var binding = new CustomBinding();
binding.Elements.Add(new TextMessageEncodingBindingElement(MessageVersion.Soap11WSAddressingAugust2004, Encoding.UTF8));
binding.Elements.Add(new HttpTransportBindingElement());
var client = new NSTWsProvider.NtsWSProviderClient(binding, new EndpointAddress("https://test1-cnsp.ekstern-test.nspop.dk:8443/nts/service"));
client.Endpoint.EndpointBehaviors.Add(new SealEndpointBehavior());
client.Endpoint.EndpointBehaviors.Add(new ViaBehavior(new Uri("http://test1.ekstern-test.nspop.dk:8080/sosigw/proxy/soap-request")));
var dgwsHeader = new Header()
{
SecurityLevel = 4,
SecurityLevelSpecified = true,
Linking = new Linking { MessageID = Guid.NewGuid().ToString("D") }
};
using (new OperationContextScope(client.InnerChannel))
{
// Adding seal-security and dgws-header soap header
OperationContext.Current.OutgoingMessageHeaders.Add(new IdCardMessageHeader(sealCard));
OperationContext.Current.OutgoingMessageHeaders.Add(XmlHeader(dgwsHeader));
// Throws Exception if not succesful.
return client.invokeAsync("test");
} |
...
Der er tilfælde hvor man måske ønsker at konfigurere en clientVia endpointbehavior på en Web Service Reference som man har tilføjet.
Det blev før gjort i app.config, men da denne ikke længere findes, er der lavet en endpointbehavior klasse som hedder 'ViaBehavior'.
Den bruges som alle andre IEndPointBehavior-klasser:
Code Block | ||
---|---|---|
| ||
client.Endpoint.EndpointBehaviors.Add(new ViaBehavior(new Uri("<via URI>"))); |
...
5.0.0 kræver ikke nær så meget konfiguration som ældre Seal.NET versioner, da meget konfiguration nu håndteres internt af biblioteket.
Det medfører desuden, at det nu fremgår af metode-signaturen for Sosi2SamlStsClient og Saml2SosiStsClient, hvis man skal tage stilling til en konfiguration.
...
AbstractCrendentialVault, GenericCertStoreCredentialVault og GenericCredentialVault er fjernet.
Man kan enten give certifikatet direkte til metoder som skal bruge et certifikat, eller læse det ind fra et certificate store med:
Code Block | ||
---|---|---|
| ||
new dk.nsi.seal.Vault.ThumbprintCertStoreCredentialVault(certThumbprint).GetSystemCredentials(); |
Internt bruger ThumbprintCertStoreCredentialVault X509Store klassen til at loade et certifikatet fra et certificate store.
Man kan også implementere sin egen klasse til det, ved at arve fra dk.nsi.seal.Vault.ICredentialVault.
Essentielt er ICredentialVault bare en måde at give et certifikat til en metode.
...
DgwsHeader er fjernet, og DgwsMessageHeader er omdøbt til XmlMessageHeader, da den ikke gør noget DGWS specifikt, men tager noget XML og indsætter det som Header content, når den tilføjes til WCF OutgoingMessageHeaders.
Den laves nu med en static metode 'XmlMessageHeader.XmlHeader', som direkte tager den værdi der før blev givet til DgwsHeader constructor. Se XmlMessageHeader.
...
Net samspiller med en række NSP komponenter. Det kan være en god idé at sætte sig ind i disse, før man går i gang med at udvikle systemer, der benytter sig af Seal.Net. Disse komponenter er listet nedenfor, med links til deres egen ”Kom Godt i Gang Guide”.
STS (Security Token Service)
Det kræver autentificering at få adgang til NSP-komponenter. STS fungerer som en fælles komponent, som kan udstede adgangsgivende billetter til andre komponenter, så disse kun kræver simpel verifikation.
Her er et par steder, man kan starte med at læse om STS:
https://www.nspop.dk/display/public/web/STS+-+Guide+til+anvendere
https://www.nspop.dk/display/public/web/STS+-+Guide+til+anvendere%3A+Borgeromvekslinger
https://www.nspop.dk/display/public/web/STS+-+Guide+til+anvendere%3A+Medarbejderomvekslinger
NTS (NSP Test Service)
NTS er et værktøj til verificering af korrektheden af et DGWS SOAP-request. Hvis der opleves problemer med en service, kan et request i stedet blive sendt til NTS, som vil levere et uddybende svar, om hvad der måtte være galt med det pågældende request. NTS tjekker en række egenskaber ved requests, som f.eks. UTF-8 encoding og eksistensen af de obligatoriske DGWS header-elementer. Yderligere information kan findes her.
NGW (NSP GateWay)
NGW er en særlig udgave af den såkaldte SOSI-GW, som har til formål at sørge for at brugeren kun bliver afkrævet koden til sit medarbejdercertifikat én gang, på tværs af systemer. SOSI-GW og NGW–NSP Gateway ”Kom Godt i Gang Guide”’erne forklarer yderligere.
DCC (DeCoupling Component)
DCC’en fungerer som en WebService Gateway hvilket begrænser kravet til klienten, om kendskab til lokationen af den specifikke service. DCC-Afkoblingskomponenten ”Kom Godt i Gang Guide”’en forklarer yderligere.
Systemkrav
Seal.NET target'er .NET Standard 2.0, så den er kompatibel med .NET 5+ og .NET Core, samt .NET Framework projekter.
Migrering til version 5.x.y fra ældre version
5.0.0 skifter target til .NET Standard 2.0, som medførerer API ændringer. Derudover er der lavet forsimplinger og oprydning af API'et.
Generelt
app.config er erstattet af appsettings.json og bruges kun til at sætte enkelte parametre:
Code Block language js { "CheckTrust": true, "CheckDate": true, "CheckCrl": false, "sosi:dgws.version": "1.0.1", "sosi:issuer": "TheSOSILibrary", "credentialVault:alias": "SOSI:ALIAS_SYSTEM" }
Værdierne her er også default-værdierne, hvis en parameter eller hele appsettings-filen udelades.
Førhen var der ikke overensstemmelse mellem hvad standardværdierne var angivet til i dokumentationen og i koden.
Koden er ændret, så den nu stemmer overens med dokumentationen.Generelt for .NET Standard og WCF gælder det, at det der før blev konfigureret i app.config, nu konfigureres i kode.
Her er et eksempel på en klient, NtsWSProviderClient, der er genereret ud fra en WCF service reference, som konfigureres i kode, frem for gennem app.config:
Code Block language c# var binding = new CustomBinding(); binding.Elements.Add(new TextMessageEncodingBindingElement(MessageVersion.Soap11WSAddressingAugust2004, Encoding.UTF8)); binding.Elements.Add(new HttpTransportBindingElement()); var client = new NSTWsProvider.NtsWSProviderClient(binding, new EndpointAddress("https://test1-cnsp.ekstern-test.nspop.dk:8443/nts/service")); client.Endpoint.EndpointBehaviors.Add(new SealEndpointBehavior()); client.Endpoint.EndpointBehaviors.Add(new ViaBehavior(new Uri("http://test1.ekstern-test.nspop.dk:8080/sosigw/proxy/soap-request"))); var dgwsHeader = new Header() { SecurityLevel = 4, SecurityLevelSpecified = true, Linking = new Linking { MessageID = Guid.NewGuid().ToString("D") } }; using (new OperationContextScope(client.InnerChannel)) { // Adding seal-security and dgws-header soap header OperationContext.Current.OutgoingMessageHeaders.Add(IdCardHeader(idCard)); OperationContext.Current.OutgoingMessageHeaders.Add(XmlHeader(dgwsHeader)); // Throws Exception if not succesful. return client.invokeAsync("test"); }
Der er tilfælde hvor man måske ønsker at konfigurere en clientVia endpointbehavior på en Web Service Reference som man har tilføjet.
Det blev før gjort i app.config, men da denne ikke længere findes, er der lavet en endpointbehavior klasse som hedder 'ViaBehavior'.
Den bruges som alle andre IEndPointBehavior-klasser:Code Block language c# client.Endpoint.EndpointBehaviors.Add(new ViaBehavior(new Uri("<via URI>")));
Da app.config ikke længere findes, fremgår det nu af metode-signaturen for Sosi2SamlStsClient og Saml2SosiStsClient, hvilke konfigurationsmuligheder der er til kaldene.
AbstractCrendentialVault, GenericCertStoreCredentialVault og GenericCredentialVault er fjernet.
Man kan enten give certifikatet direkte til metoder som skal bruge et certifikat, eller læse det ind fra et certificate store med:
Code Block language c# new dk.nsi.seal.Vault.ThumbprintCertStoreCredentialVault(certThumbprint).GetSystemCredentials();
Internt bruger ThumbprintCertStoreCredentialVault X509Store klassen til at loade et certifikatet fra et certificate store.
Man kan også implementere sin egen klasse til det, ved at arve fra dk.nsi.seal.Vault.ICredentialVault.
Essentielt er ICredentialVault bare en måde at give et certifikat til en metode.
- SealCard er fjernet, og fuldt erstattet af IdCard. 'ValidTo' og 'ValidFrom' på SealCard hedder 'CreatedDate' og 'ExpiryDate' på IdCard. Desuden findes 'IsValidInTime' på IdCard, som tjekker de to datoer, og returnerer en bool der angiver om de er overholdt.
DgwsHeader er fjernet, og DgwsMessageHeader er omdøbt til XmlMessageHeader, da den ikke gør noget DGWS specifikt, men tager noget XML og indsætter det som Header content, når den tilføjes til WCF OutgoingMessageHeaders.
Den laves nu med en static metode 'XmlMessageHeader.XmlHeader', som direkte tager den værdi der før blev givet til DgwsHeader constructor. Se XmlMessageHeader.
- IdCardMessageHeader laves nu med en static constructor IdCardMessageHeader.IdCardHeader.
- SealSigningEndpointBehavior tager nu ClientCredentials direkte i constructor, i stedet for at den specificeres gennem app.config hvor den blev givet til SealSigningEndpointBehavior gennem AddBindingParameters.
- Create-metoder i SOSIFactory er nu static.
- ICredentialVault-argument er fjernet fra 'SignatureUtil.Validate', da den ikke blev brugt til noget.
- SosiFactory.GetCredentialVault er omdøbt til GetCertificate, og returner nu X509Certificate2.
- 'dk.nsi.seal.SealCardMessageHeader' er erstattet af 'dk.nsi.seal.MessageHeaders.IdCardMessageHeader'.
Ændringer til Sosi2OioSaml
- Seal2SamlStsClient er omdøbt til Sosi2SamlStsClient.
- SosiGwCardClient er fjernet, da Sosi2SamlStsClient opfylder samme rolle.
Metoderne 'ExchangeAssertion' og 'ExchangeAssertionViaGW' i Sosi2SamlStsClient er slået sammen til én static metode der hedder 'ExchangeAssertion':
I det gamle Seal.NET bliver denne kode:Code Block language c# using (var stsClient = new Seal2SamlStsClient("Seal2EncSamlViaGW")) using (new OperationContextScope((IContextChannel)stsClient.Channel.Channel)) { OperationContext.Current.OutgoingMessageHeaders.Add(new IdCardMessageHeader(IdCard)); var oioToken = stsClient.ExchangeAssertionViaGW("http://sosi.dk") as GenericXmlSecurityToken; }
Til
Code Block language c# var oioToken = Sosi2SamlStsClient.ExchangeAssertion(clientCertificate, uri, Action.DccSosiIboIssue, "<audience>", idCard).XAssertion;
Hvor Action før, lidt forvirrende, blev bestemt af hvilken behavior der blev brugt, sættes den nu direkte. Afhængig af app.config i den gamle løsning, kan det være at en anden udgave af ExchangeAssertion skal bruges, f.eks. en der tager WsAddressing i stedet for Action. Der findes flere overloads af ExchangeAssertion der dækker forskellige scenarier.
Metoderne 'ExchangeAssertion' og 'ExchangeAssertionViaGW' er slået sammen fordi de udførte det samme, men gjorde det på forskellig vis:'ExchangeAssertion' tog en assertion direkte i parameterlisten, mens 'ExchangeAssertionViaGW' ikke tog den direkte i parameterlisten,
men i stedet blev assertion sat ind i 'OperationContext.Current.OutgoingMessageHeaders' inden 'ExchangeAssertionViaGW' blev kaldt - det er dette scenarie der er vist her, i den gamle Seal.NET kode.
Ændringer til OioSaml2Sosi
Saml2SosiStsClient.ExchangeAssertion er nu en static metode:
I det gamle Seal.NET bliver denne kode:
Code Block | ||
---|---|---|
| ||
using (var stsClient = new Saml2SosiStsClient("sts_OIOSaml2Sosi"))
{
stsClient.ChannelFactory.Credentials.ClientCertificate.Certificate = Global.StatensSerumInstitutFoces;
var healthContextAssertion = SealUtilities.MakeHealthContextAssertion(
"Test Sundhed.dk",
Global.StatensSerumInstitutFoces.SubjectName.Name,
"Sygdom.dk", userAuthorizationCode);
return stsClient.ExchangeAssertion(nemidAssertion, healthContextAssertion, "http://sosi.dk");
} |
Til
Code Block | ||
---|---|---|
| ||
Saml2SosiStsClient.ExchangeAssertion(Global.StatensSerumInstitutFoces, new Uri("<URL der før var i app.config>"), nemidAssertion, userAuthorizationCode); |
Hvor nemidAssertion er af typen 'OioSamlAssertion' i stedet for 'Saml2Assertion'.
En 'OioSasmlAssertion' kan laves ud fra et XML dokument på følgende måde:
Code Block | ||
---|---|---|
| ||
var exampleXmlDoc = new XDocument().Root;
var ast = new dk.nsi.seal.Model.OioSamlAssertion(exampleXmlDoc);
// ast gemmer blot på XML så:
ast.XAssertion == exampleXmlDoc // true |
Seal.NET API
Overordnet
Seal.NET er designet til at blive brugt med WCF service references, som laves ud fra WSDL filer. I en WSDL beskrives en snitflade til Den Gode Webservice (DGWS), samt skemaer der beskriver de specifikke DGWS klasser. Når der genereres en proxy til hhv. klient eller server, dannes disse klasser på typestærk form i den autogenererede proxy.
Eksempler på genererede klasser er Security, Assertion og Header.
Seal.Net giver mulighed for at konstruere to forskellige ID-kort, UserIdCard og SystemIdCard, til anvendelse i fagsystemer indenfor sundhedsvæesnet. Disse konstrueres vha. klassen 'SOSIFactory'.
Seal.NET indeholder nogle IEndPointBehavior-klasser som kan benyttes af WCF services genereret ud fra WSDL. Disse er beskrevet længere nede under afsnittet EndpointBehaviors.
Headers
Headers er typer/XML-elementer som primært bruges til sikkerhed i DGWS. I nogle sammenhænge kaldes disse derfor blot "sikkerhed". De kan dog også være mere generelle, og indeholde tekniske og logistiske data, der vedrører forsendelse af request. Brugen af de følgende headers vises i afsnittet med eksempler.
Security
En Security er det samlende element for sikkerhedsoplysninger i et request, som indeholder informationer om signering, token og kryptering. For at lave en Security, kræver det at man først har et ID-kort. I Seal.NET findes Security som en type med samme navn. Typen er dog blevet erstattet af IdCardMessageHeader, som tager et ID-kort, og sætter security elementet i requestet ud fra det.
DGWS Header
En header med DGWS-specifikke detaljer. Sættes i et request med XmlMessageHeader.
Andre
WhiteListingHeader
Nogle services kræver flere headers end blot DGWS og security. F.eks. kræver FMK en whitelisting header, som den bruger til at foretage autorisation af klientsystemer. Denne header genereres med klienten som en type i kodebasen, når klienten genereres ud fra FMK's WSDL. Med andre ord indeholder WSDL-filen hvilke headers der er påkrævet.
Klienter
Saml2SosiStsClient
Konverterer en SAML assertion til et ID kort.
Sosi2SamlStsClient
Konverterer et ID kort til en SAML assertion, enten via direkte kald til STS eller via SOSI Gateway.
ID kort
IdCard indpakker svaret fra en STS (assertion) og giver mulighed for at benytte data i fremtidige kald.
IdCard er en abstract klasse, som implementeres af SystemIdCard og UserIdCard, som hhv. repræsenter enten et system eller en bruger.
MessageHeaders
Disse MessageHeaders bruges til at indsætte relevant data i headeren på et request, som er lavet med en klient genereret ud fra en WCF service reference.
For at stemme overens med service references, implementerer MessageHeader-klasserne 'System.ServiceModel.Channels.Message'
fra https://www.nuget.org/packages/System.ServiceModel.Primitives/, som er det service references arbejder med.
Rent lavpraktisk betyder det at MessageHeaders kan gives til 'OutgoingMessageHeaders.Add', og så bliver den data MessageHeaderen har, sat ind i headeren på det request man laver.
Nedenstående eksempler demonstrerer dette, hvor dk.nsi.seal.dgwstypes.Header og NSTWsProvider.NtsWSProviderClient er genereret ud fra en WSDL, ved at bruge nævnte WCF service references.
IdCardMessageHeader
Benyttes til at tilføje et ID kort til headeren af et WCF request.
Laves med en static constructor 'IdCardMessageHeader.IdCardHeader'.
Eksempel:
Code Block | ||
---|---|---|
| ||
using static dk.nsi.seal.MessageHeaders.IdCardMessageHeader;
var client = new NtsWSProviderClient(new BasicHttpsBinding(), new EndpointAddress("https://test1- |
Ændringer til Sosi2OioSaml
- Seal2SamlStsClient er omdøbt til Sosi2SamlStsClient.
- SosiGwCardClient er fjernet, da Sosi2SamlStsClient opfylder samme rolle.
Metoderne 'ExchangeAssertion' og 'ExchangeAssertionViaGW' i Sosi2SamlStsClient er slået sammen til én static metode der hedder 'ExchangeAssertion':
I det gamle Seal.NET bliver denne kode:Code Block language c# using (var stsClient = new Seal2SamlStsClient("Seal2EncSamlViaGW")) using (new OperationContextScope((IContextChannel)stsClient.Channel.Channel)) { OperationContext.Current.OutgoingMessageHeaders.Add(new IdCardMessageHeader(IdCard)); var oioToken = stsClient.ExchangeAssertionViaGW("http://sosi.dk") as GenericXmlSecurityToken; }
Til
Code Block language c# Sosi2SamlStsClient.ExchangeAssertion(clientCertificate, "<audience>", uri, idCard).XAssertion;
Den findes også i en udgave der ikke tager et clientCertificate.
Metoderne er slået sammen fordi de alle udførte det samme, men gjorde det på forskellig vis:
'ExchangeAssertion' tog en assertion direkte i parameterlisten, mens 'ExchangeAssertionViaGW' ikke tog den direkte i parameterlisten,
men i stedet blev assertion sat ind i 'OperationContext.Current.OutgoingMessageHeaders' inden 'ExchangeAssertionViaGW' blev kaldt - det er dette scenarie der er vist her, i den gamle Seal.NET kode.
Ændringer til OioSaml2Sosi
Saml2SosiStsClient.ExchangeAssertion er nu en static metode:
I det gamle Seal.NET bliver denne kode:
Code Block | ||
---|---|---|
| ||
using (var stsClient = new Saml2SosiStsClient("sts_OIOSaml2Sosi"))
{
stsClient.ChannelFactory.Credentials.ClientCertificate.Certificate = Global.StatensSerumInstitutFoces;
var healthContextAssertion = SealUtilities.MakeHealthContextAssertion(
"Test Sundhed.dk",
Global.StatensSerumInstitutFoces.SubjectName.Name,
"Sygdom.dk", userAuthorizationCode);
return stsClient.ExchangeAssertion(nemidAssertion, healthContextAssertion, "http://sosi.dk");
} |
Til
Code Block | ||
---|---|---|
| ||
Saml2SosiStsClient.ExchangeAssertion(Global.StatensSerumInstitutFoces, new Uri("<URL der før var i app.config>"), nemidAssertion, userAuthorizationCode); |
Hvor nemidAssertion er af typen 'OioSamlAssertion' i stedet for 'Saml2Assertion'.
...
Code Block | ||
---|---|---|
| ||
var exampleXmlDom = new XDocument().Root;
var ast = new dk.nsi.seal.Model.OioSamlAssertion(exampleXmlDom);
ast.XAssertion == exampleXmlDom // true |
Seal.NET API
Overordnet
Seal.NET er designet til at blive brugt med WCF service references, som laves ud fra WSDL filer. I en WSDL beskrives en snitflade til Den Gode Webservice (DGWS), samt skemaer der beskriver de specifikke DGWS klasser. Når der genereres en proxy til hhv. klient eller server, dannes disse klasser på typestærk form i den autogenererede proxy.
Eksempler på genererede klasser er Security, Assertion og Header, som vises længere nede.
Seal.NET indeholder en række IEndPointBehavior-klasser som kan benyttes af WCF service references.
Klienter
Saml2SosiStsClient
Konverter en SAML assertion til et ID kort.
Eksempel:
Code Block | ||
---|---|---|
| ||
using dk.nsi.seal;
var response = Saml2SosiStsClient.ExchangeAssertion(clientCertificate, new Uri("http://test2.ekstern-test.nspop.dk:8080/sts/services/OIOSaml2Sosi"), nemidAssertion, authorizationCode); |
Soisi2SamlStsClient
Konverterer et ID kort til en SAML assertion, enten via direkte kald til STS eller via SOSI Gateway.
Eksempel:
Code Block | ||
---|---|---|
| ||
using dk.nsi.seal;
var response = Sosi2SamlStsClient.ExchangeAssertion(clientCertificate, new Uri("http://test1.ekstern-test.nspop.dk:8080/sosigw/proxy/soap-request"), "/ststest", idCard);
var responseXml = response.XAssertion;
// Der findes også et overload der ikke tager et klientcertifikat
Sosi2SamlStsClient.ExchangeAssertion(uri, "/ststest", idCard); |
ID kort
...
IdCard er en abstract klasse, som implementeres af SystemIdCard og UserIdCard, som hhv. repræsenter enten et system eller en bruger.
MessageHeaders
Disse MessageHeaders bruges til at indsætte relevant data i headeren for et request, som er lavet med en klient genereret ud fra en WCF service reference.
For at stemme overens med service references, implementerer MessageHeader-klasserne 'System.ServiceModel.Channels.Message'
fra https://www.nuget.org/packages/System.ServiceModel.Primitives/, som er det service references arbejder med.
Rent lavpraktisk betyder det at MessageHeaders kan gives til 'OutgoingMessageHeaders.Add', og så bliver den data MessageHeaderen har, sat ind i headeren på det request man laver.
Nedenstående eksempler demonstrerer dette, hvor dk.nsi.seal.dgwstypes.Header og NSTWsProvider.NtsWSProviderClient er genereret ud fra en WSDL, ved at bruge nævnte WCF service references.
IdCardMessageHeader
Benyttes til at tilføje et ID kort til headeren af et WCF request.
Laves med en static constructor 'IdCardMessageHeader.IdCardHeader'.
Eksempel:
Code Block | ||
---|---|---|
| ||
using static dk.nsi.seal.MessageHeaders.IdCardMessageHeader;
var client = new NtsWSProviderClient(new BasicHttpsBinding(), new EndpointAddress("https://test1-cnsp.ekstern-test.nspop.dk:8443/nts/service"));
using (new OperationContextScope(client.InnerChannel))
{
OperationContext.Current.OutgoingMessageHeaders.Add(IdCardHeader(idCard)); // Tilføj ID Kort med IdCardHeader
var response = client.invokeAsync("test");
} |
XmlMessageHeader
Den Gode Webservice (DGWS) specificerer en ekstra headertype baseret på XML ( dk.nsi.seal.dgwstypes.Header), som kan indsættes ud fra et objekt, der serialiseres til XML med XmlMessageHeader.
XmlMessageHeader indeholder en static constructor-metode, XmlHeader, til at lave instanser af den.
Eksempel på XmlHeader:
Code Block | ||
---|---|---|
| ||
using static dk.nsi.seal.MessageHeaders.XmlMessageHeader;
...
reply.Headers.Add(XmlHeader(header)); |
Mere komplet eksempel hvor dk.nsi.seal.dgwstypes.Header serialiseres til XML og indsættes:
Code Block | ||
---|---|---|
| ||
var client = new NSTWsProvider.NtsWSProviderClient(binding, new EndpointAddress("https://test1-cnsp.ekstern-test.nspop.dk:8443/nts/service")); var dgwsHeader = using (new dk.nsi.seal.dgwstypes.Header(OperationContextScope(client.InnerChannel)) { SecurityLevel = 4, SecurityLevelSpecified = true,OperationContext.Current.OutgoingMessageHeaders.Add(IdCardHeader(idCard)); // Tilføj ID Kort med IdCardHeader Linking = new Linking { MessageID = Guid.NewGuid().ToString("D") } }; using (new OperationContextScope(client.InnerChannel)) { OperationContext.Current.OutgoingMessageHeaders.Add(XmlHeader(dgwsHeader)); // Indsæt header som XML, ud fra serialiseret header var response = client.invokeAsync("test"); } |
Endpointbehaviors
Bruges til at tilføje processering af requests og responses af WCF klienter.
var response = client.invokeAsync("test");
} |
XmlMessageHeader
Den Gode Webservice (DGWS) specificerer en ekstra headertype baseret på XML ( dk.nsi.seal.dgwstypes.Header), som kan indsættes ud fra et objekt, der serialiseres til XML med XmlMessageHeader.
XmlMessageHeader indeholder en static constructor-metode, XmlHeader, til at lave instanser af den.
Eksempel på XmlHeaderEksempel:
Code Block | ||
---|---|---|
| ||
using static dk.nsi.seal.MessageHeaders.XmlMessageHeader;
...
reply.Headers.Add(XmlHeader(header)); |
Mere komplet eksempel hvor dk.nsi.seal.dgwstypes.Header serialiseres til XML og indsættes:
Code Block | ||
---|---|---|
| ||
var client = new NSTWsProvider.NtsWSProviderClient(new BasicHttpBinding()binding, new EndpointAddress("https://test1-cnsp.ekstern-test.nspop.dk:8443/nts/service")); client.Endpoint.EndpointBehaviors.Add(new ViaBehavior(new Uri("http://test1.ekstern-test.nspop.dk:8080/sosigw/proxy/soap-request"))); // Tilføj Via endpointbehaviorvar dgwsHeader = new dk.nsi.seal.dgwstypes.Header() { SecurityLevel = 4, SecurityLevelSpecified = true, Linking = new Linking { MessageID = Guid.NewGuid().ToString("D") } }; using (new OperationContextScope(client.InnerChannel)) { var response client.invokeAsync("test"); } |
Findes under namespace 'dk.nsi.seal'. Endpointbehaviors implementer System.ServiceModel.Dispatcher.IClientMessageInspector fra NuGet Gallery | System.ServiceModel.Primitives 4.10.0.
SealSigningEndpointBehavior
Tilpasser request XML header med manglende DGWS attributter og underskriver request vha. et associeret certifikat der gives til dens constructor. Yderligere valideres underskriften af response.
SealEndpointBehavior
TODO
ViaBehavior
Portering af ClientViaBehavior Class (System.ServiceModel.Description) | Microsoft Learn til .NET Standard.
Meget simpel klasse, der internt blot sætter en enkelt værdi til den via URL man angiver.
Factories
SosiFactory har static metoder der kan generere nye IdCards.
...
OperationContext.Current.OutgoingMessageHeaders.Add(XmlHeader(dgwsHeader)); // Indsæt header som XML, ud fra serialiseret header
var response = client.invokeAsync("test");
} |
Endpointbehaviors
Bruges til at tilføje processering af requests og responses af WCF klienter.
Eksempel:
Code Block | ||
---|---|---|
| ||
var client = new NSTWsProvider.NtsWSProviderClient(new BasicHttpBinding(), new EndpointAddress("https://test1-cnsp.ekstern-test.nspop.dk:8443/nts/service"));
client.Endpoint.EndpointBehaviors.Add(new ViaBehavior(new Uri("http://test1.ekstern-test.nspop.dk:8080/sosigw/proxy/soap-request"))); // Tilføj Via endpointbehavior
using (new OperationContextScope(client.InnerChannel))
{
var = response client.invokeAsync("test");
} |
Findes under namespace 'dk.nsi.seal'. Endpointbehaviors implementer System.ServiceModel.Dispatcher.IClientMessageInspector fra NuGet Gallery | System.ServiceModel.Primitives 4.10.0.
SealSigningEndpointBehavior
Tilpasser request XML header med manglende DGWS attributter og underskriver request vha. et associeret certifikat der gives til dens constructor. Yderligere valideres underskriften af response.
SealEndpointBehavior
Tjekker om det returnerede svar indeholder fejl og smider en exception der indeholder en beskrivelse af fejlen.
ViaBehavior
Portering af ClientViaBehavior Class (System.ServiceModel.Description) | Microsoft Learn til .NET Standard.
Meget simpel klasse, der internt blot sætter en enkelt værdi til den via URL man angiver.
Factories
SosiFactory har static metoder der kan generere nye IdCards.
ItSystemName er navnet på det system, som har oprettet ID-kortet.
ItSystemName er et krav fra DGWS-specifikation, og er navnet på det system som har oprettet ID-kortet.
OioSamlFactory kan generere nye Requests. Normalt laver man en DOM builder som genererer selve XML'en og bagefter en ModelBuilder for at lave selve Requesten. Requesten kan så blive sendt ved hjælp af dk.nsi.seal.SealUtilities.SignIn funktion. Derudover kan man sende requests fra OioSamlFactory afsted uden brug af klienter.
DomBuilders
Dombuilders er et hierarki, som bliver brugt til at generere XML kode. Til venstre er der 3 klasser der håndterer bygning af selve assertions, mens det højre klassehierarki bliver brugt til at generere selve SOAP beskeden uden Assertion.
Requests
Requests er selve modeller over XML'en. De har diverse convenience methods til at hente informationer direkte ud fra XML'en.
Vaults
Vaults bruges til at holde certifikater, eller læse dem ind fra enhedens trust store.
'ThumbprintCertStoreCredentialVault' læser certifikater fra enhedens trust store.
'InMemoryCredentialVault' er et simpelt dataobjekt, der indeholder et certifikat.
Begge er forholdsvis simple klasser med én metode, 'GetSystemCredentials', som returner et enkelt certifikat.
'InMemoryCredentialVault' kan bruges når man selv ønsker at bestemme hvordan certifikater læses ind - man læser certifikatet ind som et X509Certificate2, og giver det til 'InMemoryCredentialVault', som så kan gives videre til metoderne i Seal.NET.
På sigt kan dette blive simplificeret, så man direkte kan give et X509Certificate2, i stedet for at man skal forbi 'ICredentialVault', som er det interface vaults arver fra.
Findes under namespace 'dk.nsi.seal.Vault'.
Federation
Federations bliver brugt når man skal validere certfikatet fra den service man snakker med. En Federation gives til 'dk.nsi.seal.Model.SignatureUtil.Validate'.
Klassen 'SosiFederation' vil validere servicens certifikat op mod OCES2/OCES3 root certifikatet for at sikre, at servicen er autoriseret.
Klassen 'SosiTestFederation' vil validere op mod OCES2/OCES3 test root certifikat.
Hvis SignatureUtil.Validate kaldes uden en Federation, skal root certifikatet af den pågældende services certifikat (eller selve certifikatet) ligge i trust store på den enhed programmet eksekveres af.
På windows vil det betyde at importere det givne certifikat som et 'trusted root certificate', med programmet 'Manage Computer Certificates'.
Hjælpefunktioner
Indeholder forskellige funktioner. F.eks. til at signere og validere en signatur.
Brug af Seal.NET API
I dette afsnit beskrives overordnet hvordan Seal.Net benyttes til at opbygge en klient eller en service applikation.
Konfiguration
Der er to slags valideringer af et certifikat, der kan aktiveres/deaktiveres i appsettings.json.
CheckTrust
CheckTrust specificerer om certifikatet skal valideres op mod et root certifikat og om chainen skal valideres. Hvis en federation er specificeret så er det valideringen mod den federation, som bliver aktiveret/deaktiveret.
Skal slås fra ved self signed certifikater.
Code Block | ||
---|---|---|
| ||
{
"CheckTrust": true
} |
CheckTrust er per default True.
CheckCrl
CheckCrl specificerer om certifikatet skal checkes op mod en Certificate Revocation List. Skal slås fra ved self
DomBuilders
Dombuilders er et hierarki, som bliver brugt til at generere XML kode. Til venstre er der 3 klasser der håndterer bygning af selve assertions, mens det højre klasse hierarki bliver brugt til at generere selve SOAP beskeden uden Assertion.
Requests
Requests er selve modeller over XML'en. De har diverse convenience methods til at hente informationer direkte ud fra XML'en.
Vaults
Vaults bruges til at holde certifikater, eller læse dem ind fra enhedens trust store.
'ThumbprintCertStoreCredentialVault' læser certifikater fra enhedens trust store.
'InMemoryCredentialVault' er et simpelt dataobjekt, der indeholder et certifikat.
Begge er forholdsvis simple klasser med én metode, 'GetSystemCredentials', som returner et enkelt certifikat.
'InMemoryCredentialVault' kan bruges når man selv ønsker at bestemme hvordan certifikater læses ind - man læser certifikatet ind som et X509Certificate2, og giver det til 'InMemoryCredentialVault', som så kan gives videre til metoderne i Seal.NET.
På sigt kan dette blive simplificeret, så man direkte kan give et X509Certificate2, i stedet for at man skal forbi 'ICredentialVault', som er det interface vaults arver fra.
Findes under namespace 'dk.nsi.seal.Vault'.
Federation
Federations bliver brugt når man skal validere certfikatet fra den service man snakker med. En Federation gives til 'dk.nsi.seal.Model.SignatureUtil.Validate'.
Klassen 'SosiFederation' vil validere servicens certifikat op mod OCES2/OCES3 root certifikatet for at sikre, at servicen er autoriseret.
Klassen 'SosiTestFederation' vil validere op mod OCES2/OCES3 test root certifikat.
Hvis SignatureUtil.Validate kaldes uden en Federation, skal root certifikatet af den pågældende services certifikat (eller selve certifikatet) ligge i trust store på den enhed programmet eksekveres af.
På windows vil det betyde at importere det givne certifikat som et 'trusted root certificate', med programmet 'Manage Computer Certificates'.
...
Hjælpefunktioner
Indeholder forskellige funktioner. F.eks. til at signere og validere en signatur.
Brug af Seal.NET API
I dette afsnit beskrives overordnet hvordan Seal.Net benyttes til at opbygge en klient eller en service applikation.
Konfiguration
Der er to slags valideringer af et certifikat, der kan aktiveres/deaktiveres i appsettings.json.
CheckTrust
CheckTrust specificerer om certifikatet skal valideres op mod et root certifikat og om chainen skal valideres. Hvis en federation er specificeret så er det valideringen mod den federation, som bliver aktiveret/deaktiveret.
Skal slås fra ved self signed certifikater.
Code Block | ||
---|---|---|
| ||
{
"CheckTrust": true
} |
CheckTrust er per default True.
CheckCrl
CheckCrl specificerer om certifikatet skal checkes op mod en Certificate Revocation List. Skal slås fra ved self-signed certifikater.
Code Block | ||
---|---|---|
| ||
{ "CheckCrl": false } |
...
En klient til en WebService af typen Den Gode Webservice benyttes som enhver anden webservice.
I Visual Studio tilføjes en Service-Reference til den pågældende WSDL. Herefter genereres en proxy indeholdende alle datatyper for webservicen.
Det er også muligt at benytte WCF svcutil tool hvis Visual Studio ikke er tilstrækkelig.Herefter kan der være flere klient-scenarier:
...
Det er en god ide at se kommentarerne igennem i kodeeksemplerne, da de også gælder i de efterfølgende eksempler.
Opstarts-eksempel med kald til NTS
Når man har generet sin klient ud fra den WSDL som tilhører den service man gerne vil snakke med (i dette tilfælde NTS), så er man klar til at begynde at bruge Seal.Net til at lave et kald til servicen.
Først et "bare-bones" eksempel på et kald til NTS:
Code Block |
---|
private static Task<invokeResponse> CallNts(IdCard idc) // invokeResponse-typen kommer fra klienten der er genereret ud fra WSDL
{
// NtsWSProviderClient er klienten generet ud fra WSDL
var client = new NtsWSProviderClient(new BasicHttpBinding(), new EndpointAddress("http://test1.ekstern-test.nspop.dk:8080/nts/service"));
client.Endpoint.EndpointBehaviors.Add(new SealEndpointBehavior()); // SealEndpointBehavior er beskrevet under afsnittet 'EndpointsBehaviors'
var dgwsHeader = new Header // Header-type som er generet ud fra NTS WSDL. Gennem denne sættes DGWS-specifikke detaljer.
{
SecurityLevel = 4,
SecurityLevelSpecified = true,
Linking = new Linking { MessageID = Guid.NewGuid().ToString("D") }
};
using (new OperationContextScope(client.InnerChannel))
{
// Tilføjer security og DGWS header til request
OperationContext.Current.OutgoingMessageHeaders.Add(IdCardHeader(idc));
OperationContext.Current.OutgoingMessageHeaders.Add(XmlHeader(dgwsHeader));
return client.invokeAsync("test");
}
} |
Header typen findes også i Seal.NET som en selvstændig type. Det er den samme type som bliver genereret ud fra service WSDL, da alle WSDL bruger den samme header, da den er specificieret af DGWS standarden. Så om man bruger Header fra Seal.NET, eller Header fra den kode der er generet ud fra WSDL, giver det samme i det request der sendes afsted.
Her skal man være opmærksom på at den WSDL man genererer sin WSDL ud fra, måske indeholder Header og Security (der findes WSDL'er med sikkerhed som vil have disse headers, og tilsvarende WSDL'er uden sikkerhed, hvor disse headers ikke vil være tilstede. Den samme service kan uden problemer have begge udgaver). Hvis den gør det, så vil det sidste kald "client.invokeAsync" ikke blot kræve body af SOAP-beskeden (rettere sagt, den værdi man ønsker at sende - her "test"), men også Security og Header typen. Hvis dette er tilfældet, bør man omskrive sin kode til ovenstående. Hvorfor og hvordan, er beskrevet i afsnittet 'Fejlfinding' under 'Invalid ID-kort ved kald til service'.
Afhængig af hvilken service man gerne vil sende requests til, kan der være brug for mere konfiguration af sin klient, som kan gøres vha. CustomBinding og EndpointsBehaviors:
Code Block |
---|
private static Task<invokeResponse> CallNts(IdCard idCard)
{
var binding = new CustomBinding(); // Med en CustomBinding kan der styres flere ting, f.eks. hvilken udgave af SOAP man ønsker at bruge
binding.Elements.Add(new TextMessageEncodingBindingElement(MessageVersion.Soap11WSAddressingAugust2004, Encoding.UTF8));
binding.Elements.Add(new HttpTransportBindingElement())
var client = new NSTWsProvider.NtsWSProviderClient(binding, new EndpointAddress("https://test1-cnsp.ekstern-test.nspop.dk:8443/nts/service"))
client.Endpoint.EndpointBehaviors.Add(new SealEndpointBehavior());
client.Endpoint.EndpointBehaviors.Add(new ViaBehavior(new Uri("http://test1.ekstern-test.nspop.dk:8080/sosigw/proxy/soap-request"))) // Kald via SOSI-GW
var dgwsHeader = new Header
{
SecurityLevel = 4,
SecurityLevelSpecified = true,
Linking = new Linking { MessageID = Guid.NewGuid().ToString("D") }
}
using (new OperationContextScope(client.InnerChannel))
{
// Adding seal-security and dgws-header soap header
OperationContext.Current.OutgoingMessageHeaders.Add(IdCardHeader(idCard));
OperationContext.Current.OutgoingMessageHeaders.Add(XmlHeader(dgwsHeader))
return client.invokeAsync("test");
}
} |
Begge kodeeksempler indgår i tests i Seal.NET kodebasen i (bl.a.) klasserne 'SosiGWTest' og 'NemIdAssertionTest'.
Specificikke eksempler for forskellige scenarier
Der kan være flere klient-scenarier:
- Føderalt: Et ID-kort der oprettes lokalt valideres via et kald til en STS, som returnerer et kort der er digitalt underskrevet. Dette kort benyttes til fremtidige kald af webservices. Service Udbyderen skal nu kun autentificere STS'en.
- NemId:Hvis en bruger allerede er logget på et system via NemLogin, kan dette login benyttes til at kalde en webservice. Til NemLogin er associeret en SAML token. Denne token skal veksles til et DGWS ID kort. Når ID kortet er modtaget, benyttes det til fremtidige kald.
- SOSI Gateway: Benyttes bl.a. til at cache ID kort, så en session kan håndteres af SOSI Gateway.
- MitID: MitID omvekslinger.
- OIOSAML: Kald til STS for at få tokens til eksterne systemer, f.eks. til Sikker Browser Opstart (SBO).
OioSaml2Sosi
Eksempel:
Code Block | ||
---|---|---|
| ||
using dk.nsi.seal;
var response = Saml2SosiStsClient.ExchangeAssertion(clientCertificate, new Uri("http://test2.ekstern-test.nspop.dk:8080/sts/services/OIOSaml2Sosi"), nemidAssertion, authorizationCode); |
Føderalt
I et føderalt login skal en bruger først logges på føderationen (STS'en). Dette gøres ved at kalde 'SealUtilities.SignIn' med et lokalt signeret ID kort.
Herefter kan den ønskede service kaldes med det føderalt signerede ID kort, som Signin returnerede.
Her vises et vejledende eksempel hvor FMK kaldes ved brug af føderationen:
Code Block | ||
---|---|---|
| ||
var userInfo = new UserInfo(
cpr,
givenName,
surName,
email,
occupation,
role,
authCode
);
var idCardRequest = SOSIFactory.CreateNewUserIdCard(
systemName,
userInfo,
new CareProvider(systemCareProviderIdFormat, systemCareProviderId, systemCareProviderName),
AuthenticationLevel.MocesTrustedUser,
username,
password,
userCertificate,
alternativeIdentifier
);
SOSIFactory factory = CreateFactory();
idCardRequest.Sign<Assertion>(factory.SignatureProvider); // Signér lokalt ID-kort
var idc = SealUtilities.SignIn( // Kald STS, og hvis den godkender det lokalt signerede ID-kort, fås et STS-signeret ID-kort
idCardRequest,
systemName,
"http://test2.ekstern-test.nspop.dk:8080/sts/services/NewSecurityTokenService"
);
var client = new MedicineCardPortTypeClient(MedicineCardPortTypeClient.EndpointConfiguration.MedicineCardPort, new EndpointAddress(new Uri("https://test2.fmk.netic.dk/fmk12/ws/MedicineCard")));
using (new OperationContextScope(client.InnerChannel))
{
// Adding seal-security and dgws-header soap header
OperationContext.Current.OutgoingMessageHeaders.Add(IdCardHeader(idc));
OperationContext.Current.OutgoingMessageHeaders.Add(XmlHeader(dgwsHeader))
var response = client.GetMedicineCard_2015_06_01Async(
Security: null, // Security og header er sat til'null', da de er på OutgoingMessageHeaders ovenover. Se afsnittet 'Fejlfinding' under 'Invalid ID-kort ved kald til service'
Header: null, // dgwsHeader kan formentlig godt gives her i stedet for OutgoingMessageHeaders
WhitelistingHeader: makeWhitelistingHeader,
GetMedicineCardRequest: new GetMedicineCardRequestType
{
PersonIdentifier = new PersonIdentifierType { source = "CPR", Value = requestCpr }
}
);
} |
Token til eksternt system (SBO)
Eksempel på direkte kald til STS for at få en SBO token:
Code Block | ||
---|---|---|
| ||
using dk.nsi.seal;
// Signer ID kort lokalt og send det til STS for at få et ID kort signeret af STS.
var assertion = idCard.GetAssertion<dk.nsi.seal.dgwstypes.Assertion>();
var localSignedAssertion = SealUtilities.SignAssertion(assertion, UserCert);
idCard.Xassertion = SerializerUtil.Serialize(localSignedAssertion).Root;
var stsSignedIdCard = SealUtilities.SignIn(idCard, "test", TestConstants.SecurityTokenService);
var response = Sosi2SamlStsClient.ExchangeAssertion(new Uri("http://test1.ekstern-test.nspop.dk:8080/sts/services/Sosi2OIOSaml"), "/ststest", stsSignedIdCard);
var responseXml = response.XAssertion; |
SOSI Gateway
Her vises og beskrives scenarier hvor SOSI Gateway bruges sammen med 'Seal.NET'.
Oprettelse af ID kort i SOSI Gateway
Her vises oprettelse af et SOSI ID kort i GW på baggrund af et bruger-signeret ID kort.
Oprettelse af ID kort i GW er en forudsætning for at nedenstående scenarier virker.
ID kort oprettes ved at sende det ønskede ID kort til SOSI Gateway, som vil gemme kortet i dens cache.
Ved efterfølgende kald til SOSI GW vil den kun kigge på Name ID (også kaldet Alternative Identifier i andre sammenhænge) i ID kortet der sendes, og kigge i dens cache om den har et ID kort med samme Name ID liggende. Hvis den har, vil den erstatte ID kortet i det request den har modtaget, med det der ligger i dens cache.
Der bruges en WCF service reference, SosiGWFacadeClient, der er lavet ud fra den WSDL fil som SOSI GW udstiller:
Code Block | ||
---|---|---|
| ||
public static async Task<Assertion> LoginToGateway(IdCard idCard, X509Certificate2 userCert)
{
var sosiGwAssertion = idCard.GetAssertion<GW.AssertionType>();
var security = new GW.Security
{
Timestamp = new GW.Timestamp { Created = DateTimeEx.UtcNowRound - TimeSpan.FromMinutes(5) },
Assertion = sosiGwAssertion
};
const string endpointAddress = "http://test1.ekstern-test.nspop.dk:8080/sosigw/service/sosigw";
await using var gwClient = new SosiGWFacadeClient(SosiGWSoapBinding, endpointAddress);
var dig = (await gwClient.requestIdCardDigestForSigningAsync(security, "whatever")).requestIdCardDigestForSigningResponse;
var digestHash = SHA1.HashData(dig.DigestValue);
var signature = userCert.GetRSAPrivateKey().SignHash(digestHash, HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1);
var cardRequestBody = new signIdCardRequestBody |
...
TODO
Til efterfølgende eksempler benyttes nogle metoder til at oprette instanser af datatyper.
MakeHeader og MakeSecurity.
Disse metoder opretter instanser af de førnævnte klasser; Security og Header.
Der benyttes desuden variablerne callingSystem og user, som kan ses under " eksempler på generering af proxyklasser".
Eksemplerne viser et kald til en FKM webservice. Metodekaldet er GetMedicineCard_2015_06_01
Føderalt
I et føderalt login skal en bruger først logges på føderationen
- var factory = CreateFactory();
factory.GetCredentialVault().SetSystemCredentials(user.Certificate);
UserInfo userInfo = new UserInfo(user.Cpr, user.GivenName, user.SurName, user.Email, user.Occupation, user.Role, user.AuthCode);
var idCardRequest = factory.CreateNewUserIdCard(system.SystemName, userInfo, new CareProvider(system.CareProviderIdFormat, system.CareProviderId, system.CareProviderName), AuthenticationLevel.MocesTrustedUser, "", "", user.Certificate, "");
idCardRequest.Sign<Assertion>(factory.SignatureProvider);
- var idc = SealUtilities.SignIn(idCardRequest, system.SystemName, "http://test2.ekstern-test.nspop.dk:8080/sts/services/NewSecurityTokenService");
- var client = new MedicineCardPortTypeClient("MedicineCardPort");
- var response = client.GetMedicineCard_2015_06_01(
new GetMedicineCardRequest_2015_06_01
{
Security = SecurityHeaderUtil.MakeSecurityUsingDgwsTypes(idc),
Header = requestHeader,
WhitelistingHeader = makeWhitelistingHeader,
GetMedicineCardRequest = new GetMedicineCardRequestType
{
PersonIdentifier = new PersonIdentifierType
{
source = "CPR",
Value = requestCpr
}
}
});
- Der initieres et signeret IdCard vha. en SOSIFactory ud fra user og callingSystem
- STS kaldes med kortet. Der returneres et nyt IdCard underskrevet af STS
- Der oprettes en instans af Service proxy klientklassen, i dette tilfælde FMK.
- Der oprettes et Security element der indeholder den Assertion der er underskrevet af STS, samt et MedcomHeader element. Herefter kaldes Servicen.
Konfigurationen er det samme som ved Direkte kald i forrige afsnit.
<endpoint
address="https://test2.fmk.netic.dk/fmk12/ws/MedicineCard"
behaviorConfiguration="sealbehavior"
binding="basicHttpBinding"
bindingConfiguration="MedicineCardBinding"
contract="MedicinCard.MedicineCardPortType"
name="MedicineCardPort"
/>
<basicHttpBinding>
<binding name="MedicineCardBinding">
<security mode="Transport"/>
</binding>
</basicHttpBinding>
<behavior name="sealbehavior" >
<sbhe/>
</behavior>
<behaviorExtensions>
<add name="sbhe" type="dk.nsi.seal.SealBehaviorExtentionElement, Seal" />
</behaviorExtensions>
SOSI Gateway
Nå SOSI Gateway skal benyttes skal der ført oprettes en service reference SOSI Gateway. Hvis ikke det allerede er oprettet, oprettes også en service reference til servicen, i nedenstående eksempel FMK.
Følgende kode opretter et login på SOSI Gateway.
...
- var factory = CreateFactory();
...
- LoginToGateway(idCardRequest, global.NsiLge1);
- var client = new MedicineCardPortTypeClient("SosiGWFMK");
- var response = client.GetMedicineCard_2015_06_01(
new GetMedicineCardRequest_2015_06_01
{
Security = SecurityHeaderUtil.MakeSecurityUsingDgwsTypes(idc),
Header = requestHeader,
WhitelistingHeader = makeWhitelistingHeader,
GetMedicineCardRequest = new GetMedicineCardRequestType
{
PersonIdentifier = new PersonIdentifierType
{
source = "CPR",
Value = requestCpr
}
}
});
...
SOSI Gateway oprettelse af ID kort
Her vises Oprettelse af et SOSI ID kort i GW på baggrund af et bruger-signeret ID kort.
Der bruges en WCF service reference, SosiGWFacadeClient, der er lavet ud fra den WSDL fil som SOSI GW udstiller:
Code Block | ||
---|---|---|
| ||
public static async Task LoginToGateway(IdCard idCard, X509Certificate2 userCert) { var sosiGwAssertion = idCard.GetAssertion<AssertionType>(); var security = new GW.Security { TimestampSignatureValue = signature, KeyInfo = new GW.TimestampKeyInfo { Created = DateTimeEx.UtcNowRound - TimeSpan.FromMinutes(5) }, { Assertion Item = sosiGwAssertion }; new GW.X509Data { Item = userCert.Export(X509ContentType.Cert) } const string endpointAddress = "http://test1.ekstern-test.nspop.dk:8080/sosigw/service/sosigw"; } using}; var gwClient = new SosiGWFacadeClient(SosiGWSoapBinding, endpointAddress); var dig = (await gwClient.requestIdCardDigestForSigningAsync(security, "whatever")).requestIdCardDigestForSigningResponse; var digestHash = SHA1.HashData(dig.DigestValue);// The STS signed card is saved in the sosiGw cache and is used for future calls through the proxy var signatureres = userCert.GetRSAPrivateKey().SignHash(digestHash, HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1)(await gwClient.signIdCardAsync(security, cardRequestBody)).signIdCardResponse; varif cardRequestBody(res != new signIdCardRequestBody signIdCardResponse.ok) { throw new Exception("Gateway logon error"); } SignatureValue = signature, // Convert the GW Assertion to a KeyInfo = new GW.KeyInfodgwsType Assertion var sosiGwAssertionDocument {= SerializerUtil.Serialize(sosiGwAssertion).Root; return Item = new GW.X509Data { Item = userCert.Export(X509ContentType.Cert) } } }; // The STS signed card is saved in the sosiGw cache and is used for future calls through the proxy var res = (await gwClient.signIdCardAsync(security, cardRequestBody)).signIdCardResponse; if (res != signIdCardResponse.ok) { throw new Exception("Gateway logon error"); } // Convert the GW Assertion to a dgwsType Assertion var sosiGwAssertionDocument = SerializerUtil.Serialize(sosiGwAssertion).Root; SerializerUtil.Deserialize<Assertion>(sosiGwAssertionDocument, typeof(AssertionType).Name); } |
SOSI Gateway SBO
Dette bruges til almindelige SOAP kald, hvor GW vil berige ID kortet med det den har gemt i dens cache. Det er derfor et krav at ID kortet først er oprettet i GW. Bruges f.eks. til FMK og DDS.
Her vises et eksempel med FMK:
var idCardRequest = factory.CreateNewUserIdCard(system.SystemName, userInfo, new CareProvider(system.CareProviderIdFormat, system.CareProviderId, system.CareProviderName), AuthenticationLevel.MocesTrustedUser, "", "", user.Certificate, "");
- LoginToGateway(idCardRequest, global.NsiLge1);
...
SerializerUtil.Deserialize<dk.nsi.seal.dgwstypes.Assertion>(sosiGwAssertionDocument, nameof(GW.AssertionType));
} |
Kald gennem SOSI Gateway
Dette bruges til almindelige SOAP kald, hvor GW vil berige ID kortet med det den har gemt i dens cache. Det er derfor et krav at ID kortet først er oprettet i GW.
Bruges bl.a. til FMK og DDS.
Her vises et vejledende eksempel med FMK:
Code Block | ||
---|---|---|
| ||
var idCardRequest = SOSIFactory.CreateNewUserIdCard(
systemName,
new UserInfo(requestCpr, givenName, surName, email, occupation, role, authorizationcode),
new CareProvider(careProviderIdFormat, careProviderId, careProviderName),
AuthenticationLevel.MocesTrustedUser, userName, password, user.Certificate, "alternativeIdentifier");
await LoginToGateway(idCardRequest, certificate);
var binding = new CustomBinding();
binding.Elements.Add(new TextMessageEncodingBindingElement(MessageVersion.Soap11WSAddressingAugust2004, Encoding.UTF8));
binding.Elements.Add(new HttpTransportBindingElement());
var client = new Fmk.MedicineCardPortTypeClient(
binding, // MedicineCardPortTypeClient.EndpointConfiguration.MedicineCardPort kan evt. bruges i stedet for CustomBinding
new EndpointAddress(new Uri("http://test2.ekstern-test.nspop.dk:8080/sosigw/proxy/soap-request")));
client.Endpoint.EndpointBehaviors.Add(
new ViaBehavior(new Uri("https://test2.fmk.netic.dk/fmk12/ws/MedicineCard")));
using (new OperationContextScope(client.InnerChannel))
{
OperationContext.Current.OutgoingMessageHeaders.Add(IdCardHeader(idCardRequest)); // Samme ID-kort der blev gemt i SOSI-GW
OperationContext.Current.OutgoingMessageHeaders.Add(XmlHeader(dgwsHeader));
var response = await |
...
client.GetMedicineCard_2015_06_ |
...
01Async(
Security: null,
Header: null,
WhitelistingHeader: whitelistingHeader,
GetMedicineCardRequest: new GetMedicineCardRequestType
{
PersonIdentifier = new PersonIdentifierType
{
source = "CPR",
Value = requestCpr
}
});
}
|
Der henvises til dokumentation af SOSI Gateway for yderligere detaljer.
SOSI Gateway SBO
En token til SBO kan hentes gennem SOSI Gateway
new GetMedicineCardRequest_2015_06_01
{
Security = SecurityHeaderUtil.MakeSecurityUsingDgwsTypes(idc),
Header = requestHeader,
WhitelistingHeader = makeWhitelistingHeader,
GetMedicineCardRequest = new GetMedicineCardRequestType
{
PersonIdentifier = new PersonIdentifierType
{
source = "CPR",
Value = requestCpr
}
}
});
SOSI Gateway SBO
SOSI Gateway kan bruges til SBO (Sikker Browser Opstart).
Det første der skal gøres er at logge ind i SOSI GW. Dette gøres ved at sende det ID kort man har til SOSI Gateway, som vil gemme kortet i dens cache.
Ved efterfølgende kald til SOSI GW vil den kun kigge på Name ID (også kaldet Alternative Identifier i andre sammenhænge) i ID kortet der sendes, og kigge i dens cache om den har et ID kort med samme Name ID liggende. Hvis den har, vil den erstatte ID kortet i det request den har modtaget, med det der ligger i dens cache.
Se SOSI Gateway oprettelse af ID kort.
, se Oprettelse af ID kort i SOSI Gateway.
Herefter kan en token til SBO hentes med 'Sosi2SamlStsClient' på følgende mådeHerefter kan ID kort ombyttes til SAML tokens med 'Sosi2SamlStsClient':
Code Block | ||
---|---|---|
| ||
var uri = new Uri("http://test1.ekstern-test.nspop.dk:8080/sosigw/proxy/soap-request"); var response = Sosi2SamlStsClient.ExchangeAssertion(uri, "audience", idCard).XAssertion; |
Som beskrevet, behøver ID kortet her ikke indeholde andet end det samme Name ID som det ID kort der blev brugt til at logge ind med, da SOSI GW så erstatter ID kortet med det den har i sin cache.
Eksempler ved brug af OioSamlFactory
Brug af NemId:
Efterfølgende kode viser hvordan en NemidLogin Saml2Assertion konverteres til en DGWSAssertion. For herefter at oprette en Security instans der indeholder denne Assertion og kalde en FMK service.
- var callingSystem = new CallingSystem(
systemName: "Seal.Net.Fmk.Demo",
careProviderId: "30808460",
careProviderName: "TRIFORK SERVICES A/S",
careProviderIdFormat:
dk.nsi.seal.dgwstypes.SubjectIdentifierType.medcomcvrnumber,
certificate: new X509Certificate2("Resources/certificates/Statens_Serum_Institut_FOCES.p12", "Test1234"));
var user = new User(
cpr: "1802602810",
givenName: "Stine",
surName: "Svendsen",
email: "stineSvendsen@example.com",
role: "læge",
authCode: "ZXCVB",
occupation: "Overlæge",
certificate:
new X509Certificate2("Resources/certificates/MOCES_cpr_gyldig.p12", "Test1234"));
- var userVault = new GenericCredentialVault("UserVault");
userVault.SetSystemCredentials(user.Certificate);
// This nemidAssertion is expected to have been generated at an earlier login.
- var nemidAssertion = NemIdAssertionBuilder.MakeNemIdAssertion(user.Certificate, system.Certificate, system, user);
- var assertion = new OioSamlAssertion(samlAssertion);
- var factory = new OIOSAMLFactory();
- var domBuilder = factory.CreateOiosamlAssertionToIdCardRequestDomBuilder();
domBuilder.SigningVault = userVault;
domBuilder.OioSamlAssertion = assertion;
domBuilder.ItSystemName = system.SystemName;
domBuilder.UserAuthorizationCode = user.AuthCode;
domBuilder.UserEducationCode = null;
domBuilder.UserGivenName = user.GivenName;
domBuilder.UserSurName = user.SurName;
- var requestDoc = domBuilder.Build();
- var request = factory.CreateOioSamlAssertionToIdCardRequestModelBuilder() .Build(requestDoc);
- var idCard = SealUtilities.SignIn(request, "http://test2.ekstern-test.nspop.dk:8080/sts/services/OIOSaml2Sosi");
- var client = new MedicineCardPortTypeClient(_fmkEndpoint);
- using (new OperationContextScope(client.InnerChannel))
{
var response = client.GetMedicineCard_2015_06_01(
new GetMedicineCardRequest_2015_06_01
{
Security = SecurityHeaderUtil.MakeSecurityUsingDgwsTypes(idCard),
Header = MakeHeader(),
WhitelistingHeader = MakeWhitelistingHeader(),
GetMedicineCardRequest = new GetMedicineCardRequestType
{
PersonIdentifier = new PersonIdentifierType
{
source = "CPR",
Value = "2603558084"
}
}
});
Her kan man se brugen af OioSamlFactory til at udveksle en Nemid assertion med FMK.
- Generer bruger og system information for nem tilgængelighed.
- Opret ny CredentialVault med bruger certifikat.
- Opret en ny Saml2Assertion ud fra informationerne.
- Opret OioSamlAssertion ud fra NemidAssertion
- Opret ny OioSamlFactory
- Opret ny OiosamlAssertionToIdCardRequestDomBuilder og initialiser med korrekte informationer.
- Byg dokumentet
- Opret OioSamlAssertionToIdCardRequestModelBuilder og byg requesten.
- Brug Sealutilities.Signin til at sende requesten til serveren. Returnerer nyt IdCard signed fra STS
- Opret ny klient til FMK kommunikation
- Kald FMK.
2.3.2. BST2SOSI
Oprettelsen af et bst2sosi request er meget i stil med et bst2idws request:
Gliffy Diagram | ||||||
---|---|---|---|---|---|---|
|
2.3.3 OIO2BST_CITIZEN
Det er muligt at genere, parse og validere OIO2BST_CITIZEN bootstrap tokens. Dette sker via klasserne OIO2BSTCitizenSAMLAssertionBuilder og OIO2BSTCitizenSAMLAssertion klasserne. OIOSAMLFactory anvendes til at lave en instans af OIO2BSTCitizenSAMLAssertionBuilder.
For kryptering og dekryptering af disse tokens kan der hentes inspiration i testen TestEncryptDecrypt i klassen OIO2BSTCitizenTest.
2.4. OIOBSTSAMLAssertion-factory
OIOBSTSAMLAssertionFactory benyttes til at oprette OIO bootstraptoken objekter givet et xml element.
Sådanne bootstraptokens kan enten være for medarbejdere (hertil benyttes createOIOBSTSAMLAssertion(...)) eller borgere (hertil benyttes createOIOBSTCitizenSAMLAssertion(...)), og identificeres ud fra deres spec version attribut.
Eksempler på generering af objekter fra proxy
Nedenstående eksempler viser initieringer at klasser der er autogenereret ud fra en DGWS WSDL.
CallingSystem og User
...
Security
...
await LoginToGateway(IdCard, UserCert);
var uri = new Uri("http://test1.ekstern-test.nspop.dk:8080/sosigw/proxy/soap-request");
var wsAddressing = WsAddressing.New("http://test1.ekstern-test.nspop.dk:8080/sts/services/Sosi2OIOSaml");
var oioToken = Sosi2SamlStsClient.ExchangeAssertion(uri, wsAddressing, "/ststest", IdCard).XAssertion; |
Eksempler ved brug af OioSamlFactory
Brug af NemId:
Efterfølgende kode viser hvordan en NemidLogin Saml2Assertion konverteres til en DGWSAssertion. For herefter at oprette en Security instans der indeholder denne Assertion og kalde en FMK service.
Code Block | ||
---|---|---|
| ||
var callingSystem = new CallingSystem( systemName: "Seal.Net.Fmk.Demo", careProviderId: "30808460", careProviderName: "TRIFORK SERVICES A/S", careProviderIdFormat: dk.nsi.seal.dgwstypes.SubjectIdentifierType.medcomcvrnumber, certificate: new X509Certificate2("Resources/certificates/Statens_Serum_Institut_FOCES.p12", "Test1234")); var user = new User( cpr: "1802602810", givenName: "Stine", surName: "Svendsen", email: "stineSvendsen@example.com", role: "læge", authCode: "ZXCVB", occupation: "Overlæge", certificate: new X509Certificate2("Resources/certificates/MOCES_cpr_gyldig.p12", "Test1234")); ICredentialVault userVault = <Create vault>; var assertion = new OioSamlAssertion(nemidAssertion); // nemidAssertion expected to have been generated at an earlier login. var domBuilder = OIOSAMLFactory.CreateOiosamlAssertionToIdCardRequestDomBuilder(); domBuilder.SigningVault = userVault; domBuilder.OioSamlAssertion = assertion; domBuilder.ItSystemName = system.SystemName; domBuilder.UserAuthorizationCode = user.AuthCode; domBuilder.UserEducationCode = null; domBuilder.UserGivenName = user.GivenName; domBuilder.UserSurName = user.SurName; var requestDoc = domBuilder.Build(); var request = OIOSAMLFactory.CreateOioSamlAssertionToIdCardRequestModelBuilder().Build(requestDoc); var idCard = SealUtilities.SignIn(request, "http://test2.ekstern-test.nspop.dk:8080/sts/services/OIOSaml2Sosi"); var client = new MedicineCardPortTypeClient(<FMK configuration>); using (new OperationContextScope(client.InnerChannel)) { OperationContext.Current.OutgoingMessageHeaders.Add(IdCardHeader(idCard)); OperationContext.Current.OutgoingMessageHeaders.Add(XmlHeader(MakeHeader())); var response = client.GetMedicineCard_2015_06_01Async( Security: null, Header: null, WhitelistingHeader: MakeWhitelistingHeader(), GetMedicineCardRequest: new GetMedicineCardRequestType { PersonIdentifier = new PersonIdentifierType { source = "CPR", Value = "2603558084" } } ); } static Header MakeHeader() => new() { SecurityLevel = 3, TimeOut = TimeOut.Item1440, TimeOutSpecified = true, Linking = new Linking { FlowID = Guid.NewGuid().ToString("D"), MessageID = Guid.NewGuid().ToString("D") |
...
},
FlowStatus = FlowStatus.flow_running,
FlowStatusSpecified = true,
Priority = Priority.RUTINE,
RequireNonRepudiationReceipt = RequireNonRepudiationReceipt.yes
};
// Trinene ved brugen af OioSamlFactory til at udveksle en Nemid assertion med FMK:
// 1. Generer bruger- og systeminformation for nem tilgængelighed.
// 2. Opret ny CredentialVault med bruger certifikat.
// 3. Opret en ny Saml2Assertion ud fra informationerne.
// 4. Opret OioSamlAssertion ud fra NemidAssertion
// 5. Opret ny OioSamlFactory
// 6. Opret ny OiosamlAssertionToIdCardRequestDomBuilder og initialiser med korrekte informationer.
// 7. Byg dokumentet
// 8. Opret OioSamlAssertionToIdCardRequestModelBuilder og byg requesten.Brug Sealutilities.Signin til at
// sende requesten til serveren.Returnerer nyt IdCard signed fra STS
// 9. Opret ny klient til FMK kommunikation
// 10. Kald FMK. |
2.3.2. BST2SOSI
Oprettelsen af et BST2SOSI request er meget i stil med et BST2IDWS request:
Gliffy Diagram | ||||||
---|---|---|---|---|---|---|
|
2.3.3 OIO2BST_CITIZEN
Det er muligt at genere, parse og validere OIO2BST_CITIZEN bootstrap-tokens. Dette sker via klasserne OIO2BSTCitizenSAMLAssertionBuilder og OIO2BSTCitizenSAMLAssertion. OIOSAMLFactory anvendes til at lave en instans af OIO2BSTCitizenSAMLAssertionBuilder.
For kryptering og dekryptering af disse tokens kan der hentes inspiration i testen TestEncryptDecrypt i klassen OIO2BSTCitizenTest.
2.4. OIOBSTSAMLAssertion-factory
OIOBSTSAMLAssertionFactory benyttes til at oprette OIO bootstraptoken objekter givet et xml element.
Sådanne bootstraptokens kan enten være for medarbejdere (hertil benyttes createOIOBSTSAMLAssertion(...)) eller borgere (hertil benyttes createOIOBSTCitizenSAMLAssertion(...)), og identificeres ud fra deres spec version attribut.
Eksempler på generering af objekter fra proxy
Eksempler
Seal.Net indeholder en række integrationstests. Disse har tilformål at verificere at de genererede requests rent faktisk kan forstås af STS'en og som inspiration til anvendere.
Bootstrap token tests
I klassen OIOBSTTests findes der en række tests der veksler et boot strap token til et SOSI ID kort. Der er tests af OIOH2BST, OIOH3BST og OIO3BST.
SOSI Gatweay
I klassen SosiGwTest er der tests af kald til SOSI Gateway. Her er der både test af kald mod createIdCardFromBST og requestIdCardDigestForSigning.
Fejlfinding
Invalid ID-kort ved kald til service
Denne fejl ses hvis man anvender en klient der er genereret ud fra WSDL som specificerer Security (som indeholder det signerede ID-kort). Problemet opstår fordi klienten laver om på namespaces i assertion i ID-kortet, som gør signaturen invalid.
Løsningen er i stedet at anvende 'IdCardMessageHeader' og evt. 'XmlMessageHeader'.
Her vises et eksempel med en klient genereret til FMK:
Koden der fejler:
Code Block | ||
---|---|---|
| ||
var security = new Security
{
id = Guid.NewGuid().ToString("D"),
Timestamp = new FmkClient.Timestamp
{
Created = FiveMinutesAgoUtc().ToLocalTime()
},
Assertion = idc.GetAssertion<AssertionType>() // Problemet opstår når denne Assertion bliver serialiseret i kaldet til getPersonInformation nedenunder
};
var response = client.getPersonInformationAsync(security, header, getPersonInformation); // Fejler |
Laves om til:
Code Block |
---|
using (new OperationContextScope(client.InnerChannel))
{
OperationContext.Current.OutgoingMessageHeaders.Add(IdCardHeader(idc));
OperationContext.Current.OutgoingMessageHeaders.Add(XmlHeader(header));
var response = client.getPersonInformationAsync(null, null, getPersonInformation);
} |
Hvis der findes en udgave af WSDL som ikke specificerer Security og Header, kan man undgå null. Alternativt kan man selv lave et overload der ikke tager argumenterne, og selv sætter null i metoden.
Referencer
Header
...
Make NemId Assertion
public static Saml2Assertion MakeNemIdAssertion(
X509Certificate2 userCertificate,
X509Certificate2 signingCertificate,
CallingSystem system,
User user
)
{
var ass = new Saml2Assertion(new Saml2NameIdentifier("https://saml.test-nemlog-in.dk/"))
{
Conditions = new Saml2Conditions
{
NotOnOrAfter = DateTime.Now + TimeSpan.FromHours(8),
NotBefore = DateTime.Now
},
Subject = new Saml2Subject(new Saml2NameIdentifier(userCertificate.SubjectName.Name))
};
ass.Subject.SubjectConfirmations.Add(
new Saml2SubjectConfirmation(new Uri("urn:oasis:names:tc:SAML:2.0:cm:bearer"))
{
SubjectConfirmationData = new Saml2SubjectConfirmationData
{
NotOnOrAfter = DateTime.Now + TimeSpan.FromHours(8),
Recipient = new Uri("https://staging.fmk-online.dk/fmk/saml/SAMLAssertionConsumer")
}
});
IList<Saml2Attribute> q = new List<Saml2Attribute>();
// Spec
q.Add(new Saml2Attribute(OioSamlAttributes.SpecVersion, SpecVersion) {NameFormat = BasicNameFormat});
// User
q.Add(new Saml2Attribute(OioSamlAttributes.CommonName, user.GivenName) {NameFormat = BasicNameFormat});
q.Add(new Saml2Attribute(OioSamlAttributes.Surname, user.SurName) {NameFormat = BasicNameFormat});
q.Add(new Saml2Attribute(OioSamlAttributes.Email, user.Email) {NameFormat = BasicNameFormat});
q.Add(new Saml2Attribute(OioSamlAttributes.CprNumber, user.Cpr) {NameFormat = BasicNameFormat});
q.Add(new Saml2Attribute(OioSamlAttributes.AssuranceLevel, "4") {NameFormat = BasicNameFormat});
q.Add(new Saml2Attribute(OioSamlAttributes.UserCertificate, Convert.ToBase64String(userCertificate.RawData)) {NameFormat = BasicNameFormat});
// Organization
q.Add(new Saml2Attribute(OioSamlAttributes.CvrNumber, system.CareProviderId) {NameFormat = BasicNameFormat});
q.Add(new Saml2Attribute(OioSamlAttributes.OrganizationName, system.CareProviderName) {NameFormat = BasicNameFormat});
// Certificate
var subjectSerialNumber = userCertificate.SubjectName.Name;
q.Add(new Saml2Attribute(OioSamlAttributes.CertificateSerial, userCertificate.GetSerialNumberString()) {NameFormat = BasicNameFormat});
q.Add(new Saml2Attribute(OioSamlAttributes.CertificateIssuer, userCertificate.IssuerName.Name) {NameFormat = BasicNameFormat});
q.Add(new Saml2Attribute(OioSamlAttributes.Uid, ExtractUidNumber(subjectSerialNumber)) {NameFormat = BasicNameFormat});
q.Add(new Saml2Attribute(OioSamlAttributes.RidNumber, ExtractRidNumber(subjectSerialNumber)) {NameFormat = BasicNameFormat});
ass.Statements.Add(new Saml2AttributeStatement(q));
ass.Statements.Add(
new Saml2AuthenticationStatement(
new Saml2AuthenticationContext(new Uri("element:urn:oasis:names:tc:SAML:2.0:ac:classes:X509")),
DateTime.Now));
ass.SigningCredentials = new X509SigningCredentials(signingCertificate, SignedXml.XmlDsigRSASHA1Url, SignedXml.XmlDsigSHA1Url);
return ass;
}
Eksempler
Seal.Net indeholder en række integrationstests. Disse har tilformål at verificere at de genererede requests rent faktisk kan forstås af STS'en og som inspiration til anvendere.
Bootstrap token tests
I klassen OIOBSTTests findes der en række tests der veksler et boot strap token til et SOSI ID kort. Der er tests af OIOH2BST, OIOH3BST og OIO3BST.
SOSI Gatweay
I klassen SosiGwTest er der tests af kald til SOSI Gateway. Her er der både test af kald mod createIdCardFromBST og requestIdCardDigestForSigning.
Referencer
...
Forkortelse i teksten
...
Henvisning
...
<ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="a906cdd8-a856-48fa-b3af-9e69d149de6f"><ac:plain-text-body><![CDATA[
...
[SAML2.0]
SAML2.0
https://www.oasis-open.org/committees/tc_home.php?wg_abbrev=
...
]]></ac:plain-text-body></ac:structured-macro>
...
<ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="7e8fddac-a1c4-4c1e-893d-d02f891e609d"><ac:plain-text-body><![CDATA[
...
[OIOSAML]
OIOSAML http://digitaliser.dk/resource/2377872
...
]]></ac:plain-text-body></ac:structured-macro>
...
<ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="923053d9-c34e-46e7-879d-75fa83f9df93"><ac:plain-text-body><![CDATA[
...
OIOIDWS
...
http://digitaliser.dk/resource/526486
...