/******************************************************************************* *******************************************************************************/ package at.gv.egiz.eidas.specific.modules.authmodule_eIDASv2.tasks; import java.io.InputStream; import java.math.BigInteger; import java.security.KeyFactory; import java.security.NoSuchAlgorithmException; import java.security.PublicKey; import java.security.interfaces.RSAPublicKey; import java.security.spec.InvalidKeySpecException; import java.security.spec.PKCS8EncodedKeySpec; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.lang3.StringUtils; import org.joda.time.DateTime; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.util.Base64Utils; import org.w3._2000._09.xmldsig.KeyValueType; import org.w3._2000._09.xmldsig.RSAKeyValueType; import org.w3c.dom.Element; import org.w3c.dom.Node; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; 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.data.PVPAttributeDefinitions; import at.gv.egiz.eaaf.core.api.idp.IConfiguration; import at.gv.egiz.eaaf.core.api.idp.auth.data.IIdentityLink; import at.gv.egiz.eaaf.core.api.idp.process.ExecutionContext; import at.gv.egiz.eaaf.core.exceptions.EAAFException; import at.gv.egiz.eaaf.core.exceptions.TaskExecutionException; import at.gv.egiz.eaaf.core.impl.data.Pair; import at.gv.egiz.eaaf.core.impl.data.Trible; import at.gv.egiz.eaaf.core.impl.idp.auth.builder.BPKBuilder; import at.gv.egiz.eaaf.core.impl.idp.auth.data.AuthProcessDataWrapper; import at.gv.egiz.eaaf.core.impl.idp.auth.data.SimpleIdentityLinkAssertionParser; import at.gv.egiz.eaaf.core.impl.idp.auth.modules.AbstractAuthServletTask; import at.gv.egiz.eaaf.core.impl.utils.DOMUtils; import at.gv.egiz.eaaf.core.impl.utils.XPathUtils; import at.gv.egiz.eidas.specific.connector.MSConnectorEventCodes; import at.gv.egiz.eidas.specific.modules.authmodule_eIDASv2.Constants; import at.gv.egiz.eidas.specific.modules.authmodule_eIDASv2.exception.SZRCommunicationException; import at.gv.egiz.eidas.specific.modules.authmodule_eIDASv2.exception.eIDASAttributeException; import at.gv.egiz.eidas.specific.modules.authmodule_eIDASv2.szr.SZRClient; import at.gv.egiz.eidas.specific.modules.authmodule_eIDASv2.utils.eIDASResponseUtils; import eu.eidas.auth.commons.attribute.AttributeDefinition; import eu.eidas.auth.commons.attribute.AttributeValue; import eu.eidas.auth.commons.light.ILightResponse; import eu.eidas.auth.commons.protocol.eidas.impl.PostalAddress; import szrservices.IdentityLinkType; import szrservices.PersonInfoType; import szrservices.TravelDocumentType; /** * @author tlenz * */ @Component("CreateIdentityLinkTask") public class CreateIdentityLinkTask extends AbstractAuthServletTask { private static final Logger log = LoggerFactory.getLogger(CreateIdentityLinkTask.class); //@Autowired private eIDASAttributeRegistry attrRegistry; @Autowired private IConfiguration basicConfig; @Autowired private SZRClient szrClient; /* (non-Javadoc) * @see at.gv.egovernment.moa.id.process.springweb.MoaIdTask#execute(at.gv.egovernment.moa.id.process.api.ExecutionContext, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) */ @Override public void execute(ExecutionContext executionContext, HttpServletRequest request, HttpServletResponse response) throws TaskExecutionException { try{ AuthProcessDataWrapper authProcessData = pendingReq.getSessionData(AuthProcessDataWrapper.class); ILightResponse eIDASResponse = authProcessData.getGenericDataFromSession( Constants.DATA_FULL_EIDAS_RESPONSE, ILightResponse.class); Map simpleAttrMap = converteIDASAttrToSimpleMap(eIDASResponse.getAttributes().getAttributeMap()); IIdentityLink identityLink = null; String bPK = null; //extract attributes Object eIdentifierObj = simpleAttrMap.get(Constants.eIDAS_ATTR_PERSONALIDENTIFIER); Object familyNameObj = simpleAttrMap.get(Constants.eIDAS_ATTR_CURRENTFAMILYNAME); Object givenNameObj = simpleAttrMap.get(Constants.eIDAS_ATTR_CURRENTGIVENNAME); Object dateOfBirthObj = simpleAttrMap.get(Constants.eIDAS_ATTR_DATEOFBIRTH); //check if availabe if (eIdentifierObj == null || !(eIdentifierObj instanceof String)) throw new eIDASAttributeException(Constants.eIDAS_ATTR_PERSONALIDENTIFIER); if (familyNameObj == null || !(familyNameObj instanceof String)) throw new eIDASAttributeException(Constants.eIDAS_ATTR_CURRENTFAMILYNAME); if (givenNameObj == null || !(givenNameObj instanceof String)) throw new eIDASAttributeException(Constants.eIDAS_ATTR_CURRENTGIVENNAME); if (dateOfBirthObj == null || !(dateOfBirthObj instanceof DateTime)) throw new eIDASAttributeException(Constants.eIDAS_ATTR_DATEOFBIRTH); //connect SZR-Gateway if(basicConfig.getBasicMOAIDConfigurationBoolean( Constants.CONIG_PROPS_EIDAS_SZRCLIENT_DEBUG_USEDUMMY, false)) { log.warn("SZR-Dummy IS ACTIVE! IdentityLink is NOT VALID!!!!"); // create fake IdL // - fetch IdL template from resources InputStream s = CreateIdentityLinkTask.class.getResourceAsStream("/resources/xmldata/fakeIdL_IdL_template.xml"); Element idlTemplate = DOMUtils.parseXmlValidating(s); identityLink = new SimpleIdentityLinkAssertionParser(idlTemplate).parseIdentityLink(); // replace data Element idlassertion = identityLink.getSamlAssertion(); // - set fake baseID; Node prIdentification = XPathUtils.selectSingleNode(idlassertion, SimpleIdentityLinkAssertionParser.PERSON_IDENT_VALUE_XPATH); prIdentification.getFirstChild().setNodeValue((String) eIdentifierObj); //build personal identifier which looks like a baseID // String fakeBaseID = new BPKBuilder().buildBPK(eIdentifier, "baseID"); // Logger.info("Map eIDAS eIdentifier:" + eIdentifier + " to fake baseID:" + fakeBaseID); // prIdentification.getFirstChild().setNodeValue(fakeBaseID); // - set last name Node prFamilyName = XPathUtils.selectSingleNode(idlassertion, SimpleIdentityLinkAssertionParser.PERSON_FAMILY_NAME_XPATH); prFamilyName.getFirstChild().setNodeValue((String) familyNameObj); // - set first name Node prGivenName = XPathUtils.selectSingleNode(idlassertion, SimpleIdentityLinkAssertionParser.PERSON_GIVEN_NAME_XPATH); prGivenName.getFirstChild().setNodeValue((String) givenNameObj); // - set date of birth Node prDateOfBirth = XPathUtils.selectSingleNode(idlassertion, SimpleIdentityLinkAssertionParser.PERSON_DATE_OF_BIRTH_XPATH); String formatedDateOfBirth = new SimpleDateFormat("yyyy-MM-dd").format(((DateTime)dateOfBirthObj).toDate()); prDateOfBirth.getFirstChild().setNodeValue(formatedDateOfBirth); identityLink = new SimpleIdentityLinkAssertionParser(idlassertion).parseIdentityLink(); Pair bPKCalc = new BPKBuilder().generateAreaSpecificPersonIdentifier( identityLink.getIdentificationValue(), identityLink.getIdentificationType(), pendingReq.getServiceProviderConfiguration().getAreaSpecificTargetIdentifier()); bPK = bPKCalc.getFirst(); } else { //contact SZR Gateway log.debug("Starting connecting SZR Gateway"); PersonInfoType personInfo = new PersonInfoType(); PersonNameType personName = new PersonNameType(); PhysicalPersonType naturalPerson = new PhysicalPersonType(); TravelDocumentType eDocument = new TravelDocumentType(); naturalPerson.setName(personName ); personInfo.setPerson(naturalPerson ); personInfo.setTravelDocument(eDocument ); //parse some eID attributes String dateOfBirth = new SimpleDateFormat("yyyy-MM-dd").format(((DateTime)dateOfBirthObj).toDate()); Trible eIdentifier = eIDASResponseUtils.parseEidasPersonalIdentifier((String)eIdentifierObj); String uniqueId = (String)eIdentifierObj; String citizenCountry = eIdentifier.getFirst(); //person information personName.setFamilyName((String)familyNameObj); personName.setGivenName((String)givenNameObj); 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)); //TODO: that should be removed eDocument.setIssueDate(basicConfig.getBasicConfiguration( Constants.CONIG_PROPS_EIDAS_SZRCLIENT_PARAMS_ISSUING_DATE, Constants.SZR_CONSTANTS_DEFAULT_ISSUING_DATE)); eDocument.setIssuingAuthority(basicConfig.getBasicConfiguration( Constants.CONIG_PROPS_EIDAS_SZRCLIENT_PARAMS_ISSUING_AUTHORITY, Constants.SZR_CONSTANTS_DEFAULT_ISSUING_AUTHORITY)); //TODO: keys are not available in eIDAS List keyValue = dummyCodeForKeys(); /*TODO: * Validate if IDL signature is valid after using this method * MAYBE we had to switch to 'getIdentityLinkInRawMode' method! */ IdentityLinkType result = szrClient.getIdentityLink( personInfo, keyValue, basicConfig.getBasicMOAIDConfigurationBoolean( Constants.CONIG_PROPS_EIDAS_SZRCLIENT_DEBUG_INSERTERNB, true) ); Element idlFromSZR = (Element)result.getAssertion(); identityLink = new SimpleIdentityLinkAssertionParser(idlFromSZR).parseIdentityLink(); //get bPK from SZR bPK = szrClient.getBPK( personInfo, pendingReq.getServiceProviderConfiguration().getAreaSpecificTargetIdentifier(), basicConfig.getBasicConfiguration( Constants.CONIG_PROPS_EIDAS_SZRCLIENT_PARAMS_VKZ, "no VKZ defined")); } if (identityLink == null) { log.error("ERnB did not return an identity link."); throw new SZRCommunicationException("ernb.00", null); } revisionsLogger.logEvent(pendingReq, MSConnectorEventCodes.SZR_IDL_RECEIVED); if (bPK == null) { log.error("ERnB did not return a bPK for target: " + pendingReq.getServiceProviderConfiguration().getAreaSpecificTargetIdentifier()); throw new SZRCommunicationException("ernb.01", null); } revisionsLogger.logEvent(pendingReq, MSConnectorEventCodes.SZR_BPK_RECEIVED); log.debug("ERnB communication was successfull"); authProcessData.setForeigner(true); authProcessData.setIdentityLink(identityLink); authProcessData.setGenericDataToSession( PVPAttributeDefinitions.EID_ISSUING_NATION_NAME, eIDASResponseUtils.parseEidasPersonalIdentifier((String) simpleAttrMap.get(Constants.eIDAS_ATTR_PERSONALIDENTIFIER)).getFirst()); //set bPK and bPKType into auth session authProcessData.setGenericDataToSession( PVPAttributeDefinitions.BPK_NAME, extendBPKbyPrefix( bPK, pendingReq.getServiceProviderConfiguration().getAreaSpecificTargetIdentifier()) ); authProcessData.setGenericDataToSession( PVPAttributeDefinitions.EID_SECTOR_FOR_IDENTIFIER_NAME, pendingReq.getServiceProviderConfiguration().getAreaSpecificTargetIdentifier()); //store pending-request requestStoreage.storePendingRequest(pendingReq); } catch (eIDASAttributeException e) { throw new TaskExecutionException(pendingReq, "Minimum required eIDAS attributeset not found.", e); } catch (EAAFException e) { throw new TaskExecutionException(pendingReq, "IdentityLink generation for foreign person FAILED.", e); } catch (Exception e) { log.error("IdentityLink generation for foreign person FAILED.", e); throw new TaskExecutionException(pendingReq, "IdentityLink generation for foreign person FAILED.", e); } } private List dummyCodeForKeys() { if (basicConfig.getBasicMOAIDConfigurationBoolean( Constants.CONIG_PROPS_EIDAS_SZRCLIENT_PARAMS_KEYS_USEDUMMY, false)) { List keyvalueList = new ArrayList(); try { PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(Constants.SZR_CONSTANTS_DEFAULT_PUBL_KEY); KeyFactory kf = KeyFactory.getInstance("RSA"); PublicKey pb = kf.generatePublic(spec); RSAPublicKey rsapb = (RSAPublicKey)pb; BigInteger modulus = rsapb.getModulus(); BigInteger exponent = rsapb.getPublicExponent(); // set key values RSAKeyValueType rsa = new RSAKeyValueType(); rsa.setExponent(new String(Base64Utils.encode(exponent.toByteArray()))); rsa.setModulus(new String(Base64Utils.encode(modulus.toByteArray()))); KeyValueType key = new KeyValueType(); key.setRSAKeyValue(rsa); keyvalueList.add(key); return keyvalueList; } catch (NoSuchAlgorithmException | InvalidKeySpecException e) { log.error("TestCode has an internal ERROR", e); } } return null; } private String extendBPKbyPrefix(String bpk, String type) { String bPKType = null; if (type.startsWith(EAAFConstants.URN_PREFIX_WBPK)) bPKType = type.substring((EAAFConstants.URN_PREFIX_WBPK).length()); else if (type.startsWith(EAAFConstants.URN_PREFIX_CDID)) bPKType = type.substring((EAAFConstants.URN_PREFIX_CDID).length()); else if (type.startsWith(EAAFConstants.URN_PREFIX_EIDAS)) bPKType = type.substring((EAAFConstants.URN_PREFIX_EIDAS).length()); if (bPKType != null ) { log.trace("Authenticate user with bPK/wbPK " + bpk + " and Type=" + bPKType); return bPKType + ":" + bpk; } else { log.warn("Service Provider Target with: " + type + " is NOT supported. Set bPK as it is ..."); return bpk; } } //TODO: update for complexe attributes private Map converteIDASAttrToSimpleMap( ImmutableMap, ImmutableSet>> attributeMap) { Map result = new HashMap(); for (AttributeDefinition el : attributeMap.keySet()) { final Class parameterizedType = el.getParameterizedType(); if ((DateTime.class).equals(parameterizedType)) { DateTime attribute = eIDASResponseUtils.translateDateAttribute(el, attributeMap.get(el).asList()); if (attribute != null) result.put(el.getFriendlyName(), attribute); else log.info("Ignore empty 'DateTime' attribute"); } else if ((PostalAddress.class).equals(parameterizedType)) { PostalAddress addressAttribute = eIDASResponseUtils.translateAddressAttribute(el, attributeMap.get(el).asList()); if (addressAttribute != null) result.put(el.getFriendlyName(), addressAttribute); else log.info("Ignore empty 'PostalAddress' attribute"); } else { List natPersonIdObj = eIDASResponseUtils.translateStringListAttribute(el, attributeMap.get(el).asList()); String stringAttr = natPersonIdObj.get(0); if (StringUtils.isNotEmpty(stringAttr)) result.put(el.getFriendlyName(), stringAttr); else log.info("Ignore empty 'String' attribute"); } } return result; } }