Smartcard-based eID integration into OpenNCP
Table of Contents
1. Introduction
In this page we'll present how the smartcard-based eID building block developed by the e-SENS project is deployed and integrated into the OpenNCP framework. The eID component is used in the identification and authentication of the patient at the PoC. To be able to take advantage of it, the patient must be holder of a card that identifies him in his country of origin and the physician's PoC must be equipped with a card reader.
The smartcard-based eID includes the following e-SENS eID levels:
Level | Name | Functions and Description |
|---|---|---|
1 | Local Attribute Retrieval and Mapping Service (LARMS) |
|
2 | Local Authentication Modules (LAM) |
|
3 | Local Authentication Modules and DSS (LAM+) |
Level 0 is considered the default one where manual input of patient identifiers is needed. Description of the different levels can also be found in the eID Task Force meeting minutes. Specific documentation about the eID building block will be handed over by e-SENS to the CEF eHealth DSI by the end of the e-SENS project (March 2017).
From now on, every reference to eID component shall be understood as a reference to the smartcard-based eID component.
2. Technical description of the eID workflow
The eID component is a Java Web Start application that automatically installs and runs in the physician's PoC and is able to interact with and process information from a set of relevant smartcards. The OpenNCP Portal is the component responsible for interacting with the eID component. After selecting the country of the patient in the Portal, the physician will find a link to download the eID component and automatically run it using the Java WS installation of the PoC. After that, the physician can use the PoC's card reader to start using the card's facilities in conjunction with the Portal. And how does this happen?
2.1. Read freely accessible patient data from smartcard (LARMS)
Every country that wishes to allow their citizens to be identified by the eID component in a foreign PoC should first change their search mask in order to map their identifiers to a set of defined friendly names (attributes):
cardIssuerCountry
cardType
cardId
healthInsuranceId
healthInsuranceCompanyId
healthInsuranceCompanyName
givenName
surname
dateOfBirth
gender
fiscalNumber
socialSecurityNumber
civilianIdNumber
ehicValidity
ehicBenefactor
fullAddress
issueDate
terminationDate
photo
The different identifiers that can be retrieved from the different cards can be checked in the source code under open-ecard/addons/larms/src/main/resources/*.vm.
So, for instance, in the case of Austria, it's needed to map its 3 mandatory identifiers (patient ID, given name, surname) to their corresponding friendly names, by appending the friendlyName XML attribute to the specific XML element, with the appropriate value, e.g.:
Austria search mask
<patientSearch>
<!-- min and max -1 means no length check -->
<!-- id format="LLLLLLNNLNNLNNNL" means 'L'etter 'N'umber -->
<!-- validation contains the fields which are mandatory -->
<!-- more then one validation means or -->
<!-- only one input field no validation necessary because minimum value which has to be filled out is 1 -->
<country code="AT">
<searchFields>
<textField label="patient.data.surname" min="3" max="-1" dtoIndex="1" friendlyName="surname"/>
<textField label="patient.data.givenname" min="3" max="-1" dtoIndex="2" friendlyName="givenName"/>
<birthDate label="patient.data.birth.date" min="-1" max="-1"/>
<id label="patient.search.patient.id" min="-1" max="-1" domain="2.16.17.710.780.1000.990.1" friendlyName="healthInsuranceId"/>
</searchFields>
<validation>
<field label="patient.data.surname" />
</validation>
<validation>
<field label="patient.data.givenname" />
</validation>
</country>
</patientSearch>This information of the search mask is then mapped into the service.SearchMask, model.Identifier and service.Demographics classes by means of EpsosHelperService's getCountry*/getCountries* methods, which will provide that data to be stored in MyBean. When the physician selects the flag of the patient's country in the Portal, it is displayed a representation of that country's search mask (view1.xhtml).
view1.xhtml
<h:form prependId="false" id="searchPatient">
<h3>#{msg['ui.searchmask.info']}</h3>
<h:panelGrid columns="2" >
<c:forEach items="#{myBean.identifiers}" var="identifier" varStatus="idLoop">
<h:outputLabel value="#{identifier.key}"/>
<p:inputText id="#{not empty identifier.friendlyName ? identifier.friendlyName : ''.concat('uservalue-').concat(idLoop.index)}" value="#{identifier.userValue}" required="true"/>
</c:forEach>
<c:forEach items="#{myBean.demographics}" var="demographic" varStatus="demographicsLoop">
<h:outputLabel value="#{demographic.label}:" rendered="#{myBean.showDemographics}"/>
<c:choose>
<c:when test="#{demographic.type=='text'}">
<p:inputText id="#{not empty demographic.friendlyName ? demographic.friendlyName : ''.concat('userValue2-').concat(demographicsLoop.index)}"
value="#{demographic.userValue}" required="#{demographic.mandatory}"/>
</c:when>
<c:when test="#{demographic.type=='calendar'}">
<p:calendar id="#{not empty demographic.friendlyName ? demographic.friendlyName : ''.concat('userDateValue2-').concat(demographicsLoop.index)}"
value="#{demographic.userDateValue}" yearRange="c-100:c+0" pattern="yyyyMMdd" navigator="true" >
<f:convertDateTime pattern="yyyyMMdd"/>
</p:calendar>
</c:when>
</c:choose>
</c:forEach>
</h:panelGrid>
<a id="sc_link" target="_blank" href="/jnlp/openecard.jnlp">#{msg['patient.search.downloadeid']}</a>
...The main difference with countries supporting eID for their citizens is that the id attribute of the input fields is assigned the value of the friendlyName attribute in the XML of the search mask (explanation of how the previous snippet of code works can be found here).
After displaying the page, a Javascript polling mechanism starts (code at the end of view1.xhtml). Each 10 seconds, it tries to reach the Java WS application by calling a REST web service that returns the freely accessible data from the smartcard. The eID component exposes its web services under the hostname www.localhost-ecard-client.de, port 24727. For instance, the LARMS service is exposed under /larms/getAttributes:
LARMS JWT REST service
http://www.localhost-ecard-client.de:24727/larms/getAttributes?servicelevel=basic&format=JWTWhen it succeeds in calling the eID component through this web service, the polling stops and it retrieves a Base64-encoded JSON Web Token (JWT) with the following format:
header.body.After decoding the body, it's able to retrieve the whole set (or a subset, depending on the card specificities) of the attributes previously listed, by looking for their namespaces, which are:
Sample JWT from Portuguese test card
{"sub":"card_holder",
"iss":"https://www.localhost-ecard-client.de:24728/larms/getAttributes",
"iat":"2016-07-26 16:03:41.794",
"jti":"a5b7d66e-99cf-4b37-a422-41fae3e999fc",
"http://www.esens.eu/attributes/smartcard/CardIssuerCountry":"pt",
"http://www.esens.eu/attributes/smartcard/CardType":"pt-cdc",
"http://www.esens.eu/attributes/smartcard/HealthInsuranceId":{"urn:oid:1.2.3.4.5.6.7.8.10":"898765368"},
"http://eidas.europa.eu/attributes/naturalperson/CurrentFamilyName":"Valido Emv Cap",
"http://eidas.europa.eu/attributes/naturalperson/CurrentGivenName":"Ricardo",
"http://eidas.europa.eu/attributes/naturalperson/DateOfBirth":"1975-12-01",
"http://eidas.europa.eu/attributes/naturalperson/Gender":"M",
"http://www.esens.eu/attributes/smartcard/FiscalNumber":"399990070",
"http://www.esens.eu/attributes/smartcard/SocialSecurityNumber":"11999999936",
"http://www.esens.eu/attributes/smartcard/CivilianIdNumber":"990009050",
"http://www.esens.eu/attributes/smartcard/IssueDate":"2014-02-06",
"http://www.esens.eu/attributes/smartcard/TerminationDate":"2019-02-06",
"http://www.esens.eu/attributes/smartcard/Photo":"data:image/jp2;base64,AA..."}Then, it finds the page's input elements with id attribute equals to the friendly names and sets them with the equivalent attributes read from the card, e.g.:
$("input[id = '<portlet:namespace/>:fiscalNumber']").val(payload['http://www.esens.eu/attributes/smartcard/FiscalNumber']).attr("readonly", true);In the end of the polling cycle, the search mask is shown filled with the attributes read from the card (the input fields get disabled to prevent the physician from changing the values) and the physician is able to proceed with the usual patient demographics query. The end of this first workflow marks the end of the eID level 1 functionalities (LARMS).
2.2. Patient Authentication (LAM/LAM+)
After successfully performing the patient demographics query and proceeding to the next page, the physician has to request the list of documents (either Patient Summaries (PS) or ePrescriptions (eP)). For that request, a TRC Assertion is needed (TRCA). In the default scenario, the physician requests the TRCA to be generated without the intervention of the patient (i.e., it'll be signed with the NCP-B signature certificate). In a eID level 2 or 3 scenario, the physician needs to request the patient to introduce his authentication PIN code in order to give access to protected data of his smartcard (to sign the TRCA with the patient's smartcard qualified certificate). Hence, signing of the patient's consent is possible. For this purpose, a new button was added in this page (viewPatientConfirmation.xhtml for PS; viewPatientConfirmationForDocuments.xhtml for eP):