/* * Copyright 2018 A-SIT Plus GmbH * AT-specific eIDAS Connector has been developed in a cooperation between EGIZ, * A-SIT Plus GmbH, A-SIT, and Graz University of Technology. * * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the "License"); * You may not use this work except in compliance with the License. * You may obtain a copy of the License at: * https://joinup.ec.europa.eu/news/understanding-eupl-v12 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * This product combines work with different licenses. See the "NOTICE" text * file for details on the various modules and licenses. * The "NOTICE" text file is part of the distribution. Any derivative works * that you distribute must include a readable copy of the "NOTICE" text file. */ package at.asitplus.eidas.specific.modules.auth.eidas.v2.test; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyList; import static org.mockito.Mockito.when; import java.io.IOException; import java.security.InvalidKeyException; import java.security.MessageDigest; import java.security.NoSuchProviderException; import java.util.List; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBException; import javax.xml.bind.Unmarshaller; import javax.xml.parsers.ParserConfigurationException; import javax.xml.ws.soap.SOAPFaultException; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.RandomStringUtils; import org.apache.commons.lang3.StringUtils; import org.apache.cxf.binding.soap.SoapFault; import org.joda.time.DateTime; import org.jose4j.lang.JoseException; import org.junit.Assert; import org.junit.Before; import org.junit.Ignore; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.util.Base64Utils; import org.w3c.dom.Element; import org.xml.sax.SAXException; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonMappingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.skjolberg.mockito.soap.SoapServiceRule; import at.asitplus.eidas.specific.connector.test.config.dummy.MsConnectorDummyConfigMap; import at.asitplus.eidas.specific.modules.auth.eidas.v2.Constants; import at.asitplus.eidas.specific.modules.auth.eidas.v2.dao.ErnbEidData; import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.EidasSAuthenticationException; import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.SzrCommunicationException; import at.asitplus.eidas.specific.modules.auth.eidas.v2.szr.SzrClient; import at.asitplus.eidas.specific.modules.auth.eidas.v2.utils.EidasResponseUtils; import at.gv.e_government.reference.namespace.persondata._20020228.PersonNameType; import at.gv.e_government.reference.namespace.persondata._20020228.PhysicalPersonType; import at.gv.egiz.eaaf.core.api.data.EaafConstants; import at.gv.egiz.eaaf.core.api.idp.auth.data.IIdentityLink; import at.gv.egiz.eaaf.core.exceptions.EaafParserException; import at.gv.egiz.eaaf.core.impl.data.Triple; import at.gv.egiz.eaaf.core.impl.idp.auth.data.SimpleIdentityLinkAssertionParser; import at.gv.egiz.eaaf.core.impl.utils.DomUtils; import szrservices.GetBPKFromStammzahlEncryptedResponse; import szrservices.GetBPKFromStammzahlEncryptedResponseType; import szrservices.GetIdentityLinkEidasResponse; import szrservices.IdentityLinkType; import szrservices.PersonInfoType; import szrservices.SZR; import szrservices.SZRException_Exception; import szrservices.SignContentEntry; import szrservices.SignContentResponse; import szrservices.SignContentResponseType; import szrservices.TravelDocumentType; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = { "/SpringTest-context_tasks_test.xml", "/SpringTest-context_basic_mapConfig.xml"}) public class SzrClientTest { private static final Logger log = LoggerFactory.getLogger(SzrClientTest.class); @Autowired SzrClient szrClient; @Autowired MsConnectorDummyConfigMap basicConfig; private static ObjectMapper mapper = new ObjectMapper(); private static final String givenName = "Franz"; private static final String familyName = "Mustermann"; private static final String dateOfBirth = "1989-05-05"; private static final String eIDASeID = "IS/AT/1234sdgsdfg56789ABCDEF"; private static final String DUMMY_TARGET = EaafConstants.URN_PREFIX_CDID + "ZP"; private SZR szrMock = null; ErnbEidData eidData = null; @Rule public SoapServiceRule soap = SoapServiceRule.newInstance(); /** * Initialize jUnit test. */ @Before public void initializer() { if (szrMock == null) { szrMock = soap.mock(SZR.class, "http://localhost:1234/demoszr"); } eidData = new ErnbEidData(); eidData.setFamilyName(familyName); eidData.setGivenName(givenName); eidData.setDateOfBirth(new DateTime()); eidData.setCitizenCountryCode("IS"); eidData.setPseudonym("1234sdgsdfg56789ABCDEF"); basicConfig.putConfigValue("eidas.ms.auth.eIDAS.szrclient.eidasbind.mds.inject", "false"); } @Test public void getStammzahlenEcryptedTest() throws JAXBException, SZRException_Exception, SzrCommunicationException { final GetBPKFromStammzahlEncryptedResponse szrResponse = new GetBPKFromStammzahlEncryptedResponse(); final GetBPKFromStammzahlEncryptedResponseType result1 = new GetBPKFromStammzahlEncryptedResponseType(); szrResponse.getOut().add(result1); result1.setKey(RandomStringUtils.randomAlphanumeric(20)); // when(szrMock.getBPKFromStammzahlEncrypted(anyList())) // .thenReturn(Arrays.asList(result1)); when(szrMock.getStammzahlEncrypted(any(), any())).thenReturn(result1.getKey()); String stammzahlEncrypted = szrClient.getEncryptedStammzahl(new PersonInfoType()); Assert.assertEquals("bcBind not match", result1.getKey(), stammzahlEncrypted); when(szrMock.getStammzahlEncrypted(any(), any())).thenReturn(null); try { stammzahlEncrypted = szrClient.getEncryptedStammzahl(new PersonInfoType()); } catch (SzrCommunicationException e) { Assert.assertTrue("Not correct error", e.getMessage().contains("ernb.01")); } } @Test public void getEidasBindRealSzrResponse() throws SZRException_Exception, SzrCommunicationException, IOException { final SignContentResponse szrResponse = new SignContentResponse(); final SignContentEntry result1 = new SignContentEntry(); final SignContentResponseType content = new SignContentResponseType(); content.getOut().add(result1); szrResponse.setSignContentResponse(content); result1.setKey("bcBindReq"); result1.setValue(IOUtils.toString(SzrClient.class.getResourceAsStream("/data/szr/signed_eidasBind.jws"))); when(szrMock.signContent(any(), anyList(), anyList())).thenReturn(content); final String bcBind = szrClient .getEidsaBind(RandomStringUtils.randomAlphabetic(10), RandomStringUtils.randomAlphabetic(10), RandomStringUtils.randomAlphabetic(10), eidData); Assert.assertNotNull("bcBind is null", bcBind); Assert.assertEquals("bcBind not match", result1.getValue(), bcBind); } @Test public void eidasBindNull() throws SZRException_Exception { when(szrMock.signContent(any(), anyList(), anyList())).thenReturn(null); try { szrClient .getEidsaBind(RandomStringUtils.randomAlphabetic(10), RandomStringUtils.randomAlphabetic(10), RandomStringUtils.randomAlphabetic(10), eidData); } catch (SzrCommunicationException e) { Assert.assertTrue("Not correct error", e.getMessage().contains("ernb.01")); } } @Test public void eidasBindInvalidResponse() throws SZRException_Exception { final SignContentEntry result2 = new SignContentEntry(); final SignContentResponseType content1 = new SignContentResponseType(); content1.getOut().add(result2); when(szrMock.signContent(any(), anyList(), anyList())).thenReturn(content1); try { szrClient .getEidsaBind(RandomStringUtils.randomAlphabetic(10), RandomStringUtils.randomAlphabetic(10), RandomStringUtils.randomAlphabetic(10), eidData); } catch (SzrCommunicationException e) { Assert.assertTrue("Not correct error", e.getMessage().contains("ernb.01")); } } public void eidasBindEmptyResponse() throws SZRException_Exception { final SignContentEntry result2 = new SignContentEntry(); final SignContentResponseType content1 = new SignContentResponseType(); content1.getOut().add(result2); result2.setKey("bcBindReq"); result2.setValue(""); when(szrMock.signContent(any(), anyList(), anyList())).thenReturn(content1); try { szrClient .getEidsaBind(RandomStringUtils.randomAlphabetic(10), RandomStringUtils.randomAlphabetic(10), RandomStringUtils.randomAlphabetic(10), eidData); } catch (SzrCommunicationException e) { Assert.assertTrue("Not correct error", e.getMessage().contains("ernb.01")); } } @Test public void eidasBindValid() throws SZRException_Exception, SzrCommunicationException, JsonMappingException, JsonProcessingException, JoseException { final SignContentResponse szrResponse = new SignContentResponse(); final SignContentEntry result1 = new SignContentEntry(); final SignContentResponseType content = new SignContentResponseType(); content.getOut().add(result1); szrResponse.setSignContentResponse(content); result1.setKey("bcBindReq"); result1.setValue(RandomStringUtils.randomAlphanumeric(100)); when(szrMock.signContent(any(), anyList(), anyList())).thenReturn(content); final String bcBind = szrClient .getEidsaBind(RandomStringUtils.randomAlphabetic(10), RandomStringUtils.randomAlphabetic(10), RandomStringUtils.randomAlphabetic(10), eidData); Assert.assertNotNull("bcBind is null", bcBind); Assert.assertEquals("bcBind not match", result1.getValue(), bcBind); } @Test public void eidasBindValidWithMds() throws SZRException_Exception, SzrCommunicationException, JoseException, JsonMappingException, JsonProcessingException { basicConfig.putConfigValue("eidas.ms.auth.eIDAS.szrclient.eidasbind.mds.inject", "true"); final SignContentResponse szrResponse = new SignContentResponse(); final SignContentEntry result1 = new SignContentEntry(); final SignContentResponseType content = new SignContentResponseType(); content.getOut().add(result1); szrResponse.setSignContentResponse(content); result1.setKey("bcBindReq"); result1.setValue(RandomStringUtils.randomAlphanumeric(100)); when(szrMock.signContent(any(), anyList(), anyList())).thenReturn(content); final String bcBind = szrClient .getEidsaBind(RandomStringUtils.randomAlphabetic(10), RandomStringUtils.randomAlphabetic(10), RandomStringUtils.randomAlphabetic(10), eidData); Assert.assertNotNull("bcBind is null", bcBind); Assert.assertEquals("bcBind not match", result1.getValue(), bcBind); } @Test public void getIdentityLinkRawModeValidResponse() throws SZRException_Exception, EaafParserException, NoSuchProviderException, IOException, InvalidKeyException, EidasSAuthenticationException, JAXBException { setSzrResponseIdentityLink("/data/szr/szr_resp_valid_1.xml"); try { log.debug("Starting connecting SZR Gateway"); final IdentityLinkType result = szrClient.getIdentityLinkInRawMode(getPersonInfo()); Assert.assertNotNull(result); Assert.assertNotNull(result.getAssertion()); final IIdentityLink identityLink = new SimpleIdentityLinkAssertionParser((Element) result.getAssertion()) .parseIdentityLink(); Assert.assertNotNull(identityLink); System.out.println(identityLink.getSerializedSamlAssertion()); checkElement("Mustermann", identityLink.getFamilyName()); checkElement("Hans", identityLink.getGivenName()); checkElement("1989-05-05", identityLink.getDateOfBirth()); checkElement("urn:publicid:gv.at:baseid", identityLink.getIdentificationType()); checkElement("k+zDM1BVpN1WJO4x7ZQ3ng==", identityLink.getIdentificationValue()); Assert.assertNotNull(identityLink.getSerializedSamlAssertion()); Assert.assertNotNull(identityLink.getSamlAssertion()); } catch (final SzrCommunicationException e) { Assert.fail(); } } @Test public void getIdentityLinkRawModeErrorTravelerDocExists() throws SZRException_Exception, EaafParserException, NoSuchProviderException, IOException, InvalidKeyException, EidasSAuthenticationException, JAXBException, ParserConfigurationException, SAXException { setSzrExceptionIdentityLink("/data/szr/szr_resp_error_travelerdocexists.xml"); try { log.debug("Starting connecting SZR Gateway"); szrClient.getIdentityLinkInRawMode(getPersonInfo()); Assert.fail(); } catch (final SzrCommunicationException e) { checkElement("ernb.02", e.getErrorId()); Assert.assertNotNull(e.getCause()); org.springframework.util.Assert.isInstanceOf(SOAPFaultException.class, e.getCause()); Assert.assertNotNull(((SOAPFaultException) e.getCause()).getFault()); checkElement("p344:F455", ((SOAPFaultException) e.getCause()).getFault().getFaultCode()); checkElement( "The travel document you sent to insert a person already exists for another person. " + "Either check the document or have the person altered accordingly", ((SOAPFaultException) e.getCause()).getFault().getFaultString()); } } @Ignore @Test public void getBpkTest() throws SZRException_Exception, EidasSAuthenticationException { final List bPK = szrClient.getBpk(getPersonInfo(), DUMMY_TARGET, basicConfig .getBasicConfiguration(Constants.CONIG_PROPS_EIDAS_SZRCLIENT_PARAMS_VKZ, "no VKZ defined")); if (bPK.isEmpty()) { throw new SzrCommunicationException("ernb.01", new Object[]{"bPK list is empty"}); } for (final String b : bPK) { if (StringUtils.isEmpty(b)) { throw new SzrCommunicationException("ernb.01", new Object[]{"bPK is null or empty"}); } } } private void checkElement(String expected, String value) { Assert.assertNotNull(value); Assert.assertEquals(expected, value); } private void setSzrResponseIdentityLink(String responseXmlPath) throws JAXBException, SZRException_Exception { final JAXBContext jaxbContext = JAXBContext .newInstance(szrservices.ObjectFactory.class, org.w3._2001._04.xmldsig_more.ObjectFactory.class, org.w3._2000._09.xmldsig.ObjectFactory.class, at.gv.e_government.reference.namespace.persondata._20020228.ObjectFactory.class); final Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller(); final GetIdentityLinkEidasResponse szrResponse = (GetIdentityLinkEidasResponse) jaxbUnmarshaller .unmarshal(this.getClass().getResourceAsStream(responseXmlPath)); when(szrMock.getIdentityLinkEidas(any(PersonInfoType.class))).thenReturn(szrResponse.getGetIdentityLinkReturn()); } private void setSzrExceptionIdentityLink(String responseXmlPath) throws JAXBException, ParserConfigurationException, SAXException, IOException, SZRException_Exception { final Element detailerror = DomUtils.parseXmlNonValidating(this.getClass().getResourceAsStream(responseXmlPath)); final javax.xml.namespace.QName qName = new javax.xml.namespace.QName("urn:SZRServices", "F455", "p344"); final SoapFault fault = new SoapFault( "The travel document you sent to insert a person already exists for another person. " + "Either check the document or have the person altered accordingly", qName); fault.setRole("urn:SZRServices"); fault.setDetail(detailerror); when(szrMock.getIdentityLinkEidas(any(PersonInfoType.class))).thenThrow(fault); } private String createHashFromUniqueId(String uniqueId) throws EidasSAuthenticationException { try { final MessageDigest md = MessageDigest.getInstance("SHA-256"); final byte[] hash = md.digest(uniqueId.getBytes("UTF-8")); final String hashBase64 = new String(Base64Utils.encode(hash), "UTF-8").replaceAll("\r\n", ""); return hashBase64; } catch (final Exception ex) { throw new EidasSAuthenticationException("internal.03", new Object[]{}, ex); } } private PersonInfoType getPersonInfo() throws EidasSAuthenticationException { final PersonInfoType personInfo = new PersonInfoType(); final PersonNameType personName = new PersonNameType(); final PhysicalPersonType naturalPerson = new PhysicalPersonType(); final TravelDocumentType eDocument = new TravelDocumentType(); naturalPerson.setName(personName); personInfo.setPerson(naturalPerson); personInfo.setTravelDocument(eDocument); // parse some eID attributes final Triple eIdentifier = EidasResponseUtils.parseEidasPersonalIdentifier(eIDASeID); final String uniqueId = createHashFromUniqueId(eIdentifier.getThird()); final String citizenCountry = eIdentifier.getFirst(); // person information personName.setFamilyName(familyName); personName.setGivenName(givenName); naturalPerson.setDateOfBirth(dateOfBirth); eDocument.setIssuingCountry(citizenCountry); eDocument.setDocumentNumber(uniqueId); // eID document information eDocument.setDocumentType(basicConfig .getBasicConfiguration(Constants.CONIG_PROPS_EIDAS_SZRCLIENT_PARAMS_EDOCUMENTTYPE, Constants.SZR_CONSTANTS_DEFAULT_DOCUMENT_TYPE)); return personInfo; } }