diff options
Diffstat (limited to 'modules/authmodule-eIDAS-v2/src')
3 files changed, 598 insertions, 89 deletions
| diff --git a/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/service/AuthBlockSigningService.java b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/service/AuthBlockSigningService.java index 098e76ce..1998fa85 100644 --- a/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/service/AuthBlockSigningService.java +++ b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/service/AuthBlockSigningService.java @@ -1,5 +1,6 @@  package at.asitplus.eidas.specific.modules.auth.eidas.v2.service; +import java.io.Serializable;  import java.security.Key;  import java.security.KeyStore;  import java.security.KeyStoreException; @@ -44,7 +45,7 @@ import lombok.extern.slf4j.Slf4j;  /**   * Service to build and sign AuthBlock's for E-ID system. - *  + *   * @author tlenz   *   */ @@ -55,157 +56,206 @@ public class AuthBlockSigningService {    private static final String KEYSTORE_FRIENDLYNAME = "AuthBlock_Signing";    private static ObjectMapper mapper = new ObjectMapper(); -   +    @Autowired    IConfiguration basicConfig; -   +    @Autowired    EaafKeyStoreFactory keyStoreFactory; -      private Pair<KeyStore, Provider> keyStore; -   +    /** -   * Build and sign an AuthBlock for E-ID system.  -   *  +   * Build and sign an AuthBlock for E-ID system. +   *     * @param pendingReq data that should be added into AuthBlock     * @return serialized JWS -   * @throws JsonProcessingException In case of a AuthBlock generation error  -   * @throws JoseException  In case of a JWS signing error -   * @throws EaafException  In case of a KeyStore or Key error +   * @throws JsonProcessingException In case of a AuthBlock generation error +   * @throws JoseException           In case of a JWS signing error +   * @throws EaafException           In case of a KeyStore or Key error     */ -  public String buildSignedAuthBlock(IRequest pendingReq)  +  public String buildSignedAuthBlock(IRequest pendingReq)        throws JsonProcessingException, EaafException, JoseException { -     -    //TODO: set Challenge to SAML2 requestId to create link between authentication request and authBlock -     + +    // TODO: set Challenge to SAML2 requestId to create link between authentication +    // request and authBlock +      // build AuthBlock -    EidasAuchBlock authBlock = new EidasAuchBlock(); -    authBlock.setChallenge(UUID.randomUUID().toString()); -    authBlock.setTimestamp(LocalDateTime.now(ZoneOffset.UTC).truncatedTo(ChronoUnit.SECONDS)); -    authBlock.setUniqueId(pendingReq.getRawData(MsEidasNodeConstants.DATA_REQUESTERID, String.class));  -    authBlock.setPiiTransactionId(pendingReq.getUniquePiiTransactionIdentifier()); -     -    //set Binding PublicKey if available -    Object bindingPubKey = pendingReq.getRawData(MsEidasNodeConstants.EID_BINDING_PUBLIC_KEY_NAME); -    if (bindingPubKey instanceof String) { -      authBlock.setBindingPublicKey((String) bindingPubKey); -       -    } -     -    String jwsPayload = mapper.writeValueAsString(authBlock); +    final String jwsPayload = mapper.writeValueAsString(buildAuthBlock(pendingReq));      log.debug("Building and sign authBlock with data: {}", jwsPayload); -     -    //sign JWS -    return JoseUtils -        .createSignature(keyStore, getKeyAlias(), getKeyPassword(), jwsPayload, false, -                         KEYSTORE_FRIENDLYNAME);     + +    // sign JWS +    return JoseUtils.createSignature( +        keyStore, getKeyAlias(), getKeyPassword(), jwsPayload, false, KEYSTORE_FRIENDLYNAME); + +  } + +  private Serializable buildAuthBlock(IRequest pendingReq) { +    if (basicConfig.getBasicConfigurationBoolean( +        MsEidasNodeConstants.PROP_CONFIG_AUTHBLOCK_LEGACY_USE, false)) { +      final EidasAuchBlockV1 authBlock = new EidasAuchBlockV1(); +      authBlock.setChallenge(UUID.randomUUID().toString()); +      authBlock.setTimestamp(LocalDateTime.now(ZoneOffset.UTC).truncatedTo(ChronoUnit.SECONDS)); +      authBlock.setUniqueId(pendingReq.getRawData(MsEidasNodeConstants.DATA_REQUESTERID, String.class)); +      authBlock.setPiiTransactionId(pendingReq.getUniquePiiTransactionIdentifier()); + +      // set Binding PublicKey if available +      final Object bindingPubKey = pendingReq.getRawData(MsEidasNodeConstants.EID_BINDING_PUBLIC_KEY_NAME); +      if (bindingPubKey instanceof String) { +        authBlock.setBindingPublicKey((String) bindingPubKey); + +      } +      return authBlock; + +    } else { +      final EidasAuchBlockV2 authBlock = new EidasAuchBlockV2(); +      authBlock.setChallenge(UUID.randomUUID().toString()); +      authBlock.setTimestamp(LocalDateTime.now(ZoneOffset.UTC).truncatedTo(ChronoUnit.SECONDS)); + +      // set Binding PublicKey if available +      final Object bindingPubKey = pendingReq.getRawData(MsEidasNodeConstants.EID_BINDING_PUBLIC_KEY_NAME); +      if (bindingPubKey instanceof String) { +        authBlock.setBindingPublicKey((String) bindingPubKey); + +      } +      return authBlock; + +    }    } -      /**     * Get the Base64 encoded PublicKey that is used to sign the AuthBlock. -   *  +   *     * @return Base64 encoded PublicKey     * @throws EaafKeyAccessException In case of an unknown or invalid key     */ -  public String getBase64EncodedPublicKey() throws EaafKeyAccessException {        -    Pair<Key, X509Certificate[]> keyPair = EaafKeyStoreUtils.getPrivateKeyAndCertificates( -        keyStore.getFirst(), getKeyAlias(), getKeyPassword(), true, KEYSTORE_FRIENDLYNAME);        +  public String getBase64EncodedPublicKey() throws EaafKeyAccessException { +    final Pair<Key, X509Certificate[]> keyPair = EaafKeyStoreUtils.getPrivateKeyAndCertificates( +        keyStore.getFirst(), getKeyAlias(), getKeyPassword(), true, KEYSTORE_FRIENDLYNAME);      return Base64.getEncoder().encodeToString(keyPair.getSecond()[0].getPublicKey().getEncoded()); -     +    }    @PostConstruct -  private void initialize() throws KeyStoreException, EaafException {    +  private void initialize() throws KeyStoreException, EaafException {      log.debug("Initializing AuthBlock signing service ... "); -    // read Connector wide config data TODO connector wide!    -    String keyStoreName = basicConfig +    // read Connector wide config data TODO connector wide! +    final String keyStoreName = basicConfig          .getBasicConfiguration(MsEidasNodeConstants.PROP_CONFIG_AUTHBLOCK_KEYSTORE_NAME); -    String keyStorePw = basicConfig +    final String keyStorePw = basicConfig          .getBasicConfiguration(MsEidasNodeConstants.PROP_CONFIG_AUTHBLOCK_KEYSTORE_PASSWORD); -    String keyStorePath = basicConfig +    final String keyStorePath = basicConfig          .getBasicConfiguration(MsEidasNodeConstants.PROP_CONFIG_AUTHBLOCK_KEYSTORE_PATH); -    String keyStoreType = basicConfig +    final String keyStoreType = basicConfig          .getBasicConfiguration(MsEidasNodeConstants.PROP_CONFIG_AUTHBLOCK_KEYSTORE_TYPE); -     -    //build new KeyStore configuration -    KeyStoreConfiguration keyStoreConfiguration = new KeyStoreConfiguration(); +    // build new KeyStore configuration +    final KeyStoreConfiguration keyStoreConfiguration = new KeyStoreConfiguration();      keyStoreConfiguration.setFriendlyName(KEYSTORE_FRIENDLYNAME); -     +      keyStoreConfiguration.setSoftKeyStoreFilePath(keyStorePath);      keyStoreConfiguration.setSoftKeyStorePassword(keyStorePw); -    keyStoreConfiguration.setKeyStoreType(KeyStoreConfiguration.KeyStoreType.fromString(keyStoreType));     +    keyStoreConfiguration.setKeyStoreType(KeyStoreConfiguration.KeyStoreType.fromString(keyStoreType));      keyStoreConfiguration.setKeyStoreName(keyStoreName); -     -    //validate KeyStore configuration + +    // validate KeyStore configuration      keyStoreConfiguration.validate(); -         -    //validate key alias + +    // validate key alias      if (StringUtils.isEmpty(getKeyAlias())) { -      throw new EaafConfigurationException("config.08",  -          new Object[] {MsEidasNodeConstants.PROP_CONFIG_AUTHBLOCK_KEY_ALIAS}); -       +      throw new EaafConfigurationException("config.08", +          new Object[] { MsEidasNodeConstants.PROP_CONFIG_AUTHBLOCK_KEY_ALIAS }); +      } -         -    //build new KeyStore based on configuration -    keyStore =  keyStoreFactory.buildNewKeyStore(keyStoreConfiguration); -     -    //check if Key is accessible + +    // build new KeyStore based on configuration +    keyStore = keyStoreFactory.buildNewKeyStore(keyStoreConfiguration); + +    // check if Key is accessible      EaafKeyStoreUtils.getPrivateKeyAndCertificates(          keyStore.getFirst(), getKeyAlias(), getKeyPassword(), true, KEYSTORE_FRIENDLYNAME); -     -    log.info("AuthBlock signing-service successful initialized"); -     -  }    -   + +    log.info("AuthBlock signing-service successful initialized {}", +        basicConfig.getBasicConfigurationBoolean(MsEidasNodeConstants.PROP_CONFIG_AUTHBLOCK_LEGACY_USE, false) +            ? " in legacy mode" +            : ""); + +  } +    private char[] getKeyPassword() { -    final String value = basicConfig.getBasicConfiguration(MsEidasNodeConstants.PROP_CONFIG_AUTHBLOCK_KEY_PASSWORD); +    final String value = basicConfig.getBasicConfiguration( +        MsEidasNodeConstants.PROP_CONFIG_AUTHBLOCK_KEY_PASSWORD);      if (value != null) {        return value.trim().toCharArray();      }      return null; -     -  } +  }    private String getKeyAlias() {      return basicConfig          .getBasicConfiguration(MsEidasNodeConstants.PROP_CONFIG_AUTHBLOCK_KEY_ALIAS); -     +    } -   +    /**     * Technical AuthBlock for eIDAS Authentication. -   *  +   *     * @author tlenz     *     */    @Data    @JsonInclude(JsonInclude.Include.NON_NULL) -  private static class EidasAuchBlock { +  @Deprecated +  private static class EidasAuchBlockV1 implements Serializable { + +    private static final long serialVersionUID = 8437172632081476257L;      @JsonProperty("challenge")      private String challenge; -     +      @JsonProperty("timestamp")      @JsonSerialize(using = LocalDateTimeSerializer.class)      @JsonDeserialize(using = LocalDateTimeDeserializer.class)      @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", timezone = "UTC")      private LocalDateTime timestamp; -     +      @JsonProperty("appId")      private String uniqueId; -     +      @JsonProperty("piiTransactionId")      private String piiTransactionId; -     + +    @JsonProperty("bindingPublicKey") +    private String bindingPublicKey; + +  } + +  /** +   * AuthBlock for Binding Authentication. +   * +   * @author tlenz +   * +   */ +  @Data +  @JsonInclude(JsonInclude.Include.NON_NULL) +  public class EidasAuchBlockV2 implements Serializable { + +    private static final long serialVersionUID = -2013435642666124497L; + +    @JsonProperty("challenge") +    private String challenge; + +    @JsonProperty("issuedAt") +    @JsonSerialize(using = LocalDateTimeSerializer.class) +    @JsonDeserialize(using = LocalDateTimeDeserializer.class) +    @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", timezone = "UTC") +    private LocalDateTime timestamp; +      @JsonProperty("bindingPublicKey")      private String bindingPublicKey; -     +    } -    } diff --git a/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/CreateIdentityLinkTaskEidLegacyTest.java b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/CreateIdentityLinkTaskEidLegacyTest.java new file mode 100644 index 00000000..a7d625f5 --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/CreateIdentityLinkTaskEidLegacyTest.java @@ -0,0 +1,459 @@ +package at.asitplus.eidas.specific.modules.auth.eidas.v2.test.tasks; + +import static at.asitplus.eidas.specific.core.MsEidasNodeConstants.PROP_CONFIG_SP_NEW_EID_MODE; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; + +import java.net.URISyntaxException; +import java.security.KeyStore; +import java.security.Provider; +import java.security.cert.X509Certificate; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.annotation.Nonnull; +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBException; +import javax.xml.bind.Unmarshaller; + +import org.apache.commons.lang3.RandomStringUtils; +import org.apache.commons.lang3.StringUtils; +import org.joda.time.DateTime; +import org.jose4j.jwa.AlgorithmConstraints; +import org.jose4j.jwa.AlgorithmConstraints.ConstraintType; +import org.jose4j.jws.AlgorithmIdentifiers; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.github.skjolber.mockito.soap.SoapServiceRule; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; + +import at.asitplus.eidas.specific.core.MsEidasNodeConstants; +import at.asitplus.eidas.specific.core.test.config.dummy.MsConnectorDummyConfigMap; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.Constants; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.dao.MatchedPersonResult; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.dao.SimpleEidasData; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.EidPostProcessingException; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.EidasAttributeException; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.service.ICcSpecificEidProcessingService; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.tasks.CreateIdentityLinkTask; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.utils.EidasResponseUtils; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.utils.JoseUtils; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.utils.JoseUtils.JwsResult; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.utils.MatchingTaskUtils; +import at.asitplus.eidas.specific.modules.core.eidas.EidasConstants; +import at.asitplus.eidas.specific.modules.core.eidas.service.EidasAttributeRegistry; +import at.gv.egiz.eaaf.core.api.IRequest; +import at.gv.egiz.eaaf.core.api.IRequestStorage; +import at.gv.egiz.eaaf.core.api.data.EaafConfigConstants; +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.process.ExecutionContext; +import at.gv.egiz.eaaf.core.exceptions.EaafException; +import at.gv.egiz.eaaf.core.exceptions.EaafStorageException; +import at.gv.egiz.eaaf.core.impl.credential.EaafKeyStoreFactory; +import at.gv.egiz.eaaf.core.impl.credential.EaafKeyStoreUtils; +import at.gv.egiz.eaaf.core.impl.credential.KeyStoreConfiguration; +import at.gv.egiz.eaaf.core.impl.data.Pair; +import at.gv.egiz.eaaf.core.impl.idp.auth.data.AuthProcessDataWrapper; +import at.gv.egiz.eaaf.core.impl.idp.module.test.DummySpConfiguration; +import at.gv.egiz.eaaf.core.impl.idp.module.test.TestRequestImpl; +import at.gv.egiz.eaaf.core.impl.idp.process.ExecutionContextImpl; +import at.gv.egiz.eaaf.core.impl.utils.Random; +import eu.eidas.auth.commons.attribute.AttributeDefinition; +import eu.eidas.auth.commons.attribute.AttributeValue; +import eu.eidas.auth.commons.attribute.ImmutableAttributeMap; +import eu.eidas.auth.commons.attribute.ImmutableAttributeMap.Builder; +import eu.eidas.auth.commons.protocol.eidas.impl.PostalAddress; +import eu.eidas.auth.commons.protocol.impl.AuthenticationResponse; +import lombok.val; +import szrservices.GetIdentityLinkEidasResponse; +import szrservices.PersonInfoType; +import szrservices.SZR; +import szrservices.SZRException_Exception; +import szrservices.SignContentEntry; +import szrservices.SignContentResponseType; + +@RunWith(SpringJUnit4ClassRunner.class) +@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_CLASS) +@ContextConfiguration(locations = { +    "/SpringTest-context_tasks_test.xml", +    "/SpringTest-context_basic_mapConfig.xml"}) +public class CreateIdentityLinkTaskEidLegacyTest { + +  @Autowired(required = true) +  private CreateIdentityLinkTask task; + +  @Autowired(required = true) +  private MsConnectorDummyConfigMap basicConfig; +  @Autowired +  protected EidasAttributeRegistry attrRegistry; + +  @Autowired +  EaafKeyStoreFactory keyStoreFactory; + +  @Autowired +  ICcSpecificEidProcessingService eidPostProcessor; +   +  @Autowired +  private IRequestStorage requestStorage; + +  final ExecutionContext executionContext = new ExecutionContextImpl(); +  private MockHttpServletRequest httpReq; +  private MockHttpServletResponse httpResp; +  private TestRequestImpl pendingReq; +  private DummySpConfiguration oaParam; +  private SZR szrMock; + +  private static final String PW = "f/+saJBc3a}*/T^s"; +  private static final String ALIAS = "connectorkeypair"; + +  private static final List<String> BINDING_AUTH_ALGORITHM_WHITELIST_SIGNING = Collections.unmodifiableList(Arrays +      .asList(AlgorithmIdentifiers.ECDSA_USING_P256_CURVE_AND_SHA256, +          AlgorithmIdentifiers.ECDSA_USING_P521_CURVE_AND_SHA512, AlgorithmIdentifiers.RSA_PSS_USING_SHA256, +          AlgorithmIdentifiers.RSA_PSS_USING_SHA512)); + +  private static ObjectMapper mapper = new ObjectMapper(); + +  private AuthenticationResponse response; +  private MatchedPersonResult matchingInfos; + +  @Rule +  public final SoapServiceRule soap = SoapServiceRule.newInstance(); + +  /** +   * jUnit test set-up. +   * @throws EidasAttributeException  +   * @throws EidPostProcessingException  +   */ +  @Before +  public void setUp() throws EaafStorageException, URISyntaxException, EidPostProcessingException, EidasAttributeException { + +    httpReq = new MockHttpServletRequest("POST", "https://localhost/authhandler"); +    httpResp = new MockHttpServletResponse(); +    RequestContextHolder.resetRequestAttributes(); +    RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(httpReq, httpResp)); + +    basicConfig.putConfigValue("eidas.ms.auth.eIDAS.szrclient.debug.useDummySolution", "false"); +    basicConfig.putConfigValue("eidas.ms.auth.eIDAS.authblock.use.legacy.version", "true"); +     +    final Map<String, String> spConfig = new HashMap<>(); +    spConfig.put(EaafConfigConstants.SERVICE_UNIQUEIDENTIFIER, "testSp"); +    spConfig.put("target", "urn:publicid:gv.at:cdid+XX"); +    spConfig.put(PROP_CONFIG_SP_NEW_EID_MODE, "true"); +    oaParam = new DummySpConfiguration(spConfig, basicConfig); +    pendingReq = new TestRequestImpl(); + +    response = buildDummyAuthResponse(false); +    pendingReq.getSessionData(AuthProcessDataWrapper.class) +        .setGenericDataToSession(Constants.DATA_FULL_EIDAS_RESPONSE, response); +     +    final Map<String, Object> eidasAttributes = convertEidasAttrToSimpleMap( +        response.getAttributes().getAttributeMap());                   +    final SimpleEidasData eidData = eidPostProcessor.postProcess(eidasAttributes);     +    MatchingTaskUtils.storeInitialEidasData(pendingReq, eidData); +     +    matchingInfos = MatchedPersonResult.builder() +        .bpk(RandomStringUtils.randomAlphabetic(5)) +        .givenName(eidData.getGivenName()) +        .familyName(eidData.getFamilyName()) +        .dateOfBirth(eidData.getDateOfBirth()) +        .countryCode(eidData.getCitizenCountryCode()) +        .build();         +    MatchingTaskUtils.storeFinalMatchingResult(pendingReq, matchingInfos); +     +    pendingReq.setSpConfig(oaParam); +    pendingReq.setPendingReqId(at.gv.egiz.eaaf.core.impl.utils.Random.nextProcessReferenceValue()); +    pendingReq.setAuthUrl("http://test.com/"); +    pendingReq.setTransactionId("avaasbav"); +    pendingReq.setPiiTransactionId(RandomStringUtils.randomAlphanumeric(10)); + +    executionContext.put(MsEidasNodeConstants.REQ_PARAM_SELECTED_COUNTRY, "XX"); +    executionContext.put(EaafConstants.PROCESS_ENGINE_REQUIRES_NO_POSTAUTH_REDIRECT, true); + +    szrMock = soap.mock(SZR.class, "http://localhost:1234/demoszr"); +  } + +  @Test +  public void successfulProcessWithDeInfos() throws Exception { +    //initialize test +    response = buildDummyAuthResponse(true); +    pendingReq.getSessionData(AuthProcessDataWrapper.class) +        .setGenericDataToSession(Constants.DATA_FULL_EIDAS_RESPONSE, response); + +    SimpleEidasData eidData = eidPostProcessor.postProcess( +        convertEidasAttrToSimpleMap(response.getAttributes().getAttributeMap())); +    MatchingTaskUtils.storeInitialEidasData(pendingReq, eidData); +     +    matchingInfos = MatchedPersonResult.builder() +        .bpk(RandomStringUtils.randomAlphabetic(5)) +        .givenName(eidData.getGivenName()) +        .familyName(eidData.getFamilyName()) +        .dateOfBirth(eidData.getDateOfBirth()) +        .countryCode(eidData.getCitizenCountryCode()) +        .build();         +    MatchingTaskUtils.storeFinalMatchingResult(pendingReq, matchingInfos); +     +    String vsz = RandomStringUtils.randomNumeric(10); +    when(szrMock.getStammzahlEncrypted(any(), any())).thenReturn(vsz); +    SignContentResponseType signContentResp = new SignContentResponseType(); +    final SignContentEntry signContentEntry = new SignContentEntry(); +    signContentEntry.setValue(RandomStringUtils.randomAlphanumeric(10)); +    signContentResp.getOut().add(signContentEntry); +    when(szrMock.signContent(any(), any(), any())).thenReturn(signContentResp); + +    String randomTestSp = RandomStringUtils.randomAlphabetic(10); +    pendingReq.setRawDataToTransaction(MsEidasNodeConstants.DATA_REQUESTERID, randomTestSp); + +    //perform test +    task.execute(pendingReq, executionContext); + +    //validate state +    // check if pendingRequest was stored +    IRequest storedPendingReq = requestStorage.getPendingRequest(pendingReq.getPendingRequestId()); +    Assert.assertNotNull("pendingReq not stored", storedPendingReq); + +    //check data in session +    final AuthProcessDataWrapper authProcessData = storedPendingReq.getSessionData(AuthProcessDataWrapper.class); +    Assert.assertNotNull("AuthProcessData", authProcessData); +    Assert.assertNotNull("eidasBind", authProcessData.getGenericDataFromSession(MsEidasNodeConstants.AUTH_DATA_EIDAS_BIND, String.class)); + +    String authBlock = authProcessData.getGenericDataFromSession(MsEidasNodeConstants.AUTH_DATA_SZR_AUTHBLOCK, String.class); +    Assert.assertNotNull("AuthBlock", authBlock); + +    Assert.assertTrue("EID process", authProcessData.isEidProcess()); +    Assert.assertTrue("foreigner process", authProcessData.isForeigner()); +    Assert.assertEquals("EID-ISSUING_NATION", "LU", +        authProcessData.getGenericDataFromSession(PvpAttributeDefinitions.EID_ISSUING_NATION_NAME, String.class)); + +    // check authblock signature +    final AlgorithmConstraints constraints = new AlgorithmConstraints(ConstraintType.PERMIT, +        BINDING_AUTH_ALGORITHM_WHITELIST_SIGNING.toArray(new String[BINDING_AUTH_ALGORITHM_WHITELIST_SIGNING.size()])); +    Pair<KeyStore, Provider> keyStore = getKeyStore(); +    X509Certificate[] trustedCerts = EaafKeyStoreUtils +        .getPrivateKeyAndCertificates(keyStore.getFirst(), ALIAS, PW.toCharArray(), true, "junit").getSecond(); +    JwsResult result = JoseUtils.validateSignature(authBlock, Arrays.asList(trustedCerts), constraints); +    Assert.assertTrue("AuthBlock not valid", result.isValid()); +    JsonNode authBlockJson = mapper.readTree(result.getPayLoad()); +    Assert.assertNotNull("deserialized AuthBlock", authBlockJson); + +    Assert.assertNotNull("no piiTransactionId in pendingRequesdt", +        storedPendingReq.getUniquePiiTransactionIdentifier()); +    Assert.assertFalse("'challenge' is null", authBlockJson.get("challenge").asText().isEmpty()); +    Assert.assertEquals("piiTransactionId", storedPendingReq.getUniquePiiTransactionIdentifier(), +        authBlockJson.get("piiTransactionId").asText()); +    Assert.assertEquals("appId", randomTestSp, authBlockJson.get("appId").asText()); +    Assert.assertFalse("'timestamp' is null", authBlockJson.get("timestamp").asText().isEmpty()); +    Assert.assertFalse("binding pubKey", authBlockJson.has("bindingPublicKey")); + +  } + + +   +  @Test +  public void successfulProcessWithDataFromMatching() throws Exception { +    //initialize test +    String vsz = RandomStringUtils.randomNumeric(10); +    when(szrMock.getStammzahlEncrypted(any(), any())).thenReturn(vsz); +    SignContentResponseType signContentResp = new SignContentResponseType(); +    final SignContentEntry signContentEntry = new SignContentEntry(); +    signContentEntry.setValue(RandomStringUtils.randomAlphanumeric(10)); +    signContentResp.getOut().add(signContentEntry); + +    when(szrMock.signContent(any(), any(), any())).thenReturn(signContentResp); + +    String randomTestSp = RandomStringUtils.randomAlphabetic(10); +    String bindingPubKey = RandomStringUtils.randomAlphabetic(10); +    pendingReq.setRawDataToTransaction(MsEidasNodeConstants.DATA_REQUESTERID, randomTestSp); +    pendingReq.setRawDataToTransaction(MsEidasNodeConstants.EID_BINDING_PUBLIC_KEY_NAME, bindingPubKey); + +     +    //perform test +    task.execute(pendingReq, executionContext); +     +     +    //validate state +    // check if pendingRequest was stored +    IRequest storedPendingReq = requestStorage.getPendingRequest(pendingReq.getPendingRequestId()); +    Assert.assertNotNull("pendingReq not stored", storedPendingReq); + +    //check data in session +    final AuthProcessDataWrapper authProcessData = storedPendingReq.getSessionData(AuthProcessDataWrapper.class); +    Assert.assertNotNull("AuthProcessData", authProcessData); +    Assert.assertNotNull("eidasBind", authProcessData.getGenericDataFromSession(MsEidasNodeConstants.AUTH_DATA_EIDAS_BIND, String.class)); + +    // check authblock signature +    String authBlock = authProcessData.getGenericDataFromSession(MsEidasNodeConstants.AUTH_DATA_SZR_AUTHBLOCK, String.class); +    Assert.assertNotNull("AuthBlock", authBlock); + +    final AlgorithmConstraints constraints = new AlgorithmConstraints(ConstraintType.PERMIT, +        BINDING_AUTH_ALGORITHM_WHITELIST_SIGNING.toArray(new String[BINDING_AUTH_ALGORITHM_WHITELIST_SIGNING.size()])); +    Pair<KeyStore, Provider> keyStore = getKeyStore(); +    X509Certificate[] trustedCerts = EaafKeyStoreUtils +        .getPrivateKeyAndCertificates(keyStore.getFirst(), ALIAS, PW.toCharArray(), true, "junit").getSecond(); +    JwsResult result = JoseUtils.validateSignature(authBlock, Arrays.asList(trustedCerts), constraints); +    Assert.assertTrue("AuthBlock not valid", result.isValid());         +    JsonNode authBlockJson = mapper.readTree(result.getPayLoad());     +    Assert.assertNotNull("deserialized AuthBlock", authBlockJson); +     +    Assert.assertNotNull("no piiTransactionId in pendingRequesdt",  +        storedPendingReq.getUniquePiiTransactionIdentifier());     +    Assert.assertFalse("'challenge' is null", authBlockJson.get("challenge").asText().isEmpty()); +    Assert.assertEquals("piiTransactionId", storedPendingReq.getUniquePiiTransactionIdentifier(), +        authBlockJson.get("piiTransactionId").asText()); +    Assert.assertEquals("appId", randomTestSp, authBlockJson.get("appId").asText()); +    Assert.assertFalse("'timestamp' is null", authBlockJson.get("timestamp").asText().isEmpty()); +         +  } +    +  private Pair<KeyStore, Provider> getKeyStore() throws EaafException { +    // read Connector wide config data TODO connector wide! +    String keyStoreName = basicConfig.getBasicConfiguration(MsEidasNodeConstants.PROP_CONFIG_AUTHBLOCK_KEYSTORE_NAME); +    String keyStorePw = basicConfig.getBasicConfiguration(MsEidasNodeConstants.PROP_CONFIG_AUTHBLOCK_KEYSTORE_PASSWORD); +    String keyStorePath = basicConfig.getBasicConfiguration(MsEidasNodeConstants.PROP_CONFIG_AUTHBLOCK_KEYSTORE_PATH); +    String keyStoreType = basicConfig.getBasicConfiguration(MsEidasNodeConstants.PROP_CONFIG_AUTHBLOCK_KEYSTORE_TYPE); + + +    //build new KeyStore configuration +    KeyStoreConfiguration keyStoreConfiguration = new KeyStoreConfiguration(); +    keyStoreConfiguration.setFriendlyName("jUnit test"); + +    keyStoreConfiguration.setSoftKeyStoreFilePath(keyStorePath); +    keyStoreConfiguration.setSoftKeyStorePassword(keyStorePw); +    keyStoreConfiguration.setKeyStoreType(KeyStoreConfiguration.KeyStoreType.fromString(keyStoreType)); +    keyStoreConfiguration.setKeyStoreName(keyStoreName); + +    //build new KeyStore based on configuration +    return keyStoreFactory.buildNewKeyStore(keyStoreConfiguration); + +  } + +  @Nonnull +  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));         +    org.mockito.Mockito.when(szrMock.getIdentityLinkEidas(any(PersonInfoType.class))).thenReturn(szrResponse.getGetIdentityLinkReturn()); + +  } +   +  @Nonnull +  private AuthenticationResponse buildDummyAuthResponse(boolean withAll) throws URISyntaxException { +    return buildDummyAuthResponse(withAll, false); +     +  } + +  @Nonnull +  private AuthenticationResponse buildDummyAuthResponse(boolean withAll, boolean withEmpty) throws URISyntaxException { +    final AttributeDefinition attributeDef = attrRegistry.getCoreAttributeRegistry().getByFriendlyName( +        EidasConstants.eIDAS_ATTR_PERSONALIDENTIFIER).first(); +    final AttributeDefinition attributeDef2 = attrRegistry.getCoreAttributeRegistry().getByFriendlyName( +        EidasConstants.eIDAS_ATTR_CURRENTFAMILYNAME).first(); +    final AttributeDefinition attributeDef3 = attrRegistry.getCoreAttributeRegistry().getByFriendlyName( +        EidasConstants.eIDAS_ATTR_CURRENTGIVENNAME).first(); +    final AttributeDefinition attributeDef4 = attrRegistry.getCoreAttributeRegistry().getByFriendlyName( +        EidasConstants.eIDAS_ATTR_DATEOFBIRTH).first(); +    final AttributeDefinition attributeDef5 = attrRegistry.getCoreAttributeRegistry().getByFriendlyName( +        EidasConstants.eIDAS_ATTR_PLACEOFBIRTH).first(); +    final AttributeDefinition attributeDef6 = attrRegistry.getCoreAttributeRegistry().getByFriendlyName( +        EidasConstants.eIDAS_ATTR_BIRTHNAME).first(); +    +    final Builder attributeMap = ImmutableAttributeMap.builder(); +    attributeMap.put(attributeDef, "LU/AT/" + RandomStringUtils.randomNumeric(64)); +    attributeMap.put(attributeDef2, RandomStringUtils.randomAlphabetic(10)); +    attributeMap.put(attributeDef3, RandomStringUtils.randomAlphabetic(10)); +    attributeMap.put(attributeDef4, "2001-01-01"); +    if (withAll) { +      if (withEmpty) {  +        attributeMap.put(attributeDef5, Collections.emptySet()); +         +      } else { +        attributeMap.put(attributeDef5, RandomStringUtils.randomAlphabetic(10)); +         +      } +      attributeMap.put(attributeDef6, RandomStringUtils.randomAlphabetic(10)); + +    } + +    val b = new AuthenticationResponse.Builder(); +    return b.id("_".concat(Random.nextHexRandom16())) +        .issuer(RandomStringUtils.randomAlphabetic(10)) +        .subject(RandomStringUtils.randomAlphabetic(10)) +        .statusCode(EidasConstants.SUCCESS_URI) +        .inResponseTo("_".concat(Random.nextHexRandom16())) +        .subjectNameIdFormat("afaf") +        .levelOfAssurance(EaafConstants.EIDAS_LOA_PREFIX + RandomStringUtils.randomAlphabetic(5)) +        .attributes(attributeMap.build()) +        .build(); +  } +   +  private Map<String, Object> convertEidasAttrToSimpleMap( +      ImmutableMap<AttributeDefinition<?>, ImmutableSet<? extends AttributeValue<?>>> attributeMap) { +    final Map<String, Object> result = new HashMap<>(); +    for (final AttributeDefinition<?> el : attributeMap.keySet()) { +      final Class<?> parameterizedType = el.getParameterizedType(); +      if (DateTime.class.equals(parameterizedType)) { +        convertDateTime(attributeMap, result, el); +      } else if (PostalAddress.class.equals(parameterizedType)) { +        convertPostalAddress(attributeMap, result, el); +      } else { +        convertString(attributeMap, result, el); +      } +    } +    return result; +  } + +  private void convertString(ImmutableMap<AttributeDefinition<?>, +                             ImmutableSet<? extends AttributeValue<?>>> attributeMap, +                             Map<String, Object> result, AttributeDefinition<?> el) { +    final List<String> natPersonIdObj = EidasResponseUtils +        .translateStringListAttribute(el, attributeMap.get(el)); +    final String stringAttr = natPersonIdObj.get(0); +    if (StringUtils.isNotEmpty(stringAttr)) { +      result.put(el.getFriendlyName(), stringAttr); + +    } +  } + +  private void convertPostalAddress(ImmutableMap<AttributeDefinition<?>, +                                    ImmutableSet<? extends AttributeValue<?>>> attributeMap, +                                    Map<String, Object> result, AttributeDefinition<?> el) { +    final PostalAddress addressAttribute = EidasResponseUtils +        .translateAddressAttribute(el, attributeMap.get(el).asList()); +    if (addressAttribute != null) { +      result.put(el.getFriendlyName(), addressAttribute); + +    } +  } + +  private void convertDateTime(ImmutableMap<AttributeDefinition<?>, +                               ImmutableSet<? extends AttributeValue<?>>> attributeMap, +                               Map<String, Object> result, AttributeDefinition<?> el) { +    final DateTime attribute = EidasResponseUtils.translateDateAttribute(el, attributeMap.get(el).asList()); +    if (attribute != null) { +      result.put(el.getFriendlyName(), attribute); + +    } +  } +} diff --git a/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/CreateIdentityLinkTaskEidNewTest.java b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/CreateIdentityLinkTaskEidNewTest.java index 36c0c2af..9060762c 100644 --- a/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/CreateIdentityLinkTaskEidNewTest.java +++ b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/CreateIdentityLinkTaskEidNewTest.java @@ -1,6 +1,7 @@  package at.asitplus.eidas.specific.modules.auth.eidas.v2.test.tasks;  import static at.asitplus.eidas.specific.core.MsEidasNodeConstants.PROP_CONFIG_SP_NEW_EID_MODE; +import static org.junit.Assert.assertNull;  import static org.mockito.ArgumentMatchers.any;  import static org.mockito.Mockito.times;  import static org.mockito.Mockito.verify; @@ -262,11 +263,10 @@ public class CreateIdentityLinkTaskEidNewTest {      Assert.assertNotNull("no piiTransactionId in pendingRequesdt",          storedPendingReq.getUniquePiiTransactionIdentifier()); -    Assert.assertEquals("piiTransactionId", storedPendingReq.getUniquePiiTransactionIdentifier(), -        authBlockJson.get("piiTransactionId").asText()); -    Assert.assertEquals("appId", randomTestSp, authBlockJson.get("appId").asText());      Assert.assertFalse("'challenge' is null", authBlockJson.get("challenge").asText().isEmpty()); -    Assert.assertFalse("'timestamp' is null", authBlockJson.get("timestamp").asText().isEmpty()); +    Assert.assertFalse("'timestamp' is null", authBlockJson.get("issuedAt").asText().isEmpty());    +    assertNull("piiTransactionId", authBlockJson.get("piiTransactionId")); +    assertNull("appId", authBlockJson.get("appId"));      Assert.assertFalse("binding pubKey", authBlockJson.has("bindingPublicKey")); @@ -385,12 +385,12 @@ public class CreateIdentityLinkTaskEidNewTest {      Assert.assertNotNull("deserialized AuthBlock", authBlockJson);      Assert.assertNotNull("no piiTransactionId in pendingRequesdt",  -        storedPendingReq.getUniquePiiTransactionIdentifier()); -    Assert.assertEquals("piiTransactionId", storedPendingReq.getUniquePiiTransactionIdentifier(),  -        authBlockJson.get("piiTransactionId").asText()); -    Assert.assertEquals("appId", randomTestSp, authBlockJson.get("appId").asText());     +        storedPendingReq.getUniquePiiTransactionIdentifier());          Assert.assertFalse("'challenge' is null", authBlockJson.get("challenge").asText().isEmpty()); -    Assert.assertFalse("'timestamp' is null", authBlockJson.get("timestamp").asText().isEmpty()); +    Assert.assertFalse("'timestamp' is null", authBlockJson.get("issuedAt").asText().isEmpty());    +    assertNull("piiTransactionId", authBlockJson.get("piiTransactionId")); +    assertNull("appId", authBlockJson.get("appId")); +          Assert.assertTrue("binding pubKey", authBlockJson.has("bindingPublicKey"));      Assert.assertEquals("binding PubKey", bindingPubKey, authBlockJson.get("bindingPublicKey").asText()); | 
