Page History
...
Nap-reference består af en java backend service (nap-reference-facade) samt en front for backend (nap-reference-web), som anvender bygget med angular fremworket og som anvender version 1.0.0 af nap-typescript-sdk og nap-angular-sdk.
...
Når nap-reference får overført en patientkontekst kaldes facaden med det cpr nummer sam SOR værdi i en "X-OrganizationSor" header (denne værdi er hardcoded i dette tilfælde, da den ikke kan læses ud af SOSI IDkortet)". Facaden validere kaldet og viderestiller til Dokumentdelingsservice (DDS)..
...
Angular frameworket lægger sig op af MVC (model-view-controller) design mønstremønsteret, og dette er implementeret i nap-reference-web.
Der er simple komponenter til at visning af aftaler, hjælpinformationhjælpeinformationer, fejl osv.
Services
Services håndterer forretningslogikken.
...
Nap-reference-web benytter sig af en json konfigurationsfil (assets/configurtation.json), som loades via configuration-servicen.
Denne konfigurationsfil bliver således overskrevet i de forskellige docker-compose setups.
For yderligere information omkring konfiuration henvises til NAP Ref.Impl. - Guide til udviklere.
Der findes 2 konfigurationer en til dev (configurations-dev.json samt configurations.json) som adskiller sig i serverens url.
Configurations-dev.json er anvendes til når nap-refence-web er under udvikling og køres via ng serve (så der kommer live reloading af kodeændringer), hvor configurations.json anvendes i sig til når nap-reference-web er pakket og deployet sammen med nap-reference-facade i kontekst roden.
For yderligere information omkring konfiguration henvises til NAP Ref.Impl. - Guide til udviklere.
Da INSP Da NSP web applikationer og services kan blive deployet på vilkårlige url'er, og skal kunne loade ressourcer relativt til, hvor de er deployet, er det vigtigt at applikationen fungerer med relative paths.
Dette er opnået ved hashrouting.
| Code Block |
|---|
@NgModule({
imports: [RouterModule.forRoot(routes, { useHash: true })],
exports: [RouterModule]
})
export class AppRoutingModule { }
|
Du kan læse mere på https://angular.io/guide/router
Debugging
Hvis Nap-reference-web åbnes i browser kan den debugges med almindelige developer tools.
Hvis den åbnes i nap-java-host, er den eneste debugging mulighed . console.konsol logs().
Testing
Nap-reference-web benytter sig af testframeworket Karma, da det kommer default med angular. Karma bruger Istanbul til at generere test-coverage rapporter. Testene køres i en headless chromium browser.
...
nap-reference-web gør brug af det udstillede interface i nap-angular-sdk, og nedenfor er der eksempler på hvordan det er blevet brugt.
...
Security (SAML logout samt Session-close
...
NapEvent)
Der er lavet en AuthService, som sørger for at håndtere sessioner.
Nedenstående funktionalitet findes i src/app/services/auth.service.ts.
I constructoren Auth service lytter man på indkommende beskeder fra NAP SDK'et, og filtrerer beskeder, således det kun er beskeder af typen SessionOpen og SessionClose som håndteres. I constructoren bliver der ligeledes sendt en besked til NAP SDK'et om man gerne vil anmode om at starte en ny trusted session (SessionOpen), hvor brugeres SAMLAssertion overføres..
Hvis bruger ønsker at blive logget ud sendes en besked med SessionClose fra det kontekst brugeren har igangsat eventet. Det betyder at eventet både kan sendes fra indlejret system til værtsystem og omvendt.
Når brugeren skal logges ud skal browseren flyttes til den saml/Logout på den server, der holder sessionenHvis der logges ud, sendes en besked med SessionClose, og brugerens SAMLAssertion slettes.
| Code Block | ||
|---|---|---|
| ||
export class AuthServiceimport { privateInjectable sessionMessageSubject} = new BehaviorSubject<NAPMessage | undefined>( undefined ); /** * The current session * * @memberof AuthService */ public session$ = this.sessionMessageSubject.asObservable(); constructor(private napSDK: NapAngularService) { this.napSDK.incoming$ .pipe( filterEvents([ NAPEventCatalogue.v1.SessionOpen, NAPEventCatalogue.v1.SessionClose, ]) )from '@angular/core'; import { NapAngularService } from 'nap-angular-sdk'; import { filterEvents, NAPEventCatalogue, NAPMessage } from 'nap-typescript-sdk'; import { combineLatest, merge, Observable, Subject } from 'rxjs'; import { map, switchMap, tap } from 'rxjs/operators'; import { v4 as UUID } from 'uuid'; import { ConfigurationsService } from './configurations.service'; /** * Service to handle user session * * @export AuthService * @class AuthService */ @Injectable({ providedIn: 'root', }) export class AuthService { innerLogout = new Subject<undefined>(); logOut$: Observable<boolean> = merge( this.innerLogout, this.napSDK.incoming$.pipe( .subscribe((napMessage) => { filterEvents([NAPEventCatalogue.v1.SessionClose]), )).pipe( if (napMessage.event.typeswitchMap(() ===> NAPEventCataloguethis.v1.SessionOpen) {logOutUrl$), tap(logOutUrl => { this.sessionMessageSubject.next(napMessage); // Direct the window }to elsethe { OIOSaml logout filter thiswindow.sessionMessageSubjectlocation.nextassign(undefinedlogOutUrl); } }); const napMsg: NAPMessage = {console.log('Will redirect:' + logOutUrl); } date: new Date().toISOString(), id: UUID(),map(() => true) ); private eventlogOutUrl$: {Observable<string> type: NAPEventCatalogue.v1.SessionOpen },= combineLatest([ }; this.configService.fetch( //config Ask for the SAMLassertion in host=> config.serverUrl ), this.napSDKconfigService.sendMessage(napMsg); } /**fetch(config => config.logOutEndpoint) ]).pipe( * Trigger logout event */ logout(): void { this.sessionMessageSubject.next(undefined); map(([serverUrl, logOutUrl]) => serverUrl + logOutUrl), ) constructor( private napSDK: NapAngularService, constprivate napMsgconfigService: NAPMessageConfigurationsService =) { } date: new Date().toISOString(), id: UUID(),/** * completes the current session and logs out the user */ event:logout(): void { type: NAPEventCatalogue.v1.SessionClose }, } console.log('NapReferenceWeb Logging out'); this.napSDKinnerLogout.sendMessagenext(napMsgundefined); } } |
Patient-Open og Patient-close
I komponenten appointment (src/app/appoinment/), vises de forskellige aftaler for den givne patient.
For at få den nuværende patient, sendes en besked med typen PatientOpen igennem SDK'et. Dette gøres i constructoren.
Herefter lyttes der på indkommende beskeder med typen PatientOpen. Der gøres brug af en hjælpe metode i nap-typescript-sdk, FHIRValueGetter.getPatientInfo(), som konvertere den indkommende besked til et objekt som indeholder patient oplysningerne.
Hvis den nuværende patient skal lukkes, set fra det indlejrede systems perspektiv, sendes der en besked med typen PatientClose.
const napMsg: NAPMessage = {
date: new Date().toISOString(),
id: UUID(),
event: { type: NAPEventCatalogue.v1.SessionClose },
};
this.napSDK.sendMessage(napMsg);
}
}
|
Patient-Open og Patient-close
I komponenten appointment (src/app/appoinment/), vises de forskellige aftaler for den givne patient.
For at få den nuværende patient, sendes en besked med typen PatientOpen igennem SDK'et. Dette gøres i constructoren.
Herefter lyttes der på indkommende beskeder med typen PatientOpen. Der gøres brug af en hjælpe metode i nap-typescript-sdk, FHIRValueGetter.getPatientInfo(), som konvertere den indkommende besked til et objekt som indeholder patient oplysningerne.
Hvis den nuværende patient skal lukkes, set fra det indlejrede systems perspektiv, sendes der en besked med typen PatientClose.
| Code Block |
|---|
| Code Block |
constructor(
private napSDK: NapAngularService,
private appointmentService: AppointmentService,
private authService: AuthService
) {
const napMsg: NAPMessage = {
date: new Date().toISOString(),
id: UUID(),
event: {
type: NAPEventCatalogue.v1.PatientOpen,
},
};
this.napSDK.sendMessage(napMsg);
}
public currentPatient$: Observable<NAPPatientInfo | undefined> = this.napSDK.incoming$.pipe(
filterEvent(NAPEventCatalogue.v1.PatientOpen),
map(message => FHIRValueGetter.getPatientInfo(message))
); |
...
Fejlen bliver sendt hvis kaldet til getAppointments() fejler.
| Code Block |
|---|
/** * privateGeneretas appointmentEndPoint$Requests to = this.configurationService.fetch( config => config.appointmentsEndpoint ); private serverUrl = this.configurationService.fetch(config => config.serverUrl); private createNapErrorMessage(error: GenericAppError): NAPMessage { return { date: new Date().toISOString(), id: UUID(), event: { type: NAPEventCatalogue.v1.SessionError, context: [ { resource: { resourceType: FHIRValueSetter.FHIRResourceType.Basic, code: { coding: [ { code: NAPEventCatalogue.v1.SessionError, system: FHIRValueSetter.FHIRSystem.NAP, get appoitnemnts for a given person and organization * * @export AppointmentService * @class AppointmentService */ @Injectable({ providedIn: 'root' }) export class AppointmentService { /** * The appointment endpoint * * @private * @memberof AppointmentService */ private appointmentEndPoint$ = this.configurationService.fetch( config => config.appointmentsEndpoint ); /** * The server url * * @private * @memberof AppointmentService */ private serverUrl = this.configurationService.fetch(config => config.serverUrl); /** * A refresh indicator * * @private * @memberof AppointmentService */ private serviceActivator = new BehaviorSubject(undefined); constructor( private http: HttpClient, private errorService: ErrorService, private configurationService: ConfigurationsService, private napSDK: NapAngularService ) { } /** * Make a HTTP GET to the serverurl/appointmentendpoint * @param patientIdentifier */ public getAppointments(patientIdentifier: string | undefined): Observable<any[] | undefined> { return combineLatest( [ this.serverUrl, }this.appointmentEndPoint$, this.serviceActivator ], ).pipe( }, identifier: [switchMap(([serverUrl, endpointPath, _]) => this.http.get<any[]>(serverUrl + endpointPath + '/' + patientIdentifier)), catchError(error => { this.errorService.postError(error); system: FHIRValueSetter.FHIRIdentifierSystem.NAPErrorMessage, value: errorthis.napSDK.sendMessage(NAPEventCatalogue.v1.MessageFactory.createSessionErrorMessage(UUID(), error.innerError?.message ?, error.innerError?.message : '', errorMessage)); // indicate to the host that something went wrong },return of(undefined); }), ); } {/** * Triggers a data update of the service */ refresh(): system: FHIRValueSetter.FHIRIdentifierSystem.NAPErrorDescription,void { value: error.errorMessage, }, ], }, }, ], } } } public getAppointments(patientIdentifier: string | undefined): Observable<any[] | undefined> { return combineLatest( [ this.serverUrl, this.appointmentEndPoint$, this.serviceActivator ] ).pipe( switchMap(([serverUrl, endpointPath, _]) => this.http.get<any[]>(serverUrl + endpointPath + '/' + patientIdentifier)), catchError(error => { this.errorService.postError(error); this.napSDK.sendMessage(this.createNapErrorMessage(error)); // indicate to the host that something went wrong return of(undefined); }), ); } |
Nap-reference-facade
Nap-reference-facade er bygget med java 8 og fungerer som illustration på:
- Projekt opsætning overholdende https://www.nspop.dk/display/public/web/Husregler+for+udvikling+til+NSP.
- Sikkerhed i NAP kontekst Sikkerhedsarkitektur for iNSP løsninger
Brug af Dokumentdelingsservice (DDS)
Opsætning og struktur
Dependencies
Dependencies er hentet fra https://nexus.nspop.dk/nexus/content/groups/public og de dependencies, som stilles til rådighed af wildfly8 platformen er angivet med scope provided.
For at kunne kalde Dokumentdelingsservice (DDS) er følgende dependencies anvendt:
...
dk.sosi.seal...
Java-bibliotek til understøttelse af "Den Gode Webservice" og validering af SAMLassertion, se http://digitaliser.dk/group/374971.
...
dk.s4.hl7.builders...
Dansk profileret XML converter af hl7 clinical documents
...
org.openehealth.ipf.commons...
this.serviceActivator.next(undefined);
}
} |
Nap-reference-facade
Nap-reference-facade er bygget med java 8 og fungerer som illustration på:
- Projekt opsætning overholdende https://www.nspop.dk/display/public/web/Husregler+for+udvikling+til+NSP.
- Sikkerhed i NAP kontekst Sikkerhedsarkitektur for iNSP løsninger
Brug af Dokumentdelingsservice (DDS)
Opsætning og struktur
Dependencies
Dependencies er hentet fra https://nexus.nspop.dk/nexus/content/groups/public og de dependencies, som stilles til rådighed af wildfly8 platformen er angivet med scope provided.
For at kunne kalde Dokumentdelingsservice (DDS) er følgende dependencies anvendt:
dk.sosi.seal | Java-bibliotek til understøttelse af "Den Gode Webservice" og validering af SAMLassertion, se http://digitaliser.dk/group/374971. |
dk.s4.hl7.builders | Dansk profileret XML converter af hl7 clinical documents |
org.openehealth.ipf.commons | Dansk profileret bibliotek til Cross Enterprise Document sharing. Bruges til at integrere Dokumentdelingsservice (DDS). Du kan læse mere på https://github.com/KvalitetsIT/aftaledeling/tree/master/dgws-eksempel/src/main/java/dk/sds/appointment. |
dk.digst.oiosaml2.java | Danske profilering af OASIS SAML 2.0 standarden. |
Konfiguration
Alt konfiguration foregår ved at loade filer fra et selv-defineret wildfly modul og ind i classpath under deployment.
Dette gør wildfly ved at modulet defineres i jboss-deployment-structure.xml.
Der findes flere information om hvordan nap-refernece-facade konfigureres på NAP Ref.Impl. - Guide til udviklere.
Testing
Testene bliver eksekveret af maven-surefire-plugin med test frameworket junit. Test coverage bliver målt af Jacoco.
Dokumentation
Kodedokumentationen overholder javadoc standarden således dette kan generes med et værktøj fra fx den IDE man bruger.
Sikkerhed
Sikkerhedsarkitekturen følger det skitserede i Sikkerhedsarkitektur for iNSP løsninger. Dermed er der åben for mulighederne for integration til udbredte procedure Sikker browser opstart, samt understøtter tilslutning til Nemlogin.
dk.digst.oiosaml2.java
Anvendes som autentifikationsfilter. Nedenfor er et eksempel på registrering af SPFilteret.
| Code Block | ||
|---|---|---|
| ||
@WebListener
public class SpringLoader implements ServletContextListener {
protected static final String ANNOTATION_CONFIG_CONTEXT = "ANNOTATION_CONFIG_APPLICATION_CONTEXT";
/**
* Initialize standalone spring context. Registers the spring configuration and finally register it at the servlet context
*/
@Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
AnnotationConfigApplicationContext springContext = new AnnotationConfigApplicationContext();
springContext.register(SpringContext.class);
springContext.refresh();
final ServletContext servletContext = servletContextEvent.getServletContext( |
Konfiguration
Alt konfiguration foregår ved at loade filer fra et selv-defineret wildfly modul og ind i classpath under deployment.
Dette gør wildfly ved at modulet defineres i jboss-deployment-structure.xml.
Der findes flere information om hvordan nap-refernece-facade konfigureres på NAP Ref.Impl. - Guide til udviklere.
Testing
Testene bliver eksekveret af maven-surefire-plugin med test frameworket junit. Test coverage bliver målt af Jacoco.
Dokumentation
Kodedokumentationen overholder javadoc standarden således dette kan generes med et værktøj fra fx den IDE man bruger.
Sikkerhed
dk.sosi.seal bliver brugt til at verificere SAMLassertion.
| Code Block | ||
|---|---|---|
| ||
/** * @param headers Map of request headers * @return Saml assertion if its valid or null in case of invalid SAML assertion * @throws AuthenticationException If ant authentication exception occure */ public OIOSAMLAssertion extractAndValidate(MultivaluedMap<String, String> headers) throws AuthenticationException { final List<String> authentication = headers.get(AUTHENTICATION_PROPERTY); try {servletContext.setAttribute(ANNOTATION_CONFIG_CONTEXT, springContext); ServletRegistration String xml servletRegistration = new String(Base64.decode(authentication.get(0)), StandardCharsets.UTF_8servletContext.addServlet("SAMLDispatcherServlet", DispatcherServlet.class); Document doc = parseXml(xml); servletRegistration.addMapping("/saml/*"); Element encryptedAssertionElm FilterRegistration.Dynamic filterRegistration = docservletContext.getDocumentElement(addFilter("LoginFilter", SPFilter.class); filterRegistration.addMappingForUrlPatterns(null, PrivateKey privateKeyForAudience = certificateVault.getSystemCredentialPair().getPrivateKey(); false, "/api/*"); // decrypt the xml for the assertion and parse itfilterRegistration.addMappingForUrlPatterns(null, false, "/saml/*"); filterRegistration.setInitParameter("a", "b"); } @Override finalpublic Element element = EncryptionUtil.decryptAndDetach(encryptedAssertionElm, privateKeyForAudience);void contextDestroyed(ServletContextEvent servletContextEvent) { Object ctx OIOSAMLAssertion assertion = new OIOSAMLAssertion(element); servletContextEvent.getServletContext().getAttribute(ANNOTATION_CONFIG_CONTEXT); log.debug("extracted: \n" + assertion.getUID());if(ctx instanceof AnnotationConfigApplicationContext) { validateAssertion(assertion((AnnotationConfigApplicationContext)ctx).close(); } return assertion; } catch (IOException | ParserConfigurationException | SAXException e) { throw new AuthenticationException("Could not validate authentication header", e); } } |
Snitfladebeskrivelse og brug
}
} |
SPfilteret sørger for at validere den assertion der kommer fra en given iDP (https://www.nspop.dk/display/public/web/Sikkerhedsservices+%28STS%29+-+Leverancebeskrivelse i dette tilfælde).
Der findes flere information om hvordan oisaml konfigureres på NAP Ref.Impl. - Guide til udviklere.
SOSI idkort fra Samlassertion
Desuden er der implementeret et service specifikt autentifikationsfilter, der udtrækker det IDkort, som er indlejret i en SAMLassertion så det kan bruges i DGWS kald.
| Code Block | ||
|---|---|---|
| ||
@Provider
public class AuthFilter implements ContainerRequestFilter {
// https://howtodoinjava.com/resteasy/resteasy-containerrequestfilter-example/
static private final Logger log;
public static final Response ACCESS_DENIED = Response.status(401).build();
private static final String[][] XML_PATH_TO_SAML_ASSERTION = {
{NameSpaces.WSA_1_0_SCHEMA, WSATags.metadata.getTagName()},
{NameSpaces.LIBERTY_DISCOVERY_SCHEMA, LibertyDiscoveryTags.securityContext.getTagName()},
{NameSpaces.LIBERTY_SECURITY_SCHEMA, LibertySecurityTags.token.getTagName()},
{NameSpaces.SAML2ASSERTION_SCHEMA, SAMLTags.ASSERTION}
};
static {
log = Logger.getLogger(AuthFilter.class);
}
// https://howtodoinjava.com/resteasy/resteasy-containerrequestfilter-example/
@Override
public void filter(ContainerRequestContext requestContext) {
final RequestContext context = RequestContext.getContext();
final UserAssertion userAssertion = UserAssertionHolder.get();
context.setAssertion(userAssertion);
context.setUserIdCard(getIdCardFromAssertion(userAssertion));
}
private UserIDCard getIdCardFromAssertion(UserAssertion ua) {
UserAttribute attribute = ua.getAttribute(OIOSAMLAttributes.DISCOVERY_EPR);
if (attribute == null) {
if (log.isDebugEnabled()) log.debug("No embedded idcard in SAML assertion");
return null;
}
if (!Attribute.URI_REFERENCE.equals(attribute.getFormat())) {
if (log.isDebugEnabled()) log.debug("Attribute of name " + OIOSAMLAttributes.DISCOVERY_EPR +
" is not an embedded idcard - NameFormat mismatch (was + " + attribute.getFormat() +
", expected " + Attribute.URI_REFERENCE);
// NOTE: It does not seem robust to differentiate bootstrap tokens based on the NameFormat attribute, since:
// 1. Bootstrap tokens from sts (SBOv2) are defined to have format "uri reference" which seems wrong given that they contain xml
// 2. Bootstrap tokens from nemlogin (oioidws) have no defined format (NameFormat is missing). Maybe this will be corrected at some point?
// However a better option for differentiating token types is not obvious..
return null;
}
if (log.isDebugEnabled()) log.debug("Extracting idcard from SAML assertion");
String attributeValue = attribute.getValue();
InputSource inputSource = new InputSource(new StringReader(attributeValue));
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
documentBuilderFactory.setNamespaceAware(true);
DocumentBuilder documentBuilder;
try {
documentBuilder = documentBuilderFactory.newDocumentBuilder();
Document document = documentBuilder.parse(inputSource);
Element idCardElm = getDescendant(document.getDocumentElement());
return (UserIDCard) new IDCardModelBuilder().buildModel(idCardElm);
} catch (ParserConfigurationException | SAXException | IOException e) {
log.error("Error parsing embedded idcard", e);
}
return null;
}
private Element getDescendant(Element elm) {
for (String[] qName : AuthFilter.XML_PATH_TO_SAML_ASSERTION) {
NodeList nodeList = elm.getElementsByTagNameNS(qName[0], qName[1]);
if (nodeList == null || nodeList.getLength() == 0) {
log.error("Path element not found: {" + qName[0] + "}" + qName[1]);
return null;
}
Node child = nodeList.item(0);
if (!(child instanceof Element)) {
log.error("Path component {" + qName[0] + "}" + qName[1] + " is not an element; node=" + child);
return null;
}
elm = (Element) nodeList.item(0);
}
return elm;
}
}
|
dk.sosi.seal
Seal anvendes til at indlejre et SOSI IDkort i et XML dokument som er parseable for DGWS.
Nedenstående er eksempler på en DGWS interceptor, som sætter en DGWS header for client requests til DGWS.
| Code Block | ||
|---|---|---|
| ||
/**
* Soap interceptor that adds DGWS headers to XDS calls
*/
public class DGWSInterceptor extends AbstractSoapInterceptor {
// https://www.nspop.dk/display/ESP/Teknisk+implementeringsvejledning+Aftaleoversigt
static private final Logger log;
private static final AppConfiguration conf = AppConfiguration.getInstance();
static private CredentialVault certificateVault;
private UserIDCard userIdCard;
public DGWSInterceptor(UserIDCard userIdCard) {
super(Phase.PRE_STREAM);
this.userIdCard = userIdCard;
}
static {
log = Logger.getLogger(DGWSInterceptor.class);
try {
Properties props = SignatureUtil.setupCryptoProviderForJVM();
certificateVault = new ClasspathCredentialVault(props, conf.getKeystorePath(), conf.getKeystorePassword());
} catch (Exception e) {
log.error("Initialization error", e);
}
}
@Override
public void handleMessage(SoapMessage message) throws Fault {
// DGWS is SOAP11
message.setVersion(Soap11.getInstance());
// Add the DGWS headers
SOSIFactory sosiFactory = new SOSIFactory(certificateVault, SignatureUtil.setupCryptoProviderForJVM());
Request request = sosiFactory.createNewRequest(false, null);
request.setIDCard(userIdCard);
Document sosi = request.serialize2DOMDocument();
NodeList children = sosi.getDocumentElement().getFirstChild().getChildNodes();
for (int i = 0; i < children.getLength(); i++) {
Node element = children.item(i);
QName qname = new QName(element.getNamespaceURI(), element.getLocalName());
Header dgwsHeader = new Header(qname, element);
message.getHeaders().add(dgwsHeader);
}
}
} |
Snitfladebeskrivelse og brug
Nap-reference-facades snitflader bliver beskrevet i følgende.
oiosaml
Dokumentationen OIOSAML kan læses her https://github.com/digst/OIOSAML.Java
Men overordnet bruges følgende 2 endpoints til autentifikation og logout.
/saml/SAMLAssertionConsumer
Brugeres til at valider autentifikations requests og registrere en brugers assertion i en session
/saml/Logout
Bruger til single logout. Den sletter brugerens session.
/youAreLoggedOut
Anvendes af oiosaml.java som for singleLogoutService i forbindelse med Sikker browser opstart.
Hvis en bruger, som har startet applikationen med sikker browser opstart ønskes logget ud, vil oiosaml.java navigerer brugeren til dette endpoint, når brugeren er blevet logget ud.
Dette endpoint er derfor ikke beskyttet af autentikationsfilter og vil altid returnere 200 samt en html, der fortæller brugeren er logget udNap-reference-facade har 2 snitflader som bliver beskrevet i følgende.
/aftaler/{cpr}
Den eneste aftager af denne service er nap-reference-web.
| Headers | |||
|---|---|---|---|
| Key | Value | Authentication | BASE64 encoded SAMLassertion |
| X-OrganizationSor | Sor nummer (bruges af dokumentdelingsservicen) | ||
...